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?