#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#define __DELAY_BACKWARD_COMPATIBLE__
#include <avr/io.h> //standard AVR header
#include <util/delay.h> //delay header
#include <stdio.h>
#include <string.h>
#include "avr/interrupt.h"
#define LCD_Dir DDRA /* Define LCD data port direction */
#define LCD_Port PORTA /* Define LCD data port */
#define RS PA0 /* Define Register Select pin */
#define EN PA1 /* Define Enable signal pin */
String value = "";
int temp = 0;
int decimales = 2; // Decimales a tener
// TECLADO MATRICIAL
char Key = ' ';
char lastKey = ' ';
const char KEY[4][4] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}};
char string[50] = "";
int main(void)
{
DDRB = 0xF0; /* Make PORTB lower pins as output */
// Para el keypad
DDRK = 0xF0; // En 1111 columns output [1,2,3,4] and Rows input [A,B,C,D] en 0000
PORTK = 0X0F; // Pull-ups [A,B,C,D] 00001111
int i = 6;
LCD_Init(); /* Initialization of LCD*/
ADC_init (); // Inicia el ADC // Se activan las interrupciones
ADC_conversion ();
while(1){
String key = String(get_keypad());
LCD_String_xy(0, 0, "SET:");
LCD_String_xy(1, 0, "TEMP:");
ADC_read();
if (key =="*" ) { // Si se presiona '#', se termina la cadena y se convierte en entero
LCD_Clear();
value = "";
}
if (value.length() < 4 && key != "N" && key != "#" && key != "A" && key != "B" && key != "C" && key != "D" && key != "*") {
value += key;
LCD_String_xy(0,6,value);
LCD_String_xy(0, 13, "C");
}
if (key == "#" ) {
LCD_Clear();
temp = atoi(value);
value = "";
if (temp >=0 && temp <=500){
pwm(temp); }
}
// Verificar si value tiene 4 caracteres y restablecerlo a una cadena vacía
if (value.length() >= 4) {
value = "";
LCD_Clear();
}
}
}
char get_keypad(){
int column, n=100;
for (column=0; column<4; column++){
PORTK = (~(1 << (column+4)))|(0b00001111); // Pull-ups
if (!(PINK&0x01)){
_delay_ms(n);
return KEY[0][column];
}
else if (!(PINK&0x02)){
_delay_ms(n);
return KEY[1][column];
}
else if (!(PINK&0x04)){
_delay_ms(n);
return KEY[2][column];
}
else if (!(PINK&0x08)){
_delay_ms(n);
return KEY[3][column];
}
}
_delay_ms(n);
return 'N';
}
// LCD
void delay_us(int d)
{
_delay_us(d);
}
void delay_ms(int d)
{
_delay_ms(d);
}
void LCD_Command(unsigned char cmnd)
{
LCD_Port = (LCD_Port & 0x0F) | (cmnd & 0xF0); /* sending upper nibble */
LCD_Port &= ~(1 << RS); /* RS=0, command reg. */
LCD_Port |= (1 << EN); /* Enable pulse */
_delay_us(1);
LCD_Port &= ~(1 << EN);
_delay_us(200);
LCD_Port = (LCD_Port & 0x0F) | (cmnd << 4); /* sending lower nibble */
LCD_Port |= (1 << EN);
_delay_us(1);
LCD_Port &= ~(1 << EN);
_delay_ms(2);
}
void LCD_Char(unsigned char data)
{
LCD_Port = (LCD_Port & 0x0F) | (data & 0xF0); /* sending upper nibble */
LCD_Port |= (1 << RS); /* RS=1, data reg. */
LCD_Port |= (1 << EN);
_delay_us(1);
LCD_Port &= ~(1 << EN);
_delay_us(200);
LCD_Port = (LCD_Port & 0x0F) | (data << 4); /* sending lower nibble */
LCD_Port |= (1 << EN);
_delay_us(1);
LCD_Port &= ~(1 << EN);
_delay_ms(2);
}
void LCD_Init(void) /* LCD Initialize function */
{
LCD_Dir = 0xFF; /* Make LCD port direction as o/p */
_delay_ms(20); /* LCD Power ON delay always >15ms */
LCD_Command(0x02); /* send for 4 bit initialization of LCD */
LCD_Command(0x28); /* 2 line, 5*7 matrix in 4-bit mode */
LCD_Command(0x0c); /* Display on cursor off*/
LCD_Command(0x06); /* Increment cursor (shift cursor to right)*/
LCD_Command(0x01); /* Clear display screen*/
_delay_ms(2);
}
void LCD_String(const String &str) {
for (int i = 0; i < str.length(); ++i) {
LCD_Char(str.charAt(i));
}
}
void LCD_String_xy(char row, char pos, const String &str) {
if (row == 0 && pos < 16)
LCD_Command((pos & 0x0F) | 0x80); /* Command of the first row and required position<16 */
else if (row == 1 && pos < 16)
LCD_Command((pos & 0x0F) | 0xC0); /* Command of the second row and required position<16 */
LCD_String(str); /* Call LCD string function */
}
void LCD_Int(int y, int x, int num ) {
char buffer[7]; // Buffer para almacenar el número como cadena
int i = 0;
int isNegative = 0;
// Manejar números negativos
if (num < 0) {
isNegative = 1;
num = -num;
}
// Convertir número a cadena (en orden inverso)
do {
buffer[i++] = num % 10 + '0';
num /= 10;
} while (num != 0);
// Agregar signo negativo si es necesario
if (isNegative) {
buffer[i++] = '-';
}
// Invertir la cadena
for (int j = 0; j < i / 2; j++) {
char temp = buffer[j];
buffer[j] = buffer[i - j - 1];
buffer[i - j - 1] = temp;
}
// Agregar el carácter nulo al final de la cadena
buffer[i] = '\0';
// Calcular la posición en el LCD
int position = x + (y == 1 ? 0x40 : 0); // Si y es 1, ajusta la posición a la segunda línea
// Enviar comando para establecer la posición en el LCD
LCD_Command(position | 0x80);
// Imprimir la cadena en el LCD
LCD_String(buffer);
}
void LCD_Clear()
{
LCD_Command(0x01); /* Clear display */
_delay_ms(2);
LCD_Command(0x80); /* Cursor at the home position */
}
void LCD_PrintAtPosition(int y, int x, const char *text) {
// Calcular la posición en el LCD
int position = x + (y == 1 ? 0x40 : 0); // Si y es 1, ajusta la posición a la segunda línea
// Enviar comando para establecer la posición en el LCD
LCD_Command(position | 0x80);
// Imprimir la cadena de caracteres en el LCD
while (*text) {
LCD_Char(*text);
text++;
}
}
// Direccionamiento del cursor
void LCD_set_cursor (unsigned char x, unsigned char y) {
// No se, la copie directamente del libro
unsigned char firstCharAdr [] = {0x80, 0xC0, 0x94, 0xD4};
LCD_Command (firstCharAdr [y - 1] + x - 1);
_delay_ms(1);
}
int atoi(const String &str) {
int res = 0;
int sign = 1; // 1 para positivo, -1 para negativo
// Manejar signo
for (size_t t = 0; t < str.length(); ++t) {
char c = str.charAt(t);
if (c == '-') {
sign = -1;
} else if (c >= '0' && c <= '9') {
res = res * 10 + (c - '0');
}
}
return sign * res;
}
void ADC_read() {
int adc_value = ADCL | (ADCH << 8); // Leer el valor del ADC combinando ADCL y ADCH
float voltage = (float)adc_value * (5.0 / 1023.0);
ADC_conversion();
float sensor_lecture = (500*voltage/5);
char *sensor = decimal_a_string(sensor_lecture); // Se transforma el voltaje en una string
LCD_String_xy(1,6,sensor);
LCD_String_xy(1, 13, "C");
}
void ADC_init() {
ADMUX = (1 << REFS0); // Configurar referencia de voltaje en AVCC (conexión de 5V)
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Habilitar el ADC y configurar el preescalador a 128 para una conversión lenta
ADCSRA |= (1 << ADIE); // Habilitar interrupción de ADC
}
void ADC_conversion() {
ADMUX &= 0xF8; // Limpiar los bits MUX0, MUX1 y MUX2 para seleccionar ADC0 (PC0)
ADCSRA |= (1 << ADSC); // Iniciar la conversión
}
char *decimal_a_string(float n) {
static char string[20];
int parte_entera = (int)n;
float parte_decimal = n - parte_entera;
int i = 0;
if (n < 1) {
string[i++] = '0';
}
// Asegúrate de que el valor esté en el rango [0, 600]
n = (n < 0) ? 0 : (n > 600) ? 600 : n;
// Conversion de la parte entera en un string
while (parte_entera > 0) {
string[i++] = parte_entera % 10 + '0';
parte_entera /= 10;
}
if (i == 0) {
string[i++] = '0';
}
// Invertir la cadena de la parte entera
for (int j = 0, k = i - 1; j < k; j++, k--) {
char temp = string[j];
string[j] = string[k];
string[k] = temp;
}
string[i++] = '.'; // Agregar el punto decimal
// Conversion de la parte decimal en un string
for (int m = 0; m < decimales; m++) {
parte_decimal *= 10;
int digito = (int)parte_decimal;
string[i++] = digito + '0';
parte_decimal -= digito;
}
string[i] = '\0';
return string;
}
void pwm(int temp) {
// Set PH4 (OC4B) as an output for PWM signal (pin 7)
DDRH |= (1 << PH4);
// Configure Timer4 for PWM
TCNT4 = 0; // Reset Timer4
ICR4 = 39999; // Set top value for PWM
// Calculate DutyCycle based on temperature (0 to 500)
int dutyCycle = (temp * 100) / 500;
// Configure Timer4 for Fast PWM mode
TCCR4A = (1 << COM4B1) | (0 << COM4B0); // Non-inverting mode for OC4B
TCCR4A |= (1 << WGM11) | (0 << WGM10); // Fast PWM
TCCR4B = (1 << WGM13) | (1 << WGM12); // Fast PWM
TCCR4B |= (0 << CS12) | (1 << CS11) | (0 << CS10); // Prescaler 8
// Set the PWM value for OC4B based on duty cycle
OCR4B = (ICR4 * dutyCycle) / 100;
}