B001-Atmega16-digital tube

Publisher:BlossomJoyLatest update time:2022-01-12 Source: eefocusKeywords:Atmega16 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Complete the digital tube step by step


main content:

Step 1: Generate a 1ms time base

Step 2: Static Display

Step 3: Dynamic Scanning

Step 4: Afterglow and Ghosting

Step 5: Task function with message mechanism

Step 6: Display in the specified base



-------------------------------------------------------------------------------------------------------------------------------------

Development environment: AVR Studio 4.19 + avr-toolchain-installer-3.4.1.1195-win32.win32.x86

Chip model: ATmega16

Chip frequency: 8MHz


-------------------------------------------------------------------------------------------------------------------------------------

Step 1: Generate a 1ms time base

illustrate:

1. Use the CTC interrupt of timer 0 to generate a 1ms time base signal. In CTC mode, the initial value is automatically reloaded, which is more convenient.

2. Use OCF0 interrupt and do not need OC0 pin to output waveform.

Code:

Relevant definitions in Drv_Timer.h:

// -------------------

// Timer interrupt mode

typedef enum 

{

    INT_MODE_TOV = 0,

    INT_MODE_OCF = 1,

    INT_MODE_ICF = 2,

    INT_MODE_OCF1A = 3,

    INT_MODE_OCF1B = 4

} TIMER_INT_MODE;

 

//Timer compare match pin output mode

typedef enum 

{

    COM_MODE_NONE   = 0,

    COM_MODE_TOGGLE = 1,

    COM_MODE_CLEAR  = 2,

    COM_MODE_SET    = 3,

} TIMER_COM_MODE;

 

// Timer 0

typedef enum 

{

    T0_WGM_NOMAL = 0,

    T0_WGM_PHASE_PWM = 1,

    T0_WGM_CTC = 2,

    T0_WGM_FAST_PWM  = 3,

 

    T0_CLK_SOURCE_NONE     = 0,

    T0_CLK_SOURCE_CLK_1    = 1,

    T0_CLK_SOURCE_CLK_8    = 2,

    T0_CLK_SOURCE_CLK_64   = 3,

    T0_CLK_SOURCE_CLK_256  = 4,

    T0_CLK_SOURCE_CLK_1024 = 5,

    T0_CLK_SOURCE_T0_FALL  = 6,

    T0_CLK_SOURCE_T0_RAISE = 7

} TIMER0_MODE;

Operation function in Drv_Timer.c:

// ==========================================================================================================

//TIMER0 initialization

// 

// Parameter: wave_mode working mode/waveform generation mode selection

// OC_mode compare match/PWM output mode selection

// clk_source clock source and prescaler selection

// 

// When writing TCCR0, you need to clear bit7=FOC0

// 

// Timer overflow period T = ((1.0 / 8000000) * 1000000) * clk_source * 256 ( @ 8MHz )

// ==========================================================================================================

void Drv_Timer0_init(const uint8_t wave_mode, const uint8_t com_mode, const uint8_t clk_source)

{

    uint8_t wgm00,wgm01;

 

    wgm00 =  wave_mode & 0x01;

    wgm01 = (wave_mode & 0x02) >> 1;

 

    // When writing TCCR0, you need to clear bit7=FOC0 to 0

    TCCR0 = (wgm00 << 6)| // Operation mode/waveform generation mode selection

            (wgm01 << 3)|

            ((com_mode & 0x03) << 4)| // Compare match/PWM output mode selection

            ((clk_source & 0x07) << 0); // Clock source and prescaler selection

}

 

// ==========================================================================================================

//TIMER0 interrupt enable

// 

// Parameter: int_mode = INT_MODE_TOV or INT_MODE_OCF or INT_MODE_ICF

//       enable    = ENABLE 或 DISABLE

// 

// illustrate:

// 1. OC0 pin must first be configured as a compare match pin, and then modify the data direction register DDB3

// 2. You can enable/disable interrupts of a mode separately

// 

// ==========================================================================================================

void Drv_Timer0_INT_Enable(const uint8_t int_mode, const uint8_t enable)

{

    if(INT_MODE_TOV == int_mode)

    {

        if(DISABLE == enable)

        {

            TIMSK &= ~(1 << TOIE0);

        }

        else

        {

            TIMSK |=  (1 << TOIE0);

        }

        TIFR |= (1 << TOV0);

        return ;

    }

    if(INT_MODE_OCF == int_mode)

    {

        if(DISABLE == enable)

        {

            TIMSK &= ~(1 << OCIE0);

        }

        else

        {

            TIMSK |=  (1 << OCIE0);

        }

        TIFR |= (1 << OCF0);

    }

}

 

// ==========================================================================================================

// Set the values ​​of TCNT0 and OCR0

// 

// (1). Under compare match, OCR0 needs to be set after TCNT0 is set

// ==========================================================================================================

void Drv_Timer0_set_TCNT0_OCR0(const uint8_t tcnt0, const uint8_t ocr0)

{

    TCNT0 = tcnt0;

    OCR0  = ocr0;

}

Set timer 0 in sys_timer.c and use PA1 to test the timing in OCF0 interrupt:

#include

#include "Drv_Timer.h"

#include "sys_timer.h"

 

// ==========================================================================================================

// System task timer

// 

// (1). Use Timer0 to generate a 1ms time stamp

// Timing period T = ((1.0/8000000)*1000000)*64*(124+1) = 1000us = 1ms

// 

// ==========================================================================================================

void sys_timer_init(void)

{

    // Timer 0 initialization: CTC mode, OC0 pin not connected, 64 prescaler

    Drv_Timer0_init(T0_WGM_CTC, COM_MODE_NONE, T0_CLK_SOURCE_CLK_64);

    // Set initial values: TCNT0=0, OCR0=122

    Drv_Timer0_set_TCNT0_OCR0(0, 122);

    // Enable OCF0 interrupt

    Drv_Timer0_INT_Enable(INT_MODE_OCF, ENABLE);

}

 

// ==========================================================================================================

// System timer interrupt

// 

// (1). Use Timer0's CTC interrupt to schedule each task

// 

// ==========================================================================================================

ISR(TIMER0_COMP_vect)

{

    PORTA ^= (1 << PA1); // Use PA1 to test the timing period

}

Initialization is completed in main.c, and IO is set:

// ==========================================================================================================

// Main function

// ==========================================================================================================

#include

#include "Drv_Timer.h"

#include "system.h"

#include "sys_timer.h"

#include "config.h"

 

// ==========================================================================================================

//main function

// ==========================================================================================================

int main(void)

{

    // ---------

    // Turn off global interrupts

    cli();

 

    // System initialization (including sys_timer_init())

    sys_init();

 

    DDRA |= (1 << DDA0) | (1 << DDA1);

    PORTA &= ~((1 << PA0 ) | (1 << PA1 ));

 

    // OC0/PB3 is initialized to output 0

    DDRB |= (1 << DDB3);

    PORTB &= ~((1 << PB3 ));

 

    // Enable global interrupt

    be();

 

    // ---------

    while(1)

    {

    }

    return 0;

}


Test Results:

The oscilloscope output is as follows:

1. The PA1 pin outputs a square wave with a period of 2*1.0ms, and the pin level flips every 1.0ms.

      Use OCR0=124 and calculate to get an exact 1.0ms, but it takes time to enter the interrupt function.

      So here we use a slightly smaller OCR0=122, so that the time from interrupt generation to entering the interrupt function is more accurate to 1.0ms

      Some timing functions will accumulate time base errors, and the accumulated errors will become larger as time goes by, so try to be as precise as possible here.

      At this point, the 1.0ms timing is completed.

2. The OC0 pin has no waveform output, and we do not need to use this pin, so let it maintain the characteristics of ordinary IO.


-------------------------------------------------------------------------------------------------------------------------------------

Step 2: Static Display

illustrate:

1. This step requires displaying the specified symbol on the specified digital tube according to the circuit diagram.


1. Digital tube drive circuit diagram:

The circuit uses a common cathode digital tube:

A digital tube has 8 LEDs, which is called an 8-segment digital tube.


Common cathode means:

1. The negative poles of the 8 LEDs are connected to the com pin

2. The positive poles of the 8 LEDs correspond to 8 pins, numbered [Dp, g, f, e, d, c, b, a]


The voltage and current of the digital tube:

The current required to light up one digital tube can be found by looking up the digital tube data sheet provided by the manufacturer.

If there is no data sheet, you can estimate it to be 10-20mA and the voltage to be 2V.


Like ordinary LEDs, current limiting resistors need to be added when necessary.


In dynamic scanning, each digital tube is lit for a few milliseconds and off for tens of milliseconds, not lit all the time, so it is okay not to add a current limiting resistor, unless it is a high-current digital tube.

The driver chips of the digital tubes are 74HC138 and 74HC573, and their driving current is enough to light up one digital tube:


2. Lighting method of common cathode digital tube:

1. Input a high level at pin a, input a low level at pin b-Dp, and input a low level at com pin.

       Then, segment [a] is lit, and segments [Dp,g,f,e,d,c,b] are not lit.

       That is, only the segments whose input state is high will be lit.

2. Input high level at pins b and c, input low level at pins a and d-Dp, and input low level at com pin.

       Then, segment [b,c] is lit, and segments [a,d,e,f,g,Dp] are not lit.

       The image obtained at this time is the image of the number '1', and the corresponding segment code [Dp,g,f,e,d,c,b,a]=0b00000110=0x06.

3. Input high level at pins a, b, g, e, and d, input low level at pins c, f, and Dp, and input low level at the com pin.

       Then, segments [a,b,g,e,d] are lit, and segments [c,f,Dp] are not lit.

       The image obtained at this time is the image of the number '2', and the corresponding segment code [Dp,g,f,e,d,c,b,a]=0b01011011=0x5B.

4. That is to say, the digital tube with low level at com port is enabled, and if there is a segment not equal to 0 in its segment selection, this segment will be lit.


3. Segment code:

1. The segment codes of 16 hexadecimal digits [0-9, AF] are as follows:

static const uint8_t segment_code[17]=

{

    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,  // 0 - 9

[1] [2] [3] [4] [5]
Keywords:Atmega16 Reference address:B001-Atmega16-digital tube

Previous article:Atmega16 - BSP and Task List
Next article:A005-Software Structure-From Frontend and Backend to Scheduler

Recommended ReadingLatest update time:2024-11-17 09:36

How to interface Hall sensor using AVR microcontroller ATmega16
The working principle of the Hall sensor is based on the Hall effect proposed by Edwin Hall in 1869. The proposed statement says: "The Hall effect is the production of a voltage difference (the Hall voltage) across an electrical conductor, transverse to the current in the conductor and an applied magnetic field perpen
[Microcontroller]
How to interface Hall sensor using AVR microcontroller ATmega16
Using 89S51 to Make a Simple Parallel Programmer ATmega16
;**************************ATmega16(L) Simple Parallel Programmer**********************/  ;Description:  ;For friends who have not programmed ATmega16 parallel programmer, engineers who first used ATmega16 may  write wrong fuse bits and encryption bits during serial programming, which makes serial programming unusable
[Microcontroller]
Atmega16 based voltage meter production program + schematic diagram
The attached proteus design diagram and circuit diagram are in the attachment   /***************************************************** Project :  Version :  Date    : 2015-10-29 Author  :tengzaiba Chip type               : ATmega16 AVR Core Clock frequency: 8.000000 MHz ************************************************
[Microcontroller]
Atmega16 based voltage meter production program + schematic diagram
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号