1
Serielle Kommunikation mit UART/USART
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART
●
Serielle Kommunikation mit RS232
●
Seit 1962 !
●
Spezifikation regelt elektrische und mechanische Belange
●
Pegelanpassung zwischen TTL (0/5V) und RS232 (+/- ca.14V) nötig (MAX232)
●
-3..-25V: 1 | 3..25V: 0
●
Rx (PD0) / Tx (PD1) Pins beschalten (verbinden
mit MAX232–Platine oder USB-Adapter
2
Der Serielle Port (die Leitungen)
Begriffe:
DTE: Data Terminal Equipment (PC, Fax, verarbeitendes Gerät, male)
DCE: Data Carrier Equipment (Daten transportierendes Gerät. Modem,.., fem) RTS: Ausgang, Redy To Send, Will Daten senden
CTS: Eingang, Clear To Send, Bereitschaft Daten zu empfangen Tx : Data Transmitter, Datensendeleitung
Rx : Data Receiver; Datenempfangsleitung
RTS/CTS dienen dem Hardware Handshake
3
Handshake (Hardware)
http://www.oliver-saal.de/elektronik/rs232.php
RTS CTS
Request to Send „Sendeanforderung“; Ein High-Pegel an diesem Ausgang signalisiert, dass DTE Daten senden möchte
Clear to Send
„Sendeerlaubnis“; Ein High-Pegel an diesem Eingang ist ein Signal der Gegenstelle, dass sie Daten von DTE
entgegennehmen kann
XON/XOFF bilden die Flowcontroll-Steuerzeichen (Xon = 11h und Xoff = 13h).
Es werden nur die Datenübertragungsleitungen benötigt
Die Zeichen 0x11 und 0x13 dürfen in den Daten nicht vorkommen
Handshake (Software)
5
Pins Sub-D 9, Sub-D 25
PCCOM1 PCCOM2
RS232 Bezeichnung
1 8 DCD in
2 3 in Empfangsdaten
3 2 Sendedaten
4 20 DTR
5 7 GND
6 6 DSR in
7 4 RTS
8 5 CTS in
9 22 RI in
- 12
- 23 SPDS
9Pol männl 25Pol männl
Data Carrier Detect RxD
TxD out
out Data Terminal Ready
Ground - Bezugspotential Data Set Ready
out Request to send Sendeanfrage Clear to send
Ring Indicator (Klingel)
SpeedModeDetector
Speed select
6
Übertragungsprotokoll
http://www.mikrocontroller.net/articles/RS-232
Anmerkungen:
1: low Pegel (-15..-3V) 0: high Pegel (3.. 15V)
Modus : 8N1 (8 Datenbit, no parity bit, 1 Stopp Bit)
Baud : 9600 Baud Übertragungsgeschwindigkeit s. u.
7
Baudrate
http://www.bluray-disc.de/lexikon/baudrate
Die Baudrate ist die Größe, die in der Nachrichten- und
Übertragungstechnik die Signalrate angibt. Sie steht für die Anzahl der Zustands- oder Symboländerungen in einer bestimmten Zeiteinheit an, die eine Übertragung erfährt.
Die Einheit der Baudrate ist 1 Baud [1 Bd], benannt nach dem französischen Wissenschaftler Jean-Maurice-Emile Baudot, dem zahlreiche Erfindungen auf dem Gebiet der Telegrafie zu verdanken sind.
Die Baudrate wird häufig mit der Bitrate verwechselt. Die Bitrate steht im Gegensatz zur Baudrate aber für die Datenrate. Baudrate und
Bitrate sind gleich, wenn ein Symbol (0/1) genau einem Bit entspricht.
8
Anschluss UART/MAX232
USB-UART-Adapter:
sw : GND
rt : +5V offen lassen, wenn Programmer dran ws : tx
gr : rx
9
Steuerregister des USART des Atmega
Port Funktion Port-Adresse RAM-Adresse UCSRAUSART Status Register0x0B 0x2B
7 6 5 4 3 2 1 0
RXC TXC UDRE FE OR PE U2X MPCM
Bit Name Bedeutung Funktion
7 RXC UART Receive Complete 1: Zeichen empfangen/0: Kein Zeichen 6 TXC UART Transmit Complete 1: Daten aus Schieberegister gesendet 5 UDRE UART Data Register Empty1: Senderegister frei
4 FE Framing Error 1: Ungültiges Stop-Bit
3 DOR Overrun 1: Zeichenverlust
2 PE Paritätskontrolle 1:Paritätsfehler 1 U2X doppelte Baudrate
0 MPCM Multiprozessorbetrieb (Daten/Adressen)
10
Bit Name Bedeutung
7 RXCIE enable Interrupt receive complete 6 TXCIE enable Interrupt transmit complete
5 UDREIE enable Interrupt transmit data register free
4 RXEN enable Receive
3 TXEN enable transmit
2 UCSZ2 Zeichenlänge zusammen mit UCSZ1 und UCSZ0 aus UCSRC
1 RXB8 9. Bit received
0 TXB8 9. Bit transmit
7 6 5 4 3 2 1 0
RXCIE TXCIE UDRIE RXEN TXEN UCSZ2 RXB8 TXB8
Port Funktion Port-Adresse RAM-Adresse
UCSRB USART Steuer Register 0x0A 0x2A
11
Port Funktion Port-Adresse RAM-Adresse
UCSRC USART Steuer Register 0x20 0x40
7 6 5 4 3 2 1 0
URSEL UMSEL UPM1 UPM0 USBS UCSZ1 UCSZ0 UCPOL
Bit Name Bedeutung Funktion
7 URSEL 1: immer, wenn UCSRC angesprochen werden soll,
weil UBRRH die selbe Adresse hat
1: UCSRC 0: UBRRH
6 UMSEL synchron/asynchron 0:Asyn, 1: Synchon
5 4
UPM1 UPM0
Parität 00:none
01:reserved 10:even 11:odd
3 USBS stopp bits 0:1 Stoppbit
1:2 Stoppbits
2 UCSZ1
UCSZ0 Zeichenlänge zusammen mit UCSZ2 aus
UCSRB 000:5 bit
001:6 bit 010:7 bit 011:8 bit 111:9 bit 0 UCPOL Synchon: Phasenlage
12
Synchroner/Asyncroner Modus
●
Synchron:
– Noch nicht getestet
– Auf zusätzlicher Taktleitung wird ein Übertragungstakt geschaltet
– Bei Atmega XCK (PD4)
●
Asynchron:
– Es wird ein Datenstrom von Bits übertragen
– Start- Stopbit Kennzeichnen Anfang und Ende
einer Übertragung
13
Port Funktion Adresse Ramadresse
UDR UART I/O Data
Register 0x0C 0x2C
UBRRH Baudratenregister
(high) 0x20 0x40
UBRRL Baudratenregister
(low) 0x09 0x29
Das UART DATA Register (UDR) besteht eigentlich aus den Registern UDR transmit und UDR receive.
Beide werden über die selbe Adresse angesprochen,
offenbar erfolgt die
Unterscheidung an Hand der Lese-/Schreiboperation
Mode Calulating UBRR Calculating result. BAUD Normal mode
(asynchronous)
double speed
Aushttp://www.mikrocontroller.net /articles/AVR-Tutorial:_UART
UBRR= FCPU
16∗BAUD −1 UBRR= FCPU
8 ∗ BAUD −1
UBRR= FCPU BAUD∗ 8
BAUD∗16 −1
BAUD = FCPU
16∗UBRR 1
BAUD = FCPU
8∗ UBRR 1 Mit math. Runden
Mit Abschneiden
(C-like)
14
Tabelle für UBRR
1 MHz 1,8432 MHz 2 MHz 3,686411 MHz 4 MHz 7,3728 MHz 8 MHz
2400 25 0,20% 47 0,00% 51 0,20% 95 0,00% 103 0,20% 191 0,00% 207 0,20%
4800 12 0,20% 23 0,00% 25 0,20% 47 0,00% 51 0,20% 95 0,00% 103 0,20%
9600 6 -7,00% 11 0,00% 12 0,20% 23 0,00% 25 0,20% 47 0,00% 51 0,20%
14400 3 8,50% 7 0,00% 8 -3,50% 15 0,00% 16 2,10% 31 0,00% 34 -0,80%
19200 2 8,50% 5 0,00% 6 -7,00% 11 0,00% 12 0,20% 23 0,00% 25 0,20%
28800 1 8,50% 3 0,00% 3 8,50% 7 0,00% 8 -3,50% 15 0,00% 16 2,10%
38400 1 -18,60% 2 0,00% 2 8,50% 5 0,00% 6 -7,00% 11 0,00% 12 0,20%
57600 0 8,50% 1 0,00% 1 8,50% 3 0,00% 3 8,50% 7 0,00% 8 -3,50%
76800 0 -18,60% 1 -25,00% 1 -18,60% 2 0,00% 2 8,50% 5 0,00% 6 -7,00%
115200 0 -45,70% 0 0,00% 0 8,50% 1 0,00% 1 8,50% 3 0,00% 3 8,50%
230400 0 -72,90% 0 -50,00% 0 -45,70% 0 0,00% 0 8,50% 1 0,00% 1 8,50%
250000 0 -75,00% 0 -53,90% 0 -50,00% 0 -7,80% 0 0,00% 1 -7,80% 1 0,00%
Error = BAUD
resBAUD −1 ∗ 100
Es wird dringend empfohlen, einen mit einem Quarz
stabilisierten Oszillator zu verwenden
15
Tabelle für UBRR
11,0592 MHz 14,318 MHz 14,7456 MHz 16 MHz 18,432 MHz 20 MHz
2400 287 0,00% 372 0,00% 383 0,00% 416 -0,10% 479 0,00% 520 0,00%
4800 143 0,00% 185 0,20% 191 0,00% 207 0,20% 239 0,00% 259 0,20%
9600 71 0,00% 92 0,20% 95 0,00% 103 0,20% 119 0,00% 129 0,20%
14400 47 0,00% 61 0,20% 63 0,00% 68 0,60% 79 0,00% 86 -0,20%
19200 35 0,00% 46 -0,80% 47 0,00% 51 0,20% 59 0,00% 64 0,20%
28800 23 0,00% 30 0,20% 31 0,00% 34 -0,80% 39 0,00% 42 0,90%
38400 17 0,00% 22 1,30% 23 0,00% 25 0,20% 29 0,00% 32 -1,40%
57600 11 0,00% 15 -2,90% 15 0,00% 16 2,10% 19 0,00% 21 -1,40%
76800 8 0,00% 11 -2,90% 11 0,00% 12 0,20% 14 0,00% 15 1,70%
115200 5 0,00% 7 -2,90% 7 0,00% 8 -3,50% 9 0,00% 10 -1,40%
230400 2 0,00% 3 -2,90% 3 0,00% 3 8,50% 4 0,00% 4 8,50%
250000 2 -7,80% 3 -10,50% 3 -7,80% 3 0,00% 4 -7,80% 4 0,00%
16
Empfehlungen zum Praktikum
●
Übertragungsprotokoll 8N1
●
9600 Baud
●
Asynchone Übertragung
●
Übertragungsparameter müssen sende- und empfangsseitig übereinstimmen
●
Empfang interruptgesteuert / Pollingbetrieb, je nach Anwendungsfall
●
Quarz verwenden, make ext_11mhz, F_CPU=11059200 einstellen
●
Empfangene Zeichen müssen auch „abgeholt
werden“, ansonsten kommt es zu Datenverlust
17
Initialisierung des USART
// Baudratenteiler mit einem der beiden nachfolgenden Macros (empfohlen:9600Baud)
#define UBRR ((F_CPU+BAUD*8)/(BAUD*16)-1)
#define UBRR ((F_CPU/(16UL*BAUD))-1) /* Baudrate einstellen*/
UBRRH = (unsigned char) (UBRR_BAUD>>8);
UBRRL = (unsigned char) UBRR_BAUD&0xff;
// Aktivieren von receiver und transmitter // RXEN Receive enable
// TXEN Transmit enable
// RXCIE Receive complete Interrupt enable
UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
/* Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit, keine Paritätskontrolle */
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // 8N1
// Flush Receive-Buffer (entfernen evtl. vorhandener ungültiger Werte) do
{
uint8_t dummy;
(void) (dummy = UDR);
}
while (UCSRA & (1 << RXC));
Empfang interruptgesteuert
URSEL immer angeben,
wenn UCSRC angesprochen
wird
Bei 9600 BAUD und 11059200MHz sollten beide
Formen gehen (71)
18
USART Init
funktioniert mit 8MHz und 9600 Baud
/* Initialization of USART */
void USART_Init( unsigned int ubrr) {
/* Set baud rate */
UBRRH = (unsigned char) (ubrr >> 8);
UBRRL = (unsigned char) ubrr;
/* Enable receiver and transmitter */
/* Interrupt bei Empfang */
UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE);
/* Set frame format: 8data, 1stop bit, synchronous operation */
UCSRC = (1 << URSEL) |(1<<UCSZ1)|(1<<UCSZ0);
do {
uint8_t dummy;
(void) (dummy = UDR);
}
while (UCSRA & (1 << RXC));
sei();
}
/* Initialization of USART */
void USART_Init( unsigned int ubrr) {
/* Set baud rate */
UBRRH = (unsigned char) (ubrr >> 8);
UBRRL = (unsigned char) ubrr;
/* Enable receiver and transmitter */
/* Interrupt bei Empfang */
UCSRB = (1 << RXEN) | (1 << TXEN) | (1 << RXCIE);
/* Set frame format: 8data, 1stop bit, synchronous operation */
UCSRC = (1 << URSEL) |(1<<UCSZ1)|(1<<UCSZ0);
do {
uint8_t dummy;
(void) (dummy = UDR);
}
while (UCSRA & (1 << RXC));
sei();
}
19
/* Interrupt for USART, Rx Complete */
ISR(USART_RXC_vect) {
static BYTE rcv_data, status;
status = UCSRA; // erst Status lesen rcv_data = UDR; // dann Daten lesen
/* Check for the error (High => error, Low => OK */
/* Flags: FE - Frame Error; DOR - Data OverRun; PE - Parity Error */
if( status & ((1 << FE) | (1 << DOR) | (1 << PE)) ) {
if( status & (1 << FE)) PORTB |= 1 << PIN1; // 2. LED if( status & (1 << DOR))PORTB |= 1 << PIN2; // 3. LED if( status & (1 << PE)) PORTB |= 1 << PIN3; // 4. LED } else
{
PORTB &= ~((1 << PIN1) | (1 << PIN2) | (1 << PIN3));
if(rcv_data == '1')
PORTB |= 1 << PIN0; // Erste LED einschalten if(rcv_data == '0')
PORTB &= ~(1 << PIN0); // Erste LED ausschalten }
}
Byte empfangen
20
Byte empfangen
Hier ohne Statusabfrage, dafür mit Ringpuffer zum Zwischenspeichern empfangener Zeichen
unsigned char buffer[RING_SIZE];
volatile unsigned short irr=0, irw=0;
ISR(USART_RXC_vect) {
if(UCSRA&(1<<RXC)) {
buffer[irw]=UDR;
irw=(irw+1)%RING_SIZE;
} }
short int ugetchar(void) {
if (irr!=irw) {
char c=buffer[irr]; irr=(irr+1)%RING_SIZE; return c;
}
else return -1;
}
21
Ausgabe auf USART
void uputch(char x) {
loop_until_bit_is_set(UCSRA, UDRE);
UDR=x;
}
void uputs(char * s) {
int n=0;
while(*(s))uputch(*s++),n++;
}
void uputu(unsigned long d) {
if (d>=10) uputu(d/10);
uputch(d%10+'0');
}
void uputd(long d) {
if (d<0) {uputch('-');d=-d;}
uputu(d);
}
void uputx(unsigned long d) {
if (d>=0x10) uputx(d/0x10);
uputch(d%0x10>9?d%16+'A'-10:d
%16+'0');
}
char * itoadec (char * buf, int i, int len, char leading) {
unsigned int itmp=i>0?i:-i;
buf[len]=0;
len --;
while (len>=0) {
if (itmp>0) buf[len--]=itmp%10+'0';
else buf[len--]=(buf[len+1]!=0)?leading:'0';
itmp/=10;
}
if (i<0)buf[0]='-';
return buf;
}
char * itoahex (char * buf, unsigned int i, int len, char leading) {
buf[len]=0;
len --;
while (len>=0) {
if (i>0) buf[len--]=i%0x10<10? i%0x10+'0': i%0x10+'A'-10;
else buf[len--]=leading;
i/=0x10;
}
return buf;
}
Data Register Empty
22
Der PC, die andere Seite, init
int init() {
/*** Init ***/
//O_RDONLY, O_WRONLY or O_RDWR -
//O_NDELAY (geht weiter, wenn keine Daten da sind und gibt "-1" zurueck) // man 2 open fuer mehr Infos - see man 2 for more info
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY);
if (fd < 0){
printf("Fehler beim oeffnen von %s\n", MODEMDEVICE);
exit(-1);
}
memset(&newtio, 0, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD; //setzt die neuen Porteinstellungen newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
newtio.c_lflag = 0; /* set input mode (non-canonical, no echo, ...) */
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 1 chars received */
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &newtio);
return fd;
}
23
unsigned char receive() {
int res;
unsigned char buffer;
res = read(fd, &buffer, 1);
return buffer;
}
unsigned char send(char c) {
int res=write(fd, &c, 1);
if (res<0) printf("Fehler beim Senden\n");
return res;
}
PC, send, receive
24
Terminal als Gegenstelle
●
Initilisierung der seriellen Schnittstelle /dev/ttyS0, /dev/ttyUSB0 ….
●
Verwendung von stty
●
(stty -F /dev/ttyUSB0 ispeed 9600 ospeed 9600 cs8 clocal [ixoff])
●
stty -F /dev/ttyUSB0 speed 9600 -echo
●
Lesen ist mit cat möglich:
●
cat < /dev/ttyUSB0
●
Senden mit echo xxx > /dev/ttyS0
●
Ubuntu: Anwendungen → Zubehör → Serial port terminal
25
RS485
●
Basiert ebenfalls auf serieller Übetragung
●
Andere elektrische Umsetzung über zwei Leitungen A und B.
●
Spannungspegel auf den Leitungen „spiegeln“
sich, dadurch wird eine große Störsicherheit gewährleistet.
●
Basiert ebenfalls auf serieller Übetragung
●
Andere elektrische Umsetzung über zwei Leitungen A und B.
●
Spannungspegel auf den Leitungen „spiegeln“
sich, dadurch wird eine große Störsicherheit gewährleistet.
0 1 1 1 0
A
B A: Invertiert
B nicht Invertiert A-B < 0,25V → 1 A-B > 0,25V → 0 A: Invertiert
B nicht Invertiert A-B < 0,25V → 1 A-B > 0,25V → 0
26
RS485
●
Mehrere Geräte können an einem Bus verbunden sein.
●
Ein übliches Protokoll ist Modbus RTU.
●
Ein Gerät startet die Kommunikation und
sendet eine Geräteadresse,ein Kommando, eine Registeradressse, eine Anzahl von
Registern und ggf. Werte, wenn Werte
geschrieben werden sollen. Abgeschlossen wird das Ganze mit einer Prüfsumme.
●
Mehrere Geräte können an einem Bus verbunden sein.
●
Ein übliches Protokoll ist Modbus RTU.
●
Ein Gerät startet die Kommunikation und
sendet eine Geräteadresse,ein Kommando, eine Registeradressse, eine Anzahl von
Registern und ggf. Werte, wenn Werte
geschrieben werden sollen. Abgeschlossen
wird das Ganze mit einer Prüfsumme.
27
RS485
unsigned char requestString[] ={
0xf7, // device 0x03, // command
0x13, 0xB2, // Register (big endian)
0x00, 0x0b, // number of registers (big endian) 0x00, 0x00 // CRC (little endian)
};
uint16_t ModRTU_CRC(uint8_t * buf, int len) {
uint16_t crc = 0xFFFF;
for (int pos = 0; pos < len; pos++) {
crc ^= (uint16_t)buf[pos]; // XOR byte into least sig. byte of crc
for (int i = 8; i != 0; i--) { // Loop over each bit if ((crc & 0x0001) != 0) { // If the LSB is set
crc >>= 1; // Shift right and XOR 0xA001 crc ^= 0xA001;
}
else // Else LSB is not set crc >>= 1; // Just shift right }
}
// Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes) return crc;
}
Berechnung CRC
28
RS485
●
Das angesprochene Gerät sendet dann eine Antwort, bestehend aus
– Device (1 Byte)
– Command (1Byte)
– Start Register (2 Byte big endian)
– Numb Register (2 Byte big endian)
– Values (2 Bytes/4Bytes big endian
– …
– CRC
●
Das angesprochene Gerät sendet dann eine Antwort, bestehend aus
– Device (1 Byte)
– Command (1Byte)
– Start Register (2 Byte big endian)
– Numb Register (2 Byte big endian)
– Values (2 Bytes/4Bytes big endian
– …
– CRC
29
Modbus- Geräte:
●
Elektronische Zähler SDM630-M oder SDM230-M
●
Solarlageregler Tracer
●
Lithium Batterie Renogy
●
Elektronische Zähler SDM630-M oder SDM230-M
●
Solarlageregler Tracer
●