|
|
View previous topic :: View next topic |
Author |
Message |
bharatwalia
Joined: 04 May 2009 Posts: 35 Location: India
|
PIC16F876A TO PIC16F72 communication problem |
Posted: Thu Jul 01, 2010 2:12 am |
|
|
Hi,
I using CCS SPI Library to send data from PIC16f876A to PIC16f72.
My aim is to read voltage from pic16f76a adc and send the same over spi to pic16f72 so that it can then process the data (convert it into 7-segment).
The problem i am facing here is that when i am only using PIC16f876a reading the voltage from ADC converting the 10-bit data into 7-segment everything works fine.
But when i am sending this 10-bit data from PIC16f876A over SPI to PIC16f72 and then converting the same 10-bit adc data into 7-segment, i am not getting the same result.
here is Master's Code(PIC16F876A)
Code: |
//master.c
#include <16f876A.h>
#device adc=10
#include <timers.h>
#USE DELAY( CLOCK=4000000 ) /* Using a 4 Mhz clock */
#FUSES XT,NOWDT,NOPROTECT,NOPUT
int32 result=0;
void transmitData(void);
void getVoltage(void);
//-------------------------------------------------------------------
// The rtcc interrupt occurs when the rtcc rolls over from FF to 00.
// I have programmed it to interrupt at a 100 Hz rate.
//
// RTCC interrupt rate = Fosc / (4 * rtcc pre-scaler * rtcc pre-load)
//
// = 4 MHz / (4 * 256 * 39)
//
// = 100.16 Hz
//
// This gives us a timer tick approx. every 10 ms (9.98 ms actually).
//-------------------------------------------------------------------
#int_rtcc
void rtcc_isr(void)
{
// Reload the RTCC, so it will keep overflowing every 10 ms.
set_rtcc(RTCC_PRELOAD);
// Decrement any timers that are running.
if(gc_transmit_timer)
gc_transmit_timer--;
}
//--------------------------------------------------------
void main()
{
setup_counters(RTCC_INTERNAL,RTCC_DIV_256);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 );
setup_adc_ports(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_DIV_64);
set_tris_a(0xDB);
gc_transmit_timer = TRANSMIT_TIMER_TICKS;
while(1)
{
getVoltage();
transmitData();
}
}
//--------------------------------------------------------
void getVoltage(void)
{
result=0;
set_adc_channel(0);
delay_ms(1);
result=read_adc();
}
//---------------------------------------------------------
void transmitData(void)
{
if(gc_transmit_timer) //refresh rate.
return;
else
gc_transmit_timer = TRANSMIT_TIMER_TICKS;
spi_write(result);
}
|
Here is slave code(PIC16f72)
Code: |
//slave.c
#include <16f72.h>
#device *=8
#fuses HS,NOWDT,PUT,BROWNOUT,NOPROTECT
#use delay(clock=4000000)
void display(void);
void HTO7S(unsigned int32 Num);
#define TICKS_BETWEEN_INTERRUPTS 5000 //5000 4/4=1 =1ms
#define INTERRUPT_OVERHEAD 35 //cycles wasted
#define TMR1RESET (0xFFFF-(TICKS_BETWEEN_INTERRUPTS-INTERRUPT_OVERHEAD))
#byte port_b=6 /* define the location of register port_b */
#byte port_c=7 /* define the location of register port_c */
byte CONST LED_MAP[11] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10,0xFF};
// 0 1 2 3 4 5 6 7 8 9 OFF
byte cnt=0,value,i;
byte Column[4] = {0x80,0x40,0x02,0x10}; //Low bits(right,center,left)
byte Segment[4] = {0x12,0xE3,0xAB,0xAF};
int32 res,data;
//--------------------------------------------------------
#INT_TIMER1
void Timer1(void)
{
set_timer1(TMR1RESET);
display();
}
void main()
{
set_tris_b(0); //1 set port_b as outputs
set_tris_c(0);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); //no division
set_timer1(TMR1RESET); //65535-4965=60570
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
setup_spi(SPI_SLAVE | SPI_H_TO_L | spi_ss_disabled );
while(1)
{
while(!spi_data_is_in()) ;
data=spi_read();
HTO7S(data);
}
}
//-------------------------------------------------------
void display()
{
if(cnt>=4){
cnt=0;}
port_b=Segment[cnt];
//port_b=data;
port_c=Column[cnt];
//port_c=0xFF;
cnt++;
}
//--------------------------------------
// Convet HEX 2 byte to 7-Segment code
//--------------------------------------
void HTO7S(unsigned int32 Num)
{
unsigned int32 res; //500ms interrupt to control display
Segment[0]=LED_MAP[30*Num/10230]; //calculating look-up value from LED_MAP array.
if (Segment[0]==0x40) //turning off 1st digit if 0
Segment[0]=0xFF; //dividing the three digits
res = 30*Num%10230;
Segment[1]=LED_MAP[10*res/10230];
res=10*res%10230;
Segment[2]=LED_MAP[10*res/10230];
res=10*res%10230;
Segment[3]=LED_MAP[10*res/10230];
}
|
I am sending data from master every 400ms.
Can any body help me.
Thanks. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Thu Jul 01, 2010 3:10 am |
|
|
The obvious thing is that you are only sending 8bits of the ADC value.
A single SPI transfer, sends a _byte_ as standard.
Easiest way, use 'make8', and send one byte, then the other.
At your receive end, receive one byte, then the second, and use make16, to put the data back together.
A couple of minor 'comments'. Move your 'timer.h' include to after the fuses and the clock statement. _If_ the code in an include file uses delays, serial I/O etc., then it must be included after the clock and RS232 defintions. It is obviously not causing you a problem in this code, but it is one 'waiting to bite' in the future. get into the habit of structuring the intialisation as :
Processor file
Any #device lines
Fuses
clock statement
RS232, I2C etc., setup lines
Include other stuff
main code.
Long term, if the data gets more complex, you might want to consider implementing a SS line. Problem is, what happens if the slave and master startup slightly 'out of sync', and the slave then starts thinking the first byte it is receiving, is the 'high' byte, when the master has already sent this, and is actually sending the 'low' byte. The code will never re-synchronise....
Two ways of handling this:
1) A 'software' re-sync. Send a pair of FF bytes one after the other, followed by a zero byte. Since the high byte can never be above '3' for real data, you can then use this to work out the synchronisation.
2) Add a SS line.
The latter makes handling SPI multi byte transfers much easier....
Best Wishes |
|
|
|
|
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
|