|
|
View previous topic :: View next topic |
Author |
Message |
sv_shady
Joined: 07 Mar 2008 Posts: 28
|
Help for 2 PICs and I2C |
Posted: Fri Mar 07, 2008 3:56 pm |
|
|
Hi This is the first time I am writing in this forum and hope I'll receive the needed info. Here is the problem I am constructing a robot and right now I am working on the radio control, I am using XBeePro modules. One PIC (16F877A) reads a modified computer joystick throug the ADC, then sends the values over RS232 to the XBeePro module. The other module should receive the values, send them via RS232 to another PIC16F877a. The second pic should read the incoming data over RS232 and send it via i2c to a third PIC 16F877a which should print the data to a 2x20 display. Everything is working exept the I2C and the problem is very strange... If I send a number between 1 and 99 it appears on the display every time it is sent, but if I send a number between 100 and 255 it is printed just once and then every time it should appear on the LCD, the slave address is printed....
Here is the source for the master:
Code: | #include <16F877A.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz)
#FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#use delay(clock=10000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#use i2c(Master,FAST,sda=PIN_C4,scl=PIN_C3,force_hw)
void INIT(void)
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
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);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
}
int x = 0;
#int_RDA
void RDA_isr(void)
{
int c;
disable_interrupts(GLOBAL);
output_bit(PIN_B5, 1);
c = getc();
i2c_start();
i2c_write(0x10);
i2c_write(x);
i2c_stop();
output_bit(PIN_B5, 0);
x++;
enable_interrupts(GLOBAL);
}
void main()
{
INIT();
for(;;);
}
|
For every byte received via RS232 on the display the slave address (16) and the data (x) are printed. While x < 100 everything works fine, but when x >= 100 on the display appears the slave address 16 and instead of the value of x, 16 appears again...
And this is the source for the slave
Code: |
#include <16F877A.h>
#device adc=8
#include <string.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz)
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#use delay(clock = 10000000)
#use i2c(Slave, sda = PIN_C4, scl = PIN_C3, force_hw, address = 0x10)
#define I2C_SCL PIN_C3
#define I2C_SDA PIN_C4
#define BL PIN_B3
#define RS PIN_B2
#define RW PIN_B1
#define E PIN_B0
/*---------------------======PIN DEFINITION======-------------------------------
PIN_B3 - BackLight(BL)
PIN_B2 - Register Select (RS)
PIN_B1 - Read/Write (RW)
PIN_B0 - Enable (E)
PIN_D0 - Data Bit 0 (DB0)
PIN_D1 - Data Bit 1 (DB1)
PIN_D2 - Data Bit 2 (DB2)
PIN_D3 - Data Bit 3 (DB3)
PIN_D4 - Data Bit 4 (DB4)
PIN_D5 - Data Bit 5 (DB5)
PIN_D6 - Data Bit 6 (DB6)
PIN_D7 - Data Bit 7 (DB7)
==============================================================================*/
void Clear_Display(void);
//Clears display and AC (address counter) = 0
void Home(void);
//Sets cursor at home
void Mode_Set(int1 ID, int1 SH);
//I/D 0 - decrease SH 0 - display shift off at Read/Write
// 1 - increase 1 - display shift on at Read/Write
void Disp_Curs_On_Off(int1 D, int1 C, int1 B);
//D 0 - display off C 0 - cursor off B 0 - cursor blinking off
//D 1 - display on 1 - cursor on 1 - cursor blinking on
void Disp_Curs_Shift(int1 S_CD, int1 RL);
//S_CD 0 - cursor shift RL 0 - left
// 1 - display shift 1 - right
void Function_Set(int1 DL, int1 N, int1 F);
//DL 0 - 4bits interface N 0 - 1 row F 0 - 5x8 font
// 1 - 8bits interface N 1 - 2 rows 1 - 5x10 font
void CGRAM_Adrs(int Adrs);
//Send CGRAM Adrs, Adrs - 6bits
void DDRAM_Adrs(int Adrs);
//Send DDRAM Adrs, Adrs - 7bits
void Write_Data(int data);
//Send data(char), data - 8bits
int Read_Data(int data);
//Read data
int1 Read_BF_AC(int* AC);
//Read Busy Flag (BF) and Address Counter (AC)
void Init_LCD(void);
//initialize LCD
void Set_Zeros(void);
//Set zeros after instruction
void Write_str(char* data, int n);
//write string on the LCD
void Write_number(signed int32 d);
//write number on the LCD
void INIT(void)
{
set_tris_b(0x00);
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
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);
Init_LCD();
}
void main()
{
INIT();
for(;;)
{
if(i2c_poll())
write_number(i2c_read());
}
} |
I have deleted the functions for the LCD because they are a little bit long and work just excellent so the problem is not with them. The version of the compiler is 4.057
I am out of ideas... I have 10k pull-ups, it should be working in theory, but it doesn't. Do you have ideas where the problem might be ? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Mar 07, 2008 4:13 pm |
|
|
I didn't look at all your code in detail, but you need to fix one part:
Get rid of the two lines that enable/disable Global interrupts in the
#int_rda routine. The PIC handles it. |
|
|
sv_shady
Joined: 07 Mar 2008 Posts: 28
|
|
Posted: Fri Mar 07, 2008 11:31 pm |
|
|
First I've tried without these two lines, then I wrote them because I wanted to be sure that this is not the problem. So with or without them the problem still exists... I thing the problem is with the slave |
|
|
Ttelmah Guest
|
|
Posted: Sat Mar 08, 2008 4:56 am |
|
|
As a comment though, 'enable_interrupts(GLOBAL)', inside an interrupt handler, is a _sure formula for really major problems_. Never _ever_ do this.
The problem is that enabling the interrupt inside the handler, can allow the interrupt handler to be interrupted. This is why he chip has a 'special' interrupt 'return' function (RETFIE), which causes the return t happen, and _then_ the interrupts to be enabled 'afterwards'. Ading this, didn't prove anything, except one way to crash the code....
Now, second comment, add 'ERRORS' to the RS232 declaration. This should be considered the 'default' setting, since without it, if anything goes wrong on the RS232 (overrun etc.), the hardware will become hung. :(
Now, when you perform an 'I2C_READ', on the slave device, two different things happen, according to the status of the I2C bus. If a byte has already been received, the function returns immediately, giving the value of the byte in the holding register. If no byte is waiting, the function will delay, and wait for a byte tbe received. By using I2C_POLL, you avoid this second behaviour. The fact that the system goes wrong >100, says that in fact the problem _is_ with the LCD code (there is no significance to '100', internally to the PIC, or the I2C bus, while there is to a printout routine). The problem is almost certainly, that the LCD code, _takes longer_ to print the value, and almost certainly the intermediate 'data' value, is being missed...
Look at making the slave code interrupt driven (look at ex_slave.c), so that bytes _will_ be handled, whatever is happening in the LCD code.
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
|