// Antonio Sergio Castro de Carvalho Junior
// Sistema de segurança com teclado matricial e display 7 segmentos
// Senha predefinida: 1234 (pode alterar os valores em correct_password para mudar)
// Três tentativas falhas bloqueiam o sistema por 30 segundos
// Servo motor simula a trava do cofre
// LED verde indica acesso liberado, vermelho indica falha/bloqueio
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/time.h"
#include "hardware/pwm.h"
// ************ CONFIGURAÇÃO DE PINOS ************
// Pinos dos segmentos do display (A-G)
const uint8_t segment_pins[] = {0, 1, 2, 3, 4, 5, 6};
// Pinos de seleção dos displays (multiplexação)
const uint8_t mux_display_pins[] = {10, 11, 12, 13};
// Configuração do teclado matricial
// Linhas (rows) como saídas, colunas (cols) como entradas
const uint8_t row_pins[4] = {14, 15, 16, 17}; // Linhas 1-4
const uint8_t col_pins[4] = {18, 19, 20, 21}; // Colunas 1-4
// LEDs indicadores
const uint8_t green_led_pin = 22; // LED verde (acesso liberado)
const uint8_t red_led_pin = 26; // LED vermelho (erro/bloqueio)
// Controle do servo motor
const uint servo_pin = 28; // Pino do servo motor
// ************ TABELAS DE CONVERSÃO ************
// Mapeamento dos dígitos para os segmentos (0-9)
const uint8_t display[10][7] = {
//A,B,C,D,E,F,G
{1,1,1,1,1,1,0}, // 0
{0,1,1,0,0,0,0}, // 1
{1,1,0,1,1,0,1}, // 2
{1,1,1,1,0,0,1}, // 3
{0,1,1,0,0,1,1}, // 4
{1,0,1,1,0,1,1}, // 5
{1,0,1,1,1,1,1}, // 6
{1,1,1,0,0,0,0}, // 7
{1,1,1,1,1,1,1}, // 8
{1,1,1,0,0,1,1} // 9
};
// Mapeamento das teclas do keypad
const char keys[4][4] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
// ************ VARIÁVEIS GLOBAIS ************
const uint8_t correct_password[4] = {1,2,3,4}; // Senha correta
uint8_t digit_buffer[4] = {255,255,255,255}; // Buffer de dígitos (255 = vazio)
// Controle de temporização
bool waiting_to_clear_buffer = false; // Flag para limpar display
absolute_time_t buffer_clear_time; // Tempo para limpeza do buffer
// Controle de segurança
int failed_attempts = 0; // Contador de tentativas falhas
bool is_locked = false; // Estado de bloqueio
absolute_time_t lock_release_time; // Tempo de desbloqueio
// Configuração do servo motor
uint slice_num; // Slice PWM do servo
uint channel; // Canal PWM do servo
const float SERVO_MIN_US = 500.0f; // Pulso mínimo (0 graus)
const float SERVO_MAX_US = 2500.0f; // Pulso máximo (180 graus)
// Controle do LED piscante
bool blink_state = false; // Estado atual do LED
absolute_time_t last_blink_time; // Última mudança de estado
// ************ FUNÇÕES DO SISTEMA ************
// Configura o ângulo do servo (0-180 graus)
void set_servo_angle(float angle) {
// Limita o ângulo entre 0 e 180 graus
angle = (angle < 0.0f) ? 0.0f : (angle > 180.0f) ? 180.0f : angle;
// Calcula a largura do pulso em microssegundos
float pulse_width = SERVO_MIN_US + (angle/180.0f)*(SERVO_MAX_US - SERVO_MIN_US);
// Converte para duty cycle (20ms = 20000us período)
uint32_t duty_cycle = (uint32_t)((pulse_width * 20000)/20000);
// Aplica o duty cycle
pwm_set_chan_level(slice_num, channel, duty_cycle);
}
// Configuração inicial dos periféricos
void setup() {
// Configuração dos pinos do display
for(int i = 0; i < 7; i++) {
gpio_init(segment_pins[i]);
gpio_set_dir(segment_pins[i], GPIO_OUT);
}
// Configuração da multiplexação do display
for(int i = 0; i < 4; i++) {
gpio_init(mux_display_pins[i]);
gpio_set_dir(mux_display_pins[i], GPIO_OUT);
gpio_put(mux_display_pins[i], 1); // Desliga displays inicialmente
}
// Configuração do teclado matricial
for(int i = 0; i < 4; i++) {
// Linhas como saídas em nível alto
gpio_init(row_pins[i]);
gpio_set_dir(row_pins[i], GPIO_OUT);
gpio_put(row_pins[i], 1);
// Colunas como entradas com pull-up
gpio_init(col_pins[i]);
gpio_set_dir(col_pins[i], GPIO_IN);
gpio_pull_up(col_pins[i]);
}
// Configuração dos LEDs
gpio_init(green_led_pin);
gpio_set_dir(green_led_pin, GPIO_OUT);
gpio_put(green_led_pin, 0); // Inicia desligado
gpio_init(red_led_pin);
gpio_set_dir(red_led_pin, GPIO_OUT);
gpio_put(red_led_pin, 0); // Inicia desligado
// Configuração do servo motor
gpio_set_function(servo_pin, GPIO_FUNC_PWM);
slice_num = pwm_gpio_to_slice_num(servo_pin);
channel = pwm_gpio_to_channel(servo_pin);
// Configura PWM para 50Hz (período de 20ms)
pwm_config config = pwm_get_default_config();
pwm_config_set_clkdiv(&config, 125.0f); // Divisor de clock
pwm_config_set_wrap(&config, 20000); // Período de 20ms
pwm_init(slice_num, &config, true);
// Posição inicial fechada
set_servo_angle(0.0f);
}
// Exibe um dígito no display especificado
void show_digit(uint8_t display_index, uint8_t digit) {
// Desliga todos os displays
for(int i = 0; i < 4; i++) {
gpio_put(mux_display_pins[i], 1);
}
sleep_us(10); // Pequeno delay para evitar ghosting
if(digit < 10) {
// Ativa os segmentos correspondentes ao dígito
for(int i = 0; i < 7; i++) {
gpio_put(segment_pins[i], display[digit][i]);
}
// Habilita o display selecionado
gpio_put(mux_display_pins[display_index], 0);
} else {
// Desliga todos os segmentos
for(int i = 0; i < 7; i++) {
gpio_put(segment_pins[i], 0);
}
}
}
// Lê o teclado matricial e retorna a tecla pressionada
char read_keypad() {
for(int row = 0; row < 4; row++) {
gpio_put(row_pins[row], 0); // Ativa linha
// Verifica colunas
for(int col = 0; col < 4; col++) {
if(gpio_get(col_pins[col]) == 0) { // Tecla pressionada
gpio_put(row_pins[row], 1); // Desativa linha antes de retornar
return keys[row][col];
}
}
gpio_put(row_pins[row], 1); // Desativa linha
}
return '\0'; // Nenhuma tecla pressionada
}
// Verifica se a senha digitada está correta
void check_password() {
bool match = true;
for(int i = 0; i < 4; i++) {
if(digit_buffer[i] != correct_password[i]) {
match = false;
break;
}
}
if(match) {
// Senha correta - libera acesso
gpio_put(green_led_pin, 1);
gpio_put(red_led_pin, 0);
failed_attempts = 0; // Reseta contador
set_servo_angle(90.0f); // Abre o cofre
} else {
// Senha incorreta
gpio_put(red_led_pin, 1);
gpio_put(green_led_pin, 0);
failed_attempts++;
set_servo_angle(0.0f); // Mantém cofre fechado
// Bloqueia após 3 tentativas
if(failed_attempts >= 3) {
is_locked = true;
lock_release_time = make_timeout_time_ms(30000); // 30 segundos
blink_state = true; // Inicia piscagem
last_blink_time = get_absolute_time();
gpio_put(red_led_pin, blink_state);
gpio_put(green_led_pin, 0);
}
}
// Prepara para limpar o display após 500ms
waiting_to_clear_buffer = true;
buffer_clear_time = make_timeout_time_ms(500);
}
// Limpa o buffer de dígitos
void clear_digit_buffer() {
for(int i = 0; i < 4; i++) {
digit_buffer[i] = 255; // 255 = dígito vazio
}
}
// ************ LOOP PRINCIPAL ************
int main() {
setup();
while(true) {
// Verifica estado de bloqueio
if(is_locked) {
// Verifica se o tempo de bloqueio expirou
if(time_reached(lock_release_time)) {
is_locked = false;
failed_attempts = 0;
gpio_put(green_led_pin, 0);
gpio_put(red_led_pin, 0);
} else {
// Pisca LED vermelho a cada 500ms
absolute_time_t now = get_absolute_time();
if(absolute_time_diff_us(last_blink_time, now) >= 500000) {
blink_state = !blink_state;
gpio_put(red_led_pin, blink_state);
last_blink_time = now;
}
// Desliga todos os displays durante bloqueio
for(int i = 0; i < 4; i++) {
show_digit(i, 255); // 255 = display desligado
}
sleep_ms(10);
continue; // Pula o resto do loop
}
}
// Leitura do teclado
char key = read_keypad();
if(key != '\0') {
// Trata teclas numéricas
if(key >= '0' && key <= '9') {
// Armazena dígito no buffer
for(int i = 0; i < 4; i++) {
if(digit_buffer[i] == 255) {
digit_buffer[i] = key - '0';
break;
}
}
// Verifica se buffer está cheio
bool buffer_full = true;
for(int i = 0; i < 4; i++) {
if(digit_buffer[i] == 255) {
buffer_full = false;
break;
}
}
if(buffer_full) {
check_password();
}
}
// Modificação principal: Debounce não bloqueante
absolute_time_t release_start = get_absolute_time();
do {
// Atualiza display durante espera
for(int i = 0; i < 4; i++) {
show_digit(i, digit_buffer[i]);
sleep_us(2000);
}
sleep_us(100);
} while (read_keypad() != '\0' && !time_reached(release_start + 1000000)); // Timeout de 1s
// Debounce não bloqueante
absolute_time_t bounce_end = make_timeout_time_ms(50);
while (!time_reached(bounce_end)) {
for(int i = 0; i < 4; i++) {
show_digit(i, digit_buffer[i]);
sleep_us(2000);
}
}
}
// Atualização dos displays
for(int i = 0; i < 4; i++) {
show_digit(i, digit_buffer[i]);
sleep_us(2000); // Taxa de refresh
}
// Limpeza automática do buffer
if(waiting_to_clear_buffer && time_reached(buffer_clear_time)) {
clear_digit_buffer();
waiting_to_clear_buffer = false;
// Desliga LEDs se não estiver bloqueado
if(!is_locked) {
gpio_put(green_led_pin, 0);
gpio_put(red_led_pin, 0);
}
}
sleep_ms(1); // Reduz consumo de CPU
}
return 0;
}
Loading
pi-pico-w
pi-pico-w