1 | /////////////////////////////////////Main.c
|
2 |
|
3 | /*
|
4 | *******************************************************************************
|
5 | *
|
6 | * UART Interrupt Demo
|
7 | *
|
8 | * ATmega32 mit 3,6864 MHz Quarz an XTAL1/XTAL2
|
9 | *
|
10 | * LOW Fuse Byte = 0xFF
|
11 | *
|
12 | * An PD2 muss eine LED mit 1-kOhm-Vorwiderstand angeschlossen werden
|
13 | * An PD0/PD1 ist ein MAX232 angeschlosssen, um Daten vom PC zu empfangen/senden
|
14 | *
|
15 | *******************************************************************************
|
16 | */
|
17 | // Systemtakt in Hz, das L am Ende ist wichtig, NICHT UL verwenden!
|
18 | #define F_CPU 8000000L
|
19 |
|
20 | // "Morsedauer" für ein Bit in Millisekunden
|
21 | #define BITZEIT 100
|
22 |
|
23 | #include <avr/io.h>
|
24 | #include <avr/interrupt.h>
|
25 | #include <util/delay.h>
|
26 | #include "uart.h"
|
27 |
|
28 | // lange, variable Wartezeit, Einheit in Millisekunden
|
29 | void long_delay(uint16_t ms) {
|
30 | for (; ms>0; ms--) _delay_ms(1);
|
31 | }
|
32 |
|
33 |
|
34 |
|
35 | // Ein Byte im RS232 Format auf eine LED ausgeben
|
36 |
|
37 | void morse(uint8_t data) {
|
38 | uint8_t i;
|
39 |
|
40 | // Startbit, immer 0
|
41 | PORTD &= ~(1 << PD2); // LED aus
|
42 | long_delay(BITZEIT);
|
43 |
|
44 | for(i=0; i<8; i++) {
|
45 | if (data & 0x01) // Prüfe Bit #0
|
46 | PORTD |= (1 << PD2); // LED an
|
47 | else
|
48 | PORTD &= ~(1 << PD2); // LED aus
|
49 | long_delay(BITZEIT);
|
50 | data >>= 1; // nächstes Bit auf Bit #0 schieben
|
51 | }
|
52 | // Stopbit, immer 1
|
53 | PORTD |= (1 << PD2); // LED an
|
54 | long_delay(BITZEIT);
|
55 | }
|
56 |
|
57 | // Hauptprogramm
|
58 |
|
59 | int main (void) {
|
60 |
|
61 | char stringbuffer[64]; // Allgemeiner Puffer für Strings
|
62 | uint8_t buffer_full=0; // noch ein Flag, aber nur in der Hauptschleife
|
63 | char * charpointer; // Hilfszeiger
|
64 | char test[7] = "Hallo";
|
65 | // IO konfigurieren
|
66 |
|
67 | DDRB = 0xFF;
|
68 | DDRC = 0xFF;
|
69 | DDRD = 0xFF;
|
70 |
|
71 | // UART konfigurieren
|
72 |
|
73 | UBRRH = UBRR_VAL >> 8;
|
74 | UBRRL = UBRR_VAL & 0xFF;
|
75 | UCSRB = (1<<RXCIE) | (1<<RXEN) | (1<<TXEN) |(1<<UDRIE);
|
76 |
|
77 | // Stringpuffer initialisieren
|
78 |
|
79 | stringbuffer[0] = '\n';
|
80 | stringbuffer[1] = '\r';
|
81 |
|
82 | // Interrupts freigeben
|
83 |
|
84 | sei();
|
85 |
|
86 | // Endlose Hauptschleife
|
87 |
|
88 | while(1) {
|
89 |
|
90 | put_string(test);
|
91 |
|
92 | // "Sinnvolle" CPU Tätigkeit
|
93 | PORTD &= ~(1<<PD2);
|
94 | long_delay(300);
|
95 | PORTD |= (1<<PD2);
|
96 | long_delay(300);
|
97 |
|
98 |
|
99 | // Wurde ein kompletter String empfangen
|
100 | // und der Buffer ist leer?
|
101 | if (uart_rx_flag==1 && buffer_full==0) {
|
102 | // ja, dann String lesen,
|
103 | // die ersten zwei Zeichen
|
104 | // aber nicht überschreiben
|
105 | get_string(stringbuffer+2);
|
106 | buffer_full=1;
|
107 | }
|
108 |
|
109 | // Ist letzte Stringsendung abgeschlossen
|
110 | // und ein neuer String verfügbar?
|
111 | if (uart_tx_flag==1 && buffer_full==1) {
|
112 | // Newline + Carrige return anfügen
|
113 | strcat(stringbuffer, "\n\r");
|
114 | put_string(stringbuffer); // zurücksenden
|
115 | buffer_full=0; // Buffer ist wieder verfügbar
|
116 | // Alle Zeichen per LED morsen
|
117 | charpointer = stringbuffer;
|
118 | while(*charpointer) morse(*charpointer++);
|
119 | }
|
120 | }
|
121 | }
|
122 |
|
123 |
|
124 |
|
125 |
|
126 | ///////////////////////////////////////////////////uart.h
|
127 |
|
128 | #ifndef UART_H
|
129 | #define UART_H
|
130 |
|
131 | // Systemtakt in Hz, das L am Ende ist wichtig, NICHT UL verwenden!
|
132 | #define F_CPU 8000000L
|
133 |
|
134 | #include <avr/io.h>
|
135 | #include <avr/interrupt.h>
|
136 | #include <string.h>
|
137 |
|
138 | // Baudrate, das L am Ende ist wichtig, NICHT UL verwenden!
|
139 | #define BAUD 9600L
|
140 |
|
141 | // Berechnungen
|
142 | // clever runden
|
143 | #define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)
|
144 | // Reale Baudrate
|
145 | #define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))
|
146 | // Fehler in Promille
|
147 | #define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000)
|
148 |
|
149 | #if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))
|
150 | #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch!
|
151 | #endif
|
152 |
|
153 | // globale Variablen für den UART
|
154 |
|
155 | // Puffergrösse in Bytes, RX und TX sind gleich gross
|
156 | #define uart_buffer_size 32
|
157 |
|
158 | char uart_rx_buffer[uart_buffer_size]; // Empfangspuffer
|
159 | char uart_tx_buffer[uart_buffer_size]; // Sendepuffer
|
160 | volatile uint8_t uart_rx_flag=0; // Flag, String komplett empfangen
|
161 | volatile uint8_t uart_tx_flag=1; // Flag, String komplett gesendet
|
162 |
|
163 |
|
164 | void put_string(char *daten);
|
165 | void get_string(char *daten);
|
166 |
|
167 | ISR(USART_RX_vect);
|
168 | ISR(USART_UDRE_vect);
|
169 |
|
170 |
|
171 |
|
172 | #endif
|
173 |
|
174 |
|
175 | //////////////////////////////////////////////////////uart.c
|
176 |
|
177 | #include "uart.h"
|
178 |
|
179 | // einen String senden
|
180 | // vor Aufruf der Funktion muss man prüfen, ob uart_t_flag==1 ist
|
181 | // nur dann kann ein neuer String gesendet werden
|
182 |
|
183 | void put_string(char *daten) {
|
184 |
|
185 | if (uart_tx_flag==1) {
|
186 | // String daten ind en Sendepuffer kopieren
|
187 | strcpy(uart_tx_buffer, daten);
|
188 | // Flag für 'Senden ist komplett' löschen,
|
189 | uart_tx_flag = 0;
|
190 | // UDRE Interrupt einschalten, los gehts
|
191 | UCSRB |= (1<<UDRIE);
|
192 | }
|
193 | }
|
194 |
|
195 | // einen empfangenen String kopieren
|
196 | // vor Aufruf der Funktion muss man prüfen, ob uart_rx_flag==1 ist
|
197 | // anderenfalls ist der RX Buffer noch ungültig
|
198 |
|
199 | void get_string(char *daten) {
|
200 |
|
201 | if (uart_rx_flag==1) {
|
202 | // String kopieren
|
203 | strcpy(daten, uart_rx_buffer);
|
204 | // Flag löschen
|
205 | uart_rx_flag = 0;
|
206 | }
|
207 | }
|
208 |
|
209 | // UART RX complete interrupt
|
210 |
|
211 | // hier werden Daten vom PC empfangen und in einem String zwischengespeichert
|
212 | // Wird ein Stringterminator empfangen, wird ein Flag gesetzt, welches dem
|
213 | // Hauptprogramm den kompletten Empfang signalisiert
|
214 |
|
215 | ISR(USART_RX_vect) {
|
216 |
|
217 | static uint8_t uart_rx_cnt; // Zähler für empfangene Zeichen
|
218 | uint8_t data;
|
219 |
|
220 | // Daten auslesen, dadurch wird das Interruptflag gelöscht
|
221 | data = UDR;
|
222 |
|
223 | // Ist Puffer frei für neue Daten?
|
224 | if (!uart_rx_flag) {
|
225 | // ja, ist Ende des Strings (RETURN) erreicht?
|
226 | if (data=='\r') {
|
227 | // ja, dann String terminieren
|
228 | uart_rx_buffer[uart_rx_cnt]=0;
|
229 | // Flag für 'Empfangspuffer voll' setzen
|
230 | uart_rx_flag=1;
|
231 | // Zähler zurücksetzen
|
232 | uart_rx_cnt=0;
|
233 | }
|
234 | else if (uart_rx_cnt<(uart_buffer_size-1)) {
|
235 | // Daten in Puffer speichern
|
236 | // aber durch if() Pufferüberlauf vermeiden
|
237 | uart_rx_buffer[uart_rx_cnt]=data;
|
238 | uart_rx_cnt++; // Zähler erhöhen
|
239 | }
|
240 | }
|
241 | }
|
242 |
|
243 | // UART TX data register empty interrupt
|
244 | // hier werden neue Daten in das UART-Senderegister geladen
|
245 |
|
246 | ISR(USART_UDRE_vect) {
|
247 | // Zeiger auf Sendepuffer
|
248 | static char* uart_tx_p = uart_tx_buffer;
|
249 | uint8_t data;
|
250 |
|
251 | // zu sendendes Zeichen lesen,
|
252 | // Zeiger auf Sendepuffer erhöhen
|
253 | data = *uart_tx_p++;
|
254 |
|
255 | // Ende des nullterminierten Strings erreicht?
|
256 | if (data==0 ) {
|
257 | UCSRB &= ~(1<<UDRIE); // ja, dann UDRE Interrupt ausschalten
|
258 | uart_tx_p = uart_tx_buffer; // Pointer zurücksetzen
|
259 | uart_tx_flag = 1; // Flag setzen, Übertragung beeendet
|
260 | }
|
261 | else UDR = data; // nein, Daten senden
|
262 | }
|