#include "pico/stdlib.h" // Biblioteca padrão do Pico SDK
#include "hardware/gpio.h" // Biblioteca para controle dos pinos GPIO
#include "hardware/pwm.h"
#include <stdio.h> // Biblioteca para entrada e saída padrão (printf, etc.)
#include <stdlib.h> // Biblioteca para alocação de memória dinâmica (malloc, free)
#include <stdint.h> // Biblioteca para tipos de dados inteiros de tamanho fixo (uint8_t, etc.)
#include <stdbool.h> // Biblioteca para tipo de dado booleano (true, false)
#include <string.h>
// Definição das constantes do cofre
#define PASSWORD_LENGTH 4 // Tamanho da senha
#define MAX_ATTEMPTS 3 // Máximo de tentativas
#define BLOCK_TIME_MS 30000 // Bloqueio de 30 segundos
// Definição dos pinos do teclado matricial
#define ROWS 4
#define COLS 3
const uint8_t row_pins[ROWS] = {2, 3, 4, 5};
const uint8_t col_pins[COLS] = {6, 7, 8};
// Mapa de teclas do teclado matricial
const char key_map[ROWS][COLS] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
// Variáveis Globais do cofre
const char correct_password[PASSWORD_LENGTH + 1] = "1234"; // Senha predefinida (inclui o caractere nulo)
char entered_password[PASSWORD_LENGTH + 1] = ""; // Senha digitada pelo usuário
// Servo Motor
#define SERVO_PIN 22 // GPIO 22 para o servomotor
#define SERVO_LOCKED_DUTY 500 // Duty cycle para a posição "travada"
#define SERVO_UNLOCKED_DUTY 2400 // Duty cycle para a posição "destravada"
// Definições e estruturas para o TM1637 (copiado do seu código)
#define TM1637_CMD1 64 // 0x40 Comando de dados (incremento de endereço, modo normal)
#define TM1637_CMD2 192 // 0xC0 Comando de endereço (define o endereço inicial da memória do display)
#define TM1637_CMD3 128 // 0x80 Comando de controle do display (liga/desliga, define o brilho)
#define TM1637_DSP_ON 8 // 0x08 Bit para ligar o display
#define TM1637_DELAY 10 // 10us de delay entre os pulsos de clock e dados (para o timing do TM1637)
static const uint8_t _SEGMENTS[] = {
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71,
0x3D, 0x76, 0x06, 0x1E, 0x76, 0x38, 0x55, 0x54, 0x3F, 0x73, 0x67, 0x50, 0x6D, 0x78, 0x3E, 0x1C,
0x2A, 0x76, 0x6E, 0x5B, 0x00, 0x40, 0x63};
typedef struct {
int clk_pin;
int dio_pin;
int brightness;
} TM1637;
// Protótipos das funções (organizados por módulo)
// Keypad
char read_keypad();
void read_password(char *password, int max_length);
int compare_passwords(const char *password, const char *correct_password);
// Servo
void init_servo();
void set_servo_locked();
void set_servo_unlocked();
// TM1637 (Display)
TM1637 *TM1637_create(int clk_pin, int dio_pin, int brightness);
void TM1637_init(TM1637 *display, int clk_pin, int dio_pin, int brightness);
void TM1637_start(TM1637 *display);
void TM1637_stop(TM1637 *display);
void TM1637_write_data_cmd(TM1637 *display);
void TM1637_write_dsp_ctrl(TM1637 *display);
void TM1637_write_byte(TM1637 *display, uint8_t b);
int TM1637_brightness(TM1637 *display, int val);
void TM1637_write(TM1637 *display, uint8_t *segments, int pos);
uint8_t *TM1637_encode_string(TM1637 *display, const char *string);
uint8_t TM1637_encode_char(TM1637 *display, char c);
void TM1637_number(TM1637 *display, int num);
void TM1637_show(TM1637 *display, const char *string, bool colon);
void TM1637_free(TM1637 *display);
// Implementações das funções (organizadas por módulo)
// Keypad
char read_keypad() {
for (int col = 0; col < COLS; col++) {
gpio_init(col_pins[col]);
gpio_set_dir(col_pins[col], GPIO_OUT);
gpio_put(col_pins[col], 0);
for (int row = 0; row < ROWS; row++) {
gpio_init(row_pins[row]);
gpio_set_dir(row_pins[row], GPIO_IN);
gpio_pull_up(row_pins[row]);
if (gpio_get(row_pins[row]) == 0) {
sleep_ms(50);
while (gpio_get(row_pins[row]) == 0);
return key_map[row][col];
}
}
gpio_put(col_pins[col], 1);
gpio_set_dir(col_pins[col], GPIO_IN);
}
return '\0';
}
void read_password(char *password, int max_length) {
int i = 0;
char key;
memset(password, 0, max_length + 1); // Limpar a string antes de usar
// Mostrar mensagem no display
//TM1637_show(mydisplay, "CODE", false); // <== Acesso ao display aqui causaria problema!
printf("Digite a senha (e '#' para confirmar):\n");
while (i < max_length) {
key = read_keypad();
if (key != '\0') {
if (key == '#') {
password[i] = '\0'; // Terminar a string
printf("\nSenha digitada: %s\n", password);
return;
} else {
password[i] = key;
i++;
printf("*"); // Mostrar um asterisco para cada caractere digitado
}
}
sleep_ms(50);
}
password[max_length] = '\0'; // Garante que a string seja terminada
printf("\nSenha digitada: %s (tamanho máximo atingido)\n", password);
}
int compare_passwords(const char *password, const char *correct_password) {
return strcmp(password, correct_password); // Retorna 0 se as senhas forem iguais
}
// Servo
void init_servo() {
gpio_set_function(SERVO_PIN, GPIO_FUNC_PWM);
uint slice_num = pwm_gpio_to_slice_num(SERVO_PIN);
pwm_config config = pwm_get_default_config();
pwm_config_set_clkdiv(&config, 125.0f);
pwm_init(slice_num, &config, true);
}
void set_servo_locked() {
pwm_set_gpio_level(SERVO_PIN, SERVO_LOCKED_DUTY);
printf("Cofre travado!\n");
}
void set_servo_unlocked() {
pwm_set_gpio_level(SERVO_PIN, SERVO_UNLOCKED_DUTY);
printf("Cofre destravado!\n");
}
// TM1637 (Display) - Copiado e colado do seu código (com algumas pequenas correções)
TM1637 *TM1637_create(int clk_pin, int dio_pin, int brightness) {
TM1637 *display = (TM1637 *)malloc(sizeof(TM1637));
if (display == NULL) {
perror("Falha ao alocar memória para TM1637");
exit(EXIT_FAILURE);
}
TM1637_init(display, clk_pin, dio_pin, brightness);
return display;
}
void TM1637_init(TM1637 *display, int clk_pin, int dio_pin, int brightness) {
display->clk_pin = clk_pin;
display->dio_pin = dio_pin;
if (brightness < 0 || brightness > 7) {
fprintf(stderr, "Erro: Brilho fora do intervalo (0-7). Definindo para o padrão (7).\n");
display->brightness = 7;
} else {
display->brightness = brightness;
}
gpio_init(display->clk_pin);
gpio_set_dir(display->clk_pin, GPIO_OUT);
gpio_init(display->dio_pin);
gpio_set_dir(display->dio_pin, GPIO_OUT);
gpio_put(display->clk_pin, 0);
gpio_put(display->dio_pin, 0);
sleep_us(TM1637_DELAY);
TM1637_write_data_cmd(display);
TM1637_write_dsp_ctrl(display);
}
void TM1637_start(TM1637 *display) {
gpio_put(display->dio_pin, 0);
sleep_us(TM1637_DELAY);
gpio_put(display->clk_pin, 0);
sleep_us(TM1637_DELAY);
}
void TM1637_stop(TM1637 *display) {
gpio_put(display->dio_pin, 0);
sleep_us(TM1637_DELAY);
gpio_put(display->clk_pin, 1);
sleep_us(TM1637_DELAY);
gpio_put(display->dio_pin, 1);
}
void TM1637_write_data_cmd(TM1637 *display) {
TM1637_start(display);
TM1637_write_byte(display, TM1637_CMD1);
TM1637_stop(display);
}
void TM1637_write_dsp_ctrl(TM1637 *display) {
TM1637_start(display);
TM1637_write_byte(display, TM1637_CMD3 | TM1637_DSP_ON | display->brightness);
TM1637_stop(display);
}
void TM1637_write_byte(TM1637 *display, uint8_t b) {
for (int i = 0; i < 8; i++) {
gpio_put(display->dio_pin, (b >> i) & 1);
sleep_us(TM1637_DELAY);
gpio_put(display->clk_pin, 1);
sleep_us(TM1637_DELAY);
gpio_put(display->clk_pin, 0);
sleep_us(TM1637_DELAY);
}
gpio_put(display->clk_pin, 0);
sleep_us(TM1637_DELAY);
gpio_put(display->clk_pin, 1);
sleep_us(TM1637_DELAY);
gpio_put(display->clk_pin, 0);
sleep_us(TM1637_DELAY);
}
int TM1637_brightness(TM1637 *display, int val) {
if (val == -1) {
return display->brightness;
}
if (val < 0 || val > 7) {
fprintf(stderr, "Erro: Brilho fora do intervalo (0-7).\n");
return -1;
}
display->brightness = val;
TM1637_write_data_cmd(display);
TM1637_write_dsp_ctrl(display);
return 0;
}
void TM1637_write(TM1637 *display, uint8_t *segments, int pos) {
if (pos < 0 || pos > 5) {
fprintf(stderr, "Erro: Posição fora do intervalo (0-5).\n");
return;
}
TM1637_write_data_cmd(display);
TM1637_start(display);
TM1637_write_byte(display, TM1637_CMD2 | pos);
for (int i = 0; i < 4; i++) {
TM1637_write_byte(display, segments[i]);
}
TM1637_stop(display);
TM1637_write_dsp_ctrl(display);
}
uint8_t *TM1637_encode_string(TM1637 *display, const char *string) {
int len = 0;
while (string[len] != '\0' && len < 4) {
len++;
}
uint8_t *segments = (uint8_t *)malloc(len * sizeof(uint8_t));
if (segments == NULL) {
perror("Falha ao alocar memória para segmentos");
exit(EXIT_FAILURE);
}
for (int i = 0; i < len; i++) {
segments[i] = TM1637_encode_char(display, string[i]);
}
return segments;
}
uint8_t TM1637_encode_char(TM1637 *display, char c) {
int o = (int)c;
if (o == 32) {
return _SEGMENTS[36]; // espaço
} else if (o == 42) {
return _SEGMENTS[38]; // estrela/graus
} else if (o == 45) {
return _SEGMENTS[37]; // traço
} else if (o >= 65 && o <= 90) {
return _SEGMENTS[o - 55]; // A-Z maiúsculo
} else if (o >= 97 && o <= 122) {
return _SEGMENTS[o - 87]; // a-z minúsculo
} else if (o >= 48 && o <= 57) {
return _SEGMENTS[o - 48]; // 0-9
} else {
fprintf(stderr, "Erro: Caractere fora do intervalo: %d '%c'\n", o, (char)o);
return 0x00;
}
}
void TM1637_number(TM1637 *display, int num) {
num = (num < -999) ? -999 : (num > 9999) ? 9999 : num;
char string[5];
snprintf(string, sizeof(string), "%4d", num);
uint8_t *segments = TM1637_encode_string(display, string);
TM1637_write(display, segments, 0);
free(segments);
}
void TM1637_show(TM1637 *display, const char *string, bool colon) {
uint8_t *segments = TM1637_encode_string(display, string);
int len = 0;
while (string[len] != '\0' && len < 4) {
len++;
}
uint8_t display_segments[4] = {0, 0, 0, 0};
for (int i = 0; i < len && i < 4; i++) {
display_segments[i] = segments[i];
}
TM1637_write(display, display_segments, 0);
free(segments);
}
void TM1637_free(TM1637 *display) {
free(display);
}
// Variável global para o display
TM1637 *mydisplay;
int main() {
stdio_init_all();
sleep_ms(2000);
printf("Iniciando...\n");
// Inicializa o servo motor
init_servo();
set_servo_locked(); // Inicialmente travado
// Inicializa o display TM1637
int clk_pin = 26;
int dio_pin = 27;
mydisplay = TM1637_create(clk_pin, dio_pin, 7);
// Exibe "LOCK" inicialmente
TM1637_show(mydisplay, "LOCK", false);
while (true) {
//TM1637_show(mydisplay, "CODE", false); // Movemos para dentro da read_password não funciona bem.
read_password(entered_password, PASSWORD_LENGTH);
if (compare_passwords(entered_password, correct_password) == 0) {
printf("Senha correta!\n");
TM1637_show(mydisplay, "OPEN", false);
set_servo_unlocked();
sleep_ms(5000); // Mantém destravado por 5 segundos
set_servo_locked();
TM1637_show(mydisplay, "LOCK", false); // Volta a mostrar "LOCK"
} else {
printf("Senha incorreta.\n");
TM1637_show(mydisplay, "FAIL", false);
printf("Cofre permanece travado!\n");
sleep_ms(2000);
TM1637_show(mydisplay, "LOCK", false); // Volta a mostrar "LOCK"
}
sleep_ms(1000); // Pequeno delay antes de pedir a senha novamente
}
}