Hallo,
ich habe einen PIC18F2685 vorliegen, der u.a. seriell kommunizieren
kann.
Die serielle Kommunikation ist über Interrupts gelöst. Mein Problem
besteht aktuell darin, dass nach Senden des Stopbits des letzten Byte
die TX-Leitung nochmal kurz (ca. 10 µs) auf 0 gezogen wird, bevor diese
in Ruhelage = 1 geht.
Nachfolgende Schaltungen (MAX232) geben diese weiter, und der Empfänger
hat damit ein Problem. Daher habe ich mich auf die Suche gemacht, woher
dieses Verhalten kommt. Andere PICs, die ich kenne (PIC16) haben dieses
Verhalten nicht.
Ich vermute, dass es vielleicht ein Reihenfolgenproblem mit dem
Interrupt oder dem Setzen von den notwendigen Registern ist.
Ich versuche, den wesentlichen Teil der Kommunikation herauszulösen, um
das nachvollziehbar darzustellen:
void interruptGlobalLow()
{
//rs232 byte send
if(TXIF)
{
rs232Com_check();
TXIF = 0;
}
}
void rs232_Init()
{
TRISC=0b.1000.0011;
TXIE = 0;
RCIE = 0;
CREN = 0;
SPEN = 0;
SYNC = 0;
BRGH = 1;
BRG16 = 1;
ADDEN=0;
ABDEN=0;
WUE=0;
RCIF=TXIF=0; // clear interrupt flags
//Baudrateneinstellung (9600,8,'n',1)
SPBRGH=4;
SPBRG=16;
RX9 = 0; // no 9th bit (parity)
TX9 = 0;
TXIE = 1;
RCIE = 1;
CREN = 1;
RCIF=TXIF=0;
SPEN = 1;
TXIP = RCIP = 0; // low interrupts
RCIF=TXIF=0;
}
void rs232Com_check()
{
if (rs232_sending==0)
return;
if (rs232_inxSendBuffer>rs232_sizeSendBuffer)
{
rs232_sending=0;
TXEN = 0;
}
else
{
uns8 send = rs232_sendBuffer[rs232_inxSendBuffer];
++rs232_inxSendBuffer;
send_with_parity( send );
}
}
rs232Com_StartSend()
{
// rs232_inxSendBuffer = Index des Sendepuffers
// rs232_sendBuffer = Sendepuffer, wird woanders gefüllt und es ist
sichergestellt, dass dieser zu dieser Zeit auf gefüllt ist
rs232_sizeSendBuffer = rs232_inxSendBuffer;
rs232_inxSendBuffer=1;
rs232_sending=1;
// start send first byte
TXEN = 1;
TXREG = rs232_sendBuffer[0];
}
void main()
{
while(1)
{
if(rs232_sending == 0)
{
rs232Com_StartSend();
}
}
}
Anbei noch 2 Screenshots der Oszi-Kommunikation. Letztes Byte ist 0xEF,
danach sieht man den negativen Peak, der meiner Meinung hier nicht
hergehört.
Hat jemand ne Idee, woran das liegen kann. Ich habe mir das Datenblatt
schon mehrfach angeschaut, komme aber aktuell nicht weiter.
Vielen Dank.
Ja, das hatte ich auch schon probiert.
Wenn ich TXIE nutze, sehe ich schon vor dem Senden mehrmals das TXIF=1
gesetzt wird. Auch nach dem Senden wird TXIF=1 sehr oft gesetzt, obwohl
keine Kommunikation mehr stattfindet.
Net F. schrieb:> Auch nach dem Senden wird TXIF=1 sehr oft gesetzt, obwohl> keine Kommunikation mehr stattfindet
Genau dafür ist es ja da.
(TXIF zeigt an, dass das TXREG frei ist und mit einem neuen Byte befüllt
werden kann)
Wenn mehrere Bytes gesendet werden sollen, dann schiebt man das erste in
TXREG und aktiviert den Interrupt mit TXEN = 1. Sobald TXREG frei wird,
wird der IR ausgelöst und in diesem schiebt man das nächste Byte in
TXREG. Handelt es sich dabei um das letzte zu übertragende Byte, dann
deaktiviert man den IR wieder (TXIE = 0)
if(TXIF)
sollte eher
if ((TXIF) && (TXIE))
prinzipiell solltest du den TXIF flag meiner Meinung nach nicht löschen.
Sondern eher:
- Im Interrupt Daten schicken
- Wenn es keine Daten mehr gibt dann den TXIE auf 0 setzen
Daten verschicken sollte über einen Ringbuffer gehen. Versenden guckt ob
der Transmitt schon läuft, wenn ja dann daten richtung Ringbuffer
schreiben, wenn nicht, dann daten ins TX register schreiben.
void putCharRS232(unsigned char data) {
if (ringBuffer_addItem(&myRingBuffer_rs232_tx, data) != -1) {
if (PIE1bits.TXIE == 0) {
PIE1bits.TXIE = 1;
}
} else {
missedTxCharRS232++;
}
}
int isrSerialTx(void) {
unsigned char data = 0;
if (ringBuffer_getItem(&myRingBuffer_rs232_tx, &data) != -1) {
TXREG = data;
} else {
PIE1bits.TXIE = 0;
}
return 0;
}
kyrk schrieb:> sollte eher> if ((TXIF) && (TXIE))>> prinzipiell solltest du den TXIF flag meiner Meinung nach nicht löschen.
Guter Einwand mit dem zusätzlichen TXIE. Mache ich auch immer, damit ich
es nicht vergesse, falls ein zweiter IR in diesem Vektor behandelt
werden soll.
TXIF ist übrigens read-only und kann nicht gelöscht werden.
Es geht automatisch auf 0, wenn das TXREG beschrieben wird und auch
automatisch wieder auf 1, sobald TXREG frei wird.
Volker S. schrieb:> kyrk schrieb:>> sollte eher>> if ((TXIF) && (TXIE))>>>> prinzipiell solltest du den TXIF flag meiner Meinung nach nicht löschen.>> Guter Einwand mit dem zusätzlichen TXIE. Mache ich auch immer, damit ich> es nicht vergesse, falls ein zweiter IR in diesem Vektor behandelt> werden soll.>> TXIF ist übrigens read-only und kann nicht gelöscht werden.> Es geht automatisch auf 0, wenn das TXREG beschrieben wird und auch> automatisch wieder auf 1, sobald TXREG frei wird.
Dass TXIF read-only ist, hatte ich in der Doku gelesen. Allerdings ist
der Quellcode nicht von mir, den hatte ich geerbt.
Ich war der Meinung, dass der TXIF-Interrupt nur gerufen wird, wenn der
Sendepuffer wieder frei ist. Ich hatte wie hier schon mehrfach
geschrieben, nachdem ich das letzte Byte in TXREG geschoben hatte,
TXIE=0 gesetzt.
Trotzdem bin ich mehrfach in den TXIF-Interrupt gekommen.
Mit der zusätzlichen if ((TXIF) && (TXIE)) - Abfrage sieht das Ganze
besser aus.
Danke für den Tipp!
Net F. schrieb:> Trotzdem bin ich mehrfach in den TXIF-Interrupt gekommen.> Mit der zusätzlichen if ((TXIF) && (TXIE)) - Abfrage sieht das Ganze> besser aus.
Dann gibt es da aber evtl. ein anderes Problem!
Der IR wird wohl noch von einer anderen Quelle ausgelöst und das ist
dann ganz schlecht, weil er ja nicht behandelt wird. (der kommt immer
wieder)
Zum Testen einfach eine Endlosschleife in die ISR:
1
voidinterruptGlobalLow()
2
{
3
//rs232 byte send
4
if(PIE1bits.TXIE&&PIR1bits.TXIF)
5
{
6
...
7
return;
8
}
9
while(1){
10
Nop();// ??? Breakpoint ???
11
}
12
}
Falls das Programm da rein läuft, muss du die Ursache dafür finden.