Sei sulla pagina 1di 9

El Protocolo I2C

Una de las herramientas de comunicacin muy usada en el mundo de los microcontroladores es el protocolo
serial I2C, el compilador C18 tiene implementado un conjunto de librerias y rutinas para este propsito, sin
embargo jijijiji no tienen una libreria de aplicacin especfica por ejemplo para el DS1307 (entre otros...),
tiene una libreria para el manejo de memorias eeprom externas pero solo para la 24XX01, pues solo permite
ingresar 1 byte de direccin de memoria.
En vista de tales inconvenientes (y para no quedar atrs del CCS) nos aventuraremos en la odisea de

implementar nuestras propias rutinas jijiji , empezaremos con las memorias eeprom, y luego nos daremos
un paseito por el DS1307, si alguien propone algn otro chip para hacer su libreria pues bienvenido sea .

Ah! pero antes estudiemos brevemente el modulo I2C que lleva incorporado el PIC18F2525 (en los demas PICs
de esta gama la principal diferencia est en la ubicacin de los pines SDA y SCL).

Mdulo MSSP en Modo I2C


En el pic 18F2525 el protocolo I2C utiliza los siguientes pines para comunicarse, los cuales deben estar
configurados como entradas al inicializar el modo I2C:

Estos pines del pic cuando se configuran como puerto serial del mdulo I2C demandan una resistencia de PULL
UP en ambos pines, esto se debe al protocolo I2C. Esta resistencia puede ser de 10K -- 2K tirada a 5V, pero en
el simulador usaremos un tipo de componente llamado PULL-UP, no olviden que la posicion de estos pines
varia segn el modelo del pic18F, tener cuidado al momento de implementarlo si no tienen el 18F2525, no
olviden setearlos como entradas.

A continuacin tenemos los registros que administran el control del mdulo:

Estos registros poseen las diversas configuraciones que puede optar el mdulo I2C, para nuestros objetivos
vamos a dejarlo habilitado como dispositivo I2C Maestro, bus de 100KHz para cristal de 4MHz, sin
interrupciones, y unos detalles ms que los podremos ver en sus registros de control:

En este registro se puede configurar lo siguiente:

SSPEN:habilita el puerto serial y los pines SCL y SDA.


SSPM3-SSPM0: modo de operacin del MSSP, escogemos la opcin de Modo I2C Master.

En este registro se puede configurar lo siguiente:

GCEN: habilita interrupcion para modo esclavo, pero no lo vamos a usar.


En este registro se puede configurar lo siguiente:

SMP: velocidad del bus, slew rate, escojemos la opcin 100KHz.


CKE: dejarla deshabilitada.

El registro SSPSR es el buffer de desplazamiento usado para enviar o recibir informacin de forma serial.
El registro SSPBUF es el registro donde se escribe o se guarda el valos a enviar o recibir.

El registro SSPADD es el que guarda el valor de recarga del Generador de Baudios con el cual obtenemos la
velocidad del bus I2C, para nuestra experiencia requerimos 100KHz con 4MHz entonces segn la frmula:

SSPADD = 9

Veamos en detalle las rutinas de la librera memoria_externa.h

putrsI2C
Esta rutina permite enviar al modulo I2C una cadena ubicada en la memoria de program (ROM), su aplicacin
se encuentra en la rutina EscribeDatos_i2c_eeprom.

EscribeDato_i2c_eeprom
Tiene 4 argumentos de entrada y retorna un valor 0 si no existen errores, de lo contrario devolver un valor
negativo.
Cdigo: C

1. unsigned char EscribeDato_i2c_eeprom( unsigned char control, unsigned


char address1, unsigned char address2, unsigned char data )

Ejm:
EscribeDato_i2c_eeprom(0XA0,0X00,0X00,'@');

En este ejemplo queremos escribir el carcter ascii @ en la posicin 0x0000 de la memoria de datos de la
eeprom externa cuyo registro de control es 0XA0.

EscribeDatos_i2c_eeprom
Tiene 4 argumentos de entrada donde uno de ellos es una cadena ubicada en la memoria de programa del pic
(ROM), y como salida retorna un valor 0 si no existen errores, de lo contrario devolver un valor negativo.
Cdigo: C

1. unsigned char EscribeDatos_i2c_eeprom( unsigned char control,


unsigned char address1, unsigned char address2, const rom char *wrptr
)

Ejm:
EscribeDatos_i2c_eeprom(0XA0,0X00,0X10,"|||PERU|||");

Escribimos la cadena |||PERU||| a partir de la posicin 0x0010 de la memoria de datos de la eeprom externa cuyo
registro de control es 0XA0.

EscribeCadena_i2c_eeprom
Tiene 4 argumentos de entrada donde uno de ellos es una cadena ubicada en la memoria de datos del pic
(RAM), y como salida retorna un valor 0 si no existen errores, de lo contrario devolvera un valor negativo.
Cdigo: C

1. unsigned char EscribeCadena_i2c_eeprom( unsigned char control,


unsigned char address1, unsigned char address2, unsigned char *wrptr
)

Ejm:
unsigned char henry[]="*micro_cadaver*",

EscribeCadena_i2c_eeprom(0XA0,0X00,0X00,henry);

Escribimos la cadena henry a partir de la posicin 0x0000 de la memoria de datos de la eeprom externa cuyo
registro de control es 0XA0.

LeeDato_i2c_eeprom
Tiene 3 argumentos de entrada y como argumento de salida nos retorna el contenido del buffer de recepcin
SSPBUF, de lo contrario nos dar un valor negativo.
Cdigo: C

1. unsigned int LeeDato_i2c_eeprom( unsigned char control, unsigned char


address1, unsigned char address2 )

Ejm:
caracter=LeeDato_i2c_eeprom(0XA0,0X00,0X00);

Con esta rutina podemos leer un byte de la memoria eeprom externa, en el ejemplo estamos leyendo un byte
ubicado en 0x0000 de la memoria con registro de control 0xA0.

LeeDatos_i2c_eeprom
Tiene 5 argumentos de entrada y como argumento de salida retorna un 0 y la cadena cargada con la cantidad de
bytes solicitados, de lo contrario nos dar un valor negativo.
Cdigo: C

1. unsigned char LeeDatos_i2c_eeprom( unsigned char control, unsigned


char address1, unsigned char address2,unsigned char *rdptr, unsigned
char length )
Ejm:
unsigned char recepcion[16];

LeeDatos_i2c_eeprom(0XA0,0X00,0X10,recepcion,10);

Con esta rutina podemos leer varios bytes de la memoria eeprom externa, en el ejemplo estamos leyendo 10
bytes ubicados desde 0x0010 de la memoria externa con registro de control 0xA0 y los estamos guardando en la
cadena recepcin. Tener en cuenta que la cadena donde se van a cargar los valores debe ser mayor que la
cantidad solicitada de bytes, en este ejemplo se ve claramente que recepcin es una cadena con 16 elementos y
en la rutina de lectura especificamos que queremos descargar solo 10 bytes.

Ack_i2c_eeprom
Genera un ACK para liberar el bus I2C, hacer esto despus de cualquier escritura.
Cdigo: C

1. unsigned char Ack_i2c_eeprom( unsigned char control )

Ejm:
EscribeDato_i2c_eeprom(0XA0,0X00,0X00,'@');
Ack_i2c_eeprom(0XA0);

1. #include <p18f2525.h>
2. #include <delays.h>
3. #include <i2c.h>
4. #include "C:\PIC\18F\MEMO\memoria_externa.h"
5. #include "C:\PIC\18F\MEMO\LCD4b2x16.h"
6.
7. #pragma config OSC = XT,FCMEN = OFF,IESO = OFF //CONFIG1H
8. #pragma config PWRT = ON,BOREN = OFF,BORV = 0 //CONFIG2L
9. #pragma config WDT = OFF,WDTPS = 32768 //CONFIG2H
10. #pragma config MCLRE = ON,LPT1OSC = OFF,PBADEN = OFF,CCP2MX =
PORTC//CONFIG3H
11. #pragma config STVREN = OFF,LVP = OFF,XINST = OFF,DEBUG =
OFF//CONFIG4L
12. #pragma config CP0 = ON,CP1 = ON,CP2 = ON//CONFIG5L
13. #pragma config CPB = ON,CPD = ON//CONFIG5H
14. #pragma config WRT0 = ON,WRT1 = ON,WRT2 = ON//CONFIG6L
15. #pragma config WRTB = ON,WRTC = ON,WRTD = ON//CONFIG6H
16. #pragma config EBTR0 = ON,EBTR1 = ON,EBTR2 = ON//CONFIG7L
17. #pragma config EBTRB = ON//CONFIG7H
18.
19. int caracter;
20. unsigned char henry[]="*micro_cadaver*",
21. cadena[16];
22. void main(void)
23. {
24. TRISA = 0X00;
25. TRISB = 0X00;
26. TRISC = 0X18;
27. LATA = 0X00;
28. LATB = 0X00;
29. LATC = 0X00;
30. Delay1KTCYx(100);
31. Inicializa_LCD();
32. Comando_LCD(CURSOR_OFF & BLINK_OFF);
33. //*******************************************************
34. // configuracin del modulo i2c
35. //*******************************************************
36. OpenI2C(MASTER,SLEW_OFF);//inicializo modulo
37. SSPADD = 9;//100KHz para 4MHz
38. //*******************************************************
39. EscribeDato_i2c_eeprom(0XA0,0X00,0X00,'@');
40. Ack_i2c_eeprom(0XA0);
41. caracter=LeeDato_i2c_eeprom(0XA0,0X00,0X00);
42. Dato_LCD(caracter);
43. Delay1KTCYx(500);
44.
45. EscribeDatos_i2c_eeprom(0XA0,0X00,0X10,"|||PERU|||");
46. Ack_i2c_eeprom(0XA0);
47.
48. EscribeCadena_i2c_eeprom(0XA0,0X00,0X00,henry);
49. Ack_i2c_eeprom(0XA0);
50.
51. Comando_LCD(0X80);
52. LeeDatos_i2c_eeprom(0XA0,0X00,0X10,cadena,10);
53. Dato_String_LCD(cadena);
54.
55. Comando_LCD(0XC0);
56. LeeDatos_i2c_eeprom(0XA0,0X00,0X00,cadena,15);
57. Dato_String_LCD(cadena);
58.
59. while(1);
60.
61. //*******************************************************
62. //*******************************************************
63. }

1. #include <p18f2525.h>
2. #include <delays.h>
3. #include <i2c.h>
4. #include "C:\PIC\18F\MEMO\memoria_externa.h"
5. #pragma config OSC = XT,FCMEN = OFF,IESO = OFF //CONFIG1H
6. #pragma config PWRT = ON,BOREN = OFF,BORV = 0 //CONFIG2L
7. #pragma config WDT = OFF,WDTPS = 32768 //CONFIG2H
8. #pragma config MCLRE = ON,LPT1OSC = OFF,PBADEN = OFF,CCP2MX =
PORTC//CONFIG3H
9. #pragma config STVREN = OFF,LVP = OFF,XINST = OFF,DEBUG =
OFF//CONFIG4L
10. #pragma config CP0 = ON,CP1 = ON,CP2 = ON//CONFIG5L
11. #pragma config CPB = ON,CPD = ON//CONFIG5H
12. #pragma config WRT0 = ON,WRT1 = ON,WRT2 = ON//CONFIG6L
13. #pragma config WRTB = ON,WRTC = ON,WRTD = ON//CONFIG6H
14. #pragma config EBTR0 = ON,EBTR1 = ON,EBTR2 = ON//CONFIG7L
15. #pragma config EBTRB = ON//CONFIG7H
16.
17. int caracter;
18. unsigned char henry[]="Henry Ricardo Laredo Quispe, mas
conocido como el micro_cadaver! i wish i was on the top the mountain
happy shinny people i want",
19. cadena[16];
20. void main(void)
21. {
22. TRISA = 0X00;
23. TRISB = 0X00;
24. TRISC = 0X18;
25. LATA = 0X00;
26. LATB = 0X00;
27. LATC = 0X00;
28. Delay1KTCYx(250);
29. //*******************************************************
30. // configuracin del modulo i2c
31. //*******************************************************
32. OpenI2C(MASTER,SLEW_OFF);//inicializo modulo
33. SSPADD = 9;//100KHz para 4MHz
34. //*******************************************************
35. EscribeDato_i2c_eeprom(0XA0,0X00,0X00,'@');
36. Ack_i2c_eeprom(0XA0);
37. caracter=LeeDato_i2c_eeprom(0XA0,0X00,0X00);
38.
39. EscribeCadena_i2c_eeprom(0XA0,0X00,0X00,henry);
40. Ack_i2c_eeprom(0XA0);
41. while(1);
42. //*************************************************
43. }
Punteros
Un apuntador o puntero es una variable de 16 bits que contiene una direccin. As si Data en un char y ptr
es un puntero que apunta a l tendremos lo siguiente:

Definicin:
44. Cdigo:
45. char *ptr; // Declaracin de una variable puntero a una variable char.
int *ptr; // Declaracin de una variable puntero a una variable int.
unsigned char *ptr; //Declaracin de una variable puntero a una variable unsigned
char.
46. Operadores unitarios:
&: Operador de direccin.
Da la direccin de una variable, por lo que la expresin ptr=&Data asigna la direccin de Data a ptr,
dicindose entonces que ptr apunta a Data.
*: Operador de indireccin.
Da acceso a la variable que apunta el apuntador. Por ejemplo la expresin *ptr=0xAA asigna a la
variable que apunta prt el valor 0xAA, sea Data=0xAA.-
Algunos ejemplos:
47. Cdigo:
48. Data1= *ptr + 10; // A lo que apunta ptr se le suma 10 y se le asigna a Data1.-
(*ptr)++; // Se incrementa en 1 lo que apunta ptr.-
*ptr++; // Se incrementa el puntero a la siguiente direccin de variable(Depender
que tipo de variable se apunta)
++*ptr; // Se incrementa en 1 lo que apunta ptr.-
ptr2=ptr; // se asigna al segundo puntero lo que apunta ptr. sea los 2 punteros
apuntan a la misma variable.-
49.
Punteros y arreglos:
Si declaramos un arreglo como:
50. Cdigo:
51. char Datos[10];
52. Declaramos un ptr:
53. Cdigo:
54. char *ptr;
55. Podemos asignar al puntero la primer posicin del arreglo:
56. Cdigo:
57. ptr=& Datos[0];
58. Y podemos cargar a Datos[0] y Datos[5] de la siguiente manera:
59. Cdigo:
60. *ptr=0xAA;
*(ptr+5)=0x48;
61. Cargar un buffer dentro de otro:
62. Cdigo:
unsigned int *ptr,*ptr2;
unsigned int Datos01[20], Datos02[5]={0xFFAA,0xCC45,0x7895,0x3568,0xCC21};
ptr=&Datos01[8]; // Vamos a cargar en el arreglo 1 a partir de la posicin 8.-
for(ptr2=Datos02;ptr2<Datos02+5;ptr2++,ptr++){
*ptr=*ptr2;
}
63.
Punteros y funciones.

En C los argumentos de las funciones se pasan por valor, as que no debera de ser posible en una
funcin modificar variables de la funcin que la llama. Digo debera porque pruebas hechas en C18 si lo
permite pero vamos a tratar C convencional para que sirva para otras compiladores.-

Usemos el ejemplo convencional para mostrar esto, por ejemplo si queremos reorganizar variables:

Forma incorrecta:
64. Cdigo:
65. void funcion(void){
char a,b;
a=10;
b=15;
swap(a,b);
}
void swap(char q,char p){
char temp;
temp=q;
q=p;
p=temp;
}
66.
Como vemos estamos modificando variables de la funcin que llama a swap. La forma correcta es
hacerlo por pasaje de referencia, sea le entregamos a la funcin swap la direccin de las variables:
67. Cdigo:
68. void funcion(void){
char a,b;
a=10;
b=15;
swap(&a,&b);
}
void swap(char *q,char *p){
char temp;
temp=*q;
*q=*p;
*p=temp;
}
69.
Tambin el uso de punteros en argumentos de funciones nos es sumamente til para que una funcin
pueda retornar ms de una variable entregando por referencia un arreglo.

Por ejemplo en un arreglo colocamos el nombre de un archivo ms su extensin, y queremos una


funcin que separe en dos arreglos distintos el nombre y la extensin:
70. Cdigo:
71. void funcin(void){
char NombreMasExt[13]= Tutorial.pdf;
char Nombre[9],Ext[4];

separamos(NombreMasExt,Nombre,Ext);
}

void separamos(char *ptr,char *nptr,char *eptr){


do{
*nptr++=*ptr++;
}while(*ptr!=.); // Hasta que se direccione el .
*nptr=\0; // Siempre que se trabaje con string se debe indicar finalizacin
con \0
*ptr++; // Pasamos a direccionar la siguiente letra, despus de .
do{
*eptr++=*ptr++;
}while(*ptr!=\0);
*eptr=\0;
}
72.
Nota: Cuando se trabaja con string se debe tener en cuenta una posicin que indica final del string \0.

Potrebbero piacerti anche