Tuesday, August 24, 2021

Using Timer/Counter0 of Atmega16 To Multiplex A Display

 

Introduction

A an ATMega16 Timer/Counter0 tutorial, we have briefly demonstrated about its technical details and usage. Setting up its clock source, prescaler, and checking/clearing its interrupt flag is done with less than a dozen of codes in AVR GCC.

Using Timer/Counter0 To Multiplex A Display

As it’s usually mentioned, a timer could be used to create a timing delay. But a delay time powered by a timer is very flexible. The program doesn’t need to wait until the delay time ended. It just required to check the timer interrupt flag for a short time as the code was written. Remaining CPU time will execute others remaining task.

With this advantage we can use this timer delay to multiplex a multi-digits seven-segments display without wasting the CPU cycle time executing the program. As it’s implemented in a previous article, a multiplexing display was driven by a delay which was not responsive.



Timer/Counter0 Programming For A Multiplexing Display

Overview

We will use Timer/Counter0 to create a timer tick with a rate of 1ms. This 1ms timer tick drive a six-digits seven-segments display. But Each digit was active for only a 2ms period.

The program use Timer/Counter0 timer tick to drive the display. This timer tick also activate a counting variable that will regularly update on the display for every 100ms.

Hardware Preparation



This program will test on an AVR development board. So the schematic diagram is no other than the one’s on-board, as it’s appeared in some previous article.

Using Timer/Counter0 To Multiplex A Display
Schematic Diagram for this example

 

The display is a green, 0.36″ common cathode type display. The ATMega16 microcontroller clocks at 16MHz from an on-board crystal clock. Port B drives the segments while Port C drive the digits.

AVR Programming Preparation

Driving Timer/Counter0 clock source directly from the on-board crystal oscillator should be inappropriate. The software must scale this clock frequency to a reasonable frequency. The software is coded to scale this clock frequency to 1:64 that will beat TCNT0 at the rate of,

64*(1/16MHz) = 4 us

Timer/Counter0 trigger its interrupt flag for every,



256*4us = 1024us which approximate to 1 ms.

As the real hardware test, each digit must be activated for within a duration of 2ms. So an additional counter variable must be place to keep track of this 1ms timer tick.

Source code is written using a higher level programming language AVR GCC in Atmel Studio 7.

  1. /*
  2.  * timer_0_multiplexed_disp.c
  3.  *
  4.  * Created: 12/9/2020 10:04:30 AM
  5.  * Author : admin
  6.  */
  7.  
  8. #include <avr/io.h>
  9.  
  10. void driveDisplay(void);
  11. void timerTick(void);
  12.  
  13. unsigned char oneMillis=0;
  14. unsigned int oneSecond=0;
  15. unsigned long secondCount=0;
  16.  
  17. int main(void)
  18. {
  19. /*Port B drive the segments*/
  20. DDRB=0xFF;
  21. /*Port C drive the digits*/
  22. DDRC=0xFF;
  23. /*Timer/Counter0 Set to 1:64 Pre-scaler*/
  24. TCCR0=(1<<CS01)|(1<<CS00);
  25. /*Clear TOV0 Flag*/
  26. TIFR=(1<<TOV0);
  27. /*Clear Timer/Counter0 Register*/
  28. TCNT0=0;
  29. while (1)
  30. {
  31. /*Timer Task*/
  32. timerTick();
  33. /*Display The Numbers*/
  34. driveDisplay();
  35. }
  36. }
  37.  
  38. void driveDisplay(void){
  39. unsigned char cCathode[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
  40. switch(oneMillis){
  41. /*100000's digit*/
  42. case 0: PORTC=0x00;
  43. PORTB=cCathode[secondCount/100000];
  44. PORTC=(1<<5);
  45. break;
  46. /*10000's digit*/
  47. case 2: PORTC=0x00;
  48. PORTB=cCathode[(secondCount%100000)/10000];
  49. PORTC=(1<<6);
  50. break;
  51. /*1000's digit*/
  52. case 4: PORTC=0x00;
  53. PORTB=cCathode[(secondCount%10000)/1000];
  54. PORTC=(1<<7);
  55. break;
  56. /*100's digit*/
  57. case 6: PORTC=0x00;
  58. PORTB=cCathode[(secondCount%1000)/100];
  59. PORTC=(1<<2);
  60. break;
  61. /*10's digit*/
  62. case 8: PORTC=0x00;
  63. PORTB=cCathode[(secondCount%100)/10];
  64. PORTC=(1<<3);
  65. break;
  66. /*1's digit*/
  67. case 10:PORTC=0x00;
  68. PORTB=cCathode[secondCount%10];
  69. PORTC=(1<<4);
  70. break;
  71. }
  72. }
  73.  
  74. void timerTick(void){
  75. /*Check the 1ms timer tick*/
  76. if (TIFR&(1<<TOV0))
  77. {
  78. TIFR=(1<<TOV0);
  79. /*this variable drive all six digits*/
  80. if(oneMillis>10) oneMillis=0;
  81. else oneMillis++;
  82. oneSecond++;
  83. }
  84. /*Check if it's 0.1 second*/
  85. if (oneSecond>98)
  86. {
  87. oneSecond=0;
  88. secondCount++;
  89. }
  90. }

Using Timer/Counter0 To Multiplex A Display
Program testing on the ATMega16 AVR development board

The number shown on the display was a result of a long term running program since the board powered up.

Without a development board, or an absence of physical hardware prototyping we can use Proteus to test this programming example in simulator.

Using Timer/Counter0 To Multiplex A Display
Programming running on simulator

 This program works well on the ATMega16 AVR development board. This is a video of this example on YouTube.


No comments:

Post a Comment

Labels

ADC (10) Analog (14) Arduino (12) Atmega16 (19) Audio (2) AVR (20) Charger (1) Cortex-M0 (1) Counter (10) CPLD (25) Digital I/O (22) Display (34) EEPROM (2) Environment Sensor (1) esp8266 (2) Experiment Board (10) I2C (4) Interrupt (7) LCD (1) LDmicro (29) measurement and instrumentation (7) Microchip Studio (3) MikroC (1) One-Shot (3) OpAmp (1) PCB (31) PIC16 Microcontrollers (16) PIC16F877A (2) PIC16F887 MikroC (22) PLC (35) PWM (11) Regulator (1) RTC (2) Sensor (8) Shift Registers (5) SPI (5) Timer (34) UART (2) ultra-sonic sensor (1) USB (1) VHDL (21) xc8 (1) XC95108 (9) XC9536 (15) XC9572 (1) Xilinx (23) Xilinx ISE (22)