CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

RS232 INT_RDA problem getting the data returned back :(
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Sgulsen
Guest







RS232 INT_RDA problem getting the data returned back :(
PostPosted: Wed Sep 16, 2009 7:26 am     Reply with quote

Hello,

I'm working on a project that requires communication of a PIC16F877A and a device.

I can easily submit a data via RS232 HW of the PIC. But i cant say the same for receiving data. After a data is sent to the controlled device, it returns some data. I can press the x button and run if (x==0) { --- just once. I get the value "Ver= (with no value, there should be the read data)"on the LCD but after pressing the y and z buttons and repress the x button, "Ver = (with no value)" text doesnt even show up


My compiler version is 4.093

Here is my code :
Code:

#include <16f877A.h>
#use delay (clock=4000000)
#include <benim_LCD.c>
#include <stdlib.h>
#use rs232 (baud=19200, xmit=pin_C6, rcv=pin_C7, parity=N, stop=1)
#define CS PIN_D2    // CS ifadesi PIN_C2 pini yerine atanıyor
#Fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD

char keyss[50];
char k;
int8 res,x,y,z,i;

#int_rda
void scmnt ()
{
            disable_interrupts(int_rda);
            i=0;
gsp:    k = getch();
            While (k){ 
               keyss[i] = k;
               i = i+1;
               goto gsp;
            }
            printf(lcd_veri,"Ver = %s",keyss);
}

void main()

{
   port_b_pullups(TRUE);
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_CLK_DIV_4);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   
   lcd_hazirla();
   enable_interrupts(GLOBAL);
   printf("BUZ1\r");                      //Starts buzzer to make sure the devices communicate with each other

   while(1)
   {
      imlec(1,1);

      x=input(pin_b6);
      y=input(pin_b7);
      z=input(pin_d7);
     

     
      if(x==0){
         enable_interrupts(int_rda);
         printf("VER\r");          //Requests a version data from the device, the device DOES return the data, i've tested it with the Serial I/O monitor of the PCWHD, but cant read it properly
         delay_ms(500);         
      }
      if(y==0){     
         printf("BUZ0\r");         // This stops the buzzer
         printf(lcd_veri,"BUZ0");
      }
      if(z==0){     
         printf("BUZ1\r");         // This sounds a buzzer & sounds it
         printf(lcd_veri,"BUZ1");
      }
           
   }
   
}
Ttelmah
Guest







PostPosted: Wed Sep 16, 2009 9:02 am     Reply with quote

INT_RDA, means that there is _one_ character waiting.
Your code, will loop, till a 'null' (0) character is received. The null character is the _internal_ end of string marker, so if you send this, nothing will be displayed for it. Your unit almost certainly does not send a null, but probably something like a carriage return to mark the end of data. Your UART, probably contains a 'null' on wakeup, from the line idling low as the unit boots up. Hence the first response.
Code:

char keyss[50];
int1 have_sequence=false;
int8 res,x,y,z,i;

#int_rda
void scmnt (void) {
   int8 k;
   k = getch();
   if (k==0) return; //Throw away a null if received
   keyss[i++] = k;
   if (i==50) i--; //prevent buffer overflow
   if (k==13) { //Guessing at CR
      keyss[i]=0; //terminate the string
      i=0; //start filling from the start again
      have_sequence=true;
   }
}

//Then in the main, something like:
   int8 waitcount;

   if(x==0){
      enable_interrupts(int_rda);
      printf("VER\r"); //Requests a version data from the device
      waitcount=0;
      while (have_sequence==false)
           delay_ms(10);
           if (waitcount++>50) break;
      }
      if (have_sequence) printf(lcd_veri,"Ver = %s",keyss);


Best Wishes
salgulsen



Joined: 16 Sep 2009
Posts: 21

View user's profile Send private message

PostPosted: Thu Sep 17, 2009 1:42 am     Reply with quote

hmm..

Quote:
INT_RDA, means that there is _one_ character waiting.


Weirdly I thought it would release an interrupt just after the data ended. This solves one point...I fixed the code according to this.

The data received in the SIOW can be seen below :
[img=http://img190.imageshack.us/img190/959/99995465.jpg]

As you can see there is a start of data indicator in the beginning of the data stream and end of data at the end of the stream. So I've modified the code like :
Code:

char keyss[50];
int8 x,y,z,i,waitcount;
int1 have_sequence=false;

#int_rda 
void scmnt (void) {
   int8 k;
   k = getch();
   if ((k==2) || (k==0)) {//Throw away a null or a start of data if received
   return;
   }else{
   keyss[i++] = k;
   }     
   if (i==50) i--; //prevent buffer overflow
   if (k==3) { //Guessing at end of data
      keyss[i]=0; //terminate the string
      i=0; //start filling from the start again
      have_sequence=true;
   }
}


And the main call segment like :
Code:

      if(x==0){
         enable_interrupts(int_rda);
         i=0;
         have_sequence = false;
         printf("VER\r");
         waitcount=0;
         while (have_sequence==false) {
           delay_ms(10);
           if (waitcount++>50) {
           printf(lcd_veri,"Boring");
           break;
           }
         }   
         if (have_sequence) printf(lcd_veri,"Ver = %s",keyss);
      }


But LCD displays "boring"....There is something I miss but I don't know what it is...
salgulsen



Joined: 16 Sep 2009
Posts: 21

View user's profile Send private message

PostPosted: Thu Sep 17, 2009 9:42 am     Reply with quote

I've checked the entire forum & found something about the UART cache. It has a cache of 3 bytes. This might be causing my problem. I receive more than 10 bytes after each transmitted value. I tried to use the UART with ERRORS function in USE RS232 but that didn't work either. I also cleaned the buffer with reading RCREG function 3 times but it didn't work still.
I tried using kbhit() function without the ERRORS parameter, but it got the first 3 bytes of the data (check the picture above, it only gets 02 30 30). When I run it and send a data again, it only receives 02 30 (not the 3rd byte)

This ruined my whole day and I couldn't figure it out yet :( Please help me
salgulsen



Joined: 16 Sep 2009
Posts: 21

View user's profile Send private message

PostPosted: Thu Sep 17, 2009 9:45 am     Reply with quote

Also, i've changed my crystal freq to 20Mhz (used fuses:HS and use delay=20000000 functions) just to make sure it takes the data fast enough, but it didnt help,either...
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Thu Sep 17, 2009 10:05 am     Reply with quote

You set have_sequence to false just before you enter the waiting loop.
You then have half a second for the data to arrive.
How do you initiate transfer from the device to the pic ?
Could the data have already been transfered and set have_sequence true before you enter this routine ?
Or you just havn't given enought time to press the button on the device.

With the code you have shown, you have not enclosed it in a loop. If this just drops off the bottom of main then the compiler will just put a sleep op in and your printf may not output the data properly if it is relying on interrupts.
Guest








PostPosted: Thu Sep 17, 2009 2:24 pm     Reply with quote

Quote:
With the code you have shown, you have not enclosed it in a loop. If this just drops off the bottom of main then the compiler will just put a sleep op in and your printf may not output the data properly if it is relying on interrupts.


My whole code can be seen in the first message. In my second message i've changed just the interrupt part and the part that "VER\r" is sent to the controlled device

Quote:
You set have_sequence to false just before you enter the waiting loop.
You then have half a second for the data to arrive.
How do you initiate transfer from the device to the pic ?
Could the data have already been transfered and set have_sequence true before you enter this routine ?


The data comes instantly just after the command "VER\r"
Ttelmah told me that PIC would go to the interrupt INT_RDA routine for every byte that RX pin receives. thats why i declare have_sequence = false just before the "VER\n" and try to make it TRUE in the interrupt routine by waiting for the 03 (end of text ASCII character)
Ttelmah
Guest







PostPosted: Thu Sep 17, 2009 3:01 pm     Reply with quote

How big is your LCD?.
Assuming it has a reasonable number of characters, try something really crude like:
Code:

//no interrupt handler and interrupts disabled:
//just have your initialisation for LCD etc. then a main like:

    delay_ms(100); //ensure everyting is awake
    while (kbhit()) k=getc; //Flush the UART
    lcd_veri('\f'); //clear the LCD
    printf("VER\r"); //Ask for the version
    while (TRUE) {
        k=getc();
        printf(lcd_veri,"%02x",k); //Display everything received in hex
    }

Get rid of the button tests etc.

If your hex, matches what you are seeing in SIOW, then your code should work. I'd guess there is either a fractional timing error, or a word length error, so whay you get, is not the sequence you expect. Hence the code doesn't work, since '3' is not seen...

Best Wishes
salgulsen



Joined: 16 Sep 2009
Posts: 21

View user's profile Send private message

PostPosted: Fri Sep 18, 2009 1:55 am     Reply with quote

I've tested something like this, but simpler :
Code:

      printf("VER\r"); //Ring the buzzer
      while (kbhit()) {
           
            k=getc();
            printf(lcd_veri,"%x ", k);
      }

This rings the buzzer and gets the first 3 bytes (02 30 30) but not the rest. Besides that, RX gets locked... I can't get any more data. If I write ERRORS in the USE RS232 declaration, it gets more data if I send some command, but again I lose the rest of the data...
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Fri Sep 18, 2009 2:04 am     Reply with quote

Sry, I did miss the fact you posted the routine above, but also, in my defence some people will have changed that routine to the extent that the while loop is no longer there Smile

Ttelmah is correct of course about the interrupt routine. Did you put the ERRORS keyword in the #use statement ?

In your interrupt routine :-

you receive the value 3
You store it
Increment i
Then store the value 0 at i (string termination)
But you still have the value 3 there, not sure what that would do to the output.
salgulsen



Joined: 16 Sep 2009
Posts: 21

View user's profile Send private message

PostPosted: Fri Sep 18, 2009 2:09 am     Reply with quote

By the way, i've given up hope with the baud rate of 19200 (i must get high speed transfer--still) and i dropped it down to 1200..I got more data but still half of the data i need...Rest is still lost...Which means there is nothing wrong with the codes that is used to receive the data - i can call the data indeed --but there is something wrong with the hardware or some kind of bus error....I've shortened my cable length to 10 cms even though i can communicate with the same long cable both with pic and pump via PC..And it made no effect...
Ttelmah
Guest







PostPosted: Fri Sep 18, 2009 2:18 am     Reply with quote

Tell us more about benim_LCD?.
Is this modified from one of the standard drivers (flex_lcd for example). Is the LCD a standard 'text' unit?.
What is the interface to the device?.

The only reasons for dropping the speed helping, are:

1) Your receive hardware has a problem wth handling higher speed signals.
2) Your chip is doing a lot of other 'unseen' work, with interrupts disabled. Hence the question about the LCD driver.

Using the normal lcd driver from CCS, or the flex_lcd driver, the code being used so far, should be able to easily handle data over 56000bps, even with a 4MHz clock....

Best Wishes
Wayne_



Joined: 10 Oct 2007
Posts: 681

View user's profile Send private message

PostPosted: Fri Sep 18, 2009 3:51 am     Reply with quote

Could it be because the FUSES are declared after the #use statement ?
salgulsen



Joined: 16 Sep 2009
Posts: 21

View user's profile Send private message

PostPosted: Fri Sep 18, 2009 5:42 am     Reply with quote

Ttelmah wrote:
Tell us more about benim_LCD?.
Is this modified from one of the standard drivers (flex_lcd for example). Is the LCD a standard 'text' unit?.
What is the interface to the device?.

The only reasons for dropping the speed helping, are:

1) Your receive hardware has a problem wth handling higher speed signals.
2) Your chip is doing a lot of other 'unseen' work, with interrupts disabled. Hence the question about the LCD driver.

Using the normal lcd driver from CCS, or the flex_lcd driver, the code being used so far, should be able to easily handle data over 56000bps, even with a 4MHz clock....

Best Wishes


Code:
//////////////////////////////////////////////////////////////
//                    benim_LCD.c                           //
// Bu LCD sürücü dosyası 2x16 HD44780 uyumlu LCD’ler        //
// için yazılmıştır. LCD’ye sadece yazma yapılacağı için    //
// R/W ucu şaseye bağlanmalıdır. LCD bağlantısı aşağıdadır. //
//////////////////////////////////////////////////////////////
// RB0 -> LCD’nin D4 ucuna
// RB1 -> LCD’nin D5 ucuna
// RB2 -> LCD’nin D6 ucuna
// RB3 -> LCD’nin D7 ucuna
// RB4 -> LCD’nin RS ucuna
// RB5 -> LCD’nin E  ucuna
// R/W ucu direkt şaseye bağlanacak

#define e   pin_b5 // LCD'nin E ucu RB5 pinine bağlı
#define rs  pin_b4 // LCD'nin RS ucu RB4 pinine bağlı

//****** LCD'ye Komut Gönderme Fonksiyonu **********
void lcd_komut(byte komut)
{   
   output_b(komut>>4);   // Komutun yüksek değerli 4 bitini gönder
   output_low(rs);       // LCD komut almak için ayarlandı
   delay_cycles(1);      // 1 komut saykılı bekle   
   output_high(e);       // E ucu lojik-1'den lojik-0'a çekiliyor
   delay_cycles(1);      // 1 komut saykılı bekle
   output_low(e);
   delay_ms(2);          // 2 msn gecikme veriliyor

   output_b(komut&0x0F); // Komutun düşük değerli 4 bitini gönder
   output_low(rs);      // LCD veri almak için ayarlandı 
   delay_cycles(1);      // 1 komut saykılı bekle     
   output_high(e);       // E ucu lojik-1'den lojik-0'a çekiliyor
   delay_cycles(1);      // 1 komut saykılı bekle
   output_low(e);
   delay_ms(2);          // 2 msn gecikme veriliyor
}

//******* LCD'ye Veri Gönderme Fonksiyonu **********
void lcd_veri(byte veri)
{
   output_b(veri>>4);    // Verinin yüksek değerli 4 bitini gönder
   output_high(rs);      // LCD veri almak için ayarlandı
   delay_cycles(1);      // 1 komut saykılı bekle   
   output_high(e);       // E ucu lojik-1'den lojik-0'a çekiliyor
   delay_cycles(1);      // 1 komut saykılı bekle
   output_low(e);
   delay_ms(2);          // 2 msn gecikme veriliyor

   output_b(veri&0x0F); // Verinin düşük değerli 4 bitini gönder
   output_high(rs);      // LCD veri almak için ayarlandı
   delay_cycles(1);      // 1 komut saykılı bekle   
   output_high(e);      // E ucu lojik-1'den lojik-0'a çekiliyor
   delay_cycles(1);     // 1 komut saykılı bekle
   output_low(e);
   delay_ms(2);         // 2 msn gecikme veriliyor
}

//******* LCD'de İmlec Konumlandırma Fonksiyonu ********
void imlec(byte satir, byte sutun)
{
   if (satir==1)      // Eğer satır değişkeni "1" ise
      lcd_komut(0x80|(sutun-1));

   if (satir==2)      // Eğer satır değişkeni "2" ise
      lcd_komut(0x80|(0x40+(sutun-1)));
     
   if (satir==3)      // Eğer satır değişkeni "3" ise
      lcd_komut(0x94|(sutun-1));

   if (satir==4)      // Eğer satır değişkeni "4" ise
      lcd_komut(0x94|(0x40+(sutun-1)));
}

//********* LCD Başlangıç Ayarları Fonksiyonu ******
void lcd_hazirla()
{
   int i=0;
   output_low(rs); // RS ucu lojik-0
   output_low(e);  // E ucu lojik-0
   delay_ms(30);   // LCD enerjlendiğinde LCD'nin hazır olması için beklenen süre
   
   for(i=0;i<=3;i++)    // LCD'ye 3 kez 0x03 komutu gönderiliyor
   {
      lcd_komut(0x03);
      delay_ms(5);      // 5msn gecikme veriliyor
   }
   lcd_komut(0x02); // LCD'ye 4 bit iletişim komutu gönderiliyor
   lcd_komut(0x28); // 4 bit iletişim, 2 satır, 5x8 dot matris seçildi
   lcd_komut(0x08); // Display Kapalı
   lcd_komut(0x0C); // Display açık,imleç alt çizgi ve yanıp sönme yok
   lcd_komut(0x06); // Her veri yazıldığında imleç bir sağa gitsin
   lcd_komut(0x01); // Display sil. İmleç 1.satır 1.sütunda
}


Comments are in turkish, i couldnt convert them all to english..Hope you'll understand. I managed to use my 4x20 LCD display with this code, but couldn't use it with standard lcd420.c driver.


Quote:
Could it be because the FUSES are declared after the #use statement ?


Nope. I tried putting fuses before the use RS232 but nothing different happened
Ttelmah
Guest







PostPosted: Fri Sep 18, 2009 7:32 am     Reply with quote

lcd_benim, is 'why' the simple tests don't work.
If you look at the 'write' routine, it takes a minimum of just over 4mSec, to send a single byte!. Given that at 19200bps, a byte can arrive in just over 0.5mSec, it is not surprising that the internal chip buffer soon overflows, and the UART locks (without ERRORS), or loses bytes (with ERRORS).
The only commands that need this long, are things like the clear screen command.
Try the flex_lcd driver from the code library. This correctly times the writes, taking a few _uSec_ to write a normal byte. Hopefully this will make the simple tests start working, so you can genuinely 'see' if the right data is being received.

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group