1 | #define F_CPU 8000000UL
|
2 |
|
3 | #include <stdlib.h>
|
4 | #include <avr/io.h>
|
5 | #include <avr/interrupt.h>
|
6 | #include <util/delay.h>
|
7 | #include <string.h>
|
8 | #include <stdio.h>
|
9 |
|
10 | #define UART_BAUDRATE 9600
|
11 | #define UART_SETTING ((F_CPU/16L/UART_BAUDRATE)-1)
|
12 |
|
13 |
|
14 | #define PRESCALER 64
|
15 | #define PRESCALER_BITS (1<<CS22)
|
16 |
|
17 | #define MILLISEC_BASE ( F_CPU / PRESCALER / 1000 )
|
18 | #define CENTER ( MILLISEC_BASE / 2 )
|
19 |
|
20 | #define debounce( port, pin ) \
|
21 | ({ \
|
22 | static uint8_t flag = 0; \
|
23 | uint8_t i = 0; \
|
24 | \
|
25 | if( flag ){ \
|
26 | for(;;){ \
|
27 | if( !(port & 1<<pin) ){ \
|
28 | i = 0; \
|
29 | break; \
|
30 | } \
|
31 | _delay_us( 98 ); \
|
32 | if( --i == 0 ){ /* ... until key >25ms released */ \
|
33 | flag = 0; /* clear press flag */ \
|
34 | i = 0; /* 0 = key release debounced */ \
|
35 | break; \
|
36 | } \
|
37 | } \
|
38 | }else{ /* else check for key press: */ \
|
39 | for(;;){ /* loop ... */ \
|
40 | if( (port & 1<<pin) ){ /* ... until key released or ... */ \
|
41 | i = 0; /* 0 = bounce */ \
|
42 | break; \
|
43 | } \
|
44 | _delay_us( 98 ); /* * 256 = 25ms */ \
|
45 | if( --i == 0 ){ /* ... until key >25ms pressed */ \
|
46 | flag = 1; /* set press flag */ \
|
47 | i = 1; /* 1 = key press debounced */ \
|
48 | break; \
|
49 | } \
|
50 | } \
|
51 | } \
|
52 | i; /* return value of Macro */ \
|
53 | })
|
54 |
|
55 | //
|
56 | // Konfiguration der Servoleitungen
|
57 | //
|
58 | #define NR_SERVOS 3
|
59 | #define SERVO_DDR DDRD
|
60 | #define SERVO_PORT PORTD
|
61 | uint8_t ServoPuls[NR_SERVOS] = { 1<<PD6, 1<<PD5, 1<<PD4, 0,
|
62 | 0, 0, 0, 0};
|
63 |
|
64 | // uint8_t ServoPuls[NR_SERVOS] = { 1<<PD6, 1<<PD5 };
|
65 | //
|
66 | // Werte für die Servoposition
|
67 | // Gültige Werte laufen von 0 bis 2 * CENTER
|
68 | // 0 ... ganz links
|
69 | // CENTER ... Mittelstellung
|
70 | // 2 * CENTER ... ganz rechts
|
71 | //
|
72 | volatile uint8_t ServoValue[NR_SERVOS];
|
73 |
|
74 | volatile uint16_t sekunden, msekunden;
|
75 |
|
76 | ISR (TIMER2_COMP_vect)
|
77 | {
|
78 | static uint8_t ServoId = 0;
|
79 |
|
80 | //
|
81 | // den Puls des aktuellen Servos beenden
|
82 | //
|
83 | SERVO_PORT &= ~ServoPuls[ServoId];
|
84 |
|
85 | //
|
86 | // welches ist das nächste aktuelle Servo?
|
87 | //
|
88 | if( ++ServoId >= NR_SERVOS )
|
89 | ServoId = 0;
|
90 |
|
91 | //
|
92 | // die Ausgangsleitung fuer dieses Servo auf 1; den Puls beginnen
|
93 | //
|
94 | SERVO_PORT |= ServoPuls[ServoId];
|
95 |
|
96 | //
|
97 | // den Timer so einstellen, dass bei Pulsende, die ISR erneut aufgerufen wird
|
98 | //
|
99 | OCR2 = MILLISEC_BASE + ServoValue[ServoId];
|
100 | }
|
101 |
|
102 | ISR(TIMER0_COMP_vect)
|
103 | {
|
104 | static int count, count_sek;
|
105 |
|
106 | count_sek++;
|
107 |
|
108 | if(count_sek == 10)
|
109 | {
|
110 | msekunden++;
|
111 | count_sek = 0;
|
112 |
|
113 | if(msekunden == 1000)
|
114 | {
|
115 | sekunden++;
|
116 | msekunden = 0;
|
117 | }
|
118 | }
|
119 | }
|
120 |
|
121 | void init_time()
|
122 | {
|
123 | TIMSK|=(1<<OCIE0);
|
124 | TCCR0 |= (1<<WGM01) | (1<<CS01);
|
125 | OCR0 = F_CPU/8/10000;
|
126 | }
|
127 |
|
128 |
|
129 |
|
130 | /* ADC initialisieren */
|
131 | void ADC_Init(void) {
|
132 |
|
133 | uint16_t result;
|
134 |
|
135 |
|
136 | ADMUX = (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
|
137 |
|
138 | // Bit ADFR ("free running") in ADCSRA steht beim Einschalten
|
139 | // schon auf 0, also single conversion
|
140 | ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
|
141 | ADCSRA |= (1<<ADEN); // ADC aktivieren
|
142 |
|
143 | /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
|
144 | also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
|
145 |
|
146 | ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
|
147 |
|
148 | while (ADCSRA & (1<<ADSC) ) {} // auf Abschluss der Konvertierung warten
|
149 | /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
|
150 | Wandlung nicht übernommen. */
|
151 | result = ADCW;
|
152 | }
|
153 |
|
154 | /* ADC Einzelmessung */
|
155 | uint16_t ADC_Read( uint8_t channel )
|
156 | {
|
157 | // Kanal waehlen, ohne andere Bits zu beeinflußen
|
158 | ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
|
159 | ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
|
160 | while (ADCSRA & (1<<ADSC) ) {} // auf Abschluss der Konvertierung warten
|
161 | return ADCW; // ADC auslesen und zurückgeben
|
162 | }
|
163 |
|
164 | /* ADC Mehrfachmessung mit Mittelwertbbildung */
|
165 | uint16_t ADC_Read_Avg( uint8_t channel, uint8_t average )
|
166 | {
|
167 | uint32_t ergebnis = 0;
|
168 |
|
169 | for (uint8_t i = 0; i < average; ++i )
|
170 | ergebnis += ADC_Read( channel );
|
171 |
|
172 | return (uint16_t)( ergebnis / average );
|
173 | }
|
174 |
|
175 | void setup_uart()
|
176 | {
|
177 | UBRRH = (char) (UART_SETTING >> 8);
|
178 | UBRRL = (char) (UART_SETTING);
|
179 | UCSRB = (1<<RXEN) | (1<<TXEN);
|
180 |
|
181 | UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
|
182 | }
|
183 |
|
184 | void uart_putchar(char c)
|
185 | {
|
186 | // Warten bis Buffer bereit ...
|
187 | while (!(UCSRA & (1 << UDRE)))
|
188 | ;
|
189 |
|
190 | // Senden...
|
191 | UDR = c;
|
192 | }
|
193 |
|
194 | void uart_putstring(char *str)
|
195 | {
|
196 | unsigned char i;
|
197 |
|
198 | for (i=0;i<255;i++)
|
199 | {
|
200 | if (str[i] != 0)
|
201 | uart_putchar(str[i]);
|
202 | else
|
203 | break; // Ende des Strings erreicht
|
204 | }
|
205 | }
|
206 |
|
207 |
|
208 |
|
209 | char uart_getchar()
|
210 | {
|
211 | // Ist schon ein Zeichen im Buffer?
|
212 | if (bit_is_set(UCSRA, RXC))
|
213 | return UDR;
|
214 | else
|
215 | return -1;
|
216 | }
|
217 |
|
218 | void uart_readline(char *str)
|
219 | {
|
220 | char c;
|
221 | unsigned char index;
|
222 |
|
223 | index = 0;
|
224 |
|
225 | while (1)
|
226 | {
|
227 | c = uart_getchar();
|
228 | if (c != -1)
|
229 | {
|
230 |
|
231 |
|
232 |
|
233 | if (c == 13)
|
234 | {
|
235 | str[index] = 0;
|
236 |
|
237 | return;
|
238 | }
|
239 | else
|
240 | {
|
241 |
|
242 |
|
243 | str[index] = c;
|
244 | index++;
|
245 | }
|
246 | }
|
247 | }
|
248 | }
|
249 |
|
250 | void InitServo()
|
251 | {
|
252 | uint8_t i;
|
253 |
|
254 | //
|
255 | // Die Servoleitungen auf Ausgang stellen
|
256 | //
|
257 | SERVO_DDR = ServoPuls[0] | ServoPuls[1];
|
258 |
|
259 | //
|
260 | // Alle Servos in Mittelstellung
|
261 | //
|
262 | for( i = 0; i < NR_SERVOS; ++i )
|
263 | ServoValue[i] = (CENTER + (CENTER/2));
|
264 |
|
265 | //
|
266 | // Timer auf CTC Modus konfigurieren
|
267 | //
|
268 | OCR2 = MILLISEC_BASE + ServoValue[0];
|
269 | TIMSK |= (1<<OCIE2);
|
270 | TCCR2 = (1<<WGM21) | PRESCALER_BITS; // CTC mode
|
271 | }
|
272 |
|
273 |
|
274 | int main()
|
275 | {
|
276 |
|
277 | uint16_t adcval;
|
278 | uint16_t remember;
|
279 |
|
280 | int last_sek;
|
281 |
|
282 | char Buffer[25];
|
283 |
|
284 | ADC_Init();
|
285 |
|
286 | DDRC=0x00;
|
287 | PORTC=0xff;
|
288 |
|
289 | DDRB=0xff;
|
290 | PORTB=0x00;
|
291 |
|
292 | InitServo();
|
293 | sei(); // Interrupts global an
|
294 |
|
295 | last_sek = 0;
|
296 | sekunden = 0;
|
297 | msekunden = 0;
|
298 | remember = 0;
|
299 |
|
300 | init_time();
|
301 | setup_uart();
|
302 |
|
303 | uart_putstring("Setup UART: check\r\n");
|
304 |
|
305 | ServoValue[0] = (CENTER + (CENTER/2));
|
306 | uart_putstring("Setup Servo \r\n");
|
307 | uart_putstring("check\r\n");
|
308 |
|
309 | while( 1 )
|
310 | {
|
311 |
|
312 | if(debounce(PINC, PC0))
|
313 | {
|
314 |
|
315 | if(ServoValue[0] == 0)
|
316 | ServoValue[0] = 2*CENTER;
|
317 | else
|
318 | ServoValue[0] = 0;
|
319 |
|
320 | }
|
321 |
|
322 |
|
323 | if(sekunden>last_sek)
|
324 | {
|
325 | last_sek = sekunden;
|
326 |
|
327 | adcval = ADC_Read_Avg(0,200);
|
328 | sprintf( Buffer, "Wert: %d", adcval );
|
329 | uart_putstring(Buffer);
|
330 | }
|
331 | }
|
332 | }
|