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.
lunes, 4 de enero de 2010
SDCC i2c con PIC16F87x
Suscribirse a:
Enviar comentarios (Atom)
IRC
#freenode->#usljujuy
No hay comentarios:
Publicar un comentario