|
|
View previous topic :: View next topic |
Author |
Message |
jallum
Joined: 05 Mar 2008 Posts: 9
|
Master and slave I2C implemented on one PIC |
Posted: Thu Mar 06, 2008 1:33 pm |
|
|
If you are trying to set up your PIC as master of an I2C bus using SW implementation, and slave of an altogether different bus (or even the same bus I suppose) using the HW SSP module, here is some code for you:
Code: |
#include <16F877A.h>
#device adc=10
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz)
#FUSES PUT //Power Up Timer
#FUSES PROTECT //Code protected from reads
#FUSES NODEBUG //No Debug mode for ICD
#FUSES BROWNOUT //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=20M)
//NOTE: Must declare MASTER before SLAVE, i2c_isr_state() returns 0
// when MASTER is the most recent #use i2c
#use i2c(MASTER, sda=PIN_C1, scl=PIN_C0, stream=I2CM)
#use i2c(SLAVE, sda=PIN_C4, scl=PIN_C3, address=0x60, force_hw, stream=I2CS)
#use rs232(baud=57600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, stream=COM1)
#use fast_io(D)
int rcv_buf[0x10];
int wrt_buf[0x10];
int cmd=0xFF;
#int_SSP // interrupt on i2c activity
void i2c_isr(void)
{
int state, incoming;
state = i2c_isr_state();
if(state < 0x80)
{
incoming = i2c_read(I2CS);
if (state == 1)
{
cmd = incoming;
}
else if (state > 1)
{
rcv_buf[state-2]=incoming;
}
}
else
{
i2c_write(I2CS,wrt_buf[state-0x80]);
}
}
void main()
{
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
printf("\n\rbegin");
while (TRUE)
{
if (cmd<0xFF)
printf("\n\rcmd: %x", cmd);
i2c_start(I2CM);
i2c_write(I2CM,0xa0); //i2c address of a slave device
i2c_write(I2CM,0x2e); //1st byte to slave
i2c_write(I2CM,0xa0); //2nd byte to slave
i2c_stop(I2CM);
}
}
|
It is VERY important to declare the SLAVE after the MASTER. It appears that i2c_isr_state() will return 0 if the MASTER declaration is the most recently encountered #use statement, although i2c_isr_state() should only read the state of the SLAVE SSP hardware. |
|
|
XyVy
Joined: 10 Sep 2008 Posts: 2
|
|
Posted: Wed Sep 10, 2008 3:16 am |
|
|
Hello Jallum, I need to do work i2c master and slave in the same PIC, but when I introduce the #use i2c(master...) the slave side does not work, but if I delete the #use i2c(master...) line, the slave side works okey again.
What is wrong?
My code is:
Code: |
#include <16F876A.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal osc <= 4mhz
#FUSES NOPUT //No 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=4000000)
#byte port_b=0x06
#use i2c(MASTER, FAST, sda=PIN_A0, scl=PIN_A1, address=0xB0, force_sw, stream=i2cM)
#use i2c(SLAVE, FAST, sda=PIN_C4, scl=PIN_C3, address = 0x08, force_hw, stream = i2cS)
// Comandos soportados por el PIC 16F876 en nuestro software
#define INIT 0x01
#define CONSULTA_MOTOR1 0x02
#define CONSULTA_MOTOR2 0x03
#define MUEVE_MOTOR1 0x04
#define MUEVE_MOTOR2 0x05
#define INTERRUPTOR1 0x06
#define INTERRUPTOR2 0x07
#define INTERRUPTOR3 0x08
#define INTERRUPTOR4 0x09
#define STOP_MOTOR1 0x0A
#define STOP_MOTOR2 0x0B
// definimos los datos para usar i2c
char data;
char cuenta;
BYTE state;
BYTE comando;
BYTE dato;
void inicializa()
{
output_high(PIN_B2);
i2c_start(i2cM);
i2c_write(i2cM, 0xB0); // Dirección del dispositivo
i2c_write(i2cM, 0x00); // Registro de Modo
i2c_write(i2cM, 0x01); // Motor1 detenido
i2c_stop(i2cM);
output_low(PIN_B2);
}
void MueveMotor1(char dato)
{
output_high(PIN_B2);
i2c_start(i2cM);
i2c_write(i2cM, 0xB0); // Dirección del dispositivo
i2c_write(i2cM, 0x01); // Registro de modo
i2c_write(i2cM, dato); // Registro Velocidad motor 1
i2c_stop(i2cM);
output_low(PIN_B2);
}
void MueveMotor2(char dato)
{
output_high(PIN_B2);
i2c_start(i2cM);
i2c_write(i2cM, 0xB0); // Dirección del dispositivo
i2c_write(i2cM, 0x02); // Velocidad de los motores
i2c_write(i2cM, dato); // Velocidad del motor2
i2c_stop(i2cM);
output_low(PIN_B2);
}
void StopMotor1()
{
output_high(PIN_B2);
i2c_start(i2cM);
i2c_write(i2cM, 0xB0); // Dirección del dispositivo
i2c_write(i2cM, 0x01); // Registro de Modo
i2c_write(i2cM, 128);
i2c_stop(i2cM);
output_low(PIN_B2);
}
void StopMotor2()
{
output_high(PIN_B2);
i2c_start(i2cM);
i2c_write(i2cM, 0xB0); // Dirección del dispositivo
i2c_write(i2cM, 0x02); // Velocidad de los motores
i2c_write(i2cM, 128); // velocidad del motor1
i2c_stop(i2cM);
output_low(PIN_B2);
}
#INT_SSP
void ssp_interupt ()
{
state = i2c_isr_state();
if(state<0x80) //master is sending data
{
if(state == 0)
{
} else if (state == 1) //first received byte
{
output_high(PIN_B2);
comando = i2c_read(i2cS);
} if (state==2) { // 2º byte recibido
dato=i2c_read(i2cS);
}
}else if (state == 0x80) { //master is requesting data
output_high(PIN_B1);
if (input(PIN_B4)) {
i2c_write(i2cS, 1);
} else {
i2c_write(i2cS, 0);
}
i2c_write(i2cS, cuenta); //send requested data
cuenta++;
}
}
void main()
{
char data;
int pulsado=0;
char sw=0;
int activo;
cuenta=0;
port_b=0;
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
sw=0;
pulsado=0;
while (1) {
activo=input(PIN_B4);
if (activo && (sw==0) && (!pulsado)) {
output_low(PIN_B2);
MueveMotor1(255);
StopMotor2();
pulsado=1;
sw=1;
} else if (activo && (sw==1) && (!pulsado)) {
output_high(PIN_B2);
MueveMotor2(255);
StopMotor1();
pulsado=1;
sw=0;
}
delay_ms(50);
if (!input(PIN_B4)) {
output_low(PIN_B2);
pulsado=0;
}
delay_ms(50);
}
}
|
Thanks in advance! |
|
|
XyVy
Joined: 10 Sep 2008 Posts: 2
|
|
Posted: Thu Sep 11, 2008 2:40 am |
|
|
Good news guys!
I have solved my problem.
I put the uses like:
#use i2c(MASTER, sda=PIN_A0, scl=PIN_A1, address=0xB0, stream=i2cM)
#use i2c(SLAVE, sda=PIN_C4, scl=PIN_C3, address = 0x08, force_hw, stream = i2cS)
But, I believe the problem was in the following function:
Code: |
#INT_SSP
void ssp_interupt ()
{
state = i2c_isr_state(i2cS);
if(state<0x80) //master is sending data
{
if(state == 0)
{
} else if (state == 1) //first received byte
{
output_high(PIN_B2);
comando = i2c_read(i2cS);
} if (state==2) { // 2º byte recibido
dato=i2c_read(i2cS);
}
}else if (state == 0x80) { //master is requesting data
output_high(PIN_B1);
if (input(PIN_B4)) {
i2c_write(i2cS, 1);
} else {
i2c_write(i2cS, 0);
}
i2c_write(i2cS, cuenta); //send requested data
cuenta++;
}
}
|
I forgot put the "i2cS" stream in the i2c_isr_state.
The PIC works okey!!
Thanks! |
|
|
|
|
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
|