Forum: Mikrocontroller und Digitale Elektronik UART: Hex-Bytes versenden


von Louis (Gast)


Lesenswert?

Hallo Zusammen,

ich habe nicht viel Erfahrung in der uC- Programmierung. Würde mich aber 
freuen, wenn mir trotzdem jemand bei meinem Problem weiterhelfen könnte.

Folgendes: Ich möchte gerne ein Motor ansteuern. Diesen will ich z.B. 
von 10000 U/min auf 7000 U/min mit Hilfe eines ATmega328P runter regeln.

Meine erste Frage wäre zur Initialisierung des UART:
Ich verstehe nicht ganz was diese Initialisierung bedeuten sollen. Nun 
gut das UBRR ist ein 12 Bit-Register. UBRRH enthält die 4 MSB und UBRRL 
enthält die 8 LSB. F_CPU ist ja die Taktfrequenz, beim ATmega328P also 
16MHz. Ich steh da völlig auf dem Schlauch. Kann mir da jemand 
weiterhelfen. Nun gut es gibt ja genügend Bsp. Mit denen ich das 
irgendwie zusammen würfeln könnte und es vielleicht irgendwann auch 
funktioniert. Allerdings würde ich schon gerne verstehen was das 
bedeutet.

#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>

#define F_CPU 16000000UL
#define BAUD 9600UL

#define UBRR_VAL (F_CPU+BAUD*8)/(BAUD*16)-1) //???
#define BAUD_REAL (F_CPU / (16 * (UBRR_VAL+1))) //???

#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)
#if ((BAUD_ERROR < 990) || (BAUD_ERROR < 1010))
 #error Fehler der Baudrate größer 1%
 #endif

void INIT_USART0 (void){

UBRR0H = UBRR_VAL >> 8;

UBRR0L = UBRR & 0xFF;

UCSR0A   |=(1 << U2X0);

UCSR0B  |=(1 << TXEN0) | (1 << RXEN0);  // USART Receive/Transmit 
Complete

UCSR0C  |=(1<< UCSZ01) | (1 << UCSZ00)   // Charactersize 8-bit
        |(0 << USBS0)                   // 1 Stop Bit
        |(0 << UPM01) | (0<< UPM00);   // Parity Mode disabled
}

void SEND_CHAR (unsigned char DATA){
while (!(UCSR0A & (1 << UDRE0)));
UDR0 = DATA;
}

void SEND_STRING (unsigned char *DATA){
unint8_t COUNTER = 0;
while (COUNTER == 20){
SEND_CHAR(*DATA);
DATA ++;
COUNTER++;
}
}

void main (void){

unsigned char DATA [20];

INIT_USART0 ();

for(int i=0; i++; i<20){

SEND_STRING(0xB032373130373342460D);  //10000 U/min

_delay_ms(8000);

SEND_STRING(0xB032333238303832300D);  //9000 U/min

_delay_ms(8000);

SEND_STRING(0xB031463430413537360D);  //8000 U/min

_delay_ms(8000);

SEND_STRING(0xB031423538464138420D);  //7000 U/min

_delay_ms(8000);
}
}

Meine zweite Frage wäre bezüglich der Übertragung der Hex-String.
Mit dem Hyperterminal greife ich bei 10000U/min bspw. °271073B6/r ab. 
Die entsprechenden Hex-Bytes wären: B0 32 37 31 30 37 33 42 46 0D

Bei der Eingabe dieses Strings, kann ich den Motor ansteuern. Wie 
schaffe ich das jetzt mit dem UART? Der liest ja jedes einzelne Zeichen 
(1Byte) ein also:

B 1011 0000
0 0000 0000
3 0000 0011
2 0000 0010
usw.

Allerdings muss ich das so verschicken:
B0 1011 0000
32 0011 0010
37 0011 0111
usw.

Ich wollte dass erst alles via ASCII-Darstellung über den UART jagen, 
aber „°“  ist ja ein sog. nicht druckbares Zeichen. Keine Ahnung was ich 
da machen soll. Evtl. als binäre Darstellung versenden?

Wie gesagt ich bin noch Anfänger. Wäre nett, wenn mir jemand bei meinem 
Problem weiterhelfen könnte.

Grüße,
Louis

von Huch (Gast)


Lesenswert?

>Ich steh da völlig auf dem Schlauch. Kann mir da jemand
>weiterhelfen. Nun gut es gibt ja genügend Bsp. Mit denen ich das
>irgendwie zusammen würfeln könnte und es vielleicht irgendwann auch
>funktioniert. Allerdings würde ich schon gerne verstehen was das
>bedeutet.

Nun. Bitte versuche Dir erstmal das Datenblatt durchzulesen. Da steht 
genau drin, wie der UBRRx Wert abhängig von der Taktfrequenz 
ausgerechnet wird.
Lies es am besten zwei, drei Mal. Das ist keine Schande. Machen wir 
alle, wenn es beim ersten Mal noch nicht Klick macht.

Du wirst vielleicht antworten wollen, das Du das schon gelesen hast, 
auch mehrfach aber dennoch nichts verstehst.
Ich denke aber, das Du schon einige Teile verstanden haben wirst und 
entweder einige Teile noch problematisch sind oder für Dich einiges 
nebeneinander steht ohne das Du einen Zusammenhang herstellen kannst.
Wenn das so ist, dann schreib uns was Du schon verstanden hast und wir 
können Dir dann bei Details helfen oder Dich auf einen besonderen 
Abschnitt hinweisen, der eine Lücke schliesst.

von Peter (Gast)


Lesenswert?

Louis schrieb:
> void SEND_STRING (unsigned char *DATA){
> unint8_t COUNTER = 0;
> while (COUNTER == 20){
> SEND_CHAR(*DATA);
> DATA ++;
> COUNTER++;
> }
> }

das ist schon sehr mutig, was ist wenn du mal eine andere länge als 20 
senden willst? Denn der Aufrufer weiss überhaupt nichts von der länge.
Aber noch schlimmer ist das

> while (COUNTER == 20)

das mach so überhaupt keinen sinn, weil die schleife gleich verlassen 
wird, weil coutner ja 0 ist.

von Karl H. (kbuchegg)


Lesenswert?

Louis schrieb:

> Ich wollte dass erst alles via ASCII-Darstellung über den UART jagen,

wenn du es sowieso als ASCII Darstellung 'rüberjagen' willst, dann 
spricht nichts dagegen, das gleich im Klartext zu tun.

Wenn du eine Drehzahl von 1000 U/min haben willst, dann übertrage doch 
gleich den Text
"1000;"
(der ; ist ein Hilfszeichen, weilches dem Empfänger erlaubt 
festzustellen, wann er genug Zeichen für die Zahl gesammelt hat um 
sicher zu gehen, dass die Zahl auch wirklich komplett empfangen wurde

> aber „°“  ist ja ein sog. nicht druckbares Zeichen. Keine Ahnung was ich
> da machen soll. Evtl. als binäre Darstellung versenden?

Geht auch.

Aber: Auch wenn es auf den ersten Blick komplizierter aussieht, ist eine 
Übertragung im ASCII-Klarext einfacher zu handhaben.
* Du kannst auf der Leitung besser mitlesen
* Du kannst das leichter testen
* Du hast keine Probleme mit Synchronisiermechanismen
* Fehlererkennung ist meistens einfacher

Dem steht gegenüber
* eine längere Übertragungszeit gegenüber rein binärer Übertragung
* etwas mehr Aufwand beim Empfangen und 'dekodieren' der Nachricht.

(wobei insbesondere letzter Punkt nicht DAS große Problem darstellt. So 
problemlos wie gerne gesehn ist nämlich eine rein binäre Übertragung 
auch wieder nicht, solange man keine Frame-Start/Frame-Ende Bytes 
dezidiert dafür abstellen kann.

von André (Gast)


Lesenswert?

Hallo Louis

als erstes mal zu deinem ersten Problem mit dem Einstellen der UART:
Die UART wird über die entsprechenden Register eingestellt. Schau mal 
ins Datenblatt, da findest du die Register. Jedes hat 8 Bit, wobei jedes 
Bit einen Namen hat. Um das Bit zu setzen, schiebst du eine "1" an die 
Stelle (hier: UCSR0B  |=(1 << TXEN0) | (1 << RXEN0) <- Bit TXEN0 und Bit 
RXEN0 werden gesetzt)
Um die Baudrate einzustellen gibt es die Formel. Im Datenblatt ist eine 
Tabelle, die dir sagt, welche Zahl in Register UBRR0H und UBRR0L stehen 
muss. Du willst also bei einem Systemtakt von 16Mhz eine Baud von 9600 
haben. Rechne mal, auf welche Zahl du kommst und vergleich es mit der 
Tabelle, dann verstehst du das sicher.

Die Sache, was du mit den Hex-Werten vor hast, versteh ich nicht so 
richtig. Ich glaub du springst da etwas in den Zahlensytemen hin und 
her. Auch würde ich denken, dass der Wert, der an SEND_STRING übergeben 
wird, zu groß ist.

Fakt ist eins: Deine SEND_CHAR Funktion sendet ein Zeichen, 8 Bit, 1 
Byte. Ich würde also erstmal versuchen, die Bytes einzeln zu senden, 
z.B. SEND_CHAR(0xB0); SEND_CHAR(0x32); SEND_CHAR(0x37); u.s.w.

Aber vllt sagst du uns nochmal genau, was dein Empfänger erwartet, ASCII 
Zeichen oder eine Zahl, aufgeteilt in mehrere 8 Bit Blöcke, das ist mir 
nämlich nicht klar.

Viele Grüße
André

von Louis (Gast)


Lesenswert?

Hallo zusammen,
danke für die schnellen Antworten. Aber Huch hat Recht, ich schau mir 
lieber nochmal das Datenblatt durch und stell dann konkretere Fragen. 
Das war etwas zu voreilig. Bis dann

von Karl H. (kbuchegg)


Lesenswert?

Mir ist dieser Teil nicht klar und möglicherweise ist der die Ursache 
für einige Missverständnisse

> Bei der Eingabe dieses Strings, kann ich den Motor ansteuern.

Ein Motor wird nicht dadurch angesteuert, dass man ihn an eine UART 
hängt. Einen Motor hängt man an eine Versorungsspannung und er dreht. 
Unterbricht man die Spannung hört er auf zu drehen. (*)
Um einen Motor mit einer bestimmten Drehzahl drehen zu lassen, muss es 
daher so etwas wie eine Steuerelektronik geben. Und die kann man dann 
auch mittels UART ansprechen (wenn die Steuerelektronik so etwas 
vorgesehen hat)

* dein Motor hat eine eigene Steuerung, der man bestimmte Bytes
  senden muss

* du hängst den Motor an deinen AVR an und willst vom PC aus dem AVR
  sagen wie schnell der Motor drehen muss.


(Ich bin nämlich von letzterem Fall ausgegangen, komm jetzt aber drauf, 
dass dein Posting auch für ersteren Fall aufgefasst werden könnte).


(*) vereinfacht gesagt. Bitte jetzt keine Hinweise auf Schrittmotoren 
oder dlg. Darum geht es nicht. Es geht darum, dass man nicht einfach 
einen Motor mittels UART ansprechen kann.

von Louis (Gast)


Lesenswert?

Hallo,

ich habs mir jetzt also nochmals durchgeschaut.

Zu meinem 1. Problem:

UBRR = ( f+BAUD*8 ) / (BAUD*16) -1

Wird zur besseren „Rundung“ der UBRR-Wertes verwendet.
Für UBRR gibt es zwei Register: UBRRL (Low-Byte) und UBRRH (High-Byte).

>> This is a 12-bit register which contains the USART baud rate.The UBRRnH
>> contains the four most significant bits, and the UBRRnL contains the    >> 
eight least significant bits of the USART
>> baud rate.

OK, bei 9600 bps und 16MHz erhalte ich ein UBRR_Value = 103.
Wie ich das jetzt allerdings auf das UBRRL und UBRRH übertrage, bzw. 
was/wie ich dann bei UBRR0H/UBRR0L einstellen muss, ist mir noch etwas 
unklar.

UBRR0H = UBRR_VAL >> 8;
UBRR0L = UBRR & 0xFF;

Kurze Verständnisfrage: Der F-CPU ist ja nur eine Info für den Compiler, 
aber der uC läuft dadurch j a nicht schneller oder langsamer, sondern 
immer mit deram uC eingestellten Taktfrequenz, im Falle des ATmega 328P, 
also mit 16 MHz. Dennoch meine ich, dass ich in manchen 
Programmbeispielen schon gesehen hab, dass F_CPU und de eigentliche 
Taktfrequenz nicht identisch waren bzw. F_CPU nicht entsprechend der 
Taktfrequenz angegeben wurde.

Die zweite Sache:

Ich möchte mit dem uC den Motor ansteuern- ohne PC. Sorry, war etwas 
schlecht beschrieben. Das Schnittstellenprotokoll konnte ich 
identifizieren bzw. analysieren. Mit den folgenden Befehlen kann ich mit 
Hilfe des Hyperterminals die Umdrehungsgeschwindigkeit des Motors 
regulieren. Nun soll das ein uC machen.

Mit diesem Befehl kann ich die Umdrehungsgeschwindigkeit auf 10000 U/min 
einstellen °271073B6/r. Die entsprechenden Hex-Bytes (siehe 
ASCII-Tabelle) wären: B0 32 37 31 30 37 33 42 46 0D!

Bei der Eingabe dieses Strings, kann ich den Motor ansteuern. Wie
schaffe ich das jetzt mit dem UART? Der liest ja jedes einzelne Zeichen
(1Byte) ein, also:

B 1011 0000
0 0000 0000
3 0000 0011
2 0000 0010
usw.

Allerdings muss ich das so verschicken (siehe ASCII-Tabelle):
B0 1011 0000
32 0011 0010
37 0011 0111
usw.

Also ein Zeichen wird durch ein Nibble dargestellt. Zusammen ergibt sich 
ein Byte. Ich muss das in dieser Bitfolge versenden. Allerdings liest 
mein USART ja immer ein Zeichen ein und interpretiert es als ein Byte: 1 
char= 1 Byte. Denkfehler? Ich habe also zwei Zeichen, die in 1 Byte 
dargestellt sind.

Wie kann ich das via USART über die serielle Schnittstelle senden?
Kann ich einfach die ASCII-Zeichen angeben, also 
SEND_STRING("°271073B6/r")und der USART sendet mir dann die 
entsprechende Bitreihenfolge?!

Allerdings habe ich immer gemeint, das ich nicht die ASCII-Zeichen am 
USART reinbekomme bzw. versende, sondern immer deren Hex-Bytes. 
Denkfehler? Ein Terminalprogramm empfängt die Bitreihenfolge eines 
seriellen Datenstroms, also nur die Einsen und Nullen, und wandelt sie 
dann in ASCII-Zeichejn um. Wie läuft das dann beim USART?

Viele Grüße und nochmals Danke für die Antworten,
Louis

von Louis (Gast)


Lesenswert?

Hi nochmal,
wäre klasse, wenn mir da jemand vielleicht nochmal weiterhelfen 
könnte...Danke und Grüße, Louis

von Huch (Gast)


Lesenswert?

>wäre klasse, wenn mir da jemand vielleicht nochmal weiterhelfen könnte

Ich möchte mich dafür entschuldigen, dass wir Deinen zeitlichen 
Anforderungen an unsere freiwillige und kostenlose Hilfe nicht genügt 
haben. Falls Du Dich an ein anderes Forum wendest, das Deinen 
Anforderungen eher genügt, hätten wir dafür natürlich volles 
Verständnis, denn wir sind hier einfach gewohnt dann und in dem Umfang 
zu antworten wenn es uns passt. Ist natürlich völlig absurd sowas, klar. 
Aber so ist es nun mal.

von Achim M. (minifloat)


Lesenswert?

Louis schrieb:
> #if ((BAUD_ERROR < 990) || (BAUD_ERROR < 1010))

BAUD_ERROR wird auch bei korrekten Werten kleiner als 1010 sein.
Deswegen wird ein Fehler #error geworfen. Das Ungleichzeichen muss also 
anders herum, so:
1
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)
2
#if ((BAUD_ERROR < 990) || (BAUD_ERROR > 1010))
3
//                                 Hier^
4
  #error Fehler der Baudrate größer 1%
5
#endif
mfg mf

von Tom M. (tomm) Benutzerseite


Lesenswert?

Louis schrieb:
> Wie kann ich das via USART über die serielle Schnittstelle senden?

Kurioses Protokoll, aber sei's drum...

Erstmal ASCII nach Binär konvertieren:
- '0' subtrahieren
- falls noch >9, weitere 0x06 subtrahieren oder so, ascii table checken

Abschliessend ein bisschen bitschieben, um die Zahlen in die Nibbles zu 
packen.

von Louis (Gast)


Lesenswert?

Hallo Mini Float und Tom,
danke für die Antworten, werde das sofort ändern und in Angriff nehmen!
@ Huch: Tut mir Leid wenn dich mein Beitrag auf irgendwelche Art und 
Weise provoziert/verärgert hat. Allerdings war der Beitrag weder 
ironisch, noch pöbelhaft auffordernd gemeint. Ich bin halt noch blutiger 
Anfänger und ich versuch mich schon seit einiger Zeit in die Materie 
rein zu beißen und ich komme nicht richtig voran. VG, Louis

von Huch (Gast)


Lesenswert?

>@ Huch: Tut mir Leid wenn dich mein Beitrag auf irgendwelche Art und
>Weise provoziert/verärgert hat. Allerdings war der Beitrag weder
>ironisch, noch pöbelhaft auffordernd gemeint.

Pushen ist einfach unschön. Dabei ist es egal ob Du es pöbelhaft gemeint 
hast oder nicht.

>Ich bin halt noch blutiger
>Anfänger und ich versuch mich schon seit einiger Zeit in die Materie
>rein zu beißen und ich komme nicht richtig voran. VG, Louis

Schön. Aber das ist ja Dein Problem, nicht unseres.

Ganz so übel ernst brauchst Du das nicht nehmen, mein Lieber. Halte Dich 
eben vor dem Pushen erstmal ein paar Tage zurück. Das ist alles. Nicht 
schon nach knapp 1 1/2 Stunden. Halte Dir vor Augen, das wir Dir hier 
freiwillig und kostenlos helfen.

von Louis (Gast)


Lesenswert?

OK, werd ich mir merken!
Schönen Abend noch

von Ulrich (Gast)


Lesenswert?

Grüß Gott Louis,

zu deinem ersten Problem mit der Schnittstelle:

>OK, bei 9600 bps und 16MHz erhalte ich ein UBRR_Value = 103.
>Wie ich das jetzt allerdings auf das UBRRL und UBRRH übertrage, bzw.
>was/wie ich dann bei UBRR0H/UBRR0L einstellen muss, ist mir noch etwas
>unklar.

>UBRR0H = UBRR_VAL >> 8;
>UBRR0L = UBRR & 0xFF;

Meiner Meinung nach musst du dem UBRRH ne 0 zuweisen, da der berechnete 
Wert kleiner als 256 ist und somit in UBRRL alleine passt. Also:

UBRR0H = 0;
UBRR0L = UBRR_Val;

Das muss übrigen while(COUNTER != 20) heißen!

> void SEND_STRING (unsigned char *DATA){
> unint8_t COUNTER = 0;
> while (COUNTER == 20){
> SEND_CHAR(*DATA);
> DATA ++;
> COUNTER++;
> }
> }

Was die serielle Übertragung angeht, kannst du das so nicht senden. Das 
nicht druckbare Zeichen kannst du bspw. als Hex versenden. Also 
SEND_STRING(0xB0).Den Rest kannst du ganz einfach als ASCII-Zeichen 
normal versenden. SEND_STRING(’271073B6/r’), indem Zeichen für Zeichen 
übertragen wird. Wenn du in die Tabelle schaust, siehst du ja, dass das 
ASCII-Zeichen ’2 ’, 0x32 ist.

Die Übertragung findet immer binär statt. In der Speicherzelle steht der 
Wert physikalisch gesehen also in 1 und 0. Dein String besteht immer aus 
ASCII-Zeichen. Du kannst das dir vielleicht so merken, dass der 
Controller für jedes Zeichen einen binären Wert hinterlegt hat. Kommt 
bspw. ein Byte 0100 0001 über den USART, so interpretiert dein uC das 
als ASCII-Zeichen ’A’ oder 0x41.

In deinem Programm kannst du daher auch die Bytes vgl. Es ist total 
Wurst, ob du jetzt, bspw. zur Prüfung bestimmter Zeichen in einem 
String, 0x41 oder ’A’ hernimmst. Der uC weiß, das damit die Bitfolge 
0100 0001 gemeint ist. Bei diesen nicht druckbaren Zeichen musst du 
allerdings aufpassen! Die würde ich als Hex, wie oben schreiben. ASCII 
hat halt den Vorteil das es lesbarer ist und somit das Debugging 
erleichtert. Wichtig ist einfach, dass du, wenn man von einem Byte 
redet, die binäre Darstellung beachtest und nicht die Zeichen. Klar "A" 
hat 0100 0001, aber B0 (zwei Zeichen) wird ebenfalls durch 1 Byte, also 
1100 0000 präsentiert.

Ich hoffe das Hilft dir etwas weiter…
Grüße und noch frohes Schaffen!

von Juergen R. (stumpjumper)


Lesenswert?

Hallo Louis,
Du sagst daß Du 2 Zeichen in einem Byte übertragen möchtest - Du meinst 
nicht zufällig eine BCD-Codierung oder?

Zu einem anderen Teil Deiner Frage wie kann ich die wieder auseinander 
fieseln...

nibbel1=byte&0xF0;
nibbel2=byte&0x0F;

Zum Thema Hex oder ASCII schließe ich meinem Vorredner an.

von Louis (Gast)


Lesenswert?

Hallo Jürgen, Hallo Ulrich,

danke für die Antworten...

Was ich mit den zwei Zeichen in einem Byte sagen wollte, ist das ich 
gedacht hab, das wenn ich 0xB0 übertragen möchte, ich zwei Zeichen 
übertragen muss.
Allerdings hat Ulrich ja gesagt, dass ich immer nur die binäre Form 
anschauen muss. Also 1100 0000 --> 1 Byte.

Das war glaube ich mein Denkfehler! Ich hatte immer im Hinterkopf das 1 
Zeichen, 1 Byte groß ist. Wenn ich jetzt 0xB0 übertragen will muss ich 
zwei Zeichen übertragen, ist ja aber nicht so. Es geht immer nur ums 
binäre. Das scheint mir langsam klar zu sein.

Allerdings kommt mir die Sache mit der USART Initialisierung immer noch 
etwas spanisch vor...Es will nicht in meinen Kopf gehen, weshalb man das 
so macht...

>UBRR0H = UBRR_VAL >> 8;
>UBRR0L = UBRR & 0xFF;

Uffff....

Trotzdem DANKE nochmal für eure Antworten!

VG

von Juergen R. (stumpjumper)


Lesenswert?

Hallo Louis,
Der Divisor für die Baudrate ist ein 12Bit Wert (4096) deshalb reicht 
ein Bit nicht für den Wert. Man schreibt also die unteren 8 Bit in das 
eine Register und blendet die dann mit dem "&" weg um die restlichen 4 
Bit in das andere Register zu schreiben.

von Klick (Gast)


Lesenswert?

Schau mal in das Datenblatt des Controllers. Für ubrr musst du dann eben 
bei der Initialisierung dein UBR-VAL einsetzen.


void USART_Init( unsigned int ubrr)
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
.
.
.

von Louis (Gast)


Lesenswert?

Hallo Jürgen und Klick,
danke für die Antworten und den Versuch mir das verständlich zu 
machen...

Allerdings versteh ich nicht was du damit meinst...

> Der Divisor für die Baudrate ist ein 12Bit Wert (4096) deshalb reicht
> ein Bit nicht für den Wert.

OK das UBRR besteht ja aus 12 Bit = 4096

Wenn ich jetzt ein UBR-VAl von 103 habe 0110 0111 sieht das ja in dem 12 
Bit Register so aus: 0000 0110 0111

Wenn ich jetzt den Rechtsshift anwende werden die letzten 8 Bits heraus 
geschoben. Ich hab also 0000 0000 0000. Das ist wohl auch dass, was 
Ulrich mir mit 0 fürs UBRRH-Register sagen wollte, oder?

> Meiner Meinung nach musst du dem UBRRH ne 0 zuweisen, da der berechnete
> Wert kleiner als 256 ist und somit in UBRRL alleine passt. Also:

> UBRR0H = 0;
> UBRR0L = UBRR_Val;

Aber warum der Shift und nicht gleich einfach ne 0 zuweisen?
Liegt das daran, wenn ich ein Wert wie bspw. 256 als UBR_VAl habe, das 
ich dann nach dem Rechtsshift dann 0000 0000 0001 raus bekomme und die 
0001 dann ins UBRRH schreibe kann?

VG

von nicht "Gast" (Gast)


Lesenswert?

Louis schrieb:
> Kurze Verständnisfrage: Der F-CPU ist ja nur eine Info für den Compiler,
>
> aber der uC läuft dadurch j a nicht schneller oder langsamer, sondern
>
> immer mit deram uC eingestellten Taktfrequenz, im Falle des ATmega 328P,
>
> also mit 16 MHz. Dennoch meine ich, dass ich in manchen
>
> Programmbeispielen schon gesehen hab, dass F_CPU und de eigentliche
>
> Taktfrequenz nicht identisch waren bzw. F_CPU nicht entsprechend der
>
> Taktfrequenz angegeben wurde.

Wenn ich das richtig interpretiere hast du hier ebenfalls ein 
Verständnisproblem. Die Taktfrequenz ist abhängig von der Taktquelle die 
am Mikrocontroller anliegt und muss nicht gleich 16MHz sein. Im Programm 
stellst du F_CPU dementsprechend ein.

Louis schrieb:
> Liegt das daran, wenn ich ein Wert wie bspw. 256 als UBR_VAl habe, das
>
> ich dann nach dem Rechtsshift dann 0000 0000 0001 raus bekomme und die
>
> 0001 dann ins UBRRH schreibe kann?

Ja, das hast du richtig verstanden.

von Louis (Gast)


Lesenswert?

> Wenn ich das richtig interpretiere hast du hier ebenfalls ein
> Verständnisproblem. Die Taktfrequenz ist abhängig von der Taktquelle die
> am Mikrocontroller anliegt und muss nicht gleich 16MHz sein. Im Programm
> stellst du F_CPU dementsprechend ein.

Hi "nicht Gast", da hast du Recht:-) Also mein Board bzw. 
Mikrocontroller Atmega 328P wird mit einem externen Quarzoszillator 
16MHz betrieben. Ok, muss ich jetzt also mein F_CPU auf 16 MHz 
einstellen? Mein F_CPU muss also gleich dem Wert des externen 
Quarzoszillators sein, richtig?

Im Grunde ist die F_CPU nur eine Info für den Compiler, aber der uC 
läuft dadurch ja nicht schneller oder langsamer, sondern mit der 
Frequenz des externen Quarzoszillators. Wenn die beiden Werte allerdings 
nicht übereinstimmen, kann es zu Problemen bei der Übertragung mit Hilfe 
des USART und bei delay-Funktionen kommen ?!
Wie ich gelesen habe, sind diese externen Quarzoszillatoren viel genauer 
wie der interne Oszillator des uC.

Danke für die Antwort!

von F_CPU (Gast)


Lesenswert?

> Ja, das hast du richtig verstanden.

Bei delay-Funktionen gibts da auf jeden Fall Probleme. Allgemein muss 
F_CPU immer gleich der Taktfrequenz sein!!!

von KALLE (Gast)


Lesenswert?

Hallo "Pusher" ;-)
also bei 9600 bps benötigst du meiner Meinung nach nicht mal ein 
externen Oszi. WAs die Sache mit F_CPU angeht stimme ich meinem 
Vorredner zu.
N´abend

von Louis (Gast)


Lesenswert?

hallo zusammen,
also ich hab das jetzt mal mit der Ansteuerung so probiert. Allerdings 
bekomme ich die verflixten Fehler nicht raus...Arrgggg!!! Ich hänge grad 
ziemlich in der Luft...Ich will nun einfach mal die Hex-bytes versenden. 
Wie kann ich aber bspw. °271073BF als ASCII versenden? Der Controller 
muss ja bei "°" wissen, dass er jetzt 0xB0 bzw. das Byte 1011 0000 
versenden muss. VG


#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>

#define F_CPU 16000000UL
#define BAUD 9600UL

#define UBRR_VAL (F_CPU+BAUD*8)/(BAUD*16)-1)
#define BAUD_REAL (F_CPU / (16 * (UBRR_VAL+1)))
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD)

#if ((BAUD_ERROR < 990) || (BAUD_ERROR > 1010))
  #error Fehler der Baudrate größer 1%
#endif

void USART_INIT (unsigned int UBRR){

UBRR0H = (unsigned char)(UBRR>>8);
UBRR0L = (unsigned char)(UBRR);
UCSR0A   |=(1 << U2X0);
UCSR0B  |=(1 << TXEN0) | (1 << RXEN0);  // USART Receive/Transmit 
Complete
UCSR0C  |=(1<< UCSZ01) | (1 << UCSZ00); // Charactersize 8-bit, 1 Stop 
Bit, Parity Mode disabled
}

void SEND_CHAR (unsigned char c){
while (!(UCSR0A & (1 << UDRE0)));
UDR0 = c;
}

// void SEND_STRING (unsigned char *DATA){
// COUNTER=0;;
// while (COUNTER !=9){
// SEND_CHAR(*DATA);
// *DATA ++;
// COUNTER++;
// }
// }

void main (void){

USART_INIT(UBRR_VAL);

for(int i = 0; i<20; i++){

SEND_CHAR(0xB0);  //°
SEND_CHAR(0x32);  //2
SEND_CHAR(0x37);  //7
SEND_CHAR(0x31);  //1
SEND_CHAR(0x30);  //0
SEND_CHAR(0x37);  //7
SEND_CHAR(0x33);  //3
SEND_CHAR(0x42);  //B
SEND_CHAR(0x46);  //F
SEND_CHAR(0x0D);  //<Cr>

// SEND_CHAR(0xB0);  //°
// SEND_STRING(271073BF);
// SEND_CHAR(0xB0); //<Cr>

 _delay_ms(8000);

SEND_CHAR(0xB0);
SEND_CHAR(0x31);
SEND_CHAR(0x42);
SEND_CHAR(0x35);
SEND_CHAR(0x38);
SEND_CHAR(0x46);
SEND_CHAR(0x41);
SEND_CHAR(0x38);
SEND_CHAR(0x42);
SEND_CHAR(0x0D);

 _delay_ms(8000);

}
}

von Rüdi (Gast)


Lesenswert?

Was spricht denn dagegen, die Zeichen so zu versenden? Ist doch viel 
übersichtlicher...

SEND_CHAR(0xB0);
SEND_CHAR('2');  //0x32
SEND_CHAR('7');  //0x37
SEND_CHAR('1');  //0x31
SEND_CHAR('0');  //0x30
SEND_CHAR('7');  //0x37
SEND_CHAR('3');  //0x33
SEND_CHAR('B');  //0x42
SEND_CHAR('F');  //0x46
SEND_CHAR(0x0D);

Das mit der Stringfunktion kannst du so knicken!
Diese Wirrwarr da oben kannst du doch auch einfach so schreiben, völlig 
unnötig mit der Rundung:

#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>

#define FOSC 16000000         // Clock Speed
#define BAUD 9600
#define UBRR_VAL FOSC/16/BAUD-1      // Equation for //Calculating UBRRn 
Value

void USART_INIT (unsigned int UBRR){

UBRR0H = (unsigned char)(UBRR>>8);
UBRR0L = (unsigned char)(UBRR);
UCSR0A   |=(1 << U2X0);
UCSR0B  |=(1 << TXEN0) | (1 << RXEN0);  // USART Receive/Transmit 
Complete
UCSR0C  |=(1<< UCSZ01) | (1 << UCSZ00); // Charactersize 8-bit, 1 Stop 
//Bit, Parity Mode disabled
}
.
.
.

von Louis (Gast)


Lesenswert?

Hi Rüdi,
danke für die Antwort! Ich hab jetzt mal so probiert, wie du gesagt hast 
und AVR-Studio zeigt keine Fehler mehr an. Komisch, ich komme allerdings 
nicht drauf, was ich beim alten Prog. falsch gemacht hab....


#include <avr/io.h>
#include <util/delay.h>

#define FOSC 16000000         // Clock Speed
#define BAUD 9600
#define UBRR_VAL FOSC/16/BAUD-1      // Equation for //Calculating UBRRn 
Value

void USART_INIT (unsigned int UBRR){

UBRR0H = (unsigned char)(UBRR>>8);
UBRR0L = (unsigned char)(UBRR);
UCSR0A   |=(1 << U2X0);
UCSR0B  |=(1 << TXEN0) | (1 << RXEN0);  // USART Receive/Transmit 
Complete
UCSR0C  |=(1<< UCSZ01) | (1 << UCSZ00); // Charactersize 8-bit, 1 Stop 
// Bit, Parity Mode disabled
}

void SEND_CHAR (unsigned char data){
while (!(UCSR0A & (1 << UDRE0)));
UDR0 = data;
}

void main (void){

USART_INIT(UBRR_VAL);

for(int i = 0; i<20; i++){

// 10000 U/min
SEND_CHAR(0xB0);
SEND_CHAR(0x32);
SEND_CHAR(0x37);
SEND_CHAR(0x30);
SEND_CHAR(0x30);
SEND_CHAR(0x37);
SEND_CHAR(0x33);
SEND_CHAR(0x42);
SEND_CHAR(0x46);
SEND_CHAR(0x0D);

 _delay_ms(8000);

// 7000 U/min
SEND_CHAR(0xB0);
SEND_CHAR(0x31);
SEND_CHAR(0x42);
SEND_CHAR(0x35);
SEND_CHAR(0x38);
SEND_CHAR(0x46);
SEND_CHAR(0x41);
SEND_CHAR(0x38);
SEND_CHAR(0x42);
SEND_CHAR(0x0D);

 _delay_ms(8000);

}

}

von Walter (Gast)


Lesenswert?

Rüdi schrieb:
> Das mit der Stringfunktion kannst du so knicken!
> Diese Wirrwarr da oben kannst du doch auch einfach so schreiben, völlig
> unnötig mit der Rundung:
warum soll man eine unnötige Abweichung einbauen,
ich würde die Rundung auf jeden Fall drin lassen


> #define UBRR_VAL FOSC/16/BAUD-1      // Equation for //Calculating UBRRn

und hier unbedingt Klammern setzen, im Beispiel geht's zwar so, aber 
wenn man  UBRR_VAL mal anders verwendet gibt's Probleme, also
> #define (UBRR_VAL FOSC/16/BAUD-1)      // Equation for //Calculating UBRRn

von Walter (Gast)


Lesenswert?

Walter schrieb:
>> #define (UBRR_VAL FOSC/16/BAUD-1)      // Equation for //Calculating UBRRn

oops, natürlich so:
> #define UBRR_VAL (FOSC/16/BAUD-1)      // Equation for //Calculating UBRRn

von Louis (Gast)


Lesenswert?

Hallo Walter,
also im Tutorial habe ich auch gelesen, dass mit der zuerst 
geschriebenen Formel eine bessere Rundung erzielt werden kann. 
Allerdings versteh ich nicht, warum das beim Programm immer 
Fehlermeldungen hervorgerufen hat.

@Rüdi: Kann ich einfach '2' eingeben? Ich muss das doch erst in Ascii 
umwandeln, oder? Denkfehler?

> SEND_CHAR(0xB0);
> SEND_CHAR('2');  //0x32
> SEND_CHAR('7');  //0x37
> SEND_CHAR('1');  //0x31
> SEND_CHAR('0');  //0x30
> SEND_CHAR('7');  //0x37
> SEND_CHAR('3');  //0x33
> SEND_CHAR('B');  //0x42
> SEND_CHAR('F');  //0x46
> SEND_CHAR(0x0D)

VG

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.