1 | /*
|
2 | # Autor: Richard Brose
|
3 | # Title: eClock V0.1
|
4 | */
|
5 |
|
6 | /*
|
7 | 7-SEG:
|
8 | PB0 - 1-e
|
9 | PB1 - 2-d
|
10 | PB2 - 4-c
|
11 | PB3 - 6-b
|
12 | PB4 - 7-a
|
13 | PB5 - 9-f
|
14 | PB6 - 10-g
|
15 | */
|
16 |
|
17 | #include <avr/io.h>
|
18 | #include <stdint.h>
|
19 | #include <avr/pgmspace.h>
|
20 | #include <avr/interrupt.h>
|
21 |
|
22 | #ifndef F_CPU
|
23 | #define F_CPU 4000000
|
24 | #endif
|
25 |
|
26 | #include <util/delay.h>
|
27 |
|
28 |
|
29 | #define IRQS_PER_SECOND 8000 /* 500 us */
|
30 |
|
31 | #define IRQS_PER_10MS (IRQS_PER_SECOND / 100)
|
32 |
|
33 | #if (F_CPU/IRQS_PER_SECOND > 65536) || (IRQS_PER_10MS < 1) || (IRQS_PER_10MS > 255)
|
34 | # error Diese Werte fuer F_CPU und IRQS_PER_SECOND
|
35 | # error sind ausserhalb des gueltigen Bereichs!
|
36 | #endif
|
37 |
|
38 |
|
39 | #if (F_CPU % IRQS_PER_SECOND != 0) || (IRQS_PER_SECOND % 100 != 0)
|
40 | # warning Das Programm arbeitet nicht mit optimaler Genauigkeit.
|
41 | #endif
|
42 |
|
43 | // Prototypen
|
44 | void wait_10ms (const uint8_t);
|
45 | void init_timer0(void);
|
46 | void init_timer1(void);
|
47 |
|
48 | // Zähler-Variable. Wird in der ISR erniedrigt und in wait_10ms benutzt.
|
49 | static volatile uint8_t timer_10ms;
|
50 |
|
51 | #define timer (256-F_CPU/64/1000)
|
52 | int ms;
|
53 |
|
54 | volatile uint8_t toggleSecment;
|
55 |
|
56 |
|
57 |
|
58 | const uint8_t c_led[10] PROGMEM = {0b00111111, //0
|
59 | 0b00001100, //1
|
60 | 0b01011011, //2
|
61 | 0b01011110, //3
|
62 | 0b01101100, //4
|
63 | 0b01110110, //5
|
64 | 0b01110111, //6
|
65 | 0b00011100, //7
|
66 | 0b01111111, //8
|
67 | 0b01111110,};//9
|
68 |
|
69 |
|
70 | /* Einfache Funktion zum Entprellen eines Tasters */
|
71 | inline uint8_t debounce(volatile uint8_t *port, uint8_t pin)
|
72 | {
|
73 | if ( ! (*port & (1 << pin)) )
|
74 | {
|
75 | /* Pin wurde auf Masse gezogen, 100ms warten */
|
76 | _delay_ms(100);
|
77 | if ( *port & (1 << pin) )
|
78 | {
|
79 | /* Anwender Zeit zum Loslassen des Tasters geben */
|
80 | _delay_ms(100);
|
81 | return 1;
|
82 | }
|
83 | }
|
84 | return 0;
|
85 | }
|
86 |
|
87 | volatile uint8_t countTimer0;
|
88 |
|
89 |
|
90 | void wait_10ms (const uint8_t t)
|
91 | {
|
92 | timer_10ms = t;
|
93 | while (timer_10ms);
|
94 | }
|
95 |
|
96 |
|
97 | //////////////////////////////////////////////////////////////////////
|
98 | // Die Interrupt Service Routine (ISR).
|
99 | // In interrupt_num_10ms werden die IRQs gezählt.
|
100 | // Sind IRQS_PER_10MS Interrups geschehen,
|
101 | // dann sind 10 ms vergangen.
|
102 | // timer_10ms wird alle 10 ms um 1 vermindert und bleibt bei 0 stehen.
|
103 | SIGNAL (SIG_OUTPUT_COMPARE1A)
|
104 | {
|
105 | static uint8_t interrupt_num_10ms;
|
106 |
|
107 | // interrupt_num_10ms erhöhen und mit Maximalwert vergleichen
|
108 | if (++interrupt_num_10ms == IRQS_PER_10MS)
|
109 | {
|
110 | // 10 Millisekunden sind vorbei
|
111 | // interrupt_num_10ms zurücksetzen
|
112 | interrupt_num_10ms = 0;
|
113 |
|
114 | // Alle 10ms wird timer_10ms erniedrigt, falls es nicht schon 0 ist.
|
115 | // Wird verwendet in wait_10ms
|
116 | if (timer_10ms != 0)
|
117 | timer_10ms--;
|
118 | }
|
119 | }
|
120 |
|
121 |
|
122 |
|
123 | ISR(SIG_TIMER0_OVF) //Timer Interrupt Vector
|
124 | {
|
125 | //TCNT0 = timer;
|
126 | ms++;
|
127 | if(ms > 100) {
|
128 | if(toggleSecment) {
|
129 | // deaktiviere 7-SEG nr. 1
|
130 | PORTD &= ~(1 << PD4);
|
131 | // aktive 7-SEG nr. 2
|
132 | PORTD |= (1 << PD5);
|
133 | toggleSecment=0;
|
134 | }
|
135 | else
|
136 | {
|
137 | PORTD |= (1 << PD4);
|
138 | // aktive 7-SEG nr. 2
|
139 | PORTD &= ~(1 << PD5);
|
140 | toggleSecment=1;
|
141 | }
|
142 | ms=0;
|
143 | }
|
144 | }
|
145 |
|
146 | void init_timer0(void)
|
147 | {
|
148 | /* Timer0 ohne Prescaler starten */
|
149 | // TCCR0A |= (1 << CS00) | (1 << CS02);
|
150 | TCCR0B |= (1 << CS00);
|
151 |
|
152 | /* Timer0-Overflow-Interrupt aktivieren */
|
153 | TIMSK |= (1 << TOIE0);
|
154 | }
|
155 |
|
156 | void init_timer1(void)
|
157 | {
|
158 | /*TCCR1A |= (1<<WGM12);
|
159 | TCCR1B |= (1<<CS10); // PS = 1
|
160 | OCR1A = 39999; // 1 sec
|
161 |
|
162 | TIMSK |= (1 << OCIE1A ); */
|
163 |
|
164 | // Timer1: keine PWM
|
165 | TCCR1A = 0;
|
166 |
|
167 | // Timer1 ist Zähler: Clear Timer on Compare Match (CTC, Mode #4)
|
168 | // Timer1 läuft mit vollem MCU-Takt: Prescale = 1
|
169 | #if defined (CTC1) && !defined (WGM12)
|
170 | TCCR1B = (1 << CTC1) | (1 << CS10);
|
171 | #elif !defined (CTC1) && defined (WGM12)
|
172 | TCCR1B = (1 << WGM12) | (1 << CS10);
|
173 | #else
|
174 | #error Keine Ahnung, wie Timer1 fuer diesen AVR zu initialisieren ist!
|
175 | #endif
|
176 | // OutputCompare für gewünschte Timer1 Frequenz
|
177 | // TCNT1 zählt immer 0...OCR1A, 0...OCR1A, ...
|
178 | // Beim überlauf OCR1A -> OCR1A+1 wird TCNT1=0 gesetzt und im nächsten
|
179 | // MCU-Takt eine IRQ erzeugt.
|
180 | OCR1A = (unsigned short) ((unsigned long) F_CPU / IRQS_PER_SECOND-1);
|
181 |
|
182 | // OutputCompareA-Interrupt für Timer1 aktivieren
|
183 | #if defined (TIMSK1)
|
184 | TIMSK1 |= (1 << OCIE1A);
|
185 | #elif defined (TIMSK)
|
186 | TIMSK |= (1 << OCIE1A);
|
187 | #else
|
188 | #error Keine Ahnung, wie IRQs fuer diesen AVR zu initialisieren sind!
|
189 | #endif
|
190 | }
|
191 |
|
192 |
|
193 | int main(void)
|
194 | {
|
195 | // port init
|
196 | DDRB = 0xff; //output
|
197 | PORTB = 0x00; //GND
|
198 |
|
199 | DDRD |= (1 << PD4) | (1 << PD5); //PD4 und PD5 7-SEG Ein/aus
|
200 | DDRD &= ~(1 << PD0); //Input
|
201 | DDRD &= ~(1 << PD1); //Input
|
202 |
|
203 | PORTD |= (1 << PD0) | (1 << PD1); // Pull-Up Widerstand aktivieren
|
204 |
|
205 |
|
206 | // deaktiviere 7-SEG nr. 1
|
207 | PORTD &= ~(1 << PD4);
|
208 | // aktive 7-SEG nr. 2
|
209 | PORTD |= (1 << PD5);
|
210 |
|
211 |
|
212 | toggleSecment=0;
|
213 | uint8_t i=0;
|
214 |
|
215 | //PORTB = pgm_read_byte(&c_led[i]);
|
216 | init_timer0();
|
217 | init_timer1();
|
218 | sei();
|
219 |
|
220 | while(1)
|
221 | {
|
222 |
|
223 | wait_10ms (100);
|
224 | PORTB = pgm_read_byte(&c_led[i]);
|
225 | i++;
|
226 | if(i > 9)
|
227 | {
|
228 | i=0;
|
229 | }
|
230 |
|
231 |
|
232 | }
|
233 | return 1;
|
234 | }
|