#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/i2c.h"
#include "hardware/pwm.h"
#include "pico/binary_info.h"
// LCD handling method extracted forom the SDK examples.
// LCD commands
const int LCD_CLEARDISPLAY = 0x01;
const int LCD_RETURNHOME = 0x02;
const int LCD_ENTRYMODESET = 0x04;
const int LCD_DISPLAYCONTROL = 0x08;
const int LCD_CURSORSHIFT = 0x10;
const int LCD_FUNCTIONSET = 0x20;
const int LCD_SETCGRAMADDR = 0x40;
const int LCD_SETDDRAMADDR = 0x80;
// flags for display entry mode
const int LCD_ENTRYSHIFTINCREMENT = 0x01;
const int LCD_ENTRYLEFT = 0x02;
// flags for display and cursor control
const int LCD_BLINKON = 0x01;
const int LCD_CURSORON = 0x02;
const int LCD_DISPLAYON = 0x04;
// flags for display and cursor shift
const int LCD_MOVERIGHT = 0x04;
const int LCD_DISPLAYMOVE = 0x08;
// flags for function set
const int LCD_5x10DOTS = 0x04;
const int LCD_2LINE = 0x08;
const int LCD_8BITMODE = 0x10;
// flag for backlight control
const int LCD_BACKLIGHT = 0x08;
const int LCD_ENABLE_BIT = 0x04;
// By default these LCD display drivers are on bus address 0x27
static int addr = 0x27;
// Modes for lcd_send_byte
#define LCD_CHARACTER 1
#define LCD_COMMAND 0
#define MAX_LINES 2
#define MAX_CHARS 16
// Global variables, constants, functions and interrupts
// Matrix Definitions
#define Row_1 6
#define Row_2 7
#define Row_3 8
#define Row_4 9
#define Col_1 10
#define Col_2 11
#define Col_3 12
// Buzzer and Potentiometer Definitions
#define BUZZER_PIN 16
#define ADC_IN 26
// Logic Constant Definitions
#define CLOCK_DIV 64
#define DEBOUNCE_DELAY 50 // ms
int row_index = 0;
int column_index = 0;
int vil = 0;
int adc_inc = 0;
uint32_t last_button_time = 0;
int positions = 10000; // Changed from 100 to 10000 for 5 digits
// Frequency Related Definitions
int waiter = 250;
int frequency = 0;
int real_frequency = 0;
int volume = 0;
// Function declarations
void i2c_write_byte(uint8_t val);
void lcd_toggle_enable(uint8_t val);
void lcd_send_byte(uint8_t val, int mode);
void lcd_clear(void);
void lcd_set_cursor(int line, int position);
void lcd_char(char val);
void lcd_string(const char *s);
void lcd_init();
void detect_column(int row_index);
bool decrementar_ISR(struct repeating_timer *t);
void general_callback(uint gpio, uint32_t event_mask);
void cancelar_freq();
void aceptar_freq();
void unit_freq(int num);
void change_freq(int row_index, int column_index);
// Function implementations
void i2c_write_byte(uint8_t val) {
#ifdef i2c_default
i2c_write_blocking(i2c_default, addr, &val, 1, false);
#endif
}
void lcd_toggle_enable(uint8_t val) {
sleep_us(600);
i2c_write_byte(val | LCD_ENABLE_BIT);
sleep_us(600);
i2c_write_byte(val & ~LCD_ENABLE_BIT);
sleep_us(600);
}
void lcd_send_byte(uint8_t val, int mode) {
uint8_t high = mode | (val & 0xF0) | LCD_BACKLIGHT;
uint8_t low = mode | ((val << 4) & 0xF0) | LCD_BACKLIGHT;
i2c_write_byte(high);
lcd_toggle_enable(high);
i2c_write_byte(low);
lcd_toggle_enable(low);
}
void lcd_clear(void) {
lcd_send_byte(LCD_CLEARDISPLAY, LCD_COMMAND);
}
void lcd_set_cursor(int line, int position) {
int val = (line == 0) ? 0x80 + position : 0xC0 + position;
lcd_send_byte(val, LCD_COMMAND);
}
void lcd_char(char val) {
lcd_send_byte(val, LCD_CHARACTER);
}
void lcd_string(const char *s) {
while (*s) {
lcd_char(*s++);
}
}
void lcd_init() {
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x02, LCD_COMMAND);
lcd_send_byte(LCD_ENTRYMODESET | LCD_ENTRYLEFT, LCD_COMMAND);
lcd_send_byte(LCD_FUNCTIONSET | LCD_2LINE, LCD_COMMAND);
lcd_send_byte(LCD_DISPLAYCONTROL | LCD_DISPLAYON, LCD_COMMAND);
lcd_clear();
}
void general_callback(uint gpio, uint32_t event_mask) {
uint32_t current_time = to_ms_since_boot(get_absolute_time());
if (current_time - last_button_time < DEBOUNCE_DELAY) {
return; // Ignorar pulsaciones muy cercanas en el tiempo
}
last_button_time = current_time;
printf("Interrupción en GPIO %d\n", gpio);
if (gpio == Row_1 && waiter == 0) {
row_index = 1;
} else if (gpio == Row_2 && waiter == 0) {
row_index = 2;
} else if (gpio == Row_3 && waiter == 0) {
row_index = 3;
} else if (gpio == Row_4 && waiter == 0) {
row_index = 4;
}
waiter = 50;
}
bool decrementar_ISR(struct repeating_timer *t) {
if (waiter != 0) waiter--;
adc_inc--;
return true;
}
void detect_column(int row_index) {
for (int i = 0; i < 3; i++) {
gpio_put(Col_1, i == 0);
gpio_put(Col_2, i == 1);
gpio_put(Col_3, i == 2);
sleep_us(10); // Pequeña pausa para estabilización
if (gpio_get(row_index + Row_1-1) == 1) {
column_index = i + 1;
printf("row_index: %d, column_index detectada: %d\n", row_index, column_index);
return;
}
}
column_index = 0; // No se detectó ninguna column_index
printf("row_index: %d, No se detectó column_index\n", row_index);
}
void change_freq(int row_index, int column_index) {
if (row_index == 1 && column_index == 1) unit_freq(1);
if (row_index == 1 && column_index == 2) unit_freq(2);
if (row_index == 1 && column_index == 3) unit_freq(3);
if (row_index == 2 && column_index == 1) unit_freq(4);
if (row_index == 2 && column_index == 2) unit_freq(5);
if (row_index == 2 && column_index == 3) unit_freq(6);
if (row_index == 3 && column_index == 1) unit_freq(7);
if (row_index == 3 && column_index == 2) unit_freq(8);
if (row_index == 3 && column_index == 3) unit_freq(9);
if (row_index == 4 && column_index == 1) cancelar_freq();
if (row_index == 4 && column_index == 2) unit_freq(0);
if (row_index == 4 && column_index == 3) aceptar_freq();
}
void cancelar_freq() {
gpio_put(16, 0); // Turn Buzzer Down to Avoid Noise
frequency = 0;
positions = 10000; // Reset to 10000 for 5 digits
real_frequency = 0;
}
void aceptar_freq() {
if (frequency <= 20000) { // Limit to 20,000 Hz
real_frequency = frequency;
} else {
real_frequency = 20000; // Cap at 20,000 Hz
frequency = 20000;
}
}
void unit_freq(int num) {
if (positions < 1) positions = 0;
frequency += positions * num;
positions /= 10;
}
int main() {
stdio_init_all();
gpio_init_mask(0xffff);
// This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
i2c_init(i2c_default, 100 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
// Pines de entrada y salida
gpio_set_dir_out_masked(0xf); //leds de prueba
gpio_set_dir_in_masked(0x3C0); // Entradas
gpio_set_dir_out_masked(0x3C00);
// Configurar pull-down para las row_indexs
gpio_set_pulls(Row_1, false, true);
gpio_set_pulls(Row_2, false, true);
gpio_set_pulls(Row_3, false, true);
gpio_set_pulls(Row_4, false, true);
// Configurar column_indexs como salidas
gpio_set_dir(Col_1, GPIO_OUT);
gpio_set_dir(Col_2, GPIO_OUT);
gpio_set_dir(Col_3, GPIO_OUT);
// ADC
adc_init();
adc_gpio_init(ADC_IN); //adc gpio 26 y adc 0
//PWM
gpio_set_function(BUZZER_PIN, GPIO_FUNC_PWM);
uint slice_num = pwm_gpio_to_slice_num(BUZZER_PIN);
pwm_set_clkdiv_int_frac(slice_num, CLOCK_DIV, 0);
// Timer
struct repeating_timer timer;
add_repeating_timer_ms(1, decrementar_ISR, NULL, &timer);
// Botones
gpio_set_mask(0x1C00);
gpio_set_irq_enabled_with_callback(Row_1, GPIO_IRQ_EDGE_RISE, true, &general_callback);
gpio_set_irq_enabled_with_callback(Row_2, GPIO_IRQ_EDGE_RISE, true, &general_callback);
gpio_set_irq_enabled_with_callback(Row_3, GPIO_IRQ_EDGE_RISE, true, &general_callback);
gpio_set_irq_enabled_with_callback(Row_4, GPIO_IRQ_EDGE_RISE, true, &general_callback);
// Pantalla
lcd_init();
static char *message[] = {
"Freq: %05d Hz", // Changed to %05d for 5 digits
"Vol : %3d %%"
};
char buffer[100];
while (1) {
// Leer matriz
if (row_index != 0) {
detect_column(row_index);
gpio_put(column_index-1,!gpio_get(column_index-1));//led
gpio_set_mask(0x1C00); //prender column_indexs
change_freq(row_index,column_index);
row_index = 0;
column_index = 0;
}
// ADC read
if (adc_inc <= 0) {
const float conversion_factor = 3.3f / (1 << 12);
adc_inc = 200;
adc_select_input(0);
volume = adc_read() * conversion_factor * 100 * 100 / 329;
}
// PWM values
if (real_frequency >= 20) { // Cambiado de 10 a 20 Hz
uint32_t wrap = (125000000 / (real_frequency * CLOCK_DIV)) - 1;
pwm_set_wrap(slice_num, wrap);
pwm_set_chan_level(slice_num, PWM_CHAN_A, wrap * volume / 100);
pwm_set_enabled(slice_num, true); // Habilitar PWM
} else {
pwm_set_enabled(slice_num, false); // Deshabilitar PWM si la frequency es menor a 20 Hz
}
//Imprimir LCD
sprintf(buffer,message[0],frequency);
lcd_set_cursor(0,1);
lcd_string(buffer);
sprintf(buffer,message[1],volume);
lcd_set_cursor(1,2);
lcd_string(buffer);
}
}