AVR Embedded Tutorial - UART/de: what changed
Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.
| Old | New | Line | |
|---|---|---|---|
| 1 | + | ## Contents | |
| 2 | + | ||
| 3 | + | * 1 UART Polling | |
| 4 | + | * 1.1 ATmega328p (Arduino uno/nano) | |
| 5 | + | * 1.1.1 Konstanten für Inizialisierung | |
| 6 | + | * 1.1.2 Inizialisieren | |
| 7 | + | * 1.1.3 Zeichen empfangen | |
| 8 | + | * 1.1.4 Zeichen senden | |
| 9 | + | * 1.1.5 String senden | |
| 10 | + | * 1.1.6 Hauptschleife | |
| 11 | + | * 1.2 ATtiny2313 | |
| 12 | + | * 2 Interrupt | |
| 13 | + | * 2.1 Empfangspuffer | |
| 14 | + | * 2.1.1 Deklaration | |
| 15 | + | * 2.1.2 Inzialisieren | |
| 16 | + | * 2.1.3 Interrupt | |
| 17 | + | * 2.1.4 Hauptschleife | |
| 18 | + | * 2.2 Sendepuffer | |
| 19 | + | * 2.2.1 Deklaration | |
| 20 | + | * 2.2.2 Inzialisieren | |
| 21 | + | * 2.2.3 Interrupt | |
| 22 | + | * 2.2.4 String senden | |
| 23 | + | * 2.2.5 Hauptschleife | |
| 24 | + | * 3 Software - UART / UART - Emulation | |
| 25 | + | * 3.1 Konstanten | |
| 26 | + | * 3.2 Zeichen senden | |
| 27 | + | * 3.3 Zeichen empfangen | |
| 28 | + | * 4 Siehe auch | |
| 29 | + | ||
| 1 | 30 | # UART Polling | |
| 2 | 31 | ||
| 3 | 32 | ## ATmega328p (Arduino uno/nano) | |
| 4 | 33 | ||
| 5 | - | ||
| 6 | - | ||
| 7 | - | ||
| 8 | - | ||
| 9 | - | ||
| 10 | - | ||
| 11 | - | ||
| 12 | - | ||
| 34 | + | Für die serielle Ausgabe wird ein Terminal mit folgenden Einstellungen gebraucht: | |
| 13 | 35 | ||
| 14 | - | ||
| 36 | + | Baud Rate | 9600 | |
| 37 | + | ---|--- | |
| 38 | + | Bits | 8 | |
| 39 | + | Stopbits | 1 | |
| 40 | + | Parity | none | |
| 41 | + | ||
| 42 | + | Beim Betätigen von `Space` im Terminal-Programm, sollte ein "Hello World !" zurück kommen. | |
| 15 | 43 | ||
| 16 | 44 | ### Konstanten für Inizialisierung | |
| 17 | - | ||
| 18 | - | ||
| 45 | + | ``` | |
| 19 | 46 | const | |
| 20 | - | ||
| 21 | - | ||
| 22 | - | ||
| 47 | + | CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz. | |
| 48 | + | Baud = 9600; // Baudrate | |
| 49 | + | Teiler = CPU_Clock div (16 * Baud) - 1; | |
| 23 | 50 | ``` | |
| 24 | 51 | ||
| 25 | - | ||
| 52 | + | **Hinweis:** Wen den der CPU-Clock zu klein ist in die Baudrate zu hoch, gibt es Übertragungsfehler. Beispiel: Clock **1MHz** , Baud **9600** geht nicht. Aber **1MHz** und Baud **1200** gehen. | |
| 26 | 53 | ||
| 27 | 54 | ### Inizialisieren | |
| 28 | 55 | ||
| 29 | - | ||
| 30 | - | ||
| 31 | - | ||
| 32 | - | ||
| 33 | - | ||
| 34 | - | ||
| 35 | - | ||
| 36 | - | ||
| 37 | - | ||
| 38 | - | ||
| 39 | - | ||
| 56 | + | Die UART-Schnittstelle konfigurierieren. | |
| 40 | 57 | ``` | |
| 58 | + | procedure UARTInit; | |
| 59 | + | begin | |
| 60 | + | UBRR0 := Teiler; // Baud | |
| 61 | + | ||
| 62 | + | UCSR0A := 0 // Normale Geschwindigkeit | |
| 63 | + | UCSR0B := (1 shl TXEN0) or (1 shl RXEN0); // Empfangen und Senden | |
| 64 | + | UCSR0C := (%011 shl UCSZ0); // 8-Bit Übertragung, 1 Stop-Bits. | |
| 65 | + | end; | |
| 66 | + | ``` | |
| 41 | 67 | ||
| 42 | 68 | ### Zeichen empfangen | |
| 43 | - | ||
| 44 | - | ||
| 45 | - | ||
| 46 | - | ||
| 47 | - | ||
| 48 | - | ||
| 49 | - | ||
| 50 | 69 | ``` | |
| 70 | + | function UARTReadChar: char; | |
| 71 | + | begin | |
| 72 | + | while UCSR0A and (1 shl RXC0) = 0 do; // Warten, bis Zeichen ankommt. | |
| 73 | + | Result := char(UDR0); // Zeichen einlesen. | |
| 74 | + | end; | |
| 75 | + | ``` | |
| 51 | 76 | ||
| 52 | 77 | ### Zeichen senden | |
| 53 | - | ||
| 54 | - | ||
| 55 | - | ||
| 56 | - | ||
| 57 | - | ||
| 58 | - | ||
| 59 | - | ||
| 60 | 78 | ``` | |
| 79 | + | procedure UARTSendChar(c: char); | |
| 80 | + | begin | |
| 81 | + | while UCSR0A and (1 shl UDRE0) = 0 do; // Warten, bis letztes Zeichen gesendet. | |
| 82 | + | UDR0 := byte(c); // Zeichen senden. | |
| 83 | + | end; | |
| 84 | + | ``` | |
| 61 | 85 | ||
| 62 | 86 | ### String senden | |
| 63 | - | ||
| 64 | - | ||
| 65 | - | ||
| 66 | - | ||
| 67 | - | ||
| 68 | - | ||
| 69 | - | ||
| 70 | - | ||
| 71 | - | ||
| 72 | - | ||
| 73 | 87 | ``` | |
| 88 | + | procedure UARTSendString(s: ShortString); | |
| 89 | + | var | |
| 90 | + | i: integer; | |
| 91 | + | begin | |
| 92 | + | for i := 1 to length(s) do begin | |
| 93 | + | UARTSendChar(s[i]); // Zeichen einzeln senden. | |
| 94 | + | end; | |
| 95 | + | end; | |
| 96 | + | ``` | |
| 74 | 97 | ||
| 75 | 98 | ### Hauptschleife | |
| 76 | 99 | ||
| 77 | - | ||
| 78 | - | ||
| 79 | - | ||
| 100 | + | Hier wird gewartet, bis `Space` ankommt, anschliessend wir "Hello World !" gesendet. | |
| 101 | + | ``` | |
| 80 | 102 | program Project1; | |
| 81 | - | ||
| 82 | - | ||
| 83 | - | ||
| 84 | - | ||
| 85 | - | ||
| 86 | - | ||
| 87 | - | ||
| 88 | - | ||
| 103 | + | begin | |
| 104 | + | UARTInit; | |
| 105 | + | repeat | |
| 106 | + | if UARTReadChar = #32 then begin // #32 = space | |
| 107 | + | UARTSendString('Hello World !'#13#10); | |
| 108 | + | end; | |
| 109 | + | until 1 = 2; | |
| 110 | + | end. | |
| 89 | 111 | ``` | |
| 90 | 112 | ||
| 91 | 113 | ## ATtiny2313 | |
| 92 | 114 | ||
| 93 | - | ||
| 94 | - | ||
| 95 | - | ||
| 96 | - | ||
| 115 | + | Beim ATtiny2313 haben die Register eine andere Bezeichnung als beim ATmega328p. | |
| 97 | 116 | ||
| 98 | - | ||
| 117 | + | * Die **0** entfällt in der Bezeichnung. | |
| 118 | + | * **UBRR0** muss man in **UBRRH** und **UBRRL** zerlegen. | |
| 99 | 119 | ||
| 100 | - | ||
| 120 | + | Das sieht dann so aus: | |
| 121 | + | ``` | |
| 101 | 122 | UBRRH := Teiler shr 8; | |
| 102 | - | ||
| 103 | - | ||
| 104 | - | ||
| 105 | - | ||
| 123 | + | UBRRL := Byte(Teiler); | |
| 124 | + | ||
| 125 | + | UCSRB := (1 shl TXEN) or (1 shl RXEN); | |
| 126 | + | UCSRC := (%011 shl UCSZ); | |
| 106 | 127 | ``` | |
| 107 | 128 | ||
| 108 | - | ||
| 129 | + | (Der Code wurde nicht getestet) | |
| 109 | 130 | ||
| 110 | 131 | # Interrupt | |
| 111 | 132 | ||
| 112 | - | ||
| 133 | + | Beim Polling kann es passieren, das Zeichen verschluckt werden, dies passiert, wen ein Zeichen ankommt und man dieses nicht abholt. Aus diesem Grund empfiehlt es sich, den Zeichenempfang Interrupt gesteuert zum machen. | |
| 113 | 134 | ||
| 114 | - | ||
| 135 | + | Bei höheren Baudraten, ist dies zwingend. | |
| 115 | 136 | ||
| 116 | - | ||
| 137 | + | Es wir ein einfacher Ringpuffer mit 16 Zeichen verwendet. | |
| 117 | 138 | ||
| 118 | - | ||
| 139 | + | Die Beispiele zeigen dies anhand eines ATmega328p (Arduino uno/nano). | |
| 119 | 140 | ||
| 120 | 141 | ## Empfangspuffer | |
| 121 | 142 | ||
| 122 | 143 | ### Deklaration | |
| 123 | 144 | ||
| 124 | - | ||
| 125 | - | ||
| 126 | - | ||
| 145 | + | Zeichenbuffer deklarieren, hier wir ein Puffer von 16 Zeichen angelegt. | |
| 146 | + | ``` | |
| 127 | 147 | const | |
| 128 | - | ||
| 129 | - | ||
| 130 | - | ||
| 131 | - | ||
| 132 | - | ||
| 148 | + | Crxlen = 16; // Puffergrösse | |
| 149 | + | var | |
| 150 | + | RXBuf: array[0..Crxlen - 1] of byte; | |
| 151 | + | RXread: byte = 0; | |
| 152 | + | RXwrite: byte = 0; | |
| 133 | 153 | ``` | |
| 134 | 154 | ||
| 135 | 155 | ### Inzialisieren | |
| 136 | 156 | ||
| 137 | - | ||
| 138 | - | ||
| 139 | - | ||
| 140 | - | ||
| 141 | - | ||
| 142 | - | ||
| 143 | - | ||
| 144 | - | ||
| 145 | - | ||
| 146 | - | ||
| 147 | - | ||
| 157 | + | Dies ist ähnlich des Polling verfahren, der Unterschied, man teilt mit **RXCIE0** mit, das beim Zeichenempfang ein Interrupt ausgelöst wird. | |
| 148 | 158 | ``` | |
| 159 | + | procedure UARTInit; | |
| 160 | + | begin | |
| 161 | + | UBRR0 := teiler; | |
| 162 | + | ||
| 163 | + | UCSR0A := (0 shl U2X0); | |
| 164 | + | UCSR0B := (1 shl TXEN0) or (1 shl RXEN0) or (1 shl RXCIE0); | |
| 165 | + | UCSR0C := %011 shl UCSZ0; | |
| 166 | + | end; | |
| 167 | + | ``` | |
| 149 | 168 | ||
| 150 | 169 | ### Interrupt | |
| 151 | 170 | ||
| 152 | - | ||
| 153 | - | ||
| 154 | - | ||
| 155 | - | ||
| 156 | - | ||
| 157 | - | ||
| 158 | - | ||
| 159 | - | ||
| 160 | - | ||
| 161 | - | ||
| 162 | - | ||
| 163 | - | ||
| 164 | - | ||
| 165 | - | ||
| 166 | - | ||
| 167 | - | ||
| 168 | - | ||
| 171 | + | Bei auslösen des Interrupts, wird das Zeichen vom UART in Zeichenbuffer kopiert. | |
| 172 | + | ``` | |
| 173 | + | procedure UART_RX_Empfang; public Name 'USART__RX_ISR'; interrupt; | |
| 174 | + | var | |
| 175 | + | b: byte; | |
| 176 | + | begin | |
| 177 | + | ||
| 178 | + | // Zeichen einlesen | |
| 179 | + | b := UDR0; | |
| 180 | + | ||
| 181 | + | // Zeichen in Puffer schreiben. | |
| 182 | + | if b <> 0 then begin | |
| 183 | + | RxBuf[rxwrite] := b; | |
| 184 | + | Inc(RXwrite); | |
| 185 | + | if RXwrite >= Crxlen then begin | |
| 186 | + | RXwrite := 0; | |
| 187 | + | end; | |
| 188 | + | end; | |
| 169 | 189 | end; | |
| 170 | - | ||
| 171 | - | ||
| 172 | 190 | ``` | |
| 173 | 191 | ||
| 174 | 192 | ### Hauptschleife | |
| 175 | 193 | ||
| 176 | - | ||
| 177 | - | ||
| 178 | - | ||
| 194 | + | In der Hauptschleife wird geprüft, ob sich etwas im Empfangspuffer, wen ja, wird ein Zeichen davon ausgelesen. In diesem Beispiel werden, die empfangenen Zeichen in Grossbuchstaben umgewandelt und anschiessend wieder ausgegeben. | |
| 195 | + | ``` | |
| 179 | 196 | begin | |
| 180 | - | ||
| 181 | - | ||
| 182 | - | ||
| 183 | - | ||
| 184 | - | ||
| 185 | - | ||
| 186 | - | ||
| 187 | - | ||
| 188 | - | ||
| 189 | - | ||
| 190 | - | ||
| 191 | - | ||
| 192 | - | ||
| 193 | - | ||
| 194 | - | ||
| 195 | - | ||
| 196 | - | ||
| 197 | - | ||
| 198 | - | ||
| 199 | - | ||
| 200 | - | ||
| 201 | - | ||
| 202 | - | ||
| 197 | + | // UART inizialisieren, die Interrupt gesteuert ist. | |
| 198 | + | UARTInit; | |
| 199 | + | ||
| 200 | + | // Interrupt aktivieren. | |
| 203 | 201 | asm sei end; | |
| 204 | - | ||
| 205 | - | ||
| 206 | - | ||
| 207 | - | ||
| 208 | - | ||
| 209 | - | ||
| 210 | - | ||
| 211 | - | ||
| 212 | - | ||
| 213 | - | ||
| 214 | - | ||
| 202 | + | ||
| 203 | + | // Hauptschleife. | |
| 204 | + | repeat | |
| 205 | + | ||
| 206 | + | // Ist ein Zeichen im Puffer ? | |
| 207 | + | while RXwrite <> rxread do begin | |
| 208 | + | ||
| 209 | + | // Interrupt sperren. | |
| 210 | + | asm cli end; | |
| 211 | + | ||
| 212 | + | // Zeichen aus Puffer lesen | |
| 213 | + | ch := RXBuf[rxread]; | |
| 214 | + | Inc(RXread); | |
| 215 | + | if RXread >= Crxlen then begin | |
| 216 | + | RXread := 0; | |
| 217 | + | end; | |
| 218 | + | ||
| 219 | + | // Interrupt aktivieren. | |
| 220 | + | asm sei end; | |
| 221 | + | ||
| 222 | + | // Wen kleiner Buchstaben, diesen in einen grossen umwandeln. | |
| 223 | + | if ch in [$61..$7A] then begin | |
| 224 | + | Dec(ch, 32); | |
| 225 | + | end; | |
| 226 | + | ||
| 227 | + | // Zeichen ausgeben. | |
| 228 | + | UARTSendChar(char(ch)); | |
| 229 | + | end; | |
| 230 | + | until 1 = 2; | |
| 231 | + | end. | |
| 215 | 232 | ``` | |
| 216 | 233 | ||
| 217 | 234 | ## Sendepuffer | |
| 218 | 235 | ||
| 219 | 236 | ### Deklaration | |
| 220 | 237 | ||
| 221 | - | ||
| 222 | - | ||
| 223 | - | ||
| 238 | + | Sendepuffer deklarieren, hier wir ein Puffer von 16 Zeichen angelegt. | |
| 239 | + | ``` | |
| 224 | 240 | const | |
| 225 | - | ||
| 226 | - | ||
| 227 | - | ||
| 228 | - | ||
| 229 | - | ||
| 241 | + | CTXlen = 16; // Puffergrösse | |
| 242 | + | var | |
| 243 | + | TXBuf: array[0..CTXlen - 1] of byte; | |
| 244 | + | TXread: byte = 0; | |
| 245 | + | TXwrite: byte = 0; | |
| 230 | 246 | ``` | |
| 231 | 247 | ||
| 232 | 248 | ### Inzialisieren | |
| 233 | 249 | ||
| 234 | - | ||
| 235 | - | ||
| 236 | - | ||
| 237 | - | ||
| 238 | - | ||
| 239 | - | ||
| 240 | - | ||
| 241 | - | ||
| 242 | - | ||
| 243 | - | ||
| 244 | - | ||
| 250 | + | Dies ist ähnlich des Empfangsbuffer verfahren, wichtig dabei, die Interrupt-Funktion darf noch **nicht** aktiviert werden, da es am Anfang noch nichts zu senden gibt. | |
| 245 | 251 | ``` | |
| 252 | + | procedure UARTInit; | |
| 253 | + | begin | |
| 254 | + | UBRR0 := teiler; | |
| 255 | + | ||
| 256 | + | UCSR0A := (0 shl U2X0); | |
| 257 | + | UCSR0B := (1 shl TXEN0) or (1 shl RXEN0); | |
| 258 | + | UCSR0C := %011 shl UCSZ0; | |
| 259 | + | end; | |
| 260 | + | ``` | |
| 246 | 261 | ||
| 247 | 262 | ### Interrupt | |
| 248 | 263 | ||
| 249 | - | ||
| 250 | - | ||
| 251 | - | ||
| 264 | + | Der Interrupts, wird ausgelöst, sobald das Zeichen im UART gesendet wurde. | |
| 252 | 265 | ||
| 253 | - | ||
| 266 | + | Sobald der Ringpuffer leer ist, wird die Interrupt-Funktion wider deaktiviert. | |
| 254 | 267 | ||
| 255 | - | ||
| 256 | - | ||
| 257 | - | ||
| 258 | - | ||
| 259 | - | ||
| 268 | + | Die Abfrage von **UDRE0** wird hier nicht gebraucht, da der Interrupt nur ausgelöst wird, wen der Puffer leer ist. | |
| 269 | + | ``` | |
| 270 | + | procedure UART_UDRE_Senden; public Name 'USART__UDRE_ISR'; interrupt; | |
| 271 | + | begin | |
| 272 | + | // Zeichen Senden. | |
| 273 | + | UDR0 := TXBuf[TXread]; | |
| 274 | + | ||
| 275 | + | // Ringpuffer verschieben. | |
| 276 | + | Inc(TXread); | |
| 260 | 277 | ||
| 261 | - | ||
| 262 | - | ||
| 263 | - | ||
| 264 | - | ||
| 265 | - | ||
| 266 | - | ||
| 267 | - | ||
| 268 | - | ||
| 269 | - | ||
| 270 | - | ||
| 271 | - | ||
| 272 | - | ||
| 273 | - | ||
| 278 | + | // Wen Zeiger am Ende, wieder von vorn beginnen. | |
| 279 | + | if TXread >= CTXlen then begin | |
| 280 | + | TXread := 0; | |
| 281 | + | end; | |
| 282 | + | ||
| 283 | + | // Ist Ringpuffer leer, kein Interrupt mehr nötig- | |
| 284 | + | if TXread = TXwrite then begin | |
| 285 | + | UCSR0B := UCSR0B and not (1 shl UDRIE0); | |
| 286 | + | end; | |
| 287 | + | end; | |
| 274 | 288 | ``` | |
| 275 | 289 | ||
| 276 | 290 | ### String senden | |
| 277 | 291 | ||
| 278 | - | ||
| 279 | - | ||
| 280 | - | ||
| 281 | - | ||
| 282 | - | ||
| 283 | - | ||
| 284 | - | ||
| 285 | - | ||
| 286 | - | ||
| 287 | - | ||
| 288 | - | ||
| 289 | - | ||
| 290 | - | ||
| 291 | - | ||
| 292 | + | Sobald sich etwas im Rindpuffer befindet, wird der Interrupt weder aktiviert. | |
| 293 | + | ``` | |
| 294 | + | procedure UARTSendString(s: ShortString); | |
| 295 | + | var | |
| 296 | + | i: byte; | |
| 297 | + | begin | |
| 298 | + | ||
| 299 | + | // Ringpuffer mit Daten befüllen, | |
| 300 | + | for i := 1 to Length(s) do begin | |
| 301 | + | TXBuf[TXwrite] := byte(s[i]); | |
| 302 | + | Inc(TXwrite); | |
| 303 | + | if TXwrite >= CTXlen then begin | |
| 304 | + | TXwrite := 0; | |
| 305 | + | end; | |
| 306 | + | end; | |
| 307 | + | ||
| 308 | + | // Sende Interrupt aktivieren. | |
| 309 | + | UCSR0B := UCSR0B or (1 shl UDRIE0); | |
| 292 | 310 | end; | |
| 293 | - | ||
| 294 | - | ||
| 295 | - | ||
| 296 | - | ||
| 297 | - | ||
| 298 | 311 | ``` | |
| 299 | 312 | ||
| 300 | 313 | ### Hauptschleife | |
| 301 | 314 | ||
| 302 | - | ||
| 303 | - | ||
| 304 | - | ||
| 315 | + | Der String wird extra ein wenig koatisch ausgegeben, dies sollte zeigen, das die Ausgabe im Hintergrund abläuft. Im Beispiel, blinkt sogar eine LED während der Ausgabe. | |
| 316 | + | ``` | |
| 305 | 317 | var | |
| 306 | - | ||
| 307 | - | ||
| 308 | - | ||
| 309 | - | ||
| 310 | - | ||
| 311 | - | ||
| 312 | - | ||
| 313 | - | ||
| 314 | - | ||
| 315 | - | ||
| 316 | - | ||
| 317 | - | ||
| 318 | - | ||
| 319 | - | ||
| 320 | - | ||
| 321 | - | ||
| 322 | - | ||
| 323 | - | ||
| 324 | - | ||
| 325 | - | ||
| 326 | - | ||
| 327 | - | ||
| 328 | - | ||
| 329 | - | ||
| 330 | - | ||
| 331 | - | ||
| 332 | - | ||
| 318 | + | z: byte; | |
| 319 | + | s: ShortString; | |
| 320 | + | begin | |
| 321 | + | DDRB := DDRB or (1 shl 5); | |
| 322 | + | // UART inizialisieren, die Interrupt gesteuert. | |
| 323 | + | UARTInit; | |
| 324 | + | ||
| 325 | + | // Interrupt aktivieren. | |
| 326 | + | asm Sei end; | |
| 327 | + | ||
| 328 | + | // Hauptschleife. | |
| 329 | + | repeat | |
| 330 | + | UARTSendString('Hello World'); | |
| 331 | + | UARTSendString(' !'#13#10); | |
| 332 | + | ||
| 333 | + | PORTB := PORTB or (1 shl 5); | |
| 334 | + | mysleep(sl); | |
| 335 | + | ||
| 336 | + | Str(z: 3, s); | |
| 337 | + | UARTSendString(s + '. '); | |
| 338 | + | Inc(z); | |
| 339 | + | ||
| 340 | + | PORTB := PORTB and not (1 shl 5); | |
| 341 | + | mysleep(sl); | |
| 342 | + | ||
| 343 | + | until 1 = 2; | |
| 344 | + | end. | |
| 333 | 345 | ``` | |
| 334 | 346 | ||
| 335 | 347 | # Software - UART / UART - Emulation | |
| 336 | 348 | ||
| 337 | - | ||
| 349 | + | Es ist auch möglich eine UART-Schnittstelle per Software zu emulieren. | |
| 338 | 350 | ||
| 339 | - | ||
| 351 | + | Dies ist praktisch, wen man einen AVR hat, welcher keinen/zuwenig Hardware-UART hat. | |
| 340 | 352 | ||
| 341 | - | ||
| 353 | + | **Hinweis:** Dieser Code funktioniert nur mit **16MHz** CPU-Takt und **9600Baud**. Einfach **Baud** und **CPU_Clock** anzupassen reicht nicht, weil die Formel noch einen Fehler hat. | |
| 342 | 354 | ||
| 343 | - | ||
| 355 | + | **Wichtig:** Während der Übertragung, müssen Interrupts gesperrt werden. | |
| 344 | 356 | ||
| 345 | - | ||
| 357 | + | Gleichzeigtes lesen und schreiben funktioniert nicht, da kein Puffer vorhanden ist. | |
| 346 | 358 | ||
| 347 | - | ||
| 359 | + | Im Idealfall ist dies gut verwendbar, um Fehler auf ein UART-Terminal auszugeben. | |
| 348 | 360 | ||
| 349 | 361 | ## Konstanten | |
| 350 | 362 | ||
| 351 | - | ||
| 352 | - | ||
| 353 | - | ||
| 363 | + | In diesem Beispiele werden die Pin 2 & 3 von PortD verwendet. | |
| 364 | + | ``` | |
| 354 | 365 | const | |
| 355 | - | ||
| 356 | - | ||
| 357 | - | ||
| 358 | - | ||
| 359 | - | ||
| 360 | - | ||
| 361 | - | ||
| 366 | + | CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz. | |
| 367 | + | Baud = 9600; // Baudrate | |
| 368 | + | ||
| 369 | + | TXpin = (1 shl 3); // Pin 3 ( Empfangen ) | |
| 370 | + | RXpin = (1 shl 2); // Pin 2 ( Senden ) | |
| 371 | + | ||
| 372 | + | SoftTeiler = CPU_Clock div (Baud * 22); // Bitzeitzähler | |
| 362 | 373 | ``` | |
| 363 | 374 | ||
| 364 | - | ||
| 365 | - | ||
| 366 | - | ||
| 375 | + | Den Empfangs-Pin auf Input stellen. | |
| 376 | + | ``` | |
| 367 | 377 | begin | |
| 368 | - | ||
| 369 | - | ||
| 370 | - | ||
| 371 | - | ||
| 372 | - | ||
| 378 | + | DDRD := DDRD or TXpin; | |
| 379 | + | ... | |
| 380 | + | // Loop | |
| 381 | + | ... | |
| 382 | + | end. | |
| 373 | 383 | ``` | |
| 374 | 384 | ||
| 375 | - | ||
| 376 | - | ||
| 377 | - | ||
| 385 | + | **Hinweis:** Will man die gleichen Pins wie bei der Hardware-UART verwenden, muss beim Arduino der Pin **0** & **1** frei gegeben werden. | |
| 386 | + | ``` | |
| 378 | 387 | begin | |
| 379 | - | ||
| 380 | - | ||
| 381 | - | ||
| 382 | - | ||
| 383 | - | ||
| 388 | + | UCSR0B := 0; // Blockierter Pin 0 & 1 frei geben | |
| 389 | + | ... | |
| 390 | + | // Loop | |
| 391 | + | ... | |
| 392 | + | end. | |
| 384 | 393 | ``` | |
| 385 | 394 | ||
| 386 | 395 | ## Zeichen senden | |
| 387 | - | ||
| 388 | - | ||
| 389 | - | ||
| 390 | - | ||
| 391 | - | ||
| 392 | - | ||
| 393 | - | ||
| 394 | - | ||
| 395 | - | ||
| 396 | - | ||
| 397 | - | ||
| 398 | - | ||
| 399 | - | ||
| 400 | - | ||
| 401 | - | ||
| 402 | - | ||
| 403 | - | ||
| 404 | - | ||
| 405 | - | ||
| 406 | 396 | ``` | |
| 397 | + | procedure UARTSoftSendByte(c: byte); | |
| 398 | + | var | |
| 399 | + | i, Data: int16; | |
| 400 | + | j: Int8; | |
| 401 | + | begin | |
| 402 | + | asm Cli end; // Interrupt sperren | |
| 403 | + | Data := (c shl 1) or $FE00; | |
| 404 | + | for j := 0 to 9 do begin // Bit ausgeben, inklusiv Stop-Bits. | |
| 405 | + | if (Data and 1) = 1 then | |
| 406 | + | PORTD := PORTD or TXpin // HIGH | |
| 407 | + | else | |
| 408 | + | PORTD := PORTD and not TXpin; // LOW | |
| 409 | + | Data := Data shr 1; | |
| 410 | + | for i := 0 to SoftTeiler do; // Ein Takt Pause | |
| 411 | + | end; | |
| 412 | + | asm Sei end; // Interrupt erlauben | |
| 413 | + | end; | |
| 414 | + | ``` | |
| 407 | 415 | ||
| 408 | 416 | ## Zeichen empfangen | |
| 409 | 417 | ||
| 410 | - | ||
| 411 | - | ||
| 412 | - | ||
| 413 | - | ||
| 414 | - | ||
| 415 | - | ||
| 416 | - | ||
| 417 | - | ||
| 418 | - | ||
| 419 | - | ||
| 420 | - | ||
| 421 | - | ||
| 422 | - | ||
| 423 | - | ||
| 424 | - | ||
| 425 | - | ||
| 426 | - | ||
| 427 | - | ||
| 428 | - | ||
| 429 | - | ||
| 430 | - | ||
| 418 | + | **Hinweis:** Wen kein Zeichen im Empfang kommt, hängt die Schleife im Endlosen. | |
| 431 | 419 | ``` | |
| 420 | + | function UARTSoftReadByte: byte; | |
| 421 | + | var | |
| 422 | + | i: Int16; | |
| 423 | + | j: Int8; | |
| 424 | + | begin | |
| 425 | + | asm Cli end; // Interrupt sperren | |
| 426 | + | Result := 0; | |
| 427 | + | while PIND and RXpin > 0 do; // Warten bis erste fallende Flanke | |
| 428 | + | for i := 0 to SoftTeiler div 2 do; // Ein halber Takt Pause | |
| 429 | + | for j := 0 to 7 do begin | |
| 430 | + | for i := 0 to SoftTeiler do; // Ein Takt Pause | |
| 431 | + | Result := Result shr 1; | |
| 432 | + | if PIND and RXpin <> 0 then | |
| 433 | + | Inc(Result, $80); | |
| 434 | + | end; | |
| 435 | + | for i := 0 to SoftTeiler; // Ein Takt Pause | |
| 436 | + | asm Sei end; // Interrupt erlauben | |
| 437 | + | end; | |
| 438 | + | ``` | |
| 432 | 439 | ||
| 440 | + | ||
| 441 | + | ||
| 433 | 442 | # Siehe auch | |
| 434 | 443 | ||
| 435 | - | ||
| 444 | + | * Übersichtseite [[AVR Embedded Tutorial/de|AVR Embedded Tutorial]] | |
| 436 | 445 | ||
| 437 | - | ||
| 446 | + | Autor: [Mathias](</User:Mathias> "User:Mathias") | |
| 438 | 447 | ||
| 439 | 448 | --- | |
| 440 | - | ||
| 441 | - | ||
| 442 | - | ||
| 443 | - | ||
| 444 | - | ||
| 445 | - | ||
| 449 | + | *From the Free Pascal wiki, page "AVR Embedded Tutorial - UART/de", as the Internet Archive kept it on 2023-03-20. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
