Hola a todos, estoy realizando un sistema de medición de un canal análogo del Atmega328p, estoy usando un sensor LM35, tambien estoy usando un LCD 16x2 para mostrar la lectura del sensor. La idea es que se vaya sensando dicho canal, muestre los datos y a la vez un LED haga blink cada 1 segundo como indicador que el sistema esta funcionando y para esto estoy usando el Timer1 y su interrupcion por desbordamiento, adicionalmente usaré la UART para la conexion con un modulo GSM para que realice notificaciones cada vez que tenga una temperatura top. Pero tengo el problema que cada vez que sucede la interrupcion el dato que se muestra en la LCD del ADC se duplica, es decir, antes que ocurra la interrupcion el LCD muestra por ejemplo : 26. 30 ºC -- Ocurre la interrupcion(prende el led) y el valor pasa a mostrarse 52.60 ºC. En simulacion se ve funciona bien pero lo manté y me di cuenta de este detalle. Quizás alguien pueda darme alguna sugerencia, todo critica es bien recibida para mejorar.
Gracias de antemano;
*El código lo hice en Atmel Studio 7
*Estoy usando oscilador interno de 1 MHz
*Adjunto código y las librerias de ADC y LCD.
Gracias de antemano;
*El código lo hice en Atmel Studio 7
*Estoy usando oscilador interno de 1 MHz
*Adjunto código y las librerias de ADC y LCD.
Código:
#define F_CPU 1000000UL
#include <avr/io.h>
#include <stdio.h>
#include <stdint.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "lcd.h"
#include "ADC.h"
void Config_TMR1(void);
void Config_Interrupt_TMR1(void);
float Temp = 0.0;
char Str_Temp[6];
int main(void)
{
Lcd_Init();
Lcd_Clear();
Config_TMR1();
Config_Interrupt_TMR1();
DDRB |= (1<<DDB2); //B2 COMO SALIDA
PORTB &= ~(1<<PORTB2); //B2 INICIA EN OFF
while (1)
{
//Inicia lectura de ADC0, conversion y envio por LCD
Temp = (analogRead(ADC0)*(VREF/RESOLUCION))/0.01;
sprintf(Str_Temp, "%.2f", Temp);
Lcd_Set_Cursor(1,1);
Lcd_Write_String("Sist. de alarma");
Lcd_Set_Cursor(2,1);
Lcd_Write_String("Temp: ");
Lcd_Write_String(Str_Temp);
}
}
ISR(TIMER1_OVF_vect){
TCNT1 = 49911; //Cargar nuevamente al TMR1 para generar 1 segundo
//Aplicacion
PORTB ^= (1<<PORTB2);
}
void Config_TMR1(void){
TCCR1B |= (0<<CS12)|(1<<CS11)|(1<<CS10); //Elijo un preescaler de x64
TCNT1 = 49911; //Carga para generar 1 segundo
}
void Config_Interrupt_TMR1(void){
TIMSK1 |= (1<<TOIE1); //Habilito la interrup. por desbordamiento de TMR1
sei();
}
Código:
/*********************************************************************
*Libreria para LCD 16x2
*********************************************************************/
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
//****************************************************************************
// CONFIGURACIÓN DE LOS PINES DE INTERFACE
//****************************************************************************
/* Define el puerto a donde se conectará el BUS de datos del LCD
* Se utilizará el nible alto del puerto escogido (ejem. PB4-DB4,...,PB7-DB7) */
#define LCD_DATA_OUT PORTD // Registro PORT del puerto
#define LCD_DATA_DDR DDRD // Registro DDR del puerto
/* Define el puerto a donde se conectarán las líneas de control del LCD
* EN y RS (Puede ser el mismo puerto del BUS de datos) */
#define LCD_CTRL_OUT PORTB // Registro PORT del puerto
#define LCD_CTRL_DDR DDRB // Registro DDR del puerto
//Define los numeros de bits a donde se conectará el modulo LCD
#define RS 0 // Pin Register Select
#define EN 1 // Pin Enable
#define D4 4 //define el pin del MCU conectado LCD D4
#define D5 5 //define el pin del MCU conectado LCD D5
#define D6 6 //define el pin del MCU conectado LCD D6
#define D7 7 //define el pin del MCU conectado LCD D7
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void Lcd_Port(unsigned char a)
{
if(a & 1)
//D4 = 1;
LCD_DATA_OUT |= (1<<D4);
else
//D4 = 0;
LCD_DATA_OUT &= ~(1<<D4);
if(a & 2)
//D5 = 1;
LCD_DATA_OUT |= (1<<D5);
else
//D5 = 0;
LCD_DATA_OUT &= ~(1<<D5);
if(a & 4)
//D6 = 1;
LCD_DATA_OUT |= (1<<D6);
else
//D6 = 0;
LCD_DATA_OUT &= ~(1<<D6);
if(a & 8)
//D7 = 1;
LCD_DATA_OUT |= (1<<D7);
else
//D7 = 0;
LCD_DATA_OUT &= ~(1<<D7);
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void Lcd_Cmd(unsigned char a)
{
LCD_CTRL_OUT &= ~(1<<RS);// => RS = 0
Lcd_Port(a);
LCD_CTRL_OUT |= (1<<EN);// => EN = 1
_delay_ms(4);
LCD_CTRL_OUT &= ~(1<<EN);// => EN = 0
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void Lcd_Init( void ) // Esta funcion permite inicializar el modulo LCD
{
/* Configurar las direcciones de los pines de interface del LCD */
LCD_DATA_DDR |= 0xF0; //Configuro los pines del BUS de datos del LCD como salida
LCD_CTRL_DDR |= (1<<EN)|(1<<RS);//Configuro los pines de control del LCD como salida
Lcd_Port(0x00);
_delay_ms(20);
Lcd_Cmd(0x03);
_delay_ms(5);
Lcd_Cmd(0x03);
_delay_ms(11);
Lcd_Cmd(0x03);
/////////////////////////////////////////////////////
Lcd_Cmd(0x02);
Lcd_Cmd(0x02);
Lcd_Cmd(0x08);
Lcd_Cmd(0x00);
Lcd_Cmd(0x0C);
Lcd_Cmd(0x00);
Lcd_Cmd(0x06);
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void Lcd_Clear( void ) //Funcion que permite limpiar la pantalla LCD
{
Lcd_Cmd(0);
Lcd_Cmd(1);
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//Esta funcion posiciona el cursor del modulo LCD
void Lcd_Set_Cursor(unsigned char a, unsigned char b)
{
char temp,z,y;
if(a == 1)
{
temp = 0x80 + b - 1;
z = temp>>4;
y = temp & 0x0F;
Lcd_Cmd(z);
Lcd_Cmd(y);
}
else if(a == 2)
{
temp = 0xC0 + b - 1;
z = temp>>4;
y = temp & 0x0F;
Lcd_Cmd(z);
Lcd_Cmd(y);
}
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//Esta funcion imprime un caracter en el modulo LCD
void Lcd_Write_Char(char a)
{
char temp,y;
temp = a&0x0F;
y = a&0xF0;
LCD_CTRL_OUT |= (1<<RS);// => RS = 1
Lcd_Port(y>>4); //Transferencia de datos (formto 4 bits)
LCD_CTRL_OUT |= (1<<EN);// => EN = 1
_delay_us(40);
LCD_CTRL_OUT &= ~(1<<EN);// => EN = 0
Lcd_Port(temp); //Transferencia de datos (formto 4 bits)
LCD_CTRL_OUT |= (1<<EN);// => EN = 1
_delay_us(40);
LCD_CTRL_OUT &= ~(1<<EN);// => EN = 0
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//Esta funcion imprime un String (cadena) en el modulo LCD
void Lcd_Write_String(char *a)
{
int i;
for(i=0;a[i]!='\0';i++)
Lcd_Write_Char(a[i]);
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void Lcd_Shift_Right( void )
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x0C);
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void Lcd_Shift_Left( void )
{
Lcd_Cmd(0x01);
Lcd_Cmd(0x08);
}
Código:
//**Libreria para ADC Atmega328p **
//** Marcelo Higa**
#define F_CPU 1000000UL
#include <avr/io.h>
#define ADC0 0
#define ADC1 1
#define ADC2 2
#define ADC3 3
#define ADC4 4
#define ADC5 5
#define ADC6 6
#define ADC7 7
#define VREF 5.0
#define RESOLUCION 1024
void Config_ADC(void); //Funcion vacia
void Leer_Canal(uint8_t canal); //Funcion con entrada de parametro
uint16_t analogRead(uint16_t canal); //Funcion con entrada de parametro y retorno de valor
void Config_ADC(void){
ADMUX = 0X40; // VOLTAJE DE REFERENCIA DEL uC, JUSTIFICACION DEL RESULTADO A LA DERECHA
ADCSRA |= (0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); //ELEGIMOS EL CLOCK DEL RELOJ A 125 KH
DIDR0 = 0XFF; //DESHABILITO EL CANAL DIGITAL DE TODOS LOS CANALES
}
void Leer_Canal(uint8_t canal){
ADMUX = 0X40; //ACTUALIZO EL ADMUX
ADMUX |= canal; //SELECCIONO EL CANAL
}
uint16_t analogRead(uint16_t canal){
ADMUX = 0X40; //ACTUALIZO EL ADMUX
ADMUX |= canal; //SELECCIONO EL CANAL
ADCSRA |= (1<<ADEN) | (1<<ADSC); //HABILITO EL MODULO ADC E INICIO LA CONVERSION
while((ADCSRA & (1<<ADSC)) != 0); //ESPERO A QUE LA CONVERSION TERMINE
ADCSRA &= ~(1<<ADEN); //DESHABILITO EL MODULO ADC
return(ADC); //Retorna el valor al registro ADC
}