////////////////////////////////////////////////////////////////////////////////
//
// Título: ad_temperatura_lm35a_232_INT_ADC_Display LCD_CON Buffer_Versión 3.0
//
// (c)ad_temperatura_lm35a_232_ reformado 19.11.07 by umalrovi
//
// Ubicación: C:\Archivos de programa\PICC\Projects\
//
// Procesador: PIC16F877A con cristal de 20MHz
//
// Software: CS PCM Version 4.059
//
// Propósito: Se quiere visualizar el valor de un sensor de temperatura y de
// luminosidad en modo local por medio de un display LCD y en modo
// remoto por un PC, mediante el puerto de comunicaciones rs232.
//
// El PC enviará uno de los siguientes comandos descritos mas abajo y el PIC
// hará la acción oportuna.
//
// Técnica Empleada:
//
// * CAD por interrupción.
// * Interrupción serie.
// * Display LCD utilizando librería flex_lcd_2.
// * Comandos RS232 con Buffer
// * Guarda el estado del calentador en EEPROM
//
// COMANDOS rs232 (RC= retorno de carro):
//
// "C1_ON+RC" ---------- Pone el calentador en marcha
// "C1_OFF+RC" ---------- Apaga el calentador
// "STDO+RC" ---------- Mira el estado del calentador (On/Off)
// "V_CAD+RC" ---------- Valor del CAD
// "BORRAR_E+RC"---------- Borra las variables guardadas en eeprom
// "VERSION+RC" ---------- Muestra la versión del programa
// "RESET+RC" ---------- Resetea el micro por watchdog
//
//
////////////////////////////////////////////////////////////////////////////////
#include <16f877A.h> // Definiciones del PIC 16F877A
#device adc=10 // Resolución 10 BITS
#device ICD=TRUE // Habilitamos el modo IDC
#fuses HS,NOWDT,NOPROTECT,NOLVP,PUT,BROWNOUT
#use delay(clock=20000000) // Oscilador a 20 Mhz
//##############################################################################
// El compilador realiza las funciones de IO sin programar el registro dirección
// ocupa menos memoria de programa en el PIC.
//##############################################################################
#use standard_io(a)
#use standard_io(b)
#use standard_io(c)
#use standard_io(d)
#use standard_io(e)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,ERRORS)
// parity=N (no paridad), parity=E(Paridad par), parity=O (paridad impar)
// RS232 Estándar xmit salida de datos, rcv entrada de datos
////////////////////////////////////////////////////////////////////////////////
// DEFINE //
////////////////////////////////////////////////////////////////////////////////
#define LCD_DB4 PIN_D4
#define LCD_DB5 PIN_D5
#define LCD_DB6 PIN_D6
#define LCD_DB7 PIN_D7
// si solo va a utilizar escritura en el LCD conecta R/W a GND y
// comente la siguiente línea
#define USE_LCD_RW 1
// definir a continuación qué pines del PIC manejan las señales de control
#define LCD_RS PIN_D1
#define LCD_RW PIN_D2
#define LCD_E PIN_D0
#include "flex_lcd_2.c" //libreria manejo lcd editada por REDPIC
#define calentador_OFF output_low(PIN_B1)
#define calentador_ON output_high(PIN_B1)
////////////////////////////////////////////////////////////////////////////////
// CONSTANTES //
////////////////////////////////////////////////////////////////////////////////
int const lenbuff=32; // Longitud de buffer, Ajustar a lo que desees
// o te sea posible)
////////////////////////////////////////////////////////////////////////////////
// VARIABLES EN RAM //
////////////////////////////////////////////////////////////////////////////////
float adc_luminosidad=0x00;
float adc_temperatura=0x00;
float grados_temperatura=0;
int canal=0;
char grad=0b11011111; // simblo "º" según datasheet
int xbuff=0x00; // Índice: siguiente char en cbuff
char cbuff[lenbuff]; // Buffer
char rcvchar=0x00; // último caracter recibido
int1 flagcommand=0; // Flag para indicar comando disponible
int1 estado_calentador=0; // Estado del Calentador
int1 flag_reset=0; // Indica un reset por consola(PC)
////////////////////////////////////////////////////////////////////////////////
// DECLARACIÓN DE FUNCIONES //
////////////////////////////////////////////////////////////////////////////////
void toma_adc_y_transmite(void); // pilla el valor de ADC y lo envia por RS232
void visualiza_parametros_LCD(void);//muestra los valores de temp. y luminosidad
void inicbuff(void); // Borra buffer
int addcbuff(char c); // añade caracter recibido al buffer
void procesa_comando(void); // Procesa comando
//##############################################################################
//#
//# Interrupción recepcición serie USART
//#
//##############################################################################
#int_rda
void serial_isr() { // Interrupción recepción serie USART
rcvchar=0x00; // Inicializo caracter recibido
if(kbhit()){ // Si hay algo pendiente de recibir ...
rcvchar=getc(); // lo descargo y ...
addcbuff(rcvchar); // lo añado al buffer y ...
}
}
//##############################################################################
//#
//# Interrupción encargada del conversor AD
//#
//##############################################################################
# INT_AD
void AD_isr()
{
if (canal==0){
set_adc_channel(0);
canal=1;
delay_ms(1);
adc_luminosidad=Read_ADC(ADC_READ_ONLY);
delay_ms(1);
Read_ADC(ADC_START_ONLY); //inicia nueva conversion.
}else{
set_adc_channel(1);
canal=0;
delay_ms(1);
adc_temperatura=Read_ADC(ADC_READ_ONLY);
delay_ms(1);
Read_ADC(ADC_START_ONLY); //inicia nueva conversion.
}
}
////////////////////////////////////////////////////////////////////////////////
// DESARROLO DE FUNCIONES //
////////////////////////////////////////////////////////////////////////////////
void toma_adc_y_transmite(void){
disable_interrupts(int_ad);
grados_temperatura = (float) ((adc_temperatura * 391) / 1000);
printf(" L = %.0f T = %.2f (adc= %.0f)\n",adc_luminosidad,grados_temperatura,adc_temperatura);
enable_interrupts(int_AD); // Habilita las interrupciones globales
// Inicializa el CAD y cuando termine salta a vector interrupción
Read_ADC(ADC_START_ONLY);
}
void visualiza_parametros_LCD(void){
// Desabilitamos la int del CAD para pillar el valor y guardarlo en su variable
// y posteriormente hacer calculos.
disable_interrupts(int_ad);
grados_temperatura =(float)((adc_temperatura * 391) / 1000);
lcd_gotoxy(1,1);
printf(lcd_putc,"T=%.1f%cC ad=%.0f "grados_temperatura,grad,adc_temperatura);
// para expresar en el LCD el simbolo de grados hay que poner ß (alt+225) que
//corresponden al caracter decimal 223
lcd_gotoxy(7,2);
printf(lcd_putc,"Ladc=%.0f "adc_luminosidad);
if (estado_calentador==0){
lcd_gotoxy(1,2);
printf(lcd_putc,"C=OFF ");
}else{
lcd_gotoxy(1,2);
printf(lcd_putc,"C=ON ");
}
// Volvemos a Habilitar las interrupciones del CAD
enable_interrupts(int_ad);
}
void inicbuff(void){ // Inicia a \0 cbuff -------------------
int i=0;
for(i=0;i<lenbuff;i++){ // Bucle que pone a 0 todos los
cbuff[i]=0x00; // caracteres en el buffer
}
xbuff=0x00; // Inicializo el indice de siguiente
// caracter
}
int addcbuff(char c){ // Añade a cbuff -----------------------
switch(c){
case 0x0D: // Enter -> Habilita Flag para procesar
flagcommand=1; // Comando en Main
break;
case 0x08: // Del -> Borra último caracter del Buffer
if(xbuff>0) cbuff[--xbuff]=0x00;
break;
case 0x01B: // Esc -> Borra el Buffer completamente
inicbuff();
break;
default:
cbuff[xbuff++]=c; // Añade caracter recibido al Buffer
}
}
void procesa_comando(void){
int i=0;
int1 flag=0; // Indica si el comando es valido
char arg[lenbuff]; // Argumento de comando (si lo tiene)
flagcommand=0; // Desactivo flag de comando pendiente.
for(i=0;i<lenbuff;i++){ // Bucle que pone a 0 todos los
arg[i]=0x00; // caracteres en el argumento
}
if(cbuff[0]=='C'&&cbuff[1]=='1'&&cbuff[2]=='_'&&cbuff[3]=='O'&&cbuff[4]=='N'&&cbuff[5]==0x00){// Comparo inicio del buffer con comando "A1"
flag=1; // Activamos el flag para detectar comando valido
calentador_ON; // activamos puerta RB1 --> Calentador ON
disable_interrupts(int_ad);
printf("CALENTADOR --> Activado"); // mostramos stado calentador por RS232
enable_interrupts(int_AD); // Habilita las interrupciones globales
estado_calentador=1; // variable estado_calentador=ON
write_eeprom(0,estado_calentador); // Escribe en la primera posición de la eeprom el estado del calentador
}
if(cbuff[0]=='C'&&cbuff[1]=='1'&&cbuff[2]=='_'&&cbuff[3]=='O'&&cbuff[4]=='F'&&cbuff[5]=='F'&&cbuff[6]==0x00){
flag=1; // Activamos el flag para detectar comando valido
calentador_OFF; // desactivamos puerta RB1--> calentador OFF
disable_interrupts(int_ad);
printf("CALENTADOR --> Desactivado"); // Mostramos stdo calentador RS232
enable_interrupts(int_AD); // Habilita las interrupciones globales
estado_calentador=0; // Variable calentador=OFF
write_eeprom(0,estado_calentador); // Escribe en la primera posición de la eeprom el estado del calentador
}
if(cbuff[0]=='S'&&cbuff[1]=='T'&&cbuff[2]=='D'&&cbuff[3]=='O'&&cbuff[4]==0x00){
flag=1; // Activamos el flag para detectar comando valido
disable_interrupts(int_ad);
estado_calentador=read_eeprom(0); // Leemos en la primera posicion de la EEPROM el estado del calentador
if (estado_calentador==1) printf("CALENTADOR --> ESTADO ON"); // Escribimos por pantalla el estado del calentador
else printf("CALENTADOR --> ESTADO OFF");
enable_interrupts(int_AD); // Habilita las interrupciones globales
}
if(cbuff[0]=='V'&&cbuff[1]=='_'&&cbuff[2]=='C'&&cbuff[3]=='A'&&cbuff[4]=='D'&&cbuff[6]==0x00){
flag=1; // Activamos el flag para detectar comando valido
toma_adc_y_transmite();
}
if(cbuff[0]=='B'&&cbuff[1]=='O'&&cbuff[2]=='R'&&cbuff[3]=='R'&&cbuff[4]=='A'&&cbuff[5]=='R'&&cbuff[6]=='_' &&cbuff[7]=='E'&&cbuff[8]==0x00){
flag=1; // Activamos el flag para detectar comando valido
calentador_OFF; // desactivamos puerta RB1-->calentador OFF
write_eeprom(0,0); // Inicializamos a 0 las dos posiciones utilizadas
write_eeprom(1,0);
disable_interrupts(int_ad);
printf("EEPROM BORRADA");
enable_interrupts(int_AD); // Habilita las interrupciones globales
}
if(cbuff[0]=='R'&&cbuff[1]=='E'&&cbuff[2]=='S'&&cbuff[3]=='E'&&cbuff[4]=='T'&&cbuff[5]==0x00){
write_eeprom(0,estado_calentador); // Guardamos en la EEPROM el estado del calentador
flag_reset=1; // Activamos el flag de reset por consola
write_eeprom(1,flag_reset); // Guardamos el valor en la EEPROM
disable_interrupts(int_ad);
printf("RESET");
enable_interrupts(int_AD); // Habilita las interrupciones globales
// Bucle infinito para que el Watchdog resetee mi chiporro por Azicuetano
do{
}while(true);
}
if(cbuff[0]=='V'&&cbuff[1]=='E'&&cbuff[2]=='R'&&cbuff[3]=='S'&&cbuff[4]=='I'&&cbuff[5]=='O'&&cbuff[6]=='N'&&cbuff[8]==0x00){
flag=1; // Activamos el flag para detectar comando valido
disable_interrupts(int_ad);
printf("V3.5"); // Muestra por la RS232 lña versión del programa.
// lo utilizo mucho por que en Labview cada x tiempo mando el comando "VERSION"
// compruebo la comunicación si esta OK.
enable_interrupts(int_AD); // Habilita las interrupciones globales
}
if (flag==1){ // Si flag==1 es que se ha metido en algún if
flag=0; // pone a cero el flag
}
else{
disable_interrupts(int_ad);
printf("Comando no reconocido"); // Comando no reconocido
enable_interrupts(int_AD); // Habilita las interrupciones globales
}
// Una vez procesado el comando borrams por buffer de la RS232
inicbuff(); // Borro buffer.
}
////////////////////////////////////////////////////////////////////////////////
// PROGRAMA PRINCIPAL VOID MAIN() //
////////////////////////////////////////////////////////////////////////////////
void main() {
port_b_pullups(FALSE); // Resistencias de Pullup desactivadas
set_tris_B(0b0000001); // Configuramos entradas y salidas. RB1:7-->Salida ; RB0--> Entrada
setup_adc(ADC_CLOCK_DIV_32);
setup_adc_ports(AN0_AN1_AN3);
flag_reset=read_eeprom(1); //leemos la variable reset en eeprom
if (flag_reset==1){
printf("reset por consola");
}
calentador_OFF;
inicbuff(); // Borra buffer al inicio
enable_interrupts(int_rda);
enable_interrupts(int_ad);
// setup_wdt(WDT_18MS); // Configuramos el Watchdog para que salte a los 144ms
// RESTART_WDT(); // Incia o watch-dog timer
enable_interrupts(global);
canal=0;
Read_ADC(ADC_START_ONLY); // Inicia el CAD por int.
printf("\n\ AD - LM35a - Monitor\n\n"); // Presenta menu
lcd_init();
lcd_setcursor(0,0);
lcd_gotoxy(1,1);
printf(lcd_putc,"CAD Temp. LM35a \n foro todopic"); //muestra por la LCD
delay_ms(3000);
lcd_gotoxy(1,1);
printf(lcd_putc," V2.0 umalrovi \n foro todopic"); //muestra por la LCD
delay_ms(3000);
do {
visualiza_parametros_LCD();
if (flagcommand==1){
procesa_comando();
}
} while (TRUE);
}