Hola grupo, hoy a deferencia de las otras veces no voy a consultar, esta vez quiero hacer un pequeño aporte al foro, que harto me ha ayudado.
Quiero pulbicarles esta aplicación de tipo dedáctico implementada para el PIC-18F4550, pensando en aquellos que al igual que Yo nos estamos iniciando en la programación en C para microcontroladores. Elegí este PIC dada su completa arquitectura y capacidad de memoria.
En esta aplicación utilicé los módulos básicos del PIC:
1- Display LCD a 4 bit
2- Conversión AD a 10 bit
3- Timer1, con interrupción
4- Transmisión serial RS-232 a 4800 bps, con interrupción en recepción RX
5- Cominicación I2C, con RTC DS1307
6- Teclado matricial de 4x4
7- Memoria EEPROM interna
Descripción:
1- El PIC realiza un conversión AD tomando la señal por RA0
2- Se toma el valor entero de 0-1023 y se calcula además en porcentaje, ambos valores son convertidos en cadena y llevados al LCD
3- Esta cadena, resultado AD, es enviada al PC via RS-232
4- El dato recibido del PC, 1 caracter ASCII, es presentado en el LCD y alamacenado en la EEPROM en la dirección 0.
5- Se lee las variables de tiempo real del DS-1307, se convierten en cadena y se presentan en el lcd, ejemplo:"12:00:00 01/01/2000"
5- Por medio del teclado, presionando primero la tecla reloj, se habilita la programación de la hora y fecha, haciendo oscilar el cursor del LCD en la variable correspondiente le llevamos el número deseado desde el teclado, luego el dato es grabado en el DS-1307.
Siempre he programado en assembler y es obvio que tengo muchos vicios de este lenguaje, pero de todos modos trataré de resolver cualquier inquietud que este ejercicio les suscite, además recibo cualquier sugerencia, si se dé el caso, de alguna forma para mejorar un procedimiento.
Lástimosamente el puerto USB, que es mi siguiente paso, no lo domino en absoluto, pero cuando tenga algo se los compartiré.
Un abrazo a todos los miembros del FORO.
saludos.
#include <18F4550.h>
#device adc = 10
#use delay(clock=4000000)
#use i2c(master, sda=PIN_B0, scl=PIN_B1,force_hw)
#use rs232(baud=4800, xmit=PIN_C6,rcv=PIN_C7)
#fuses XT, MCLR, NOWDT
#include <stdlib.h>
//resgistros especiales del PIC
#byte porta = 0xf80
#byte portb = 0xf81
#byte portc = 0xf82
#byte portd = 0xf83
#byte porte = 0xf84
#byte t1con = 0xfcd
#byte latd = 0xf8c
#byte adcon0 = 0xfc2
#byte adcon1 = 0xfc1
#byte adcon2 = 0xfc0
#byte adresl = 0xfc3
#byte adresh = 0xfc4
//etiquetas
#define e porte,0
#define rs porte,1
#define puerto_tec latd
#define tec_c1 portd,4
#define tec_c2 portd,5
#define tec_c3 portd,6
#define tec_c4 portd,7
#define tec_f1 portd,0
#define tec_f2 portd,1
#define tec_f3 portd,2
#define tec_f4 portd,3
//definicion de funciones
void ini_lcd_4b();
void display_4b(short valor , int respaldo);
void msj1();
void teclado();
void msj_analogo();
void msj_ra0();
void conversion_ad();
void msj_analogo1();
void msj_rx();
void msj_datos_rec();
void msj_ds1307();
void leer_ds1307();
void conf_ds1307();
void confi_reloj(int valor);
//variables
char registro_tec;
char datos_rec;
short int ban_tmr1;
short int ban_tec1;
short int ban_tec2;
short int ban_tec3;
short int ban_tec4;
short int ban_tec5;
short int ban_tec6;
short int ban_tec7;
short int ban_tec8;
short int ban_tec9;
short int ban_tec10;
short int ban_tec11;
short int ban_tec12;
short int ban_tec13;
short int ban_tec14;
short int ban_tec15;
short int ban_tec16;
short int ban_reloj;
int dec_hora,uni_hora,dec_minu,uni_minu,dec_seg,uni_seg; //Definicion de variables
int dia_sem, dec_dia, uni_dia, dec_mes, uni_mes, dec_amo, uni_amo;
int cont_prg_reloj;
char analogo[5];
char ds1307[18]; //= "12:00:00 22/09/75";
int16 resultado_ad;
//definicion de constantes
byte const tabla1[] = {"! Bienvenidos !"}; //Tabla que contiene el texto a mostrar
byte const tabla2[] = {"RA0 = "}; //Tabla que contiene el texto a mostrar
byte const tabla_rx[] = {"RX="}; //Tabla que contiene el texto a mostrar
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#INT_timer1 //Vector de interrupcion por desbordamiento del
//timer 1
void interrupcion_tmr1()
{
set_timer1(3042); //62.500 * 8 (prescaler) = 0,5 seg
ban_tmr1 = 1;
}
///////////////////////////////////////////////////////////////////////////////
#int_rda //Vector de interrupcion de la recepcion de datos
void interrupcion_rx() //por el usart
{
datos_rec = getc(); //Se lee el dato recibido
write_eeprom(0,datos_rec);
}
///////////////////////////////////////////////////////////////////////////////
#zero_ram //Borrado de la memoria ram
#rom 0xf00000 = {"Hola"} //Datos precargados en la rom
//Rutina principal
void main()
{
//configuracion de puertos y registros especiales
set_tris_b(0b11111111);
set_tris_d(0x0f);
set_tris_e(0);
t1con=(0b00110101); //Configuracion del tmr1
enable_interrupts(global); //Habilitación de todas las interrupciones
enable_interrupts(INT_timer1); //Habilitación de la interrupción del Tmr1
enable_interrupts(int_rda); //Habilitación, recepcion de datos del PC
adcon0 = (0b00000001);
adcon1 = (0b00001110);
adcon2 = (0b10000000);
//configurar el display
delay_ms(2);
ini_lcd_4b();
msj1();
delay_ms(2000);
display_4b(0 , 1); //Limpia el display
delay_ms(2);
portd = 0;
bit_set(porte,7); //habilita pull-up del puerto d ???
registro_tec = '?';
datos_rec = read_eeprom(0); //se lee los datos de la eeprom
memset(analogo,'0',sizeof(analogo)); //se carga la matriz analogo con valores "0"
msj_ra0();
msj_rx();
///////////////////////////////////////
while(true)
{
delay_ms(10);
teclado();
if(ban_tmr1 == 1)
{
if(ban_reloj == 1) //si esta programando el reloj salta estas rutinas
{goto no_display;}
ban_tmr1 = 0;
conversion_ad();
msj_analogo1();
msj_datos_rec();
leer_ds1307();
msj_ds1307();
no_display:
delay_cycles(1);
}
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//rutina que envia el primer mensaje al lcd
///////////////////////////////////////////////////////////////////////////////
void msj_ds1307()
{
int i;
sprintf(ds1307,"%u%u:%u%u:%u%u %u%u/%u%u/%u%u",dec_hora, uni_hora, dec_minu, uni_minu, dec_seg, uni_seg, dec_dia, uni_dia, dec_mes, uni_mes, dec_amo, uni_amo);
display_4b(0 , 0x94); //Dirección donde se escribirá el mensaje
for(i=0;i<sizeof(ds1307)-1;i++) //Ciclo que envía el texto al LCD
{
display_4b(1 , ds1307[i]);
}
}
///////////////////////////////////////////////////////////////////////////////
void msj_rx()
{
int i;
display_4b(0 , 0x90); //Dirección donde se escribirá el mensaje
for(i=0;i<sizeof(tabla_rx)-1;i++) //Ciclo que envía el texto al LCD
{
display_4b(1 , tabla_rx[i]);
}
}
///////////////////////////////////////////////////////////////////////////////
void msj_datos_rec()
{
display_4b(0 , 0x93); //Dirección donde se escribirá el mensaje
display_4b(1 , datos_rec);
}
///////////////////////////////////////////////////////////////////////////////
void msj1()
{
int i;
display_4b(0 , 0x82); //Dirección donde se escribirá el mensaje
for(i=0;i<sizeof(tabla1)-1;i++) //Ciclo que envía el texto al LCD
{
display_4b(1 , tabla1[i]);
}
}
///////////////////////////////////////////////////////////////////////////////
void msj_ra0()
{
int i;
display_4b(0 , 0x80); //Dirección donde se escribirá el mensaje
for(i=0;i<sizeof(tabla2)-1;i++) //Ciclo que envía el texto al LCD
{
display_4b(1 , tabla2[i]);
}
}
///////////////////////////////////////////////////////////////////////////////
void msj_analogo1() //"RA0 = 0000 000%"
{
int i;
sprintf(analogo,"%04lu",resultado_ad);
printf("RA0 = %s - ",analogo); //datos ap PC, no envia retorno de carro
display_4b(0 , 0x86); //Dirección donde se escribirá el mensaje
for(i=0;i<sizeof(analogo)-1;i++) //Ciclo que envía el texto al LCD
{
display_4b(1 , analogo[i]);
}
///////////////////////////////////
i = ((int32)resultado_ad * 100) / 1024; //se calcula porcentaje
sprintf(analogo,"%03u%%",i);
puts(analogo); //datos al PC, se envia retorno de carro
display_4b(0 , 0x8b); //Dirección donde se escribirá el mensaje
for(i=0;i<sizeof(analogo)-1;i++) //Ciclo que envía el texto al LCD
{
display_4b(1 , analogo[i]);
}
}
///////////////////////////////////////////////////////////////////////////////
//rutina de inicializacion del lcd
void ini_lcd_4b()
{
display_4b(0 , 0b00111000); //Codigo para display a 4 bits
display_4b(0 , 0b00001100); //Codigo que activa el display
display_4b(0 , 0b00000110); //Que se desplace hacia la derecha
//display_4b(0 , 0b00000111)//Codigo que define el cursor para
//que desplace hacia la izquierda
//todo el mensaje
display_4b(0 , 1); //Limpia el display
delay_ms(2);
}
///////////////////////////////////////////////////////////////////////////////
void display_4b(short valor , int respaldo) //Rutina que envia al LCD una palabra de control o dirección
{
int respaldo2;
if(valor == 0)
{bit_clear(rs);}
else
{bit_set(rs);}
portd &= 0x0f;
respaldo2 = respaldo & 0xf0 ;
portd |= respaldo2;
bit_set(e);
delay_cycles(10);
bit_clear(e);
portd &= 0x0f;
respaldo2 = swap(respaldo) & 0xf0 ;
portd |= respaldo2;
bit_set(e);
delay_cycles(10);
bit_clear(e);
delay_ms(1);
}
///////////////////////////////////////////////////////////////////////////////
void conversion_ad() //rutina de conversión AD
{
set_adc_channel(0);
delay_us(10);
resultado_ad = read_adc();
}
///////////////////////////////////////////////////////////////////////////////
void teclado() //Rutina general de teclado
{
puerto_tec=(0xf0);
bit_clear(tec_c1);
delay_us(100);
if((bit_test(tec_f1)==0)&&(ban_tec1==0)) //tecla que programa el reloj
{
int respaldo;
ban_tec1 = 1;
registro_tec = 'A';
cont_prg_reloj++;
respaldo = portd;
switch(cont_prg_reloj)
{
case 1:
ban_reloj = 1;
display_4b(0, 0x94);
display_4b(0 , 0b00001101); //Codigo que hace oscilar el cursor
break;
case 2:
display_4b(0, 0x95);
break;
case 3:
display_4b(0, 0x97);
break;
case 4:
display_4b(0, 0x98);
break;
case 5:
display_4b(0, 0x9a);
break;
case 6:
display_4b(0, 0x9b);
break;
case 7:
display_4b(0, 0x9d);
break;
case 8:
display_4b(0, 0x9e);
break;
case 9:
display_4b(0, 0xa0);
break;
case 10:
display_4b(0, 0xa1);
break;
case 11:
display_4b(0, 0xa3);
break;
case 12:
display_4b(0, 0xa4);
break;
case 13:
ban_reloj = 0;
cont_prg_reloj = 0;
display_4b(0 , 0b00001100); //Codigo para que no oscile el cursor
conf_ds1307();
default:
}
portd = respaldo;
}
if((bit_test(tec_f1)==1)&&(ban_tec1==1)) //tecla soltada
{
ban_tec1 = 0;
}
if((bit_test(tec_f2)==0)&&(ban_tec2==0)) //tecla presionada
{
ban_tec2 = 1;
registro_tec = '3';
confi_reloj(3);
}
if((bit_test(tec_f2)==1)&&(ban_tec2==1)) //tecla soltada
{
ban_tec2 = 0;
}
if((bit_test(tec_f3)==0)&&(ban_tec3==0)) //tecla presionada
{
ban_tec3 = 1;
registro_tec = '2';
confi_reloj(2);
}
if((bit_test(tec_f3)==1)&&(ban_tec3==1)) //tecla soltada
{
ban_tec3 = 0;
}
if((bit_test(tec_f4)==0)&&(ban_tec4==0)) //tecla presionada
{
ban_tec4 = 1;
registro_tec = '1';
confi_reloj(1);
}
if((bit_test(tec_f4)==1)&&(ban_tec4==1)) //tecla soltada
{
ban_tec4 = 0;
}
bit_set(tec_c1);
///////////////////////////////////
bit_clear(tec_c2);
delay_us(100);
if((bit_test(tec_f1)==0)&&(ban_tec5==0)) //tecla presionada
{
ban_tec5 = 1;
registro_tec = 'D';
}
if((bit_test(tec_f1)==1)&&(ban_tec5==1)) //tecla soltada
{
ban_tec5 = 0;
}
if((bit_test(tec_f2)==0)&&(ban_tec6==0)) //tecla presionada
{
ban_tec6 = 1;
registro_tec = '6';
confi_reloj(6);
}
if((bit_test(tec_f2)==1)&&(ban_tec6==1)) //tecla soltada
{
ban_tec6 = 0;
}
if((bit_test(tec_f3)==0)&&(ban_tec7==0)) //tecla presionada
{
ban_tec7 = 1;
registro_tec = '5';
confi_reloj(5);
}
if((bit_test(tec_f3)==1)&&(ban_tec7==1)) //tecla soltada
{
ban_tec7 = 0;
}
if((bit_test(tec_f4)==0)&&(ban_tec8==0)) //tecla presionada
{
ban_tec8 = 1;
registro_tec = '4';
confi_reloj(4);
}
if((bit_test(tec_f4)==1)&&(ban_tec8==1)) //tecla soltada
{
ban_tec8 = 0;
}
bit_set(tec_c2);
///////////////////////////////////
bit_clear(tec_c3);
delay_us(100);
if((bit_test(tec_f1)==0)&&(ban_tec9==0)) //tecla presionada
{
ban_tec9 = 1;
registro_tec = 'I';
}
if((bit_test(tec_f1)==1)&&(ban_tec9==1)) //tecla soltada
{
ban_tec9 = 0;
}
if((bit_test(tec_f2)==0)&&(ban_tec10==0)) //tecla presionada
{
ban_tec10 = 1;
registro_tec = '9';
confi_reloj(9);
}
if((bit_test(tec_f2)==1)&&(ban_tec10==1)) //tecla soltada
{
ban_tec10 = 0;
}
if((bit_test(tec_f3)==0)&&(ban_tec11==0)) //tecla presionada
{
ban_tec11 = 1;
registro_tec = '8';
confi_reloj(8);
}
if((bit_test(tec_f3)==1)&&(ban_tec11==1)) //tecla soltada
{
ban_tec11 = 0;
}
if((bit_test(tec_f4)==0)&&(ban_tec12==0)) //tecla presionada
{
ban_tec12 = 1;
registro_tec = '7';
confi_reloj(7);
}
if((bit_test(tec_f4)==1)&&(ban_tec12==1)) //tecla soltada
{
ban_tec12 = 0;
}
bit_set(tec_c3);
///////////////////////////////////
bit_clear(tec_c4);
delay_us(100);
if((bit_test(tec_f1)==0)&&(ban_tec13==0)) //tecla presionada
{
ban_tec13 = 1;
registro_tec = 'B';
}
if((bit_test(tec_f1)==1)&&(ban_tec13==1)) //tecla soltada
{
ban_tec13 = 0;
}
if((bit_test(tec_f2)==0)&&(ban_tec14==0)) //tecla presionada
{
ban_tec14 = 1;
registro_tec = 'E';
}
if((bit_test(tec_f2)==1)&&(ban_tec14==1)) //tecla soltada
{
ban_tec14 = 0;
}
if((bit_test(tec_f3)==0)&&(ban_tec15==0)) //tecla presionada
{
ban_tec15 = 1;
registro_tec = '0';
confi_reloj(0);
}
if((bit_test(tec_f3)==1)&&(ban_tec15==1)) //tecla soltada
{
ban_tec15 = 0;
}
if((bit_test(tec_f4)==0)&&(ban_tec16==0)) //tecla presionada
{
int respaldo;
respaldo = portd;
ban_tec16 = 1;
registro_tec = 'S';
ban_reloj = 0;
cont_prg_reloj = 0;
display_4b(0 , 0b00001100); //Codigo para que no oscile el cursor
portd = respaldo;
}
if((bit_test(tec_f4)==1)&&(ban_tec16==1)) //tecla soltada
{
ban_tec16 = 0;
}
bit_set(tec_c4);
}
///////////////////////////////////////////////////////////////////////////////
void confi_reloj(int valor) //rutina que carga en las variables de reloj el numero presionado
{
int respaldo;
respaldo = portd;
switch(cont_prg_reloj)
{
case 1:
dec_hora = valor;
display_4b(1, dec_hora + 0x30);
display_4b(0, 0x94);
break;
case 2:
uni_hora = valor;
display_4b(1, uni_hora + 0x30);
display_4b(0, 0x95);
break;
case 3:
dec_minu = valor;
display_4b(1, dec_minu + 0x30);
display_4b(0, 0x97);
break;
case 4:
uni_minu = valor;
display_4b(1, uni_minu + 0x30);
display_4b(0, 0x98);
break;
case 5:
dec_seg = valor;
display_4b(1, dec_seg + 0x30);
display_4b(0, 0x9a);
break;
case 6:
uni_seg = valor;
display_4b(1, uni_seg + 0x30);
display_4b(0, 0x9b);
break;
case 7:
dec_dia = valor;
display_4b(1, dec_dia + 0x30);
display_4b(0, 0x9d);
break;
case 8:
uni_dia = valor;
display_4b(1, uni_dia + 0x30);
display_4b(0, 0x9e);
break;
case 9:
dec_mes = valor;
display_4b(1, dec_mes + 0x30);
display_4b(0, 0xa0);
break;
case 10:
uni_mes = valor;
display_4b(1, uni_mes + 0x30);
display_4b(0, 0xa1);
break;
case 11:
dec_amo = valor;
display_4b(1, dec_amo + 0x30);
display_4b(0, 0xa3);
break;
case 12:
uni_amo = valor;
display_4b(1, uni_amo + 0x30);
display_4b(0, 0xa4);
break;
default:
}
portd = respaldo;
}
///////////////////////////////////////////////////////////////////////////////
void leer_ds1307()
{
int respaldo;
i2c_start(); //Start
i2c_write(0b11010000); //Control
i2c_write(0b00000000); //Direccion
i2c_stop(); //Stop
i2c_start(); //Start
i2c_write(0b11010001); //Control para lectura
respaldo = i2c_read(); //Se lee los segundos
uni_seg = respaldo;
dec_seg = swap(respaldo);
uni_seg &= 0x0f;
dec_seg &= 0x0f;
respaldo = i2c_read(); //Se lee los minutos
uni_minu = respaldo;
dec_minu = swap(respaldo);
uni_minu &= 0x0f;
dec_minu &= 0x0f;
respaldo = i2c_read(); //Se lee las horas
uni_hora = respaldo;
dec_hora = swap(respaldo);
uni_hora &= 0x0f;
dec_hora &= 0x0f;
respaldo = i2c_read(); //Se lee el dia de la semana
dia_sem = respaldo;
respaldo = i2c_read(); //Se lee el dia del mes
uni_dia = respaldo;
dec_dia = swap(respaldo);
uni_dia &= 0x0f;
dec_dia &= 0x0f;
respaldo = i2c_read(); //Se lee el mes
uni_mes = respaldo;
dec_mes = swap(respaldo);
uni_mes &= 0x0f;
dec_mes &= 0x0f;
respaldo = i2c_read(); //Se lee los años
uni_amo = respaldo;
dec_amo = swap(respaldo);
uni_amo &= 0x0f;
dec_amo &= 0x0f;
respaldo = i2c_read();
i2c_stop(); //Stop
}
///////////////////////////////////////////////////////////////////////////////
void conf_ds1307()
{
int respaldo;
i2c_start(); //Start
i2c_write(0b11010000); //Control
i2c_write(0b00000000); //Direccion
respaldo = (uni_seg | (swap(dec_seg))); //Se escriben los segundos
i2c_write(respaldo);
respaldo = (uni_minu | (swap(dec_minu))); //Se escriben los minutos
i2c_write(respaldo);
respaldo = (uni_hora | (swap(dec_hora))); //Se escriben las horas
i2c_write(respaldo);
i2c_write(dia_sem);
respaldo = (uni_dia | (swap(dec_dia))); //Se escriben los dias del mes
i2c_write(respaldo);
respaldo = (uni_mes | (swap(dec_mes))); //Se escribe el mes
i2c_write(respaldo);
respaldo = (uni_amo | (swap(dec_amo))); //Se escribe el año
i2c_write(respaldo);
i2c_write(0); //Control de pulsos
i2c_stop(); //Stop
}