Para probar una placa que he hecho, he tenido que testear I2C, ADC, KEYB, LCD, RS232 y como uso Bootloader, hacerlo compatible con éste. Para las pruebas he usado un PIC18F4550 como Master I2C que realmente es el objeto de testeo y un 16F876A actuando como Slave I2C (dummy).
El compilador usado es C18 para el Master y PICC para el Slave.
Master : Fosc = 48M, I2C Hardware
Slave : Fosc = 4M, I2C Hardware
El resultado es una mezcla de código del foro, de fuera y propio. Lo pongo aquí por si a alguien le resulta útil.
Codigo Master (C18)
/*********************************************************************
Alberto: Prueba CAD + LCD + KEYB + I2C + BOOTLOADERUSB
********************************************************************/
/** I N C L U D E S **********************************************************/
#include <p18F4550.h>
#include <delays.h>
#include <stdlib.h> //Libreria para conversiones.
#include <adc.h>
#include <usart.h>
#include <i2c.h>
#include <xlcd.h>
/** V A R I A B L E S ********************************************************/
#pragma udata
/** P R I V A T E P R O T O T Y P E S ***************************************/
/** V E C T O R R E M A P P I N G *******************************************/
extern void _startup (void); // See c018i.c in your C18 compiler dir
#pragma code _RESET_INTERRUPT_VECTOR = 0x000800
void _reset (void)
{
_asm goto _startup _endasm
}
#pragma code
#pragma code _HIGH_INTERRUPT_VECTOR = 0x000808
void _high_ISR (void)
{
;
}
#pragma code _LOW_INTERRUPT_VECTOR = 0x000818
void _low_ISR (void)
{
;
}
#pragma code
/** D E C L A R A T I O N S **************************************************/
#pragma code
#define puerto_lcd PORTD
#define porte = 0xf84
#define e LATBbits.LATB7
#define rs LATBbits.LATB5
#define rw LATBbits.LATB6
void ini_lcd(void);
void write_LCD(char * cadena,int longit);
void lcd_gotoxy( int x, int y);
char read_keyb();
void ParpadeoLeds(void);
void LecturaAdc(unsigned char port,unsigned int* valor);
void FormatVoltio(unsigned int valorAdc,char *buffer);
void write_byte_i2c(char add,char idata);
char read_char_i2c(char add);
unsigned char warr[] = {8,7,6,5,4,3,2,1,0};
unsigned char rarr[15];
unsigned char *rdptr = rarr;
unsigned char *wrptr = warr;
char tabla0[] = {"INIT = "}; //Tabla que contiene el texto a mostrar
char tabla1[] = {"ADC3 = "};
char tabla2[] = {"ADC5 = "};
char tabla3[] = {"KEYB = "};
char tabla4[] = {"PULS = "};
char tabla5[] = {"I2CD = "};
char tabla6[] = {"ERRO = "};
char espacios[] = {" "};
volatile char Data, Kbhit;
void main(void){
unsigned int Canal,i;
char sbuf[6];
char puls[3];
char conv[10];
char keyb,prev_keyb,flag,data,c;
int j;
int pulsaciones = 0;
//LEDs
TRISCbits.TRISC0=0;
TRISDbits.TRISD1=0;
//ADC
TRISAbits.TRISA0=1; TRISAbits.TRISA1=1; TRISAbits.TRISA2=1; TRISAbits.TRISA3=1; TRISAbits.TRISA5=1;
TRISEbits.TRISE0=1; TRISEbits.TRISE1=1; TRISEbits.TRISE2=1; TRISBbits.TRISB2=1; TRISBbits.TRISB3=1;
OpenUSART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_LOW,77); // 9600,8,n,1
OpenADC(ADC_FOSC_64 & ADC_RIGHT_JUST & ADC_2_TAD, ADC_INT_OFF & ADC_REF_VDD_VSS ,ADC_10ANA/*0b0101*/);
OpenI2C(MASTER, SLEW_ON);// Initializar Modulo I2C
SSPADD = 119; //100kHz Baud 119 at 48MHz SSPADD = (Fosc/(4*100k))-1
ADCON1 = 0b00000101; // Vref- Vss, Vref+ Vdd, AN0-AN9 Analog resto Digit
Kbhit=0; RCONbits.IPEN=0; // Deshabilitamos Prioridades
INTCONbits.PEIE=1; // Habilitamos interrupcion de perifericos.-
INTCONbits.GIE=1; // Habilitamos interrupcion Global.
ini_lcd(); //inicia display a 8 bit
putrsUSART("Prueba");
for(c=0;c<16;c++) //Iniciamos los valores en Slave I2C
write_byte_i2c(c,('A' + c));
flag = 0;
while(1){
keyb = read_keyb();
if(keyb != 0){ //Tecla pulsada
prev_keyb = keyb;
pulsaciones++;
flag = 1;
}
else{
if(flag == 1){ //Usamos la tecla pulsada para lectura I2C
flag = 0;
data = read_char_i2c(atoi(&prev_keyb));
lcd_gotoxy(1,1);
if(data != 0){
write_LCD(tabla5,7);
write_LCD(&data,1);
write_LCD(espacios,8);
}
else{
write_LCD(tabla6,7);
write_LCD(espacios,9);
}
}
LecturaAdc(ADC_CH2,&Canal); //Lectura canal ADC
FormatVoltio(Canal,sbuf);
putrsUSART(" Canal 3 en V = ");
putsUSART(sbuf);
lcd_gotoxy(1,2);
write_LCD(tabla1,7);
write_LCD(sbuf,5);
write_LCD(espacios,4);
Delay10KTCYx(120); //delay_ms(10);
}
}
}
void lcd_tris(){
TRISBbits.TRISB5=0;
TRISBbits.TRISB6=0;
TRISBbits.TRISB7=0;
TRISD = 0;
TRISAbits.TRISA4=0;
}
//Modo 8 bits
void display_LCD(short valor , int respaldo) //Rutina que envia al LCD una palabra de control o dirección
{
int tiempo = 20; //Orig a N = 12, 10us
if(valor == 0)
rs = 0;
else
rs = 1;
puerto_lcd = respaldo;
if(respaldo & 0x02)
LATAbits.LATA4=1;
else
LATAbits.LATA4=0;
e = 1;
Delay10TCYx(tiempo);//delay_us(10);
e = 0;
Delay10TCYx(tiempo); //delay_us(10);
}
void ini_lcd(){
int i,j;
lcd_tris();
LATAbits.LATA4=0; puerto_lcd = 0; rw = 0; e = 0; rs = 0;
for(j=0;j<10;j++)
Delay10KTCYx(60); //delay_ms(500);
Delay10KTCYx(18); //Temporiza 15mS
for(i=0; i<3; i++) //Envía 3 veces el comando 0x38 a intervalos de 5 mS
{
display_LCD(0,0x38);
//delay_ms(5);
Delay10KTCYx(6);
}
display_LCD(0,0b00001111); //Secuencia de comandos a enviar a la pantalla LCD
display_LCD(0,0x06); //SHIFT_DISP_LEFT
display_LCD(0 , 0b00000001); //LCD CLEAR
display_LCD(0,0x02); //LCD HOME
Delay1KTCYx(240); //delay_ms(20);
}
void write_LCD(char * cadena,int longit) //Escribe mensaje en LCD
{
int i;
lcd_tris();
for(i=0;i<longit;i++) //Ciclo que envía el texto al LCD
display_LCD(1 , cadena[i]);
}
//Función para situar el cursor
void lcd_gotoxy( int x, int y) {
int dir;
lcd_tris();
if(y==1)
dir=0;
else
dir=0x40;
dir+=x-1;
display_LCD(0,0x80|dir);
}
void LecturaAdc(unsigned char port,unsigned int* valor){
SetChanADC(port); // Selecciono canal a convertir
Delay10TCYx(4); // Carga el capacitor sample&hold
ConvertADC(); // Comienza conversión
while(BusyADC()); // Hasta que se finalice conversión
*valor= ReadADC(); // Realizo lectura
}
void FormatVoltio(unsigned int valorAdc,char *buffer){
unsigned int valor;
char String[6];
valor = (int)((valorAdc/204.8)*1000);
itoa(valor, String); // Convertimos entero a string.-
buffer[0]=String[0];
buffer[1]='.';
buffer[2]=String[1];
buffer[3]=String[2];
buffer[4]=String[3];
buffer[5]='\0';
}
void ParpadeoLeds(void){
int i;
LATCbits.LATC0 = 1; // Parpadeo de los LEDs
LATDbits.LATD1 = 1;
for(i=0;i<10;i++)
Delay10KTCYx(120);
LATCbits.LATC0 = 0;
LATDbits.LATD1 = 0;
for(i=0;i<10;i++)
Delay10KTCYx(120);
}
unsigned int bit_test (unsigned char regist,unsigned int position){
return(regist & (0x01<<position));
}
void keyb_tris(){
TRISDbits.TRISD7=1; //Input
TRISDbits.TRISD6=1;
TRISDbits.TRISD5=1;
TRISDbits.TRISD4=1;
TRISDbits.TRISD3=0; //Output
TRISDbits.TRISD2=0;
TRISDbits.TRISD2=0; //LED
TRISDbits.TRISD0=0;
PORTEbits.RDPU = 1; //Enable Pull Up resistors on PORTD
}
void antirebotes(){
//delay_ms(50);
Delay10KTCYx(60);
}
char read_keyb(){
keyb_tris();
PORTD = 0b11110111; // verifica columna 1
if(bit_test(PORTD,7)==0)
{
antirebotes();
return ('1');
}
if(bit_test(PORTD,6)==0)
{
antirebotes();
return ('4');
}
if(bit_test(PORTD,5)==0)
{
antirebotes();
return ('7');
}
if(bit_test(PORTD,4)==0)
{
antirebotes();
return ('*');
}
PORTD = 0b11111110; // verifica columna 2
if(bit_test(PORTD,7)==0)
{
antirebotes();
return ('2');
}
if(bit_test(PORTD,6)==0)
{
antirebotes();
return ('5');
}
if(bit_test(PORTD,5)==0)
{
antirebotes();
return ('8');
}
if(bit_test(PORTD,4)==0)
{
antirebotes();
return ('0');
}
PORTD = 0b11111011; // verifica columna 3
if(bit_test(PORTD,7)==0)
{
antirebotes();
return ('3');
}
if(bit_test(PORTD,6)==0)
{
antirebotes();
return ('6');
}
if(bit_test(PORTD,5)==0)
{
antirebotes();
return ('9');
}
if(bit_test(PORTD,4)==0)
{
antirebotes();
return ('#');
}
return(0);
}
void write_byte_i2c( char add, char idata )
{
StartI2C();
putcI2C(0xA0);
putcI2C(add);
putcI2C(idata);
StopI2C();
}
char read_char_i2c( char add )
{
char dat;
StartI2C();
putcI2C( 0xa0 );
putcI2C( add );
StopI2C();
StartI2C();
putcI2C( 0xa1 );
dat = getcI2C();
StopI2C();
return (dat);
}
Codigo del Slave (Compilado con PICC):
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa0)
//BYTE address, buffer[0x10] = {'1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G'};
BYTE address, buffer[0x10];
BYTE incoming, state;
#INT_SSP
void ssp_interupt ()
{
state = i2c_isr_state();
if(state < 0x80) //Master envia datos
{
if(state == 0){
incoming = i2c_read();
}
if(state == 1){ //Direccion
incoming = i2c_read();
address = incoming;
}
if(state == 2){ //Dato
incoming = i2c_read();
buffer[address] = incoming;
}
}
if(state == 0x80) //Master pide datos
{
i2c_write(buffer[address]);
}
}
void main ()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_SSP);
while (1);
}