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

Faulty communication between two Pics 16f877a

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
dvmaster



Joined: 14 May 2016
Posts: 3

View user's profile Send private message

Faulty communication between two Pics 16f877a
PostPosted: Sat May 14, 2016 12:43 am     Reply with quote

Hey guys, so I've been programing pics for two weeks now, and just today I ran into a problem.

In one of the PICS I read a value from a potentiometer using the ADC and then send it to the other PIC using RS232, however when I built the circuit I only receive the potentiometer values a few times before the whole thing stops working, and by that I mean they both freeze and I can't even restart them using the MCLR.

Here's both codes:

Transmitter
Code:

#include <16F877a.h>
#device adc=10
#use delay (crystal = 4mhz)
#fuses  PUT, HS, NOWDT, NOLVP, NOBROWNOUT,XT
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8, parity=N, errors)

int16 digital_reading;
double angle;
int8 *p;

void main()
{         
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(RA0_ANALOG);   // set PIN_A0 as analog input channel
   set_adc_channel(0);            // point ADC to channel 0 for ADC reading
   delay_ms(5000);   
   
   while(true)
   {         
      digital_reading = read_adc();
      delay_ms(100);
      angle = digital_reading;
      p = &angle;  // pointer p points to the first byte of f   
      putc(p[0]);  // use p as an array Send the first byte
      putc(p[1]);  // Send the second byte
      putc(p[2]);  // Send the third byte
      putc(p[3]);  // Send the forth byte
      putc(p[4]);  // Send the fifth byte
      putc(p[5]);  // Send the sixth byte
      putc(p[6]);  // Send the seventh byte
      putc(p[7]);  // Send the eighth byte       
      delay_ms (2000);
   }
}


Receiver
Code:


#include <16F877a.h>
#fuses  PUT, HS, NOWDT, NOLVP, NOBROWNOUT, XT
#use delay (crystal = 4mhz)
#define LCD_RS_PIN PIN_D0                                                   
#define LCD_RW_PIN PIN_D1         
#define LCD_ENABLE_PIN PIN_D2                           
#define LCD_DATA4 PIN_D4                                                         
#define LCD_DATA5 PIN_D5                                   
#define LCD_DATA6 PIN_D6                                                                           
#define LCD_DATA7 PIN_D7     
#include <lcd.c> 
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8, parity=N, errors)
double f;
int8 *p;
 
#int_rda
 void rd_isr(void)//función de interrupción por recepción de datos USART
 {
   p = &f;
   p[0] = getc();
   p[1] = getc();
   p[2] = getc();
   p[3] = getc();
   p[4] = getc();
   p[5] = getc();
   p[6] = getc();
   p[7] = getc();   
 }

void main()
{   

   enable_interrupts(global);//Habilito interrupción USART
   enable_interrupts(int_rda);

   lcd_init ();
   printf (LCD_PUTC, "\f 08/05/2016\nUPIITA CONTROL");
   delay_ms (500);
   printf (LCD_PUTC, "\f");     
 
   while(true)
   {     
      f=f/50;     
      LCD_Gotoxy (1, 1) ;               
      printf (LCD_PUTC, "A=%f", f);       
      delay_ms(500);
      LCD_Gotoxy (1, 2) ;               
      printf (LCD_PUTC, "Ok");
      delay_ms(500);
      LCD_Gotoxy (1, 2) ;               
      printf (LCD_PUTC, "  ");
   } 
 }


As you can see it's pretty basic code, as I said I've only been doing this for a couple weeks so please bear with me. Confused
Ttelmah



Joined: 11 Mar 2010
Posts: 19506

View user's profile Send private message

PostPosted: Sat May 14, 2016 1:36 am     Reply with quote

Key big thing to understand, is that INT_RDA, means _one_ character is waiting to be received. Just one. You should not be trying to receive multiple characters in the routine.

Then you have the problem that if anything is ever missed (communications are not perfect), there is nothing to synchronise the data at each end.

Then you have the stupidity (sorry!...), of using float.
The value you have is an integer. 0 to 1023. Nothing more. You try to use 'double', but your chip doesn't actually even support a double type (it will just be treated as single).
Treat float values, as if they carried a strong risk of infection!. 99.9% of jobs should never use them. Even if you wanted to do some maths, to get an angle think instead of integer 'milli-degrees'.

So, send the value, as an integer. I'd suggest hex. The you can use a 'line feed' character to synchronise the data. Just four characters needed to send, not eight.

You also have two oscillators selected. Get rid of 'HS' - this is for crystals above 4MHz. Just XT should be there.

Then read the data sheet. Is 'ADC_CLOCK_INTERNAL' recommended at 4MHz?.

So:
TX
Code:

#include <16F877a.h>
#device adc=10
#use delay (crystal = 4mhz)
#fuses  PUT, NOWDT, NOLVP, NOBROWNOUT,XT
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8, parity=N, errors)

int16 digital_reading;

void main()
{         
   setup_adc(ADC_CLOCK_DIV_8); //look at the data sheet
   setup_adc_ports(RA0_ANALOG);   // set PIN_A0 as analog input channel
   set_adc_channel(0);            // point ADC to channel 0 for ADC reading
   delay_ms(5000);   
   
   while(true)
   {         
      digital_reading = read_adc();
      printf("%03LX\n",digital_reading); //send as 3 hex digits + LF
      delay_ms (2000);
   }
}


RX
Code:

#include <16F877a.h>
#fuses  PUT, NOWDT, NOLVP, NOBROWNOUT, XT
#use delay (crystal = 4mhz)
#define LCD_RS_PIN PIN_D0                                                   
#define LCD_RW_PIN PIN_D1         
#define LCD_ENABLE_PIN PIN_D2                           
#define LCD_DATA4 PIN_D4                                                         
#define LCD_DATA5 PIN_D5                                   
#define LCD_DATA6 PIN_D6                                                                           
#define LCD_DATA7 PIN_D7     
#include <lcd.c>
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8, parity=N, errors)
int16 reading=0;
int1 updated=FALSE;

#int_rda
void rd_isr(void)//función de interrupción por recepción de datos USART
{
    static int16 value=0;
    int8 rx_chr;
    rx_chr=getc(); //Just[u] one [/u]character
    if (rx_chr=='\n')
    {
        //have received the end of line
        reading=value;
        value=0;
        updated = TRUE; //tell the code the value has updated
    }
    else
    {
       //For each hex digit, just add to the cumulative value*16.
       value*=16;
       value+=(rx_chr<='9')?rx_chr-'0':rx_chr-'A'+10;
       //This is a horrible little C line to convert a hex digit to it's
       //numeric value.
    }
}

void main()
{   
   int16 scaled;
   enable_interrupts(global);//Habilito interrupción USART
   enable_interrupts(int_rda);

   lcd_init ();
   printf (LCD_PUTC, "\f 08/05/2016\nUPIITA CONTROL");
   delay_ms (500);
   printf (LCD_PUTC, "\f");     
 
   while(true)
   {   
      //Only change the display when a new value arrives
      if (updated)
      {
          scaled=reading*2;
          updated=FALSE;   
          LCD_Gotoxy (1, 1) ;               
          printf (LCD_PUTC, "A=%06.2Lw",scaled);       
      }
   }
}


Now, the receiver, doesn't delay. It will display the data _when it arrives_.
Then instead of dividing by 50, I'm multiplying by 2, and then displaying this as a value/100. %w, allows you to display an integer value, as a value with a decimal point. In this case xxx.xx. Two decimals, so equivalent to dividing by 100. Multiply by 2 first, gives the same result as your float maths, but literally hundreds of times faster.

Your master code sends a value every two seconds, so the slave needs to be sitting 'ready' for this.

Using 'hex' means the code can look for the line feed, and 'know' a value has arrived. Sending the raw binary values from a float, means that if a character ever gets missed, there is nothing to synchronise the transmission, and it'll not recover....
Brings the downside of the horrible conversion line from ASCII hex to numeric though... Sad
dvmaster



Joined: 14 May 2016
Posts: 3

View user's profile Send private message

PostPosted: Sat May 14, 2016 2:00 pm     Reply with quote

Hey man thanks a lot for your help, In a way it makes me feel retarded for making so many mistakes.

But I still cant get values from the pic.

It's like it never get's a value from the other pic, because it dosen't even displays what's inside the if(updated) so updated never changes value from the original false.

I've tried the following:

- Switching pics and programming each one with both codes. To make sure they both work. Even programmed them with some other code. They both work.

- Made sure Tx from the transmitter is connected to Rx of the receiver and the other way around. So basically 25 to 26 and 26 to 25.


It's like the transmitter program won't even start running.
temtronic



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

View user's profile Send private message

PostPosted: Sat May 14, 2016 3:11 pm     Reply with quote

re: transmitter

put an LED and 470r on an unused I/O pin and have it 'toggled' every time through the main loop. That way you KNOW the program is running.

you can do the same for the receive program. just 'toggle' an LED within the
if ( updated) .....

portion of code.

Jay
dvmaster



Joined: 14 May 2016
Posts: 3

View user's profile Send private message

PostPosted: Sat May 14, 2016 7:21 pm     Reply with quote

Good news, I've managed to solve it, with the codes provided.

There probably was also something sketchy with the protoboard I was using since buiding the circuit on a different one made it work.

Thanks everyone.
Ttelmah



Joined: 11 Mar 2010
Posts: 19506

View user's profile Send private message

PostPosted: Sun May 15, 2016 12:41 am     Reply with quote

Good.

I took the time to give a pretty 'full' description on this, because it is a very good place to start, and a lot of people can now use this as a description about this. Smile

You also asked clearly and well, which always helps us.

There are other reasons too. You will see 'ADC_CLOCK_INTERNAL', even used on some of the CCS examples. Duh. The data sheet really has to be your friend. Then trying to receive multiple bytes in INT_RDA, is another very common problem. We normally say 'look at ex_sisr.c' for the classic 'how to use the interrupt' example.

You had quite a lot of things 'right', so showed that you were trying (you will see we get a lot of posters who are not...).

So have fun moving ahead from here.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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