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
>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.
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.
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.
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é
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
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.
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
Hi nochmal, wäre klasse, wenn mir da jemand vielleicht nochmal weiterhelfen könnte...Danke und Grüße, Louis
>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.
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
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.
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
>@ 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.
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!
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.
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
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.
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; . . .
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
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.
> 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!
> Ja, das hast du richtig verstanden.
Bei delay-Funktionen gibts da auf jeden Fall Probleme. Allgemein muss
F_CPU immer gleich der Taktfrequenz sein!!!
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
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); } }
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 } . . .
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); } }
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.