Rev 3460 Rev 3618
1 // timer_demo2.c 1 // timer_demo2.c
2 // ------------- 2 // -------------
3 // 3 //
4 // Example file for ATmega88 (and similar AVR chips) demonstrating how to use 4 // Example file for ATmega88 (and similar AVR chips) demonstrating how to use
5 // timer interrupt to realize Clocks with LED display. 5 // timer interrupt to realize Clocks with LED display.
6 // 6 //
7 // The program uses TIMER1 to generate interrupts and the interrupt routine counts 7 // The program uses TIMER1 to generate interrupts and the interrupt routine counts
8 // fragments of second, seconds, tens of seconds etc. In the same interrupt routine 8 // fragments of second, seconds, tens of seconds etc. In the same interrupt routine
9 // the display multiplex is done. We use 4 digit 7 segment display. 9 // the display multiplex is done. We use 4 digit 7 segment display.
10 // Common anodas are connected to LED_DIGITS_PORT and segments are connected 10 // Common anodas are connected to LED_DIGITS_PORT and segments are connected
11 // to LED_SEGMENTS_PORT (use serial rezistors here, cca 100 OHM). 11 // to LED_SEGMENTS_PORT (use serial rezistors here, cca 100 OHM).
12 // 12 //
13 // (c) miho 2014 http://www.mlab.cz 13 // (c) miho 2014 http://www.mlab.cz
14 // 14 //
15 // History 15 // History
16 // 2014 01 31 - First demo 16 // 2014 01 31 - First demo
-   17 // 2014 02 07 - Added support for Comon Anoda / Comon Catoda
17   18  
18   19  
19 // System Configuration 20 // System Configuration
20 #define F_CPU 4000000 // Do not forget to set FUSEs to external XTAL osc with DIV/8 off and connect xtal 21 #define F_CPU 4000000 // Do not forget to set FUSEs to external XTAL osc with DIV/8 off and connect xtal
21   22  
22 // LED Display - Configuration 23 // LED Display - Configuration
-   24 #define LED_COMON_ANODA 0 // 0=Comon Catoda / 1=Comon Anoda
23 #define LED_DIGITS_PORT C // Digits Port (common anodas) 25 #define LED_DIGITS_PORT C // Digits Port (common anodas or comon catodas)
24 #define LED_DIGITS 4 // Number of display digits (1..8) 26 #define LED_DIGITS 6 // Number of display digits (1..8)
25 #define LED_SEGMENTS_PORT D // Segments Port (catodas) 27 #define LED_SEGMENTS_PORT D // Segments Port (catodas or anodas)
26 #define LED_SEGMENTS 8 // Usualy 7 or 8 (bit 0 is A) 28 #define LED_SEGMENTS 8 // Usualy 7 or 8 (bit 0 is A)
27 #define TICKS_PER_SEC 500 // Number of interrupts per second ( >250 to look steady) 29 #define TICKS_PER_SEC 500 // Number of interrupts per second ( >250 to look steady)
28   30  
29   31  
30 // -------------- DO NOT EDIT BELOW THIS LINE -------------- 32 // -------------- DO NOT EDIT BELOW THIS LINE --------------
31   33  
32   34  
33 // LED Display - Internal Defs 35 // LED Display - Internal Defs
34 #define LED_DIGITS_MASK ((1<<LED_DIGITS)-1) // For 4 digits 0x0F=0b00001111 36 #define LED_DIGITS_MASK ((1<<LED_DIGITS)-1) // For 4 digits 0x0F=0b00001111
35 #define LED_SEGMENTS_MASK ((1<<LED_SEGMENTS)-1) // For 7 segments 0x7F=0b01111111 37 #define LED_SEGMENTS_MASK ((1<<LED_SEGMENTS)-1) // For 7 segments 0x7F=0b01111111
36   38  
37   39  
38 // LED Display - Verify Configuration 40 // LED Display - Verify Configuration
39 #if (F_CPU / 64 % TICKS_PER_SEC) 41 #if (F_CPU / 64 % TICKS_PER_SEC)
40 #error "TICKS_PER_SEC" should be chosen so that "F_CPU / 64 / TICKS_PER_SEC" is a whole number! 42 #error "TICKS_PER_SEC" should be chosen so that "F_CPU / 64 / TICKS_PER_SEC" is a whole number!
41 #endif 43 #endif
42 #if ( (F_CPU / 64 / TICKS_PER_SEC) > 65536) 44 #if ( (F_CPU / 64 / TICKS_PER_SEC) > 65536)
43 #error "TICKS_PER_SEC" should be chosen bigger (timer is long 16bit only)! 45 #error "TICKS_PER_SEC" should be chosen bigger (timer is long 16bit only)!
44 #endif 46 #endif
45   47  
46   48  
47 // Library Headers 49 // Library Headers
48 #include <avr/interrupt.h> 50 #include <avr/interrupt.h>
49   51  
50   52  
51 // Compatibility ATmega8 / ATmega88 53 // Compatibility ATmega8 / ATmega88
52 #ifndef TIMSK 54 #ifndef TIMSK
53 #define TIMSK TIMSK1 55 #define TIMSK TIMSK1
54 #endif 56 #endif
55   57  
56   58  
57 // Macro for Port (enables to easily define IO signals) 59 // Macro for Port (enables to easily define IO signals)
58 #define GLUE(A,B) A##B 60 #define GLUE(A,B) A##B
59 #define DDR(PORT_LETTER) GLUE(DDR, PORT_LETTER) // Makes DDRC from DDR(C) etc. 61 #define DDR(PORT_LETTER) GLUE(DDR, PORT_LETTER) // Makes DDRC from DDR(C) etc.
60 #define PORT(PORT_LETTER) GLUE(PORT,PORT_LETTER) // Makes PORTC from PORT(C) 62 #define PORT(PORT_LETTER) GLUE(PORT,PORT_LETTER) // Makes PORTC from PORT(C)
61 #define PIN(PORT_LETTER) GLUE(PIN, PORT_LETTER) // Makes PINC from PIN(C) 63 #define PIN(PORT_LETTER) GLUE(PIN, PORT_LETTER) // Makes PINC from PIN(C)
62   64  
63   65  
64 // 7 Segment Decoder 66 // 7 Segment Decoder
65 unsigned char Convert(unsigned char Number) 67 unsigned char Convert(unsigned char Number)
66 { 68 {
67 // 7 Segment Decoder Table 69 // 7 Segment Decoder Table
-   70 // A
-   71 // ---
-   72 // F| | B
-   73 // | G |
-   74 // ---
-   75 // E| | C
-   76 // | |
-   77 // --- * H
-   78 // D
68 const unsigned char Decoder[] = 79 const unsigned char Decoder[] =
69 { 80 {
70 // HGFEDCBA 81 // HGFEDCBA
71 0b00111111, // 0 82 0b00111111, // 0
72 0b00000011, // 1 83 0b00000110, // 1
73 0b01101101, // 2 84 0b01011011, // 2
74 0b01100111, // 3 85 0b01001111, // 3
75 0b01010011, // 4 86 0b01100110, // 4
76 0b01110110, // 5 87 0b01101101, // 5
77 0b01111110, // 6 88 0b01111101, // 6
78 0b00100011, // 7 89 0b00000111, // 7
79 0b01111111, // 8 90 0b01111111, // 8
-   91 0b01101111, // 9
80 0b01110111 // 9 92 0b01110111, // A
-   93 0b01111100, // b
-   94 0b00111001, // C
-   95 0b01011100, // d
-   96 0b01111001, // E
-   97 0b01110000 // F
81 }; 98 };
82   99  
83 // Decoding Function 100 // Decoding Function
84 if(Number<sizeof(Decoder)) return Decoder[Number]; else return 0; 101 if(Number<sizeof(Decoder)) return Decoder[Number]; else return 0;
85 } 102 }
86   103  
87   104  
88 // Global Variable - Time Counters 105 // Global Variable - Time Counters
89 volatile unsigned int Fractions; // 1/100s 106 volatile unsigned int Fractions; // 1/100s
90 volatile unsigned char Seconds, Seconds10; // Seconds and tens of seconds 107 volatile unsigned char Seconds, Seconds10; // Seconds and tens of seconds
91 volatile unsigned char Minutes, Minutes10; // Minutes and tens of minutes 108 volatile unsigned char Minutes, Minutes10; // Minutes and tens of minutes
92 volatile unsigned char Hours, Hours10; // Hours and tens of hours 109 volatile unsigned char Hours, Hours10; // Hours and tens of hours
93   110  
94   111  
95 // Global Variable - Display Multiplex 112 // Global Variable - Display Multiplex
96 volatile unsigned char DisplayDigit; // Multiplex state 0 1 2 3 (binary counter) 113 volatile unsigned char DisplayDigit; // Multiplex state 0 1 2 3 (binary counter)
97 volatile unsigned char DisplayDigitMask; // Multiplex state 1 2 4 8 (mask 1 from N) 114 volatile unsigned char DisplayDigitMask; // Multiplex state 1 2 4 8 (mask 1 from N)
98   115  
99   116  
100 // Interrupt Routine for TIMER1 Output Compare A 117 // Interrupt Routine for TIMER1 Output Compare A
101 // Activated 500 per second 118 // Activated 500 per second
102 ISR(TIMER1_COMPA_vect) 119 ISR(TIMER1_COMPA_vect)
103 { 120 {
104 // Every 1/500s 121 // Every 1/500s
105 Fractions++; 122 Fractions++;
106 if (Fractions>(TICKS_PER_SEC-1)) 123 if (Fractions>(TICKS_PER_SEC-1))
107 { 124 {
108 // Every 1s 125 // Every 1s
109 Fractions=0; 126 Fractions=0;
110 Seconds++; 127 Seconds++;
111 if (Seconds>9) 128 if (Seconds>9)
112 { 129 {
113 // Every 10s 130 // Every 10s
114 Seconds = 0; 131 Seconds = 0;
115 Seconds10++; 132 Seconds10++;
116 if (Seconds10>5) 133 if (Seconds10>5)
117 { 134 {
118 // Every 1m 135 // Every 1m
119 Seconds10=0; 136 Seconds10=0;
120 Minutes++; 137 Minutes++;
121 if (Minutes>9) 138 if (Minutes>9)
122 { 139 {
123 // Every 10m 140 // Every 10m
124 Minutes=0; 141 Minutes=0;
125 Minutes10++; 142 Minutes10++;
126 if (Minutes10>5) 143 if (Minutes10>5)
127 { 144 {
128 // Every 1h 145 // Every 1h
129 Minutes10=0; 146 Minutes10=0;
130 Hours++; 147 Hours++;
131 if (Hours10==2 && Hours>3) 148 if (Hours10==2 && Hours>3)
132 { 149 {
133 // Every Day 150 // Every Day
134 Hours=0; 151 Hours=0;
135 Hours10=0; 152 Hours10=0;
136 } 153 }
137 if (Hours>9) 154 if (Hours>9)
138 { 155 {
139 // At 10 and 20 hours 156 // At 10 and 20 hours
140 Hours=0; 157 Hours=0;
141 Hours10++; 158 Hours10++;
142 } 159 }
143 } 160 }
144 } 161 }
145 } 162 }
146 } 163 }
147 } 164 }
148   165  
149 // LED display time multiplex - next digit 166 // LED display time multiplex - next digit
150 // 500x per second 167 // 500x per second
151 DisplayDigit++; 168 DisplayDigit++;
152 DisplayDigitMask<<=1; 169 DisplayDigitMask<<=1;
153 if (DisplayDigit == LED_DIGITS) 170 if (DisplayDigit == LED_DIGITS)
154 { 171 {
155 DisplayDigit = 0; 172 DisplayDigit = 0;
156 DisplayDigitMask = 1; 173 DisplayDigitMask = 1;
157 } 174 }
158   175  
159 // Get Segment Combination for Current Digit 176 // Get Segment Combination for Current Digit
160 unsigned char Segments=0; 177 unsigned char Segments=0;
161 switch(DisplayDigit) 178 switch(DisplayDigit)
162 { 179 {
163 case 0: Segments = Convert(Seconds); 180 case 0: Segments = Convert(Seconds);
164 break; 181 break;
165 case 1: Segments = Convert(Seconds10); 182 case 1: Segments = Convert(Seconds10);
166 break; 183 break;
167 case 2: Segments = Convert(Minutes); 184 case 2: Segments = Convert(Minutes);
168 break; 185 break;
169 case 3: Segments = Convert(Minutes10); 186 case 3: Segments = Convert(Minutes10);
-   187 break;
-   188 case 4: Segments = Convert(Hours);
-   189 break;
-   190 case 5: Segments = Convert(Hours10);
-   191 break;
170 } 192 }
-   193 #if LED_COMON_ANODA==0
-   194 // LED display update - All digits off
-   195 PORT(LED_DIGITS_PORT) |= LED_DIGITS_MASK; // common catoda 1=off
-   196 // LED display update - New segments combination
-   197 PORT(LED_SEGMENTS_PORT) = (PORT(LED_SEGMENTS_PORT) & ~LED_SEGMENTS_MASK) | (Segments & LED_SEGMENTS_MASK);
-   198 // LED display update - One digit on
-   199 PORT(LED_DIGITS_PORT) &= ~(LED_DIGITS_MASK & DisplayDigitMask); // (common anoda 0=on)
171   200 #else
172 // LED display update - All digits off 201 // LED display update - All digits off
173 PORT(LED_DIGITS_PORT) &= ~LED_DIGITS_MASK; // common anoda 0=off 202 PORT(LED_DIGITS_PORT) &= ~LED_DIGITS_MASK; // common anoda 0=off
174 // LED display update - New segments combination 203 // LED display update - New segments combination
175 PORT(LED_SEGMENTS_PORT) = (PORT(LED_SEGMENTS_PORT) & ~LED_SEGMENTS_MASK) | (~Segments & LED_SEGMENTS_MASK); 204 PORT(LED_SEGMENTS_PORT) = (PORT(LED_SEGMENTS_PORT) & ~LED_SEGMENTS_MASK) | (~Segments & LED_SEGMENTS_MASK);
176 // LED display update - One digit on 205 // LED display update - One digit on
177 PORT(LED_DIGITS_PORT) |= (LED_DIGITS_MASK & DisplayDigitMask); // (common anoda 1=on) 206 PORT(LED_DIGITS_PORT) |= (LED_DIGITS_MASK & DisplayDigitMask); // (common anoda 1=on)
-   207 #endif
178 } 208 }
179   209  
180   210  
181 // Main 211 // Main
182 int main() 212 int main()
183 { 213 {
184 // Enable LED Display Output 214 // Enable LED Display Output
185 DDR(LED_SEGMENTS_PORT) |= LED_SEGMENTS_MASK; // 8 segments 0b11111111 215 DDR(LED_SEGMENTS_PORT) |= LED_SEGMENTS_MASK; // 8 segments 0b11111111
186 DDR(LED_DIGITS_PORT) |= LED_DIGITS_MASK; // 4 digits 0b00001111 216 DDR(LED_DIGITS_PORT) |= LED_DIGITS_MASK; // 4 digits 0b00001111
187   217  
188 // Set MAX value for Timer1 218 // Set MAX value for Timer1
189 OCR1A = (F_CPU+64/2)/64/TICKS_PER_SEC-1; // 1/500s 219 OCR1A = (F_CPU+64/2)/64/TICKS_PER_SEC-1; // 1/500s
190   220  
191 // Set Timer1 to CTC with presacaller 1/64 221 // Set Timer1 to CTC with presacaller 1/64
192 // CTC Mmode counts from 0 to value stored in OCR1A 222 // CTC Mmode counts from 0 to value stored in OCR1A
193 // and generates interrupt every time it goes back to 0 223 // and generates interrupt every time it goes back to 0
194 TCCR1B |= (1<<CS11) | (1<<CS10) | (1<<WGM12); 224 TCCR1B |= (1<<CS11) | (1<<CS10) | (1<<WGM12);
195   225  
196 // Enable Interrupt for Timer1 OCRA 226 // Enable Interrupt for Timer1 OCRA
197 TIMSK |= (1<<OCIE1A); 227 TIMSK |= (1<<OCIE1A);
198   228  
199 // Enable Global (CPU) Interrupt 229 // Enable Global (CPU) Interrupt
200 sei(); 230 sei();
201   231  
202 // Main Loop 232 // Main Loop
203 for(;;) 233 for(;;)
204 { 234 {
205 // Do any job here 235 // Do any job here
206 } 236 }
207   237  
208 return 0; 238 return 0;
209 } 239 }