TODOPIC
Microcontroladores PIC => Primeros pasos - Iniciación a los microcontroladores => Mensaje iniciado por: joro en 28 de Mayo de 2020, 15:06:23
-
Hola, para practicar en casa decidí aprender sobre la comunicación I2C. Me leí el datasheet del pic18f4550 y del atmega328 del arduino. Claro que existen librerías que me ayudarían pero en esta ocasión decidí trabajar sin las librerías y manipular los registros, habilitar las interurpciones, etc. para ver si realmente entendí del tema (ya luego para proyectos me apoyaría en librerías).
Entonces, en mi código pienso usar al arduino como maestro y el pic18f4550 como esclavo, además que solo pienso realizar transmisión de datos. Tengo en el arduino conectado un display 7 segmentos que me muestra en qué estado de la comunicación I2C se encuentra (ej: si me sale '2' es porque se realizó el START) y un boton que empezaría con la comunicación. En el lado del esclavo, tengo 3 pins conectados a leds, 1 indica cuando el pic está prendido (y si se apaga luego es porque ocurrió una interrupción del I2C), y los otros 2 varían según el dato recibido del arduino (para confirmar si el dato llegó).
El problema: por parte del arduino, solo llega hasta el START, en la siguiente interrupción luego del START, el TWSR (status register) se carga con puros 1, y dicho valor no existe entre todos los estados posibles por lo que se va al 'default' y muestra el #9 en el display. Por parte del pic18F4550, ni ocurre la interrupción (ya que se apagaría el led1) del I2C.
Por último, en el pic18f4550 lo programe en assembler, los pull up resistors son de 4.7k, scl está a 100Khz (o eso es lo que intento colocar) y el clock del pic18f4550 está a 16Mhz (usando PLL)
-
(primera vez en el foro, sigo probando cómo mostrar el código)
código arduino uno, maestro I2C:
void Preparar_I2C();
volatile byte dato_envio = 0x01;
byte aux = 0x00;
#define num_0 0x40
#define num_1 0x79
#define num_2 0x24
#define num_3 0x30
#define num_4 0x19
#define num_5 0x12
#define num_6 0x02
#define num_7 0x78
#define num_8 0x00
#define num_9 0x18
void setup() {
Preparar_I2C();
pinMode(8,INPUT);
DDRD = 0xFF; //configuro puertos 0-7
PORTD = num_0; //asigno valor a esos puertos
}
void loop() {
if (digitalRead(8)==HIGH && aux==0x00 ){
TWCR = 0xE5; //START I2C
aux = 0x10;
PORTD = num_1;
}
//PORTD = TWSR >> 3;
}
ISR(TWI_vect) {
byte Estado = TWSR & 0xFC; //enmascaro
//SOLO CASO TRANSMISION DE DATOS
switch (Estado){
case 0x08: //START
TWDR = 0x1E; //cargar ADDRESS + W/R (W=0)
TWCR &= 0xDF; //Limpio START bit
PORTD = num_2;
break;
case 0x10: //REPEATED START
TWDR = 0x1E;
TWCR &= 0xDF;
PORTD = num_3;
break;
case 0x18: //SLA+W llegó
TWDR = dato_envio; //DATO A ENVIAR
PORTD = num_4;
break;
case 0x20: //SLA+W no llegó
TWCR |= 0x10; //genero STOP
PORTD = num_5;
break;
case 0x28: //Dato llegó
TWCR |= 0x10;
PORTD = num_6;
break;
case 0x30: //Dato no llegó
TWCR |= 0x10;
PORTD = num_7;
break;
case 0x38: //Arbitraje perdido SLA+W o Dato
TWCR |= 0x10;
PORTD = num_8;
break;
default:
TWCR |= 0x10;
PORTD = num_9;
break;
}
TWCR |= 0x80; //Seteo Int Flag
}
void Preparar_I2C() {
SREG |= 0x80; //Me aseguro (Ya estaba predeterminadamente)
TWCR = 0x45; //habilito I2C, ACK e INT
//SCL = 100Khz (máximo 400Khz)
TWBR = 0x48; //72
TWSR = 0x00;
}
Código pic18f4550 assember, esclavo:
list p=18f4550 ;modelo de microcontrolador
#include<p18f4550.inc> ;Libreria de modelo de registros
CONFIG FOSC = XTPLL_XT ; Oscilator + PLL enabled
CONFIG PLLDIV = 1
CONFIG CPUDIV = OSC4_PLL6 ; OSC = 16Mhz
CONFIG PWRT = ON ; Power-up Timer Enable bit (PWRT enabled)
CONFIG BOR = OFF ; Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
CONFIG WDT = OFF ; Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
CONFIG PBADEN = OFF ; PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
CONFIG LVP = OFF ; Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
CONFIG CCP2MX = ON ; CCP2 MUX bit (CCP2 input/output is multiplexed with RC1)
CONFIG MCLRE = ON ; MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
dato_leido EQU 0x60
dato_escrito1 EQU 0x61
dato_escrito2 EQU 0x62
org 0x0000 ;Vector de RESET
goto configuro
org 0x008
goto Interrupt
org 0x0020
configuro:
movlw 0x03 ;SDA y SCL como INPUT
movwf TRISB ;pin2 -> indicador de pic corriendo
bcf TRISD,0 ;muestra el dato recibido por arduino
bcf TRISD,1
movlw 0x01
movwf dato_escrito1
movlw 0x02
movwf dato_escrito2 ;revelará si D/A indica el byte actual leido o el anterior
movlw 0xC0
movwf INTCON ;General Interrupt y Peripherical
movlw 0x08
movwf PIE1 ;habilitar I2C interrupt
bcf PIR1,3 ;limpio flag
movlw 0x80
movwf SSPCON2 ;habilitar general call y SEN = 0
movlw 0x1E
movwf SSPADD ;asigno ADDRESS como esclavo
movlw 0x36
movwf SSPCON1 ;habilitar I2C y modo esclavo (sin INT en S y P)
bsf LATB,2
clrf LATD
main:
movf dato_leido,0
movwf LATD
goto main
Interrupt:
bcf LATB,2 ;indica si hubo interrupción
btfsc SSPSTAT,2 ;Chekeo R/W (R=0)
goto Estado_T
goto Estado_R
Estado_T:
btfsc SSPSTAT,5
movf dato_escrito2,0 ;si D/A=1 -> cargar dato2
btfss SSPSTAT,5
movf dato_escrito1,0 ;si D/A=0 -> cargar dato1
movwf SSPBUF
bsf SSPCON1,4 ;CKP=1 -> continuar SCL
bcf PIR1,3 ;bajar flag
retfie
Estado_R:
movf SSPBUF,0
btfsc SSPSTAT,5 ;chekeo D/A (0: anterior byte fue direccion)
movwf dato_leido ;dato recibido y guardado en registro
clrf SSPBUF ;limpiar SSPBUF y bajar flag
bcf PIR1,3
retfie
end