lunes, 4 de enero de 2010

SDCC i2c con PIC16F87x

EL codigo lo saque de iearobotics funciona exelente, lei una eeprom sin problemas.

#include <pic16f873a.h>
typedef unsigned int word;
word at 0x2007 CONFIG = _HS_OSC & _WDT_OFF & _PWRTE_ON & _BODEN_ON & _LVP_OFF & _CPD_OFF & _WRT_OFF & _DEBUG_OFF & _CP_OFF;

#define T_10ms 61
#define LED RA0
void timer0_delay(unsigned char t0ini)
{
//-- Dar valor inicial del timer
TMR0=t0ini;

//-- Flag de interrupcion a cero
T0IF=0;

//-- Esperar a que transcurra el tiempo indicado
while(T0IF==0);
}


/*******************************************************/
/* Pausa */
/* ENTRADA: duracion de la pausa en centesimas (10ms) */
/*******************************************************/
void delay(unsigned int duracion)
{
unsigned int i;

for (i=0; i<duracion; i++)
timer0_delay(T_10ms);
}

/*
****************************************
* FUNCIONES DE BAJO NIVEL DEL I2C *
****************************************
*/

// Envia Ack
// SDA = 0
void i2c_SendAck()
{
ACKDT = 0; // Establece un ACK
ACKEN = 1; // Lo envia
}


// Envia Nack para finalizar la recepecion
// SDA = 1
void i2c_SendNack()
{
ACKDT = 1; // Establece un NACK
ACKEN = 1; // Lo envia
}


// verifica ACK
// Mira si en el 9 pulso de reloj (SCL en estado a 1) la señal SDA está a 0
unsigned char i2c_CheckACK()
{
if ( ACKSTAT == 0 ) {
return 0; // correcto (lo he recibido )
} else {
return 1; // incorrecto (no lo he recibido)
}
}


// Envia la condicion de STOP
// Libera el BUS I2C, SDA y SCL a nivel alto
// SDA=1 cuando SCL=1.
void i2c_SendStop() {
PEN = 1; // send stop bit
}


// Envia la condicion de START
// Inicializa el Bus I2C, SCL y SDA a nivel bajo
// Estando SCL=1 pone SDA=0, luego pone SCL=0
void i2c_SendStart()
{
SEN = 1; // send start bit
}

// Espera a que el I2C reciba algun evento
void i2c_WaitMSSP()
{
while (SSPIF == 0); // Espera evento
SSPIF=0; // Limpia FLAG
}


// Espera a que el I2C reciba algun evento
unsigned char i2c_MSSP_Status()
{
return SSPIF;
}




// Repeated start from master
// Queremos transmitir más datos pero sin dejar el BUS, es decir
// sin mandar previamente un STOP. O por ejemplo si queremos mandar un STOP y seguidamente un
// START para que ningún otro dispositivo ocupe la línea usaremos esto.
void i2c_SendRStart() {
RSEN=1;
}


// Leer Byte por el I2C
// Devuelve byte leido
unsigned char i2c_ReadByte() {
RCEN=1; // Activar el RCEN

i2c_WaitMSSP();
return SSPBUF;
}




// Envia un Dato por el Bus I2C
// Entrada el dato a enviar
void i2c_SendByte(unsigned char dato) {
SSPBUF=dato;
}



// Fallo en el I2C
void i2c_fail() {
i2c_SendStop();
i2c_WaitMSSP();
}



/*
**************************************
* FUNCIONES DE ALTO NIVEL del I2C *
**************************************
*/


/* Configurar I2C
Configuramos el I2C como Master
y a una velocidad de 1Mhz
*/

void i2c_configure()
{
// configuramos SCL y SDA como pines de entrada
TRISC=TRISC | 0x18; // 1 entrada / 0 salida

SSPSTAT=0x0;
SSPSTAT=SSPSTAT | 0x80; // SMP=1 Slew rate disable for 100Kh @@@
// CKE=0 (modo maestro I2C) y UA=0 (7 bits)

SSPCON=0x08; // I2C master mode (uso la formula del reloj con SSPAD)
SSPCON=SSPCON | 0x20; // enable I2C SSPEN=1

SSPCON2=0x00; // no se usa por ahora
// velocidad = FOSC / ( 4 * (sspad + 1) )
// Fosc=20Mhz

SSPADD=49; // 49->100Khz @@@
//SSPADD=24; // 24 -> 400khz @@@

// Limpia Flags de eventos
SSPIF=0; //Limpia flag de eventos SSP
}



// manda un byte al dispositivo i2c
unsigned char i2c_write_byte(unsigned char address, unsigned char reg,
unsigned char dato)
{
// 1º Envia Bit de Start
i2c_SendStart();
i2c_WaitMSSP();

// 2º Envio la direccion del modulo
i2c_SendByte(address);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}

// 3º mando el registro sobre el que voy a actuar
i2c_SendByte(reg);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}

// 4º mando el dato
i2c_SendByte(dato);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}

// 6º termino el envio
i2c_SendStop();
i2c_WaitMSSP();

return 1; // Byte mandado correctamente
}


// Lee 1 byte1 del dispositivo i2c
// El dato leido lo devuelve por el parametro dato
unsigned char i2c_read_byte(unsigned char address, unsigned char reg,
unsigned char *dato)
{

// 1º Envia Bit de Start
i2c_SendStart();
i2c_WaitMSSP();

// 2º Envio la direccion del modulo
i2c_SendByte(address);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}

// 3º mando el registro sobre el que voy a actuar
i2c_SendByte(reg);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}

// 4º Repeated start
i2c_SendRStart();
i2c_WaitMSSP();

// 4º mando direccion indicando lectura
i2c_SendByte(address | 1);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}

// 5º leo el byte
*dato=i2c_ReadByte();

// 6º Mando NACK
i2c_SendNack();
i2c_WaitMSSP();

// Mando el Stop
i2c_SendStop();
i2c_WaitMSSP();

return 1; // Lectura correcta

}

//----------------------------
//- Comienzo del programa
//----------------------------

void main(void)
{
unsigned char ret;
unsigned char dato;

TRISB=0x00;
TRISA=0x00;
//-- Configurar el puerto A como digital
ADCON1=0x06;

//-- Configurar temporizador para hacer pausas
T0CS=0; PSA=0;
//-- Configurar el prescaler (division entre 64)
PS2=1; PS1=1; PS0=1;

//-- Pausa inicial
delay(100);

//-- Configurar el I2C como master
i2c_configure();

//-- Hago una pausa antes de empezar
delay(10);

//24C08A 256X4
//0xA6 = 10100110 identificador de eeprom y bit's de paginas
i2c_write_byte(0xA6, 0x0, 0xAA);
delay(10);

ret=i2c_read_byte(0xA6, 0x0, &dato);
if (ret==1) {
PORTB = dato;
}else{
LED = 1;
}


while(1);

}

Recuerden que la memoria 24C08A no utiliza los pines A0 A1 ya que los usa para acceder a los
bancos que son 4 segun la hoja de datos de atmel.
Osea para formar la palabra de control:

1010 -> identificador de la memoria, luego A2,A1,A0, R/W
en el ejemplo se accedio al 4 banco de 256 bits

10100000 para escribir el primer banco
10100001 para leer el primer banco

el pin A2 sera entonces para direccionar otras unidades conectadas al bus i2c.


No hay comentarios:

IRC

#freenode->#usljujuy

Seguidores

Eventos n_n

Tira Ecol Nano,Bilo y Luca