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 CCS Technical Support

Problems with INT_RDA. PIC 16F877.
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
nacho72



Joined: 20 Oct 2014
Posts: 13

View user's profile Send private message

Problems with INT_RDA. PIC 16F877.
PostPosted: Tue Oct 21, 2014 5:34 am     Reply with quote

Hello,

I'm trying to send and receive data using the UART of my PIC16F877, through the pins RC7 and RC6. To do so I designed a circuit, where the user can press 3 different buttons, generating a diferent signal in the TX pin.

I joined with a wire the TX pin with the RX pin, so I will be able to read exactly what I send, and finallt display the message in an LCD.

But there is a problem with the INT_RDA, because it never reach the "READ CHAR TO DISPLAY IN LCD" part.

Here is the code I have writtem:

Code:

#include "16F877.h"


#fuses NOWDT, HS
#use delay (clock=20000000)

#include <string.h>
#include <stdlib.h>
#include "lcd_ATE8.c" //for the LCD


#use RS232(UART, baud = 115200, xmit = PIN_C6 ,rcv = PIN_C7, PARITY = N, bits = 8, stop = 1, stream = BLUETOOTH)


#use fast_io(B)
#use fast_io(C)

#byte   PORTB=0x06

#bit   RB0=PORTB.0         
#bit   RB1=PORTB.1         
#bit   RB2=PORTB.2
#bit   RB3=PORTB.3
#bit   RB4=PORTB.4
#bit   RB5=PORTB.5
#bit   RB6=PORTB.6
#bit   RB7=PORTB.7

#byte   PORTC=0x07

#bit   RC7=PORTC.7         




#INT_RB
void key()
{
   int   btn;      /* Determinan el boton pulsado */

   delay_ms(20);            // Espera de 20ms para evitar rebotes.



   if(RB4)   btn=0;               
      else   if(RB5)   btn=1;         
        else     if(RB6)       btn=2;     
        else   return;


   switch (btn)
   {
      case 0:  lcd_putc("\f");   lcd_putc("H was pressed");  fprintf(BLUETOOTH,"H"); break;

      case 1:  lcd_putc("\f");   lcd_putc("W was pressed"); fprintf(BLUETOOTH,"W");break;

      case 2:  lcd_putc("\f");   lcd_putc("G was pressed");  fprintf(BLUETOOTH,"G");break;
   
   }


}

#INT_RDA
void bt()
{

   int x = 0;

   if(RC7==1) //READ CHAR TO DISPLAY IN LCD   
   {
      lcd_putc("\f");
      lcd_putc("we get something");
                //x=getc();
                //lcd_putc(x)

   }else
   {
      x=getc();
   }
}



void main()
{


      lcd_init();               
   lcd_putc("\f");         
   lcd_putc("START...");

   PORTB=0;                     
      set_tris_b(0b11110000);
   set_tris_c(0b10010000);

        enable_interrupts(GLOBAL);   
   enable_interrupts(INT_RB);   
   enable_interrupts(INT_RDA);   

   while(TRUE)   
   {
 
   }
   
}


Can anyone tell me what am I doing wrong with the INT_RDA?

Thank you very much for your time.

**This is my first post, in case I need to add further information, or something I said is not accurate, please let me know to edit the post or to write additional information below** [/img]
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 6:40 am     Reply with quote

You are printing inside the ISR... this is bad.

Look at circular buffers.... and process data or display data outside the ISR.

also you seem to be using bluetooth... get this to work first using plain wiered conections.... then go for bluetooth
_________________
CCS PCM 5.078 & CCS PCH 5.093
nacho72



Joined: 20 Oct 2014
Posts: 13

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 7:16 am     Reply with quote

Hello Gabriel,

Uhm I'm not sure how else can I print the information. I read for the UART the easiest way is using a stream.

And yes, as you said I was planning to add a Bluetooth module here, but firstly I just pluged with a wire the TX pine with the RX, so see if the interruption detects when a signal is arriving to RX. But there is the problem.

I used an oscilloscope to check the signal in RX and TX, and I saw it is always high, but it moves to low level when some bits are transmited or recieved.

So my plan was to include and if, that just store the result of getc() when the level of RC7 (RX pin) is low.

But it is not working.
nacho72



Joined: 20 Oct 2014
Posts: 13

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 7:20 am     Reply with quote

Hello Gabriel,

I think I just understood why you mean with printing outside of the ISR.

Do you mean, in the if clause, make a call to another method, for example DoPrint(). And in DoPrint() make the printing? Like this:

Code:
void DoPrinting()
{
     lcd_putc("\f");
     lcd_putc("Something to print");

}

#INT_RDA
void bt()
{

   int x = 0;

   if(RC7==1)//()   
   {
      DoPrinting();

   }else
   {
      
      x=getc();
   }
}
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 7:33 am     Reply with quote

No he doesn't...
ISRs must be small and fast !
Inside the USR set a flag then exit.
This 'flag' is just a variable (say 'uart_char_yes')
Within 'main()' check the status of that flag and act accordingly...
if it's set...do something....clear variable.

any 'printing' takes a lot of time and should NOT be done inside any ISR. The same is true about 'math' operations,esp. floating point!
Simply set a 'flag' and exit.


If you search this forum there's 1000s of examples of this.....

jay
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 8:57 am     Reply with quote

Code:
#INT_RDA
void SerialInt()
{
   Receive_String[counter_read]=getchar();         // Gets chars from uart
   counter_read++;                           // Increment counter
      if(counter_read==SIZE_BUFFER)counter_read=0;   // Circle Buffer
}



This is my default Serial ISR... others might have their own. this is what I use in most of my code.

Basically it stores in "Receive_String" all incoming serial data and when it fills up it loops back (circular buffer) to the first position and starts over writing the oldest data.

when i say printing out of the ISR is have a function in your MAIN or other places NOT IN THE ISR or even CALLED from the ISR, that prints the contents of the Buffer.

you should not call any functions from your ISR.... as temtronic says.. use flags.

GET IN GET OUT FAST - like a bad date.

G.
_________________
CCS PCM 5.078 & CCS PCH 5.093
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 8:58 am     Reply with quote

Hi,

No, that is NOT what Gabriel meant at all! What you need to do is 'buffer' the incoming serial data, and then print it outside of the interrupt as time allows. If you bog the interrupt down with printing, or calls to printing, inside the interrupt, then you are guaranteed to lose data! Look at CCS example 'ex_SISR.c' to see the proper way to setup an interrupt driven serial buffer!

Also, this topic has been hashed and rehashed literally thousands of times. You really should spend an hour or two looking at the forum archives! Trust me, it will be worth the effort!

John
nacho72



Joined: 20 Oct 2014
Posts: 13

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 9:38 am     Reply with quote

Thank you very much to all of you for your effort and recommendations. I will follow all of them and test them before posting a new version of my code.

But I would like to add something else I found in another answer from this forum.

The issue in that topic, was the code goes inside the INT_RDA so often, probably beause the pin was catching always some noise, so to avoid that situation and don't buffer noise, someone suggested to include an if() inside the INT_RDA, to check the state of the pin RX before buffering anything. They also mentioned to flush the RDA interruption a getc() is necessary, even if you don't want to use the data.

In addition, I was using an oscilloscope to measure the signal in RX, and I saw it was held in around 2V, moving from there to almost 0 repeatedly while receiving something. [something like 111111011010010011111111]

So I was thinking to write:

Code:
#INT_RDA
void SerialInt()
{

  if(RC7==0)
  {
     Receive_String[counter_read]=getchar();         // Gets chars from uart
     counter_read++;                           // Increment counter
     if(counter_read==SIZE_BUFFER)counter_read=0;   // Circle Buffer
 
   }else{
   
     getc()

   }

}



But I'm not sure if that change from 2.2V to almost 0V is going to be enough to be detected as a logical 0.

I will test these things, and keep looking for information, as you recommended me, before posting anything else.

Thanks again.
ezflyr



Joined: 25 Oct 2010
Posts: 1019
Location: Tewksbury, MA

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 10:34 am     Reply with quote

Hi,

You are talking 'bandaids' here. I've got dozens of designs, and thousands of deployed units that don't require what you are describing. What have you got connected to the Rx input pin on the PIC? Most of the time this input is connected to a MAX232 type IC if you are connected to a PC, and directly if you are connecting to a peripheral device (GPS, GSM modem, Bluetooth interface, etc.). In the direct connection case, be sure the PIC and peripheral are operating at the same voltage, or be prepared to do some level shifting of the interface signals.

John
nacho72



Joined: 20 Oct 2014
Posts: 13

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 11:54 am     Reply with quote

Hi,

Well I was reading several posts, trying the solutions they give and changing my code. But I still can't solve something as easy as triggering the INT_RDA several times.

The program goes inside the INT_RDA just the first time I launch the code, but it doesn't come back again. For testing your ideas and recommendations I wrote this simple code:

Code:
#include "16F877.h"

#fuses NOWDT, HS
#use delay (clock=20000000)

#include "lcd_ATE8.c"


#use RS232(UART, baud = 9600 /*115200*/, xmit = PIN_C6 ,rcv = PIN_C7, PARITY = N, bits = 8, stop = 1, stream = BLUETOOTH)

#use fast_io(B)
#use fast_io(C)


#byte   PORTB=0x06

#bit   RB0=PORTB.0       
#bit   RB1=PORTB.1         
#bit   RB2=PORTB.2
#bit   RB3=PORTB.3
#bit   RB4=PORTB.4
#bit   RB5=PORTB.5
#bit   RB6=PORTB.6
#bit   RB7=PORTB.7

#byte   PORTC=0x07

#bit   RC7=PORTC.7         // Se definen los puertos



#INT_RB
void tecla()
{
   int   boton;      /* Determinan el boton pulsado */

   delay_ms(20);            // Espera de 20ms para evitar rebotes.



   if(RB4)   boton=0;               
      else   if(RB5)   boton=1;         
      else     if(RB6)       boton=2;     
            else   return;


   switch (boton)
   {
      case 0:  RB3=1; fprintf(BLUETOOTH,"HHHHHHHHHHHHHHHH\r\n"); break;
      case 1:  RB3=0; fprintf(BLUETOOTH,"MMMMMMMMMMMMMMMM\r\n");break;
      case 2:  RB3=1;  fprintf(BLUETOOTH,"ZZZZZZZZZZZZZZZZ\r\n");break;
   
   }


}



#INT_RDA
void bt()
{      
   char z;
   z==getc();
   new_char = 1;   

}



void main()
{

      lcd_init();               // Inicializa el LCD.
   lcd_putc("\f");           // Borramos el display
   lcd_putc("STARTING...");

   PORTB=0;                     
      set_tris_b(0b11110000); // 1 es entrada, 0 es salida
   //set_tris_c(0b10010000);   
       
enable_interrupts(INT_RB);   
enable_interrupts(INT_RDA);   
enable_interrupts(GLOBAL);

   while(TRUE)   
   {
   
      if(new_char==1)
      {
         lcd_putc("\f");
         lcd_putc("GETTING SOMETHING");

         delay_ms(1000);
         lcd_putc("\f");

         new_char=0;         

      }
 
   }
   
}


So in this code, when pressing the buttons, something is sent throught TX, and with the oscilloscope I have checked it is recieved in the pin RX. But the only time the program goes inside RDA is at the begining. Then never again appears the message "GETTING SOMETHING".

I commented the instruction set_tris_c(0b10010000); Because in other post recommend to trust in the compiler to solve it, avoiding an extra source of problems.

I also changed the baud rate to several different values (but I think that should not change anything, after all, the pin TX is wired to RX for this testing step).

Can anyone tell me where could be the problem? I think I followed all the recommendations above, and some others that appear in related topics, but I'm sure I'm still missing something.

Thank you!
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 12:58 pm     Reply with quote

When INT_RDA triggers it is saying 'there is a character that needs to be read now'.

Your interrupt handler needs to do this. No delays, no prints etc..

It should just read the character. Set a flag to say 'I have a character - handle it', and immediately exit.

Your main code then reacts to the flag, inspects the character, delays, and prints.

At 9600bps, characters can arrive in just over 1mSec. Your 20mSec delay, can miss 9 characters.
Then the prints take over another 18mSec. Another 17 characters missed.

You just cannot handle things like this.

Repeat the mantra 50 times.

Keep interrupt handlers short. Just do what the interrupt requires. Nothing else.
nacho72



Joined: 20 Oct 2014
Posts: 13

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 1:37 pm     Reply with quote

But Ttelmah, that is for another interrupt, that one is to detect if the buttons have been pressed (and which one).

But below that I wrote the UART interruption, and it is as short as possible.


But anyway, I think I found the mistake (Or at least one possible mistake).

As I understood John said above the voltage level should be the same in RX and TX. And in my case it is not, because in the circuit I designed there are 2 resistors to adapt what in the future will be a Bluetooth module, so in TX it is around 5 but in RX it is around 3.3

Before leaving the labs I made short circuit between both, adding in the code a loop with a putc("A") and I think with that the INT_RDA was reached, but I will need to test it again tomorrow with more time.


Last edited by nacho72 on Tue Oct 21, 2014 5:36 pm; edited 1 time in total
alan



Joined: 12 Nov 2012
Posts: 357
Location: South Africa

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 1:51 pm     Reply with quote

Once you are in a interrupt you can not serve another, only when you exit.
Thus if you wait 20ms in the one interrupt you cannot get to the RDA interrupt.

Regards
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 2:03 pm     Reply with quote

You now tell us about the classic 5 vs 3 problem...

5 volt PIC, 3 volt peripheral ( bluetooth module ).

There's probably 1000+ threads about this here....

You're going to run into MORE 'fun' trying to interface them.

rule #1 . use a 3 volt PIC with 3 volt peripherals if possible. Any 'L' version PIC will work fine at 3 volts.Since 99% of all new peripherals are 3 volts the simplest,easiest, most reliable solution is to buy and use an 'L' type PIC.

rule #2. if you don't follow rule #1 , then you MUST have some form of 'level translation' between the 5 V PIC and 3 V peripheral.

rule #3, if you don't follow rule # 1 or rule #2 then you will NEVER get the project running correctly, you'll waste days if not weeks of your time, and the end result is a failure.

hth
jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19513

View user's profile Send private message

PostPosted: Tue Oct 21, 2014 2:20 pm     Reply with quote

Also, search the forum for why you don't use INT_RB to detect switches.
Using a delay here ruins everything.

You either need hardware debounce, or to use a timer interrupt for debounce, and get out of the interrupt ASAP.
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