Hi! Ich hätt eine Frage, Wie mach ich das am besten, wenn am µP ein Programm laufen soll, dass ich nur, wenn nötig, über die Serielle-Schnittestlle waren will... Genauer handelt es sich um eine Heizungssteuerung die selbständig laufen soll, nur dass ich über die Serielle den aktuellekn Status abrufen und die Temperaturgrenzwerte verändern kann... Irgendwie bekomm ich das mitn seriellen Interrupt nicht ganz hin... kann mir jemand helfen ? lg Niklas
Wo ist Dein Problem? Im Interrupt den seriellen Puffer füllen und im Hauptprogramm abarbeiten. Oder aber zwei Interruptlevel und das Ganze vernünftig aufteilen. Schreib mal, wo genau Dein Problem liegt.
Tjo... das ist so... sobald ich die interrupt routine schreibe, meldet mir erstens der linker eine warngung, die da sagt: MULTIBLE CALLER TO SEGMENT.... SEGMENT: PRINTF.... kA warum.... er übersetz den code zwar, aber er geht mir nicht in die routine hinein, wenn ich ein zeichen sende... ich glab, ich bin zu blöd... lg niki, vl. hatt jemand ein beispiel programm für mich ?! thx.
printf() ruft man tunlichst nicht ausm Interrupt auf. Ehe das so aus die Puschen kommt, sind schon tonnenweise andere Interrupts verloren gegangen. Und erst recht, wenn man es ungepuffert auf die UART schreiben läßt. Der C51-Compiler ist dahingehend optimiert, daß Funktionen nicht reentrant sind. Das müßten sie aber sein, wenn man sie von 2 verschiedenen Ausführungsleveln aufruft. Ich weiß jetzt nicht, ob von printf() auch eine reentrante Version gelinkt werden kann. Aber wie gesagt, sowas macht ja normalerweise auch keiner. Peter
P.S.: Ich sach mal, von printf() gibt es keine reentrante Version. Es mag mancher zwar lustig finden, wenn mittendrinn in einem Text vom Main plötzlich ein Text vom Interrupt erscheint (vielleicht noch die Zeichen gemischt), aber sowas hätte keinerlei praktischen Wert. printf() darf daher immer nur einmal zur Zeit ausgeführt werden. Peter
@Nik: Schreib doch Deine eigene printf-Routine. Die vielen Optionen brauchst Du eh nicht, das ist Platz- und Performanceverschwendung (und somit unnötiger Stromverbrauch). Schreib Dir interrupt-gesteuerte Routinen für den Empfang und das Senden von der seriellen Schnittstelle und mach Dir einen einen Puffer, der zur Not ein paar Zeichen aufnehmen kann. Wenn dann ein Zeichen gekommen ist, dann setz ein Flag und werte das im Hauptprogramm aus. Sobald dann ein Befehl erkannt wurde (z.B. Temperatur ändern oder Status abfragen), führe die entsprechende Aktion durch. Poste doch mal die Ausschnitte aus Deinem Programm hier.
@ Jochn.... ja, im Prinzip sollte nocht viel dahinterstecken, Was ich einfach möchjte Währe, dass wenn ein bestimmtest Zeichen erhaöten wird, ich in ein Menüinterface komme, wo ich mit die aktuelle Temperatur anschauen kann, die Hysterese verändern (num) und die Heizung manuell ein- od. ausschalten kann. Das ist natürlich nur der Prototyp des Programmen, es kommen dann noch Stellventil, Aussentemperatur und 2 Pumpen dazu.... hier mal ein Teil des Sources #include <AT89X52.H> #include <stdio.h> #ifndef READ #define READ 1 #endif #ifndef WRITE #define WRITE 0 #endif #ifndef I2CCLK #define I2CCLK 0xA0 #endif #ifndef SCL #define SCL P1_6 #endif #ifndef SDA #define SDA P1_7 #endif unsigned char _i2c_error; // bit array of error types void _I2CBitDly(void); void _I2CSCLHigh(void); void I2CSendAddr(unsigned char addr, unsigned char rd); void I2CSendByte(unsigned char bt); int _I2CGetByte(unsigned char lastone); void I2CSendStop(void); #define I2CGetByte() _I2CGetByte(0) #define I2CGetLastByte() _I2CGetByte(1) #define XTAL 11.0592 // Quarzfrequenz in MHz #define BAUD 9600 // Baudrate int b,c,kom,v,num=20,nume=0,q=1; char ch; main() { const unsigned int RCAP2 = 0x10000-XTAL*1e6/(32.0*BAUD); // Rückladewert timer-2 TMOD = 0x20; TH1 = 0xfd; TR1 = 1; SCON = 0x5a; REN = 1; // Empfänger freischalten TI = 1; // Senden des 1. Zeichens ermöglichen while(getchar() != 'x'); P1=255; //Port1 zum Empfangen bereit P1_4=0; P1_5=0; //Relais ausschalten while(1){ I2CSendAddr(0x90,WRITE); I2CSendByte(0); I2CSendStop(); I2CSendAddr(0x90,READ); b = I2CGetByte(); c = I2CGetLastByte(); I2CSendStop(); /* b... 00000000 temperatur im 2er-Komplement ^....Vorzeichen (0-positiv, 1-negativ) c... 00000000 ^....Wenn 1 dann b += 0.5°C 0x90... 10010000 ^^^^ .... Adresse des Bausteinhersteller ^^^ .... Adresse die am Baustein gesetzt werden kann ^ .... Lesen/Schreiben ( wird durch WRITE od. READ gesetz) */ printf("\nmesse...\n"); //koninuierliche Statusmeldung if (c>=128) //auf .5 Werte überprüfen kom=1; else kom=0; v=0; //---- Hysterese ---- Einschalten bei 2°C unter Sollwert, ausschalten bei 2°C über Sollwert if (b<(num-2)) //Wenn Ist-Wert 2°C kleiner als Soll-Wert -> Heizung ein P1_4=1; if (b>(num+2)) P1_4=0; //Wenn Ist-Wert 2°C größer als Soll-Wert -> Heizung aus
Hi! Wir ham erst mal vor kurzem mit dem AT89C52 mal gearbeitet und auch UART benutzt. vl bringt dir das was (ist nur die interruptroutine). void serial_IT(void) interrupt 4 { if (RI == 1) { /* if reception occur */ RI = 0; uart_data = SBUF; /* Read receive data */ SBUF = uart_data; uart_flag = 1; /* Send back same data on uart*/ } else TI = 0; /* if emission occur */ /* clear emission flag for next emission*/ } Hier empfängt der µC daten und schickt diese gleich wieder retour.
achja... :-) ein hinweis: auf der Homepage der Firma Atmel findest du beispiele dafür wie du UART und alles mögliche andere Benuzt, mit beispielen! von da habe ich auch diesen Code ;-) denn es gibt ja eben nicht nur einen UART mode ;-) Hat es so funktioniert?
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.