|
|
View previous topic :: View next topic |
Author |
Message |
vasanth
Joined: 16 Apr 2012 Posts: 3 Location: India
|
I2C - PIC16F887 |
Posted: Mon Apr 16, 2012 10:23 pm |
|
|
HI
I am using PIC 16F887 and CCS-C compiler (version 4.093) plugin in MPLAB IDE. I used i2c code posted by PCM programmer to simulate i2c operation in proteus. The code works for pic16f877 but it is not working for pic16f887. What should I change to make it work in 16f887 ? The code is as follows, I've made few changes in it. My objective is to communicate between two PIC16f887 controllers, where the slave controller collects sensor data and sends it to master controller which displays it on LCD and PC using RS232 connection.
The simulation results with 16f877 using Proteus is as follows(temperature measurement):
30 c (correct value)
-1 (wrong value)
-1
-1
and so on -1 continues.
Please help me on this...
MASTER:
Code: |
#include <16F887.H>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
#define SLAVE1_WRT_ADDR 0x12
#define SLAVE1_READ_ADDR 0x13
//====================================
void main()
{
int8 data;
while(1)
{
i2c_start();
i2c_write(SLAVE1_READ_ADDR);
data = i2c_read(0);
i2c_stop();
printf("temp %d \n\r", data);
delay_ms(1000);
}
}
|
SLAVE:
Code: |
#include <16F887.h>
#device adc=10
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x12)
int8 adc_result;
#INT_SSP
void ssp_interrupt()
{
int8 incoming, state;
state = i2c_isr_state();
if(state < 0x80) // Master is sending data
{
incoming = i2c_read();
}
if(state >= 0x80) // Master is requesting data from slave
{
i2c_write(adc_result);
}
}
//======================================
void main ()
{
setup_adc_ports( ALL_ANALOG );
setup_adc(ADC_CLOCK_DIV_4);
set_adc_channel(0);
delay_us(20);
adc_result = read_adc();
adc_result = adc_result*0.48828125;
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
while(1)
{
adc_result = read_adc();
adc_result = adc_result*0.48828125;
delay_ms(500);
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Tue Apr 17, 2012 1:38 am |
|
|
1) Forget Proteus....
It can sometimes emulate some chips, but unfortunately does not reflect problems with real hardware, and will often just not work, for no reason, or work with setups that will fail miserably in real life....
2) Change your oscillator. For 4MHz, you should be using 'XT', not 'HS'. Proteus will not complain about this, but it is likely to cause problems with some crystals.
3) Problem with the slave code. Study carefully what _must_ happen on state 0x80. On this, you _must_ read the incoming address byte before loading the reply. You are not doing this, and this could hang the I2C peripheral.
Code: |
#INT_SSP
void ssp_interrupt(void) {
int8 incoming, state;
state = i2c_isr_state();
if(state <= 0x80) { //Note the '=' here
incoming = i2c_read();
}
if(state >= 0x80) {
i2c_write(adc_result);
}
}
|
The 0x80 state, is 'unique', in that here a byte must both be read, and a new one written....
4) You have got pull-up resistors on the two bus wires?. '-1' reflects receiving the byte 0xFF, and the commonest reason for receiving this is that the bus is not properly pulled up. Look at something between 2.2KR, and 4.7KR, depending on the length of the bus.
Best Wishes |
|
|
alique89
Joined: 21 Apr 2012 Posts: 7
|
|
Posted: Sat Apr 21, 2012 5:32 pm |
|
|
try changing the place holder and see the result in hex. it might be play with the value. check if the value is not rolling over when you multiply. |
|
|
[email protected]
Joined: 07 Feb 2012 Posts: 19 Location: pakistan
|
|
Posted: Mon Apr 23, 2012 6:06 am |
|
|
I'm posting master and slave code of I2c, it really work on real-time hardware.
There is little bit error in slave code, you can replace slave code with EX_slave.c example
Code: |
#include <18F458.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
//#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xC0)
BYTE datar;
BYTE dataw=0x60;
#INT_SSP
void ssp_interupt ()
{
BYTE state;
//printf("*/n");
state = i2c_isr_state(); //0 - Address match received with R/W bit clear
//1-0x7F - Master has written data; i2c_read() will immediately return the data
//0x80 - Address match received with R/W bit set; respond with i2c_write()
//0x81-0xFF - Transmission completed and acknowledged; respond with i2c_write()
if(state == 0x00)
{
datar=i2c_read();
//printf("Adress match:%x\n",datar);
output_a(datar);
}
else if(state > 0 && state < 0x80)
{
datar= i2c_read();
//printf("Bytes:%x\n",datar);
//datar=0x00;
output_a(datar);
}
else if(state == 0x80)
{
i2c_write(dataw);
//printf("Data write on Master:%x\n",dataw);
}
else if(state > 0x80 && state < 0x100)
{
//printf("Data has been acknowledged\n");
}
}
void main ()
{
//port_b_pullups(TRUE);
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (TRUE) {}
}
|
Master
Code: |
#include <18F452.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use i2c(MASTER, SDA=PIN_C4, SCL=PIN_C3,address=0x60)
void main ()
{
while(1)
{
i2c_start();
//while(i2c_write(0xC0));// Device address
i2c_write(0xc0);
output_a(0x1);
delay_ms(1000);
//while(i2c_write(0x1F));
i2c_write(0x2);
output_a(0x2);
delay_ms(1000);
//while(i2c_write(0x7C));
i2c_write(0x3);
output_a(0x3);
delay_ms(1000);
// while(i2c_write(0x30));
i2c_write(0x4);
output_a(0x4);
delay_ms(1000);
//while(i2c_write(0x00));
i2c_write(0x5);
output_a(0x5);
delay_ms(1000);
//while(i2c_write(0x00));
i2c_stop();
}
}
|
Try it again on hardware, you will success. |
|
|
vasanth
Joined: 16 Apr 2012 Posts: 3 Location: India
|
I2C - PIC16F887 |
Posted: Mon Apr 23, 2012 7:07 pm |
|
|
THANH YOU ! ITS WORKING NOW |
|
|
vasanth
Joined: 16 Apr 2012 Posts: 3 Location: India
|
I2C - PIC16F887 |
Posted: Wed May 23, 2012 12:26 am |
|
|
Hi,
I am using PIC 16F887 and CCS-C compiler(version 4.093) plugin in MPLAB IDE.
I have dumped the code in hardware and I2C is working.
Now, I do not know at what speed the I2C communication is taking place ?
Can you help?
master
Code: | #include <16f887.h>
#device ADC=10
#use delay(clock=16000000)
#fuses HS, NOWDT, NOPROTECT, NOLVP
#use RS232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
#include <flex_lcd.c>
#define P1B PIN_D5
#define SLAVE1_WRT_ADDR 0x12
#define SLAVE1_READ_ADDR 0x13
int16 temp_adc1;
float temp1;
int16 temp_adc2;
float temp2;
int16 volt_adc1;
float volt1;
int16 volt_adc2;
float volt2;
int16 crnt_adc1;
float crnt1;
int16 crnt_adc2;
float crnt2;
int pwmv_adc1;
int8 data;
void set_deadband(int8 deadband)
{
#byte PWM1CON = 0x9B
if(deadband > 127)
deadband == 127;
PWM1CON = deadband;
}
void main()
{
lcd_init();
setup_adc(ADC_CLOCK_DIV_32);
setup_timer_2(T2_DIV_BY_16, 255, 1);
setup_ccp1(CCP_PWM_HALF_BRIDGE | CCP_PWM_H_H );
output_low(P1B);
set_deadband(127);
while(1)
{
printf ( lcd_putc, "Battery Status\n" );
delay_ms(5); //print to lcd --- clear LCD --- lcd_putc("\f");
printf ("Battery Status\n\r" ); //print to serial com
delay_ms(5);
//PWM
set_adc_channel(4); //read analog input from channel 0
delay_ms(10);
pwmv_adc1 = read_adc();
set_pwm1_duty(pwmv_adc1);
//I2c
i2c_start();
i2c_write(SLAVE1_READ_ADDR);
data = i2c_read(0);
i2c_stop();
lcd_gotoxy(1,2);
printf ( lcd_putc,"%5.1f", (float)data);
lcd_putc(" i2c_temp");
delay_ms(500);
printf("i2c_temp %d \n\r", data);
delay_ms(500);
//temperature measurement
set_adc_channel(0); //read analog input from channel 0
delay_ms(10);
temp_adc1 = read_adc();
temp1 = 5.00*temp_adc1*100.00/1023.00; // = temp_adc*0.48828125
lcd_gotoxy(1,2);
printf ( lcd_putc,"%5.1f", (float)temp1); // printf(lcd_putc, "value = %lu \n",value)
lcd_putc(223); //this number 223 will display the degree sign
lcd_putc('C');
lcd_putc(" b1_temp");
delay_ms(500);
printf ("\n");
printf ("%5.1f", (float)temp1);
putc(223);
putc('C');
puts(" b1_temp");
printf ("\n\r");
delay_ms(5);
set_adc_channel(1); //read analog input from channel 1
delay_ms(10);
temp_adc2 = read_adc();
temp2 = temp_adc2*0.48828125;
lcd_gotoxy(1,2);
printf ( lcd_putc,"%5.1f", (float)temp2);
lcd_putc(223); //this number 223 will display the degree sign
lcd_putc('C');
lcd_putc(" b2_temp");
delay_ms(500);
printf ("%5.1f", (float)temp2);
putc(223);
putc('C');
puts(" b2_temp");
printf ("\n\r");
delay_ms(5);
//voltage measrement
set_adc_channel(2); //read analog input from channel 2
delay_ms(10);
volt_adc1 = read_adc();
volt1 = (volt_adc1*0.0048875855)+9;//(volt*5)/1023
lcd_gotoxy(1,2);
printf ( lcd_putc,"%5.1f", (float)volt1);
lcd_putc('V');
lcd_putc(" b1_volt");
delay_ms(500);
printf ("%5.1f", (float)volt1);
putc('V');
puts(" b1_volt");
printf ("\n\r");
delay_ms(5);
if(volt1<=10.5)
output_high(PIN_B2);
else
output_low(PIN_B2);
set_adc_channel(5); //read analog input from channel 5
delay_ms(10);
volt_adc2 = read_adc();
volt2 = (volt_adc2*0.0048875855)+9;//(volt*5)/1023
lcd_gotoxy(1,2);
printf ( lcd_putc,"%5.1f", (float)volt2);
lcd_putc('V');
lcd_putc(" b2_volt");
delay_ms(500);
printf ("%5.1f", (float)volt2);
putc('V');
puts(" b2_volt");
printf ("\n\r");
delay_ms(5);
if(volt2<=10.5)
output_high(PIN_B3);
else
output_low(PIN_B3);
// current measurement
set_adc_channel(3); //read analog input from channel 3
delay_ms(10);
crnt_adc1 = read_adc();
crnt1 = crnt_adc1*0.0048875855;//(volt*5)/1023
lcd_gotoxy(1,2);
printf ( lcd_putc,"%5.1f", (float)crnt1);
lcd_putc('A');
lcd_putc(" b1_crnt");
delay_ms(500);
printf ("%5.1f", (float)crnt1);
putc('A');
puts(" b1_crnt");
printf ("\n\r");
delay_ms(5);
set_adc_channel(6); //read analog input from channel 6
delay_ms(10);
crnt_adc2 = read_adc();
crnt2 = crnt_adc2*0.0048875855;//(volt*5)/1023
lcd_gotoxy(1,2);
printf ( lcd_putc,"%5.1f", (float)crnt2);
lcd_putc('A');
lcd_putc(" b2_crnt");
delay_ms(500);
printf ("%5.1f", (float)crnt2);
putc('A');
puts(" b2_crnt");
printf ("\n\r");
delay_ms(5);
}
} |
slave
Code: | #include <16F887.h>
#device adc=10
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(internal=8M)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0x12)
int8 adc_result;
#INT_SSP
void ssp_interrupt()
{
int8 incoming, state;
state = i2c_isr_state();
if(state < 0x80) // Master is sending data
{
incoming = i2c_read();
}
if(state >= 0x80) // Master is requesting data from slave
{
i2c_write(adc_result);
}
}
//======================================
void main ()
{
setup_adc_ports( ALL_ANALOG );
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(0);
delay_us(20);
adc_result = read_adc();
adc_result = adc_result*0.48828125;
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
while(1)
{
adc_result = read_adc();
adc_result = adc_result*0.48828125;
delay_ms(500);
}
} |
|
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed May 23, 2012 2:23 am |
|
|
Quote: | Now, I do not know at what speed the I2C communication is taking place ? |
Check with a 'scope? (Will give you both bit-rate, and repeat-rate.)
What happens if the I2C interrupt occurs either, between these two lines, or during the float calculation?
Quote: | adc_result = read_adc();
adc_result = adc_result*0.48828125;
|
Yes, I know the probability is low in this case. (Murphy's law says that it definitely will, at THE most un-opportune moment.)
Mike |
|
|
|
|
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
|