|
|
View previous topic :: View next topic |
Author |
Message |
Ringo42
Joined: 07 May 2004 Posts: 263
|
Digital inputs |
Posted: Mon Jun 02, 2008 2:06 pm |
|
|
I have a program that reads 5 analog pins and 10 digital pins in a pic16f876a and reports back its status when queried via I2C. The analog values come back fine, but sometimes the digital values are correct, and sometimes it reports back 255's. After the 255 it does not report back at all which makes me think it is locking up. But every time it does it, it sends the analog correctly, so it looks like getting the digital values is causing the lockup.
For example, when I get a lockup I get 129 128 126 127 129 255 255 255....
Does anyone see anything silly in my code? I have tried this with 4.11 and 3.249 with the same results.
Thanks
Ringo
Code: | #include <16F876a.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use standard_io(B)
#byte PIC_SSPADD=0x93
#define initial_i2c_address 0x82
int NODE_ADDR = initial_i2c_address;// Decimal 130
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x82,slow)
#define Digital_in_0 PIN_B5
#define Digital_in_1 PIN_B4
#define Digital_in_2 PIN_B3
#define Digital_in_3 PIN_B2
#define Digital_in_4 PIN_B1
#define Digital_in_5 PIN_B0
#define Digital_in_6 PIN_C7
#define Digital_in_7 PIN_C6
#define Digital_in_8 PIN_C5
#define Digital_in_9 PIN_C2
int pin_table[] = {PIN_B5, PIN_B4, PIN_B3, PIN_B2, PIN_B1, PIN_B0, PIN_C7, PIN_C6, PIN_C5, PIN_C2};
int Dio_states[10];
int Dio_value[10];
int Analog_value[5];
int Power_up_state[10];
BYTE address, buffer[0x10];
int bytecounter=0;
int actionflag=0; //0 = nothing, 1 = read, 2 = change address
void Read_Digital_inputs();
#INT_SSP
void ssp_interupt()
{
int i;
BYTE incoming, state;
int pinnumber,pinstate,dummy;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{
incoming = i2c_read();
buffer[bytecounter]=incoming;
bytecounter++;
}
if(state == 0x80) //Master is requesting data
{
actionflag=1; //0 = nothing, 1 = read, 2 = change address
bytecounter=0;
}
}
void main ()
{
int i;
setup_adc_ports(All_ANALOG);
setup_adc( ADC_CLOCK_INTERNAL );
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
for(i=0;i<10;i++)
{
Dio_states[i]=2;//input
Dio_value[i]=0;
}
delay_ms(500);
output_high(PIN_B6);
while (1)
{
for(i=0;i<5;i++)
{
set_adc_channel(0);
delay_ms(1);
Analog_value[i]=Read_ADC();
}
if(actionflag==1) //0 = nothing, 1 = read, 2 = change address
{
Read_Digital_inputs();
for(i=0;i<5;i++)
{
i2c_write(Analog_value[i]);
delay_ms(1);
}
for(i=0;i<10;i++)
{
delay_ms(1);
i2c_write(Dio_value[i]);
}
}
}
}
void Read_Digital_inputs()
{
Dio_value[0]=input(PIN_B5);
Dio_value[1]=input(PIN_B4);
Dio_value[2]=input(PIN_B3);
Dio_value[3]=input(PIN_B2);
Dio_value[4]=input(PIN_B1);
Dio_value[5]=input(PIN_B0);
Dio_value[6]=input(PIN_C7);
Dio_value[7]=input(PIN_C6);
Dio_value[8]=input(PIN_C5);
Dio_value[9]=input(PIN_C2);
} |
_________________ Ringo Davis |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 02, 2008 2:29 pm |
|
|
I notice that you set ActionFlag to 1, but then you never clear it
when the process is finished. |
|
|
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Mon Jun 02, 2008 2:35 pm |
|
|
Damn, I had that in there, and accidentally deleted it when compacting the code. This is part of a more complicate program. So when I was taking out the other stuff I killed that line. I had the issue for I took out the line though. I'll put it back in and see if I can still replicate the problem.
Thanks for the quick response.
Ringo _________________ Ringo Davis |
|
|
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Wed Jun 04, 2008 12:35 pm |
|
|
OK, I have another weird thing going on. I'm using pins on port B and port C. If I set pin B3 as high and then B2 as an input everything is fine. But no matter how I set a pin on port C, if I set another pin on port C as an input then they all go to inputs.
I'm using #use standard_io(C) (even though that is the default), is there something else I need to do?
With the code at the end commented out, it works ok (except I can't read any of the pins). But just putting in any 1 pair of lines hoses up the entire port. So if I set a pin High, I see it blink high but then go immediately off
The code is below, see the comments at the very end.
Code: |
#include <16F876a.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
//#use rs232(baud=115200, xmit=PIN_b6, rcv=PIN_b7)
#use standard_io(B)
#use standard_io(C)
#byte PIC_SSPADD=0x93
#define initial_i2c_address 0x82
int NODE_ADDR = initial_i2c_address;// Decimal 130
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x82,slow)
#define Digital_in_0 PIN_B5
#define Digital_in_1 PIN_B4
#define Digital_in_2 PIN_B3
#define Digital_in_3 PIN_B2
#define Digital_in_4 PIN_B1
#define Digital_in_5 PIN_B0
#define Digital_in_6 PIN_C7
#define Digital_in_7 PIN_C6
#define Digital_in_8 PIN_C5
#define Digital_in_9 PIN_C2
int pin_table[] = {PIN_B5, PIN_B4, PIN_B3, PIN_B2, PIN_B1, PIN_B0, PIN_C7, PIN_C6, PIN_C5, PIN_C2};
int Dio_states[10];
int values[15];
int Power_up_state[10];
int Sensors=0;
BYTE address, buffer[0x10];
int bytecounter=0;
int actionflag=0; //0 = nothing, 1 = read, 2 = change address
void Read_Digital_inputs();
#INT_SSP
void ssp_interupt()
{
int i;
BYTE incoming, state;
int pinnumber,pinstate,dummy;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{
incoming = i2c_read();
buffer[bytecounter]=incoming;
bytecounter++;
if(bytecounter ==4 )
{
if(buffer[1]==1) // Set, GPIO
{
pinnumber=buffer[2];
pinstate=buffer[3];
bytecounter=0;
Dio_states[pinnumber]=pinstate;
if(pinstate==0)
{
output_low(pin_table[pinnumber]);
values[pinnumber+5]=0;
}
else if(pinstate==1)
{
output_high(pin_table[pinnumber]);
values[pinnumber+5]=1;
}
else if(pinstate==2)
{
Dio_states[pinnumber]=2;
// values[pinnumber+5]=input(pin_table[pinnumber]);
}
else {}
}
}//end of 4
}
if(state == 0x80) //Master is requesting data
{
// if(debug==1)
// printf("reading\r\n");
actionflag=1; //0 = nothing, 1 = read, 2 = change address
bytecounter=0;
}
}
void main ()
{
int flashcounter=0;
int i,dummy;
int data1;
int temp_node_address;
setup_adc_ports(All_ANALOG);
setup_adc( ADC_CLOCK_INTERNAL );
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
delay_ms(500);
output_high(PIN_B6);
while (1)
{
for(i=0;i<5;i++)
{
set_adc_channel(0);
delay_ms(1);
values[i]=Read_ADC();
}
Read_Digital_inputs();
if(actionflag==1) //0 = nothing, 1 = read, 2 = change address
{
actionflag=0;
for(i=0;i<15;i++)
{
delay_ms(1);
i2c_write(values[i]);
}
}
}
}
void Read_Digital_inputs()
{
if(Dio_states[0]==2)//input
values[5]=input(PIN_B5);
if(Dio_states[1]==2)//input
values[6]=input(PIN_B4);
if(Dio_states[2]==2)//input
values[7]=input(PIN_B3);
if(Dio_states[3]==2)//input
values[8]=input(PIN_B2);
if(Dio_states[4]==2)//input
values[9]=input(PIN_B1);
if(Dio_states[5]==2)//input
values[10]=input(PIN_B0);
if(Dio_states[6]==2)//input If I uncomment any of these that use port C
values[11]=input(PIN_C7); // then when I set a pin high, it immediately goes back to input
// if(Dio_states[7]==2)//input so if I only umcomment the 2 lines that deal with C7, it affects all the
// values[12]=input(PIN_C6); // port C pins.
// if(Dio_states[8]==2)//input
// values[13]=input(PIN_C5);
// if(Dio_states[9]==2)//input
// values[14]=input(PIN_C2);
} |
_________________ Ringo Davis |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 04, 2008 1:03 pm |
|
|
What compiler version did you test this with ? The version numbers
are in this format: x.xxx |
|
|
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Wed Jun 04, 2008 1:06 pm |
|
|
4.11 _________________ Ringo Davis |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 04, 2008 1:13 pm |
|
|
The version numbers are in this format: x.xxx
(That's why I put that comment in my post). |
|
|
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Wed Jun 04, 2008 1:26 pm |
|
|
Sorry, I missed a digit
CCS PCM C Compiler, Version 4.011, 34836 _________________ Ringo Davis |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 04, 2008 1:52 pm |
|
|
What I would do to fix this, or trouble-shoot it, is to strip out all the i2c
slave code, and run the program as a standalone test program.
Display the output in a terminal window with printf() statements, and
thus prove that the basic i/o is actually working, or not. Currently you
have two processes going -- Doing the i/o, and then transmitting it
through i2c. I would separate out those two processes, and prove that
each one works correctly, separately. Then combine them later. |
|
|
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Wed Jun 04, 2008 2:11 pm |
|
|
It works without the I2C stuff in there, so I started experimenting.
I'm assuming it is a compiler issue, because in the I2C routine,
this does not work:
Code: |
else if(pinstate==1)
{
output_high(pin_table[pinnumber]);
values[pinnumber+5]=1;
}
|
But this does:
Code: |
else if(pinstate==1)
{
values[pinnumber+5]=1;
switch(pinnumber)
{
case 0: output_high(PIN_B5);
break;
case 1: output_high(PIN_B4);
break;
case 2: output_high(PIN_B3);
break;
case 3: output_high(PIN_B2);
break;
case 4: output_high(PIN_B1);
break;
case 5: output_high(PIN_B0);
break;
case 6: output_high(PIN_C7);
break;
case 7: output_high(PIN_C6);
break;
case 8: output_high(PIN_C5);
break;
case 9: output_high(PIN_C2);
break;
}
} |
_________________ Ringo Davis |
|
|
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Fri Jun 06, 2008 1:52 pm |
|
|
I thought it was working, but I can read the board a few times, then it locks up. I took out the pin array so I'm using 3.249 now. I've striped the code down to bare essentials. It just returns an array of 15 over I2C. I put an led blinking routine in there so I can see when it locks up. sometimes it is on the first read, sometimes it makes it to 6 or 7, but not usually beyond that. any ideas here?
Code: |
#include <16F876a.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
//#use rs232(baud=115200, xmit=PIN_b6, rcv=PIN_b7)
#use standard_io(B)
#use standard_io(C)
#byte PIC_SSPADD=0x93
#define initial_i2c_address 0x82
int NODE_ADDR = initial_i2c_address;// Decimal 130
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x82,slow)
int Dio_states[10];
int values[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};
int Power_up_state[10];
BYTE address, buffer[0x10];
int bytecounter=0;
int actionflag=0; //0 = nothing, 1 = read, 2 = change address
#INT_SSP
void ssp_interupt()
{
int i;
BYTE incoming, state;
int pinnumber,pinstate,dummy;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{ }
if(state == 0x80) //Master is requesting data
{
actionflag=1; //0 = nothing, 1 = read, 2 = change address
bytecounter=0;
}
}
void main ()
{
int i;
int32 counter=0;
int toggle=0;
setup_adc_ports(All_ANALOG);
setup_adc( ADC_CLOCK_INTERNAL );
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
for(i=0;i<10;i++)
{
Dio_states[i]=2;//input
//values[i+5]=0;
}
delay_ms(500);
output_high(PIN_B6);
while (1)
{
counter++;
if(counter>10000)
{
counter=0;
if(toggle==0)
{
toggle=1;
output_high(Pin_B7) ;
}
else
{
toggle=0;
output_low(Pin_B7) ;
}
}
if(actionflag==1) //0 = nothing, 1 = read, 2 = change address
{
actionflag=0;
for(i=0;i<15;i++)
{
delay_ms(1);
i2c_write(values[i]);
}
}
}
}
|
_________________ Ringo Davis |
|
|
Ttelmah Guest
|
|
Posted: Sat Jun 07, 2008 4:18 am |
|
|
4.011, has problems, so you are 'right' to try with 3.249.
In your demo code, you _must_ perform the required I2C operations in your interrupt handler. So, you should read the contents of the buffer register, when you are expected to read a byte, and write the new byte for the write. The SSPOV flag will become set with the current code, since the register has not been read. So, something like:
Code: |
#INT_SSP
void ssp_interupt() {
int i;
BYTE incoming, state;
int pinnumber,pinstate,dummy;
state = i2c_isr_state();
if(state < 0x80) { //Master is sending data
incoming=I2C_READ();
}
if(state == 0x80) { //Master is requesting data
actionflag=1; //0 = nothing, 1 = read, 2 = change address
bytecounter=0;
I2C_WRITE(1); //Dummy write
}
}
|
The data sheets, do not say what the effect of the SSPOV flag being set actually 'is', but you should avoid error conditions when testing.
Best Wishes |
|
|
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Mon Jun 09, 2008 10:53 am |
|
|
I'm reading 15 bytes of data from the slave. I put the I2C_write code in the int, but I still get the same thing. A few good reads of the slave, then it all goes to 255's.
Here is the modifed code.
Code: | #include <16F876a.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
//#use rs232(baud=115200, xmit=PIN_b6, rcv=PIN_b7)
#use standard_io(B)
#use standard_io(C)
#byte PIC_SSPADD=0x93
#define initial_i2c_address 0x82
int NODE_ADDR = initial_i2c_address;// Decimal 130
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x82,slow)
int Dio_states[10];
int values[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};
int Power_up_state[10];
BYTE address, buffer[0x10];
int bytecounter=0;
int actionflag=0; //0 = nothing, 1 = read, 2 = change address
int data_counter=0;
#INT_SSP
void ssp_interupt()
{
int i;
BYTE incoming, state;
int pinnumber,pinstate,dummy;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{ }
if(state == 0x80) //Master is requesting data
{
for(i=0;i<15;i++)
{
delay_ms(1);
i2c_write(values[i]);
}
actionflag=1; //0 = nothing, 1 = read, 2 = change address
bytecounter=0;
}
}
void main ()
{
int i;
int32 counter=0;
int toggle=0;
setup_adc_ports(All_ANALOG);
setup_adc( ADC_CLOCK_INTERNAL );
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
for(i=0;i<10;i++)
{
Dio_states[i]=2;//input
//values[i+5]=0;
}
delay_ms(500);
output_high(PIN_B6);
while (1)
{
counter++;
if(counter>10000)
{
counter=0;
if(toggle==0)
{
toggle=1;
output_high(Pin_B7) ;
}
else
{
toggle=0;
output_low(Pin_B7) ;
}
}
if(actionflag==1) //0 = nothing, 1 = read, 2 = change address
{
actionflag=0;
// for(i=0;i<15;i++)
// {
// delay_ms(1);
// i2c_write(values[i]);
// }
}
}
}
|
Any other ideas?
Ringo _________________ Ringo Davis |
|
|
Ttelmah Guest
|
|
Posted: Mon Jun 09, 2008 2:48 pm |
|
|
You have put the I2C write code in, but _not_ the read code. This is the essential part, since when you send the address byte, followed by the command byte, there are two successive bytes, and the first must be read, if the overflow bit is not going to be set...
Best Wishes |
|
|
Ringo42
Joined: 07 May 2004 Posts: 263
|
|
Posted: Thu Jun 26, 2008 11:16 am |
|
|
Here is a new issue. I have the code working great for the 16F876A. I changed over to an 18F2221. I thought the code would work as is. It has the same # pins with the same functions, etc. The only difference is that with the 876 I'm using a 20mhz crystal, and with the 2221 I'm using the internal 8mhz.
I set it up like this;
Code: |
#if defined(__PCM__)
#include <16F876a.h>
#fuses HS,noWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#elif defined(__PCH__)
#include <18F2221.h>
#fuses INTRC_IO,NOWDT,NOPROTECT,NOLVP
#use delay(clock=8000000)
#byte SSPCON2 = 0xFC5
#bit SEN = SSPCON2.0
#endif |
Should this cause a problem?
Here is what I'm seeing. Reading works the same for either chip. However when I write. Using the 876 I get buffer[0] as the address, so buffer[1] is the command. However with the 2221 I get buffer[0] as the command.
It is a small difference, but I didn't think there should be any at all. is this really a chip difference, or am I missing the first byte because of the 8mhz?
I'm sending a command to set an I/O pin High. The address is 130, the command number is 1, so to set pin 1 high I send
130 1 1 1.
Here is the INT code.
Code: |
#INT_SSP
void ssp_interupt()
{
int i;
BYTE incoming, state;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{
incoming = i2c_read();
buffer[bytecounter]=incoming;
bytecounter++;
if(bytecounter ==3 )// this one works for the 2221
{
// printf("%d %d %d %d\r\n",buffer[0],buffer[1],buffer[2],buffer[3]);
if(buffer[0]==1) // Set, GPIO
{
pinnumber=buffer[1];
pinstate=buffer[2];
bytecounter=0;
Dio_states[pinnumber]=pinstate;
actionflag=3;
}
}
if(bytecounter ==4 )// this works for the 876A
{
if(buffer[1]==1) // Set, GPIO
{
pinnumber=buffer[2];
pinstate=buffer[3];
bytecounter=0;
Dio_states[pinnumber]=pinstate;
actionflag=3;
}
}//end of 4
}
if(state == 0x80) //Master is requesting data
{
for(i=0;i<15;i++)
{
delay_ms(1);
i2c_write(values[i]);
}
actionflag=1; //0 = nothing, 1 = read, 2 = change address
bytecounter=0;
}
} |
The 876A code is compiled with 3.249
the 2221 I have tried with 3.249 and 4.074
Ringo _________________ Ringo Davis |
|
|
|
|
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
|