//..............................................................................
// Inits GPIO ports
//..............................................................................
void ini_gpio(void)
{
TRISD=0; // init LEDS (RD0 - RD7 = outputs)
LATD=0; // LEDS are OFF
// enable I/O function of the next pins:
LCDSE2bits.SE16=0; // RC3 (SCL1)
LCDSE2bits.SE17=0; // RC4 (SDA1)
SDA_TRIS = 1; // SDA1 (RC4) = input
SCL_TRIS = 0; // SCL1 (RC3) = output ???
SCL=1; // SCL is high
}
En CCS, la primera vez que usé I2C. Ni siquiera declare cómo entradas o salidas a éstos pines
2.3 Serial Clock (SCL)
This input is used to synchronize the data transfer to and from the device
2.2 Serial Data (SDA)
This is a bidirectional pin used to transfer addresses and data into and out of the device
/*
* File: main.c
* Author: Raul
* PRUEBAS VARIAS RELACIONADAS CON PIC16F1947
* Created on 2018/05/21, 11:29
*/
// CONFIG1
#pragma config FOSC = HS // Oscillator Selection->HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins
#pragma config WDTE = OFF // Watchdog Timer Enable->WDT disabled
#pragma config PWRTE = OFF // Power-up Timer Enable->PWRT disabled
#pragma config MCLRE = ON // MCLR Pin Function Select->MCLR/VPP pin function is MCLR
#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 = ON // Brown-out Reset Enable->Brown-out Reset enabled
#pragma config CLKOUTEN = OFF // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
#pragma config IESO = ON // Internal/External Switchover->Internal/External Switchover mode is enabled
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is enabled
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection->Write protection off
#pragma config VCAPEN = OFF // Voltage Regulator Capacitor Enable->VCAP pin functionality is disabled
#pragma config PLLEN = OFF // PLL Enable->4x PLL disabled
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will 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
#include <xc.h>
#include <htc.h>
#include <stdio.h>
#define _XTAL_FREQ 16000000 // 16 Mhz
int block_adress = 0x00;
int word_adress = 0x00;
int eeprom_data = 0x09;
int incoming_data;
/*******************************CONFIGURACION I/O*******************************/
void Configuration_IO (void) //configuracion puertos entrada y salida solo una vez al incio
{
LATE = 0x00; LATD = 0x00; LATA = 0x00; LATF = 0x00;
LATB = 0x00; LATG = 0x00; LATC = 0x00;
TRISE = 0x00; TRISF = 0x00; TRISA = 0xFF; TRISG = 0x00;
TRISB = 0x0F; TRISC = 0x00; TRISD = 0x00;
ANSELE = 0x07; ANSELG = 0x1E; ANSELF = 0xFF; ANSELA = 0x2F;
WPUB = 0x00; WPUG = 0x00;
OPTION_REGbits.nWPUEN = 1; //resistencias internas desactivadas
APFCON = 0x00; //selecciona salidas especiales en ciertos puertos
}
/*******************************INICIAR I2C************************************/
void Configuration_I2C (void)
{
TRISCbits.TRISC4 = 1;
TRISCbits.TRISC3 = 1;
LATCbits.LATC3 = 1;
SSP1STAT = 0x80;
SSP1CON1 = 0x28;
SSP1CON3 = 0x00;
SSP1ADD = 0x27;
}
/*******************************PRINCIPAL**************************************/
void main(void) //bucle principal. A partir de while(1) se repite indefinidamente
{
Configuration_IO(); //esta parte solo hace una vez
Configuration_I2C();
while(1){ //bucle infinito
//escribir en eeprom externa//
Send_I2C_StartBit(); // send start bit
Send_I2C_ControlByte(0x00,0); // send control byte with R/W bit set low
Send_I2C_Data(word_adress); // send word address
Send_I2C_Data(eeprom_data); // send data byte
Send_I2C_StopBit(); // send stop bit
__delay_ms(200);
//leer desde la eeprom externa//
Send_I2C_StartBit(); // send start bit
Send_I2C_ControlByte(0x00,0); // send control byte with R/W bit set low
Send_I2C_Data(word_adress); // send word address
Send_I2C_StartBit(); // send start bit
Send_I2C_ControlByte(0x00,1); // send control byte with R/W bit set high
incoming_data = Read_I2C_Data(); // now we read the data coming back from the eeprom
Send_I2C_NAK(); // send a the NAK to tell the eeprom we don't want any more data
Send_I2C_StopBit(); // and then send the stop bit
PORTF = incoming_data; // saca el resultado por el puerto f donde hay conectados leds
eeprom_data = eeprom_data + 1;//aumenta en uno el dato a escribir y leer
__delay_ms(200);
}
}
/*************************RUTINAS PARA EL I2C***********************************/
void Send_I2C_Data(unsigned int databyte)
{
PIR1bits.SSPIF=0; // clear SSP interrupt bit
SSPBUF = databyte; // send databyte
while(!PIR1bits.SSPIF); // Wait for interrupt flag to go high indicating transmission is complete
}
unsigned int Read_I2C_Data(void)
{
PIR1bits.SSPIF=0; // clear SSP interrupt bit
SSPCON2bits.RCEN=1; // set the receive enable bit to initiate a read of 8 bits from the serial eeprom
while(!PIR1bits.SSPIF); // Wait for interrupt flag to go high indicating transmission is complete
return (SSPBUF); // Data from eeprom is now in the SSPBUF so return that value
}
void Send_I2C_ControlByte(unsigned int BlockAddress,unsigned int RW_bit)
{
PIR1bits.SSP1IF=0; // clear SSP interrupt bit
SSPBUF = (((0b1010 << 4) | (BlockAddress <<1)) + RW_bit); // send the control byte
while(!PIR1bits.SSP1IF); // Wait for interrupt flag to go high indicating transmission is complete
}
void Send_I2C_StartBit(void)
{
PIR1bits.SSP1IF=0; // clear SSP interrupt bit
SSPCON2bits.SEN=1; // send start bit
while(!PIR1bits.SSP1IF); // Wait for the SSPIF bit to go back high before we load the data buffer
}
void Send_I2C_StopBit(void)
{
PIR1bits.SSP1IF=0; // clear SSP interrupt bit
SSPCON2bits.PEN=1; // send stop bit
while(!PIR1bits.SSP1IF); // Wait for interrupt flag to go high indicating transmission is complete
}
void Send_I2C_ACK(void)
{
PIR1bits.SSP1IF=0; // clear SSP interrupt bit
SSPCON2bits.ACKDT=0; // clear the Acknowledge Data Bit - this means we are sending an Acknowledge or 'ACK'
SSPCON2bits.ACKEN=1; // set the ACK enable bit to initiate transmission of the ACK bit to the serial eeprom
while(!PIR1bits.SSP1IF); // Wait for interrupt flag to go high indicating transmission is complete
}
void Send_I2C_NAK(void)
{
PIR1bits.SSP1IF=0; // clear SSP interrupt bit
SSPCON2bits.ACKDT=1; // set the Acknowledge Data Bit- this means we are sending a No-Ack or 'NAK'
SSPCON2bits.ACKEN=1; // set the ACK enable bit to initiate transmission of the ACK bit to the serial eeprom
while(!PIR1bits.SSP1IF); // Wait for interrupt flag to go high indicating transmission is complete
}
Hay 2 soluciones,
- poner todos las funciones de I2C al comienzo del main.c, asi pasa por estas antes de llegar a la funcion main, como tenes las configuraciones de las IO e I2C
Otra cosa, uno de los grandes problemas en sistemas embebidos es que nosotros SI sabemos que cantidad de bits queremos en nuestras variables, y jugamos con el espacio. El problema viene con el uso de distintos compiladores.
CCS tiene un int que es de 8bits, mientras que XC8 el int es de 16 bits. Entonces complica el "paso" de uno a otro. Una forma facil de pasar esto es usar el archivo stdint.h el cual define nuevos valores que son mas claros para el usuario.
uint8_t -- Unsigned entero de 8 bits
uint16_t -- Unsigned entero de 16 bits
int8_t -- entero (con signo) de 8 bits
Otra cosa mas... solo es necesario incluir el xc.h nada mas , los demas: stdio.h, htc.h no hace falta para lo que usas.
Y obviamente si usas lo que dije antes necesitas incluir el stdint.h
Creo que esto tiene que ver con lo que me explicaste aqui
Y las librerias tienen el archivo .c y otro con la declaracion de variables llamado .h para que no salga el error que me esta saliendo a mi. Me equivoco?.
Puede ser la solucion pero entonces si se hace lo mismo con todas las funciones del pic (i2c, USART, ADC....) vamos a tener un main enorme y que va a ser un lio enorme.
Tal ves porque montaste un I2C por software, lo que esta diciendo el warning es que se detecto una transicion muy corta, es decir el pin cambio de estado en muy poco tiempo,, imaginatelo como un muy pequeño pulso. no vi el programa pero tal ves es debido a que esos pines no trabajan como open colector.
de todas formas yo reemplazaria esas funciones por una que utilice el modulo I2C.
¿Si tenes un modulo, porque complicarse pensandolo en hacer por software?
The following events will cause the SSPx Interrupt Flag bit, SSPxIF, to be set (SSPx interrupt, if enabled):
• Start condition detected
• Stop condition detected
• Data transfer byte transmitted/received
• Acknowledge transmitted/received
• Repeated Start generated
24.6.6.4 Typical transmit sequence:
1. The user generates a Start condition by setting the SEN bit of the SSPxCON2 register.
2. SSPxIF is set by hardware on completion of the Start.
3. SSPxIF is cleared by software.
4. The MSSPx module will wait the required start time before any other operation takes place.
5. The user loads the SSPxBUF with the slave address to transmit.
6. Address is shifted out the SDAx pin until all eight bits are transmitted. Transmission begins as soon as SSPxBUF is written to.
7. The MSSPx module shifts in the ACK bit from the slave device and writes its value into the ACKSTAT bit of the SSPxCON2 register.
8. The MSSPx module generates an interrupt at the end of the ninth clock cycle by setting the SSPxIF bit.
9. The user loads the SSPxBUF with eight bits of data.
10. Data is shifted out the SDAx pin until all eight bits are transmitted.
11. The MSSPx module shifts in the ACK bit from the slave device and writes its value into the ACKSTAT bit of the SSPxCON2 register.
12. Steps 8-11 are repeated for all transmitted data bytes.
13. The user generates a Stop or Restart condition by setting the PEN or RSEN bits of the SSPxCON2 register. Interrupt is generated once the Stop/Restart condition is complete
while(1){ //bucle infinito
Send_I2C_StartBit(); // start
Send_I2C_Data(0x00); // control byte con R/W bit=0
Send_I2C_Data(0x01); // direccion alta de la memoria
Send_I2C_Data(0x23); // direccion baja de la memoria
Send_I2C_Data(0x50); // dato a enviar
Send_I2C_StopBit(); // stop
__delay_ms(100); // retraso
}
Send_I2C_Data(0x00); // control byte con R/W bit=0Primero que nada, pasa el programa (e imagen del esquema) ahora como lo tenes
Segundo, tenes que recordar que no solo estas peleando con el programar, sino tambien con el simulador.
Código: C
#define EEPROM_ADDRESS (0b10100000) // Valor ya con el shift un lugar a la izquierda #define WRITE (0) #define READ (1)
Ahora si usas:Código: C
Send_I2C_Data(EEPROM_ADDRESS | WRITE);
Si no pones correctamente la dirección, la memoria al leer la dirección y ver que no es la de el (recorda que de un mismo bus podes colgar muchas cosas), procede a omitir todo lo que le llegue hasta el proximo STOP.
bit 0 SEN: Start Condition Enable bit(1)
In Master mode:
1 = Initiate Start condition on SDAx and SCLx pins. Automatically cleared by hardware
En Send_I2C_StartBit tenes la instruccion:Código: C
while(!SSP1CON2bits.SEN);
Pienso que deberias quitarla, el flag deberia suficiente como para indicarte que la operacion de Start del I2C ya termino.
24.6.6.4 Typical transmit sequence:
1. The user generates a Start condition by setting the SEN bit of the SSPxCON2 register.
2. SSPxIF is set by hardware on completion of the Start.
3. SSPxIF is cleared by software.
4. The MSSPx module will wait the required start time before any other operation takes place.
5. The user loads the SSPxBUF with the slave address to transmit.
6. Address is shifted out the SDAx pin until all eight bits are transmitted. Transmission begins as soon as SSPxBUF is written to.
7. The MSSPx module shifts in the ACK bit from the slave device and writes its value into the ACKSTAT bit of the SSPxCON2 register.
8. The MSSPx module generates an interrupt at the end of the ninth clock cycle by setting the SSPxIF bit.
9. The user loads the SSPxBUF with eight bits of data.
10. Data is shifted out the SDAx pin until all eight bits are transmitted.
11. The MSSPx module shifts in the ACK bit from the slave device and writes its value into the ACKSTAT bit of the SSPxCON2 register.
12. Steps 8-11 are repeated for all transmitted data bytes.
13. The user generates a Stop or Restart condition by setting the PEN or RSEN bits of the SSPxCON2 register. Interrupt is generated once the Stop/Restart condition is complete
void interrupt isr (void)
{
if(PIR1bits.SSPIF == 1)
{
PIR1bits.SSPIF = 0;
}
else
{
}
}