| 
	
	|  |  |  
	
		| 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
 
 |