Ich habe ein Problem, dass mir schon eine Woche schlaflose Nächte bereitet und hoffe nun hier auf ein paar aufmunternde Worte und etwas Hilfe. a) Ich treffe die Annahme, dass ein AT90S2313 (getaktet mit 7,3728MHz) jeweils einmal eine der folgenden Daten über TxD ausgibt. Dabei ist die Ausgabe als Reaktion auf einen Tastendruck zu verstehen. Dabei handelt es sich um: 0xC1 -> Ausgabe für Taste 1 0xC2 -> Ausgabe für Taste 2 0xC4 -> u.s.w. 0xC8 -> 0xD0 -> 0xE0 -> Ausgabe für Taste 6 (Anmerkung: 9600Bd, 8 Daten Bits, 1 Stop Bit, no Parity, LSB first) b) Der in a) genannte Sachverhalt lässt sich leider nicht beeinflussen/ändern c) Ein zweiter AT90S2313 (gleiche Taktung) soll mit RxD direkt an den TxD aus a) angeschlossen werden. Was nun passieren soll, kann ich zunächst nur mal in Worte fassen. Er soll in einer Routine prüfen, ob etwas an RxD empfangen wird, wenn ja - ob es eins der o.g. 6 Stück ist - wenn ja, dann soll er an einem Pin ein Relais oder einen Schaltkontakt herstellen und dann wieder prüfen, ob etwas empfangen wird. Also werden doch auch 6 I/O Pins als Ausgänge benötigt. Ich habe absolut keine Idee, wie ich das in C umsetzen kann. Hab auch schon das super WIKI-Tut durch, aber da ist nur das Senden mit dem UART genauer beschrieben.
switch (received_byte){ case 0xC1: tu_irgend_was:break; . . }
Genau das tu_irgend_was würde mich genauer interessieren! Aber so abzufragen ist ne gute Idee!
C scheint mir dafür ein ziemlicher Overkill zu sein. Mit Assembler hat man sowas in vielleicht 50 Zeilen schnell programmiert. In C passiert im Prinzip dasselbe: UCR richtig setzen, USR permanent abfragen ob es was neues gibt (RXCIE (RX Complete Interrupt Enable)), wenn nein, weiter warten, ansonsten UART Data Register lesen und eine case - Anweisung durchlaufen, in der die Ausgangspins gesetzt werden. Wo ist jetzt das Problem? Was hast Du denn bis jetzt programmiert? Was klappt nicht? Was hast Du bisher getan, um die Ursache zu finden und was hast Du herausgefunden? Hast Du schonmal in ein "normales" C-Buch geschaut? Ich denke, das wird im Tutorial ebenso vorausgesetzt wie ein bißchen Programmiererfahrung...
Hä?? tu_irgend_was könnte z.B. sein: PORTB=0x01; Wird unter http://www.mikrocontroller.net/wiki/AVR-GCC-Tutorial#Ausg.E4nge erklärt.
Vielen Dank für die ersten Antworten. Ich habe mal einen Wntwurf gemacht. Ist der Ansatz so ok? Also wo ich noch mal ran muss ist die Taktfrequenz (ist nicht 4000000) und die Aktion, die kommt, wenn Daten empfangen werden. -> Es soll ja nur ein Pin gesetzt werden!
Das sieht doch schon nicht schlecht aus. Jetzt kannst Du z.B. schreiben: data_received = USART_RECEIEVE(); if(data_received == 0xC1) PORTB = 0b00000001; if(data_received == 0xC2) PORTB = 0b00000010; if(data_received == 0xC4) PORTB = 0b00000100; if(data_received == 0xC8) PORTB = 0b00001000; if(data_received == 0xD0) PORTB = 0b00010000; if(data_received == 0xE0) PORTB = 0b00100000; und damit Pin 1 bis Pin6 an Port B schalten...
Danke! So macht es mal Spaß weiterzumachen ;) Habe es jetzt so ergänzt. Wie lange soll er nach dem "Pin-freigeben" denn warten, damit ein Schaltkontakt überhaupt zustande kommen kann?
Um das zu entscheiden, müßtest Du mal sagen, was genau passieren soll. - soll der Pin dauerhaft eingeschaltet bleiben, auch wenn ein neues Zeichen empfangen wurde? - Wie oder wann soll wieder abgeschaltet werden? So wie es jetzt ist, bleibt PortB in dem Zustand, in den er zuletzt gesetzt wurde. Wenn der Relais-Kontakt einfach nur kurz klappern soll müßtest du eine Wartefunktion aufrufen und danach wieder eine 0 auf den Port schreiben. Relais erzeugen übrigens gerne Störungen, die den Controller abstürzen lassen. Über die Forumssuche findest Du Infos, wie das zu vemeiden ist.
Habe erst jetzt Deinen Code gesehen... Warte doch erstmal 500msec - verkürzen kann man die Zeit immer noch. Oder wie sehen Deine Anforderungen aus?
Hallo Johannes, habe eine Warteschleife eingebaut WAIT(); aber ich weiß nicht, wie lange die reale Wartezeit ist. Das muss ich testen. Danke für den Tipp mit dem Relais. Ist es besser eine Transistor-Schaltung zu nehmen. Muss im Prinzip insgesamt 6 Schalter/Taster bedienen können. Wenn ich das über einen Transistor laufen lasse, kann ich mir Entprellen (oder wie das heißt) sparen? Neuer Code im Anhang ;)
UDR ist ein Register, dass du in der for-Schleife direkt abfragen kannst. Das solltest du auch mal löschen. Du solltes dieses auch auf ungleich 0 abfragen. Würde aber besser eine Bit-Variable bei jedem UART-Interrupt setzen und nach Auswertung des empfangenen Zeichens diese Variable wieder löschen. So kannst du auch die 0 auswerten. Geht ntürlich auch über das UART-RI Bit. SG Josef
@ Johannes: Das löschen des PORTB bringt nichts, da niemand das data_received Byte löscht.
Hi, es ist eben die Frage ob deine Ausgaenge galvanisch getrennt sein muessen, wenn nicht reichen Transistoren oder Mosfets aus. Vielleicht reichen aber auch Optocoupler mit Open Collector. Mfg Dirk
@Josef: Hm, bei Assembler wird das RXC - BIT doch automatisch beim Abholen des Zeichens gelöscht - bei C nicht? Wie war das doch gleich... Ich sehe gerade, ein UCSRA gibt es beim 2313 ebensowenig wie einen USART. Vielleicht einfach nochmal ins Wiki gucken... Ich würde das USR auf RXC prüfen. Wenn was gesetzt ist, UDR auslesen und auswerten. Transistoren gehen je nach Spannung ohne Probleme - bei AC klappt das nicht. Du hast noch nicht geschrieben, was Du überhaubt machen willst.
In ASM sieht das dann so aus: loop: in temp, USR sbrs temp, RXC ;Daten empfangen -> Sprung nach loop überspringen rjmp loop in temp, UDR rcall serout ; echo (das Zeichen in Temp ausgeben) anschließend in Abhängigkeit von temp was Tolles anstellen.
@Dirk: Ich denke nicht, dass sie galvanisch getrennt sein müssen. Es erfolgt ja lediglich nur eine Ausgabe gleichzeitig. @ Josef: received_data wird doch immer "neu" gefüllt, d.h. man müsste es eigentlich nicht löschen, oder? Falls doch, würde dann ein received_data = ""; reichen?
Hi, naja vielleicht reicht dir ja der Logikpegel (5V/20mA) ich wuerde die Daten anders loeschen .... #define clear 0x00 received_data = clear;
@ Johannes: Du hast Recht. USART kann ich vergessen. Leider finde ich im Wiki nichts mehr darüber. Das einzige, was ich noch gemacht habe, dass ich am Ende received_data = CLEAR; gesetzt habe (CLEAR ist zuvor mit 0x00 definiert). Tja und nun stecke ich richtig fest!!!
Hi, die richtigen Registernamen solltest du im Datasheet finden. Suchbegriff: UART .... bei den neueren AVR's heisst es USART. Mfg Dirk
Wenn Du sowieso wartest, bis ein neues Zeichen da ist, brauchst Du IIRC nichts löschen. USART gibt's nicht, dafür den UART. Genau dieser wird auch im Wiki beschrieben, und mehr brauchst Du ja auch nicht. Wo ist denn jetzt jenau das Problem? Du brauchst im Prinzip nur noch das, was ich Dir beschrieben und in Assembler gepostet habe in C umzusetzen. Wenn ich es richig sehe, mußt Du dazu lediglich UCSRA durch USR ersetzen. Die UART - Initialisierung wirst Du ja auch wohl irgendwo finden. Am besten nicht nur irgendwoher kopieren, sondern auch mal ins Datenblatt gucken und versuchen, etwas zu verstehen. "Galvanisch getrennt" bedeutet übrigens, daß der Stromkreis vom Controller und der von dem, was Du schalten willst, keinerlei elektrische Verbindung haben. Je nachdem, was Du ansteuern willst ist das unabdingbar. Gute Nacht Johannes
Danke Dirk & Johannes, werde morgen weitermachen und dann von meinen Ergebnissen berichten. Gute Nacht, Moritz
So, habe es noch einmal abgeändert. Die UART-Initialisierung war wohl korrekt, hatte nur USARD geschrieben und dann fälschlicherweise mit dem "Begriff" weitergesucht ;) Sollte es jetzt so gehen, oder wo ist noch Verbesserungsbedarf? @ Johannes: Leider kann ich Deinen Assembler-Code nicht richtig interpretieren. Ist schon in C relativ haarig für mich. Zur Schaltung: Geschaltet werden sollen (zur Zeit noch SMD) Taster, die ich gänzlich ersetzen möchte. Dabei läuft die externe Schaltung mit 3,9V. D.h. es ist besser, wenn ich die beiden Schaltkreise, die an sich nichts miteinander zu tun haben, trenne. Ich denke, dass hier der von Dirk empfohlene Optokoppler (hab mich auf elektronik-kompendium informiert) eine gute Wahl ist ;)
Bis auf die Tippfehler (|= und UARD_RECEIVE();) sieht das nach meinem Verständnis gut aus. Compiliere das Programm doch mal und lade es in Deinem Atmel oder Simulator! Johannes
Hallo, im include hast Du noch arv/io.h statt avr/io.h stehen, ist mir spontan aufgefallen. In der Wait-Schleife: time und x sind unsigned char, haben also einen max. Wert von 256. WAIT(500) ist also nicht möglich/macht nicht das, was Du erreichen willst. Bei 4Mhz Takt braucht ein Befehl 250ns, damit kannst Du abschätzen, wie lang der Ausgang geschaltet bleibt->sehr kurz! Ohne zu wissen, wieviele asm-Befehle eine For-Schleife braucht (4?) würd ich schätzen, dass Deine Wartezeit im us-Bereich liegt. Ob das reicht, musst Du selber wissen. Was passiert, wenn jd. einen Taster an a) dauerhaft drückt? Sendet der uC1 dann immer wieder z. B. 0xC1...0xC1...0xC1 Oder nur 1x? Im ersteren Fall macht Dein Programm aus einem Dauerhaft gedrückten Taster ein AN........AUS.AN..........AUS.AN..........AUS.AN.......usw. Ob das, was ich hier erzähle, in Deiner Schaltung relevant ist, musst Du selber wissen. Ich würds mal ausprobieren. Gruß, Sebastian
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.