1 | #include <avr/io.h>
|
2 | #include <avr/delay.h>
|
3 | #include <avr/interrupt.h>
|
4 |
|
5 | #ifndef F_CPU
|
6 | /* In neueren Version der WinAVR/Mfile Makefile-Vorlage kann
|
7 | F_CPU im Makefile definiert werden, eine nochmalige Definition
|
8 | hier wuerde zu einer Compilerwarnung fuehren. Daher "Schutz" durch
|
9 | #ifndef/#endif
|
10 |
|
11 | Dieser "Schutz" kann zu Debugsessions führen, wenn AVRStudio
|
12 | verwendet wird und dort eine andere, nicht zur Hardware passende
|
13 | Taktrate eingestellt ist: Dann wird die folgende Definition
|
14 | nicht verwendet, sondern stattdessen der Defaultwert (8 MHz?)
|
15 | von AVRStudio - daher Ausgabe einer Warnung falls F_CPU
|
16 | noch nicht definiert: */
|
17 | #warning "F_CPU war noch nicht definiert, wird nun nachgeholt mit 4000000"
|
18 | #define F_CPU 4000000UL // Systemtakt in Hz - Definition als unsigned long beachten
|
19 | // Ohne ergeben sich unten Fehler in der Berechnung
|
20 | #endif
|
21 |
|
22 | #define BAUD 9600UL // Baudrate
|
23 |
|
24 | // Berechnungen
|
25 | #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1) // clever runden
|
26 | #define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1))) // Reale Baudrate
|
27 | #define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) // Fehler in Promille, 1000 = kein Fehler.
|
28 |
|
29 | #if ((BAUD_ERROR<990) || (BAUD_ERROR>1010))
|
30 | #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
|
31 | #endif
|
32 |
|
33 | int uart_putc(unsigned char c);
|
34 | void uart_puts (char *s);
|
35 | uint16_t ReadChannel(uint8_t mux);
|
36 | int quersumme(int zahl);
|
37 |
|
38 |
|
39 | int main(void)
|
40 | {
|
41 | UCSRB |= (1<<TXEN); // UART TX einschalten
|
42 | UCSRC |= (1<<URSEL)|(3<<UCSZ0); // Asynchron 8N1
|
43 |
|
44 | UBRRH = UBRR_VAL >> 8;
|
45 | UBRRL = UBRR_VAL & 0xFF;
|
46 |
|
47 | uint16_t wert;
|
48 | char buffer[20];
|
49 |
|
50 | while(1)
|
51 | {
|
52 |
|
53 | wert = ReadChannel(0);
|
54 |
|
55 | itoa(wert, buffer, 10);
|
56 | uart_puts(buffer);
|
57 |
|
58 | uart_puts(" / ");
|
59 |
|
60 | wert = quersumme(wert);
|
61 |
|
62 | itoa(wert, buffer, 10);
|
63 | uart_puts(buffer);
|
64 |
|
65 | uart_puts("\r\n");
|
66 |
|
67 | _delay_ms(100);
|
68 | }
|
69 | }
|
70 |
|
71 |
|
72 | // bei neueren AVRs andere Bezeichnung fuer die Statusregister, hier ATmega16:
|
73 | int uart_putc(unsigned char c)
|
74 | {
|
75 | while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich */
|
76 | {
|
77 | }
|
78 |
|
79 | UDR = c; /* sende Zeichen */
|
80 | return 0;
|
81 | }
|
82 |
|
83 |
|
84 | /* puts ist unabhaengig vom Controllertyp */
|
85 | void uart_puts (char *s)
|
86 | {
|
87 | while (*s)
|
88 | { /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
|
89 | uart_putc(*s);
|
90 | s++;
|
91 | }
|
92 | }
|
93 |
|
94 |
|
95 | //
|
96 | // Unter Angabe des Kanals gibt diese Funktion den Analogwert zurück.
|
97 | //
|
98 | uint16_t ReadChannel(uint8_t mux)
|
99 | {
|
100 | uint8_t i;
|
101 | uint16_t result;
|
102 |
|
103 | ADMUX = mux; // Kanal waehlen
|
104 | ADMUX |= (1<<REFS0); // interne Referenzspannung nutzen
|
105 | ADMUX &= ~(1<<REFS1);
|
106 |
|
107 | ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
|
108 | // setzen auf 8 (1) und ADC aktivieren (1)
|
109 |
|
110 | /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
|
111 | also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
|
112 | ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
|
113 | while ( ADCSRA & (1<<ADSC) ) {
|
114 | ; // auf Abschluss der Konvertierung warten
|
115 | }
|
116 | result = ADCW; // ADCW muss einmal gelesen werden,
|
117 | // sonst wird Ergebnis der nächsten Wandlung
|
118 | // nicht übernommen.
|
119 |
|
120 | /* Eigentliche Messung - Mittelwert aus X aufeinanderfolgenden Wandlungen */
|
121 | result = 0;
|
122 | for( i=0; i<5; i++ )
|
123 | {
|
124 | ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
|
125 | while ( ADCSRA & (1<<ADSC) ) {
|
126 | ; // auf Abschluss der Konvertierung warten
|
127 | }
|
128 | result += ADCW; // Wandlungsergebnisse aufaddieren
|
129 | }
|
130 | ADCSRA &= ~(1<<ADEN); // ADC deaktivieren (2)
|
131 |
|
132 | result /= 5; // Summe durch X teilen = arithm. Mittelwert
|
133 |
|
134 | return result;
|
135 | }
|
136 |
|
137 |
|
138 |
|
139 | int quersumme(int zahl) {
|
140 | int quersumme=0;
|
141 | int rest=0;
|
142 |
|
143 | do {
|
144 | rest = zahl%10;
|
145 | zahl = zahl/10;
|
146 | quersumme=quersumme+rest;
|
147 | } while (zahl > 0);
|
148 |
|
149 | return quersumme;
|
150 | }
|