Sida 1 av 2
Lyckas inte ta emot alla byten på serieporten.
Postat: 11 maj 2007, 11:35:27
av ankan
Skickar jag 8 byte till PICen registrerar rf_incomming_data_length bara 2 byte. Kollade RCSTA.OERR och jag får overrun error såden verkar inte hinna med av någon anledning.
Kan ni se något direkt fel jag har gjort i avbrottet?
RCIF ska nollställas när man har läst av RCREG men det verkar ju inte fungerar ordentligt. Jag har inga andra interrupt mer än timer1 och timer2 som bara plussar på en variabel vid varje avbrott.
Kod: Markera allt
if (PIR1.RCIF && PIE1.RCIE) {
TMR2=0;
state=RECIVING;
if (!rf_incomming_data_length) {
PIR1.TMR2IF=0;
PIE1.TMR2IE=1;
}
if(rf_incomming_data_length < BASESTATION_DATA_SIZE) {
rf_incomming_data[rf_incomming_data_length]=RCREG;
if(RCSTA.OERR) {
RCSTA.CREN=0;
RCSTA.CREN=1;
}
}
else
state=RECIVED;
rf_incomming_data_length++;
}
Postat: 11 maj 2007, 11:47:06
av sodjan
Buadrate ?
Om den inte hinner med så ligger problemet någon annanstans
än i den kod som du visade.
EDIT : Det heter "Receiving" och "Received"...

Postat: 11 maj 2007, 12:48:12
av ankan
Kör 19200 baud påen PIC16F877 @8Mhz.
Tycker att det borde vara i koden jag skrev ovan som det är problem i eftersom det ska inte vara någon annan kod som gör något. När det kommer in en byte ska det läggas i rf_incomming_data tills det har kommit in ett visst antal byte eller det blir timeout.
Timer2 koden ser ut så här:
Kod: Markera allt
if (PIR1.TMR2IF && PIE1.TMR2IE) {
if (state==RECIVING)
state=RECIVED;
if (state==WAITING) {
if (tmr2_counter<18310)
tmr2_counter++;
else
state=TIMEOUT;
}
PIR1.TMR2IF=0;
}
När jag vill börja ta emot aktiverar jag RCIE och TMR2IE, nollställer tmr2_counter och hoppar till state=WAITING.
EDIT: Att RCSTA.OERR sätts till 1 är väll för att FIFOn är full. Räcker det inte med att läsa av RCREG som jag gör? Måste man göra något mer innan man lämnar interruptet?
Postat: 11 maj 2007, 13:28:07
av sodjan
> Kör 19200 baud...
Felkonfigurerad baudrate kanske ?
> ...på en PIC16F877...
Inte 877A ??
> ...@8Mhz.
Säker på at den går i 8 Mhz ??
Du utelämnar en del viktig info, så det blir väldigt spekulativt det här...
Jag kan i alla fall inte se något (i det du har visat) som ser fel ut.
Postat: 11 maj 2007, 13:47:51
av ankan
Övriga meddelanden vid uppstartser rätt ut så det borde inte vara fel på baudrate..
Missade visst ett A på modellförteckningen.
Och jag den går i 8Mhz eftersom den kör på en externkristall som är på 8Mhz och timrarna snurrar som de ska..
Det måste vara ett hastighetsproblem. Kör jag i 1200 baud hinner den registrera alla byten. Men det ska väll inte vara så svårt att köra i 19200 eller i alla fall 9600 baud?
EDIT: Märkte nu att de berodde på antalet byte. Är det 8 byte går det bra i 1200 baud men inte 7 byte. Då rapporterar den 3 byte. Skickar jag 6 byte registrerar den alla 6 byten. Så det är lite från och till verkar det som.
Postat: 11 maj 2007, 13:57:32
av $tiff
Det går inte för fort iaf. Jag brukar köra mina AVR på 38400 Baud @ 8 MHz, funkar prima!
Postat: 11 maj 2007, 14:36:42
av bearing
>När jag vill börja ta emot aktiverar jag RCIE och TMR2IE, nollställer tmr2_counter och hoppar till state=WAITING.
Fast om det kommer något när du inte "vill" så får du ju overflow. FIFOn är ju bara på 1 byte. Jag föreslår att du ser till så att den alltid tömmer bufferten när det kommer något, så att du aldrig får overflow.
Postat: 11 maj 2007, 15:28:54
av sodjan
Precis. RCIE kan vara aktiv hela tiden.
Sedna är det bara att "kasta" de tecken som kommer in
ISR'en ifall man inte vill ha dom...
Nu är jag inte säker på att det är problemet just här dock...
Om OERR sätts så har man vanligtsvis ett större design problem.
"Normalt" ska man aldrig få OERR.
Postat: 11 maj 2007, 17:31:57
av Marta
Jag hänger inte med vad Du gör med TMR2????
C är väl inte helt optimalt till sådat här hellre, det händer alldeles för många saker "backstage" för att programmeraren skall kunna ha riktigt bra kontroll.
877A har nog ingen OSCCON, så det nog knappast vara att den går i snigelfart som är felet. Har bara skummat databladet, det är så många PIC aktuella här lokalt på en gång så det går runt när jag tänker på alla FSR.
Postat: 11 maj 2007, 18:07:08
av ankan
För att ge er lite bättre överblick och sammanhang lägger jag upp hela koden här.
Jag har ännu inte kommenterat koden men jag hoppas att den inte är allt för svår att tyda. Kör med olika tillstånd som enheten kan hamna i.
BASESTATION_DATA_SIZE = 8 (eftersom det är relevant i detta fall)
Kod: Markera allt
#include "USART.h"
#include "ERx00TRS.h"
#include "1Wire_Common.h"
#include "1Wire_Node.h"
#include "Common.h"
//byte ROM_id[8];
byte ROM_id[8]={0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01};
byte ROM_data[16];
byte rf_channel;
byte rf_node_nr;
byte rf_incomming_data[BASESTATION_DATA_SIZE];
byte rf_incomming_data_length;
byte tmr1_counter=0;
unsigned tmr2_counter=0;
byte lost_counter=0;
byte next_sync=60;
enum states { START=0, LEARN, WAKE_UP, PREPARE_WAITING, WAITING, TIMEOUT, RECIVING, RECIVE_BYTE, RECIVED, NORMAL, SLEEP } state;
void main() {
byte i=0;
init();
ow_get_id(&ROM_id,OW_PORT,OW_PIN);
delay_ms(20);
state = START;
while(1) {
Lcd_Chr(1,4,(tmr1_counter/10)+0x30);
Lcd_Chr(1,5,(tmr1_counter%10)+0x30);
Lcd_Chr(1,10,(tmr2_counter/10000)+0x30);
Lcd_Chr(1,11,((tmr2_counter%10000)/1000)+0x30);
Lcd_Chr(2,4,rf_channel+0x30);
Lcd_Chr(2,9,(rf_node_nr/10)+0x30);
Lcd_Chr(2,10,(rf_node_nr%10)+0x30);
switch (state) {
case START : LCD_Out(2,12, "START");
RF_MODULE=OFF;
INTCON.INTF=0;
INTCON.INTE=1; // Aktivera LEARN-knapp
asm {
SLEEP
NOP
}
break;
case LEARN : LCD_Out(2,12, "LEARN");
RF_MODULE=ON;
delay_ms(200);
init_ER();
rf_channel=0;
rf_node_nr=0;
ER_Set_Channel(rf_channel);
ER_Set_Data_ID(rf_node_nr);
delay_ms(100);
Usart_Write_Data(&ROM_id,8);
for (i=8;i<NODE_DATA_SIZE;i++)
Usart_Write(0x00);
state = PREPARE_WAITING;
break;
case WAKE_UP : LCD_Out(2,12, "WAKEU");
tmr1_counter=0;
RF_MODULE=ON;
delay_ms(200);
init_ER();
ER_Set_Channel(rf_channel);
ER_Set_Data_ID(rf_node_nr);
state = PREPARE_WAITING;
break;
case PREPARE_WAITING : LCD_Out(2,12, "PREPA");
rf_incomming_data_length=0;
tmr2_counter=0;
PIR1.TMR2IF = 0;
// PIE1.TMR2IE = 1;
PIR1.RCIF = 0;
PIE1.RCIE = 1;
state = WAITING;
break;
case WAITING : LCD_Out(2,12, "WAITI");
break;
case TIMEOUT :
lost_counter++;
state=PREPARE_WAITING;
break;
case RECIVING :
LCD_chr(1,13,(rf_incomming_data_length+0x30));
LCD_Out(2,12, "RXING");
break;
case RECIVED : LCD_Out(2,12, "RXED ");
PIR1.TMR2IF=0;
PIE1.TMR2IE=0;
PIR1.RCIF = 0;
PIE1.RCIE = 0;
lost_counter=0;
Lcd_Chr(1,13,rf_incomming_data_length+0x30);
LCD_chr(1,15,(rf_incomming_data[0]/10)+0x30);
LCD_chr(1,16,(rf_incomming_data[0]%10)+0x30);
switch (rf_incomming_data[0]) {
case WRITE_SCRATCHPAD :
rf_channel=rf_incomming_data[1];
rf_node_nr=rf_incomming_data[2];
ER_Set_Channel(rf_channel);
ER_Set_Data_ID(rf_node_nr);
break;
case READ_SCRATCHPAD :
next_sync=rf_incomming_data[1];
Usart_Write_Data(&ROM_id,8);
Usart_Write_Data(&ROM_data,24);
tmr1_counter=0;
break;
default :
break;
}
RF_MODULE=OFF;
state=NORMAL;
break;
case NORMAL : LCD_Out(2,12, "NORMA");
if (ROM_id[0]==0x28)
ow_get_ds18b20_data(&ROM_data,OW_PORT,OW_PIN);
else {
if (ROM_id[0]==0x26)
ow_get_ds2438_data(&ROM_data,OW_PORT,OW_PIN);
}
delay_ms(20);
PIE1.TMR1IE = 1;
tmr1_counter=0;
state=SLEEP;
break;
case SLEEP : LCD_Out(2,12, "SLEEP");
asm {
SLEEP
NOP
}
break;
default : break;
}
}
}
void interrupt() {
if (PIR1.TMR1IF && PIE1.TMR1IE) {
if(tmr1_counter<next_sync)
tmr1_counter++;
else
state=WAKE_UP;
TMR1H=0x80;
PIR1.TMR1IF = 0;
}
if (INTCON.INTF && INTCON.INTE) {
state = LEARN;
INTCON.INTF=0;
}
if (PIR1.RCIF && PIE1.RCIE) {
TMR2=0;
state=RECIVING;
if (!rf_incomming_data_length) {
PIR1.TMR2IF=0;
// PIE1.TMR2IE=1;
}
if(rf_incomming_data_length < BASESTATION_DATA_SIZE) {
rf_incomming_data[rf_incomming_data_length]=RCREG;
if(RCSTA.OERR) {
RCSTA.CREN=0;
RCSTA.CREN=1;
}
}
else {
state=RECIVED;
}
rf_incomming_data_length++;
}
if (PIR1.TMR2IF && PIE1.TMR2IE) {
if (state==RECIVING)
state=RECIVED;
if (state==WAITING) {
if (tmr2_counter<18310)
tmr2_counter++;
else
state=TIMEOUT;
}
PIR1.TMR2IF=0;
}
}
void init() {
// OSCCON = 0x60; // 4 Mhz
// ANSEL = 0x00;
ADCON1 = 0x06;
PORTA = 0x00;
PORTB = 0x00;
TRISA = 0b11111110;
TRISB = 0b11111111;
T1CON = 0x0F; // Extern klockkristall
T2CON = 0x07; // 1:16 prescale
// T1CON = 0x30; // Interna klockan
PIR1.TMR1IF = 0;
PIE1.TMR1IE = 1;
INTCON = 0xD0;
Usart_Init(19200);
Lcd_Init(&PORTD);
LCD_Cmd(LCD_CLEAR); // Clear display
LCD_Cmd(LCD_CURSOR_OFF); // Turn cursor off
LCD_Out(1,1, "T1: T2:"); // Print text to LCD, 2nd row, 1st column
LCD_Out(2,1, "C#: N#: "); // Print text to LCD, 2nd row, 1st column
tmr1_counter=1;
}
Postat: 11 maj 2007, 23:49:47
av sodjan
Bara en liten fundering...
> Usart_Init(19200);
Hur vet den funktionen vilken hastighet du kör på ?
Alltså att det är just "8 MHz" den ska använda för att
beräkna värdet för baudrate registret ? Sätts det
någon annanatans ?
Postat: 12 maj 2007, 09:50:22
av ankan
Det är en färdig rutin som medföljer kompilatorn. Den hämtar frekvensen och räknar ut rätt värde och sätter baudraten till det som en konstant.
Det fungerar hur som helst åt andra hållet utan att ändra något. Dvs att PICen skickar data där alla byte kommer ut rätt.
Postat: 12 maj 2007, 10:24:39
av Marta
Vet Du *vilka* av de inkommande bytes som tas emot?
Du skriver det är två styken, är dessa de två första? Slumpmässiga? Den första och en slumpmässig? O.s.v.
Vad händer omDu flödar UART med data och förhindrar timeout ifall detta behövs? Tar den då till slut emot det förväntade antalet bytes, eller är det alltid stopp efter just två?
Postat: 12 maj 2007, 12:20:42
av sodjan
Precis, som Marta säger, det är bara gammal god felsökning som gäller...
Till Marta's åtgärder skulle jag bara vilja tilllägga att, om du kör dina 8
tecken med en rejäl paus (kan vara t.ex en halv sekund eller så),
kommer *då* alla 8 tecken över till PIC'en ?
Om det var mitt problem, så skulle jag göra en kraftigt avskalad
variant med enbart USART rutinerna för att verifiera om det är dom
som strular, eller om det ligger i någon annan del av koden.
Postat: 14 maj 2007, 16:11:28
av ankan
if (PIR1.RCIF && PIE1.RCIE) {
TMR2=0;
state=RECIVING;
if (!rf_incomming_data_length) {
PIR1.TMR2IF=0;
// PIE1.TMR2IE=1;
}
if(rf_incomming_data_length < BASESTATION_DATA_SIZE) {
rf_incomming_data[rf_incomming_data_length]=RCREG;
if(RCSTA.OERR) {
RCSTA.CREN=0;
RCSTA.CREN=1;
}
}
else {
state=RECIVED;
}
rf_incomming_data_length++;
}
Det var RC avbrottet det var problem med. När rf_incomming_data_length är lika med BASESTATION_DATA_SIZE så nollställs rf_incomming_data_length av någon anledning och jag hamnar aldrig i RECIVED. Gjorde om koden till följande i stället så fungerar det:
Kod: Markera allt
if (PIR1.RCIF && PIE1.RCIE) {
TMR2=0;
state=RECIVING;
if (!rf_incomming_data_length && mode==LEARN_MODE) {
PIR1.TMR2IF=0;
// PIE1.TMR2IE=1;
}
if (rf_incomming_data_length < BASESTATION_DATA_SIZE) {
rf_incomming_data[rf_incomming_data_length]=RCREG;
rf_incomming_data_length++;
}
else {
temp_byte=RCREG;
}
if (rf_incomming_data_length == BASESTATION_DATA_SIZE)
state=RECIVED;
}
Något blev fel vid kompileringen antagligen.