Estoy intentando usar el Configurador de Código de Microchip para establecer una comunicación I2C entre dos PIC16F1827. Mi aplicación es muy similar al ejemplo que dan con una EEPROM emulada. He usado Proteus para simular el código, pero el resultado no fue satisfactorio. Así que tengo una pregunta y un problema:
-
En el código maestro, la dirección EEPROM tiene dos bytes, pero en el código esclavo parece ser solo un byte. No entiendo por qué. He cambiado el código maestro y parece que está bien ahora, pero ¿puede alguien explicarme por qué el código maestro y el código esclavo no son compatibles?
-
Mi problema real es sobre las interrupciones I2C durante la lectura. En realidad, cuando intento hacer una lectura de un byte (supongo que la dirección EEPROM ya está configurada en el valor correcto), se producen dos interrupciones. El primero después del Ack, luego se establece el bit R_nW, los bits D_nA y ACKSTAT están claros. Luego, después de NAck (cuando el maestro recibió suficientes bytes, en este caso solo uno), se produce una segunda interrupción. Pero el bit R_nW es borrado por hardware. Por lo tanto, no puedo usar el caso "I2C1_SLAVE_READ_COMPLETED". Peor aún, se ejecuta el caso "I2C1_SLAVE_WRITE_COMPLETED". No entiendo por qué ocurre esto. Por supuesto, puedo cambiar el I2C1_ISR para evitar este problema, pero no creo que sea el mejor para resolver el problema.
Estaría muy agradecido si alguien me puede ayudar. :)
EDITAR: Siguiendo la sugerencia de Olin Lathrop, he escrito el código sin usar el MCC. Todavía tengo el mismo problema.
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <xc.h>
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin
#pragma config WDTE = ON // Watchdog Timer Enable->WDT disabled
#pragma config PWRTE = OFF // Power-up Timer Enable->PWRT disabled
#pragma config MCLRE = OFF // MCLR Pin Function Select->MCLR/VPP pin function is digital input
#pragma config CP = OFF // Flash Program Memory Code Protection->Program memory code protection is disabled
#pragma config CPD = OFF // Data Memory Code Protection->Data memory code protection is disabled
#pragma config BOREN = OFF // Brown-out Reset Enable->Brown-out Reset disabled
#pragma config CLKOUTEN = OFF // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
#pragma config IESO = OFF // Internal/External Switchover->Internal/External Switchover mode is disabled
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is disabled
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection->Write protection off
#pragma config PLLEN = OFF // PLL Enable->4x PLL disabled
#pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will not cause a Reset
#pragma config BORV = LO // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected.
#pragma config LVP = OFF // Low-Voltage Programming Enable->High-voltage on MCLR/VPP must be used for programming
#define RX_ELMNTS 32
unsigned uint8_t I2C_slave_address = 0x03; // slave address
volatile unsigned char I2C_Array[RX_ELMNTS] = // array for master to write to
{0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88,
0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xFA,
0xEA, 0xDA, 0xCA, 0xBA, 0xFB, 0xFC, 0xFD, 0xFE,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
unsigned int index_i2c = 0; // used as an index pointer in array
unsigned char junk = 0; // used to place unnecessary data
unsigned char first = 1; // used to determine whether data address
// location or actual data
unsigned char clear = 0x00; // used to clear array location once
// it has been read
void initialize(void); // Initialize routine
void main(void) {
initialize(); // call initialize routine
while (1) // main while() loop
{
asm("CLRWDT"); // while here just clear WDT and wait for
} // the ISR to be called
} // end main
void initialize(void) {
//uC SET UP
OSCCON = 0b01111010; // Internal OSC @ 16MHz
OPTION_REG = 0b11010111; // WPU disabled, INT on rising edge, FOSC/4
// Prescaler assigned to TMR0, rate @ 1:256
WDTCON = 0b00010111; // prescaler 1:65536
// period is 2 sec(RESET value)
PORTB = 0x00; // Clear PORTC
LATB = 0x00; // Clear PORTC latches
TRISB = 0b00010010; // Set RC3, RC4 as inputs for I2C
//I2C SLAVE MODULE SET UP
SSP1STAT = 0b10000000; // Slew rate control disabled for standard
// speed mode (100 kHz and 1 MHz)
SSP1CON1 = 0b00110110; // Enable serial port, I2C slave mode,
// 7-bit address
SSP1CON2bits.SEN = 1; // Clock stretching is enabled
//SSP1CON3bits.BOEN = 1; // SSPBUF is updated and NACK is generated
// for a received address/data byte,
// ignoring the state of the SSPOV bit
// only if the BF bit = 0
//SSP1CON3bits.SDAHT = 1; // Minimum of 300 ns hold time on SDA after
// the falling edge of SCL
//SSP1CON3bits.SBCDE = 1; // Enable slave bus collision detect interrupts
SSP1ADD = I2C_slave_address << 1; // Load the slave address
SSP1IF = 0; // Clear the serial port interrupt flag
BCL1IF = 0; // Clear the bus collision interrupt flag
BCL1IE = 1; // Enable bus collision interrupts
SSP1IE = 1; // Enable serial port interrupts
PEIE = 1; // Enable peripheral interrupts
GIE = 1; // Enable global interrupts
}//end initialize
void interrupt ISR() {
if (SSP1IF) {
if (SSP1STATbits.R_nW) {
if (!SSP1STATbits.D_nA) {
// read and adress
SSP1BUF = I2C_Array[index_i2c++];
SSP1CON1bits.CKP = 1;
}
if (SSP1STATbits.D_nA) {
//read and data
SSP1BUF = I2C_Array[index_i2c++];
SSP1CON1bits.CKP = 1;
}
}
if (!SSP1STATbits.R_nW) {
if (!SSP1STATbits.D_nA) {
//write and adress
first = 1;
junk = SSP1BUF;
SSP1CON1bits.CKP = 1;
}
if (SSP1STATbits.D_nA) {
//write and data
if (first) {
index_i2c = SSP1BUF;
first = 0;
} else {
if (index_i2c < RX_ELMNTS) {
I2C_Array[index_i2c++] = SSP1BUF;
} else {
junk = SSP1BUF;
}
}
if (SSP1CON1bits.WCOL) {
SSP1CON1bits.WCOL = 0;
junk = SSP1BUF;
}
SSP1CON1bits.CKP = 1;
}
}
}
if (BCL1IF) {
junk = SSP1BUF;
BCL1IF = 0;
SSP1CON1bits.CKP = 1;
}
SSP1IF = 0;
}