智能门禁项目

发布于:2025-05-16 ⋅ 阅读:(19) ⋅ 点赞:(0)

main.c

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "beep.h"
#include "keyboard.h"
#include "lock.h"
#include "oled.h"
#include "w25q128.h"
#include "password.h"



int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    uart1_init(115200);
    beep_init();
    keyboard_init();
    oled_init();
//    w25q128_init();
    lock_init();
    password_init();
    printf("hello world!\r\n");
    password_check();
    uint8_t key_last=0;
    while(1)
    { 
    oled_show_input();
        key_last =password_get_input();
        if(key_last ==POUND_KEY)
        {
            if(password_compare() == TRUE)
                password_input_right_action();
            else 
                password_input_wrong_action();
                
        
        }
        else if(key_last == STAR_KEY)
        {
            oled_show_old();
            password_get_input();
            if(password_compare() == TRUE)
                password_old_right_action();
            else
                password_old_wrong_action();
            
        
        }
        
        
    }
}

  

keyboard.c文件

#include "keyboard.h"
#include "delay.h"

static uint8_t key_value =0;    //用static 可以使得key_value变量只能在此中使用


void keyboard_init(void)
{
    //①定义初始化结构体
    GPIO_InitTypeDef gpio_initstruct;
    //②初始化GPIO函数
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();   //注意看硬件原理图中LED灯的引脚在哪一个组
    //调用GPIO初始化函数
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1| GPIO_PIN_2 | GPIO_PIN_10;                         
    gpio_initstruct.Mode = GPIO_MODE_IT_FALLING;                       //下降沿触发的中断
    gpio_initstruct.Pull =GPIO_PULLUP;                //正常状态下上拉
    gpio_initstruct.Speed =GPIO_SPEED_FREQ_HIGH;              //高速
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    

    gpio_initstruct.Pin = GPIO_PIN_11 | GPIO_PIN_12| GPIO_PIN_13;                         //
    gpio_initstruct.Mode = GPIO_MODE_INPUT;                       //列设置为输入引脚
    gpio_initstruct.Pull =GPIO_PULLDOWN;                //正常状态下 下拉

    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    
    //设置中断
    HAL_NVIC_SetPriority(EXTI0_IRQn,3,0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
    
    HAL_NVIC_SetPriority(EXTI1_IRQn,3,0);
    HAL_NVIC_EnableIRQ(EXTI1_IRQn);
    
    HAL_NVIC_SetPriority(EXTI2_IRQn,3,0);
    HAL_NVIC_EnableIRQ(EXTI2_IRQn);
    
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,3,0);
    HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

}

void EXTI0_IRQHandler(void)
{

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);

}

void EXTI1_IRQHandler(void)
{

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);

}

void EXTI2_IRQHandler(void)
{

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);

}
void EXTI15_10_IRQHandler(void)
{

    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);

}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    uint8_t row =0, column = 0;
    
    if(key_value !=0) return;   //如果多次按下则保留第一次
    
    //确定行
    if(GPIO_Pin == GPIO_PIN_0)
        row =0x10;
    else if(GPIO_Pin == GPIO_PIN_1)
        row =0x20;
    else if(GPIO_Pin == GPIO_PIN_2)
        row =0x30;
    else if(GPIO_Pin == GPIO_PIN_10)
        row =0x40;
    
    //确定列
    if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_11) == GPIO_PIN_SET)
    {
        delay_ms(10);
        while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_11))
            column =0x01;
    }
     else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12) == GPIO_PIN_SET)
    {
        delay_ms(10);
        while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_12))
            column =0x02;
    }
     else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13) == GPIO_PIN_SET)
    {
        delay_ms(10);
        while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_13))
            column =0x03;
    }
    
    //合并行列
    if (row !=0 && column !=0)
        key_value = row | column ;  //这条语令是0x10 | 0X02 =0X12  
  

}
uint8_t keyboard_get_value(void)
{
    uint8_t ch=0;

    if(key_value !=0)
    {
        if(key_value ==0x11) 
            ch='1';
        else if(key_value ==0x12) 
            ch='2';
        else if(key_value ==0x13) 
            ch='3';
        else if(key_value ==0x21) 
            ch='4';
        else if(key_value ==0x22) 
            ch='5';
        else if(key_value ==0x23) 
            ch='6';
        else if(key_value ==0x31) 
            ch='7';
        else if(key_value ==0x32) 
            ch='8';
        else if(key_value ==0x33) 
            ch='9';
        else if(key_value ==0x41) 
            ch='*';
        else if(key_value ==0x42) 
            ch='0';
        else if(key_value ==0x43) 
            ch='#';
        delay_ms(400);
        key_value=0x00;
        
    
    }
    return ch;

}

password.c文件

#include "password.h"
#include "oled.h"
#include "w25q128.h"
#include "keyboard.h"
#include "string.h"
#include "stdio.h"
#include "lock.h"
#include "beep.h"
#include "delay.h"
#define PASSWORD_SIZE    10

uint8_t pwd_input[PASSWORD_SIZE] ={0};
uint8_t pwd_read[PASSWORD_SIZE] ={0};
uint8_t i=0;
uint8_t key_value =0;
uint8_t try_times=0;


//初始化函数
void password_init(void)
{
    w25q128_init();
    

}

//清空输入缓存
void password_input_clear(void)
{
    memset(pwd_input ,0,PASSWORD_SIZE);
    i= 0;

}

//保存密码  即修改密码
void password_save(void)
{
    w25q128_erase_sector(0x000000);            //扇页擦除
    w25q128_write_page(0x000000,pwd_input,PASSWORD_SIZE);
    oled_show_changed();
    
    

}
//获取键盘的输入
uint8_t password_get_input(void)
{
    password_input_clear();
    while(1)
    {
     
        key_value =keyboard_get_value();
        if(key_value == POUND_KEY)
        {
        
            printf("按下了#号键,input:%s\r\n",pwd_input);
            return POUND_KEY;             //输入#号就退出循环了
        
        }
        else if(key_value == STAR_KEY)
        {
        
            printf("按下了*号键\r\n");
            return STAR_KEY;        输入*号就退出循环了
         
        }
        else if(key_value != 0)
        {
            printf("按下了: %c\r\n",key_value);
            oled_show_char(20+ i*10,4,key_value,16);
            pwd_input[i++] =key_value;
            
        
        }
    
    
    }

}
//密码比对
uint8_t password_compare(void)
    
{
    uint8_t i=0;
    w25q128_read_data(0x000000, pwd_read, PASSWORD_SIZE);
    
    if(strlen((char *)pwd_input) !=strlen((char *)pwd_read))
        return FAlSE;
    for(i=0;i<strlen((char *)pwd_read);i++)
    
    {
        if(pwd_input[i] !=pwd_read[i])
            return FAlSE;
        
    }
        return TRUE;
    
    

}
//密码输入正确的操作
void password_input_right_action(void)
{
    oled_show_right();
    lock_on();
    beep_on();
    delay_ms(300);
    beep_off();
    delay_ms(1000);
    lock_off();
    try_times =0;
    
}

//密码输入错误的操作
void password_input_wrong_action(void)
{
    oled_show_wrong();
    try_times++;
    if(try_times >= 3)
    {
        beep_on();
        delay_ms(1000);
        beep_off();
        try_times =0;
        
    }
     delay_ms(1000);

}
//旧密码输入正确的操作
void password_old_right_action(void)
{
    oled_show_new();
    password_get_input();
    password_save();
    
    beep_on();
    delay_ms(300);
    beep_off();
    delay_ms(500);

}

//旧密码输入错误的操作
void password_old_wrong_action(void)
{
    oled_show_wrong();
    delay_ms(1000);


}

//检查密码是否存在
void password_check(void)
{

    w25q128_read_data(0x000000, pwd_read,PASSWORD_SIZE);
    printf("读出密码为: %s\r\n",pwd_read);
    if(pwd_read[0] == '\0' || pwd_read[0] ==0xFF)
    {
        oled_show_set();
        password_get_input();
        password_save();
    
    }
    

}

oled.c文件

#include "oled.h"
#include "font.h"
#include "delay.h"

void oled_gpio_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    OLED_I2C_SCL_CLK();
    OLED_I2C_SDA_CLK();
    gpio_initstruct.Pin = OLED_I2C_SCL_PIN;                         //LED1、LED2对应的引脚
    gpio_initstruct.Pull = GPIO_PULLUP;                       //上拉
    gpio_initstruct.Mode =GPIO_MODE_OUTPUT_PP;                //开漏输出
    gpio_initstruct.Speed =GPIO_SPEED_FREQ_HIGH;              //高速
    HAL_GPIO_Init(OLED_I2C_SCL_PORT,&gpio_initstruct);
    
    
    
    gpio_initstruct.Pin = OLED_I2C_SDA_PIN;                         //LED1、LED2对应的引脚
    HAL_GPIO_Init(OLED_I2C_SDA_PORT,&gpio_initstruct);
}

void oled_i2c_start(void)
{
    OLED_SCL_SET();
    OLED_SDA_SET();
    OLED_SDA_RESET();
    OLED_SCL_RESET();
}

void oled_i2c_stop(void)
{
    OLED_SCL_SET();
    OLED_SDA_RESET();
    OLED_SDA_SET();
    
}
void oled_i2c_ack(void)
{
    OLED_SCL_SET();
    OLED_SCL_RESET();

}
void oled_i2c_write_byte(uint8_t data)                     //发送一个字节8位并保存数据 保存数据是偏移后的第一位如果是1则置SDA为高电平 反之则置低电平
{

    uint8_t i,tmp;
    tmp= data;
    for(i=0;i<8;i++)
    {

    if((tmp & 0x80) == 0x80)                   //“与” AND的运算1&0=0 0&0=0 1&1=1  这是为了看最高位是否为1
        OLED_SDA_SET();
    else
     
        OLED_SDA_RESET();
       
    tmp=tmp << 1;
    OLED_SCL_SET();
    OLED_SCL_RESET();
    
}
}
void oled_write_cmd(uint8_t cmd)
{
    oled_i2c_start();
    oled_i2c_write_byte(0x78);
    oled_i2c_ack();
    oled_i2c_write_byte(0x00);
    oled_i2c_ack();
    oled_i2c_write_byte(cmd);
    oled_i2c_ack();
    oled_i2c_stop();
    

}
void oled_write_data(uint8_t data)
    
{
    oled_i2c_start();
    oled_i2c_write_byte(0x78);
    oled_i2c_ack();
    oled_i2c_write_byte(0x40);
    oled_i2c_ack();
    oled_i2c_write_byte(data);
    oled_i2c_ack();
    oled_i2c_stop();
    

}


void oled_init(void)
{
    
    oled_gpio_init();
    
    delay_ms(100);
    oled_write_cmd(0xAE);    //设置显示开启/关闭,0xAE关闭,0xAF开启

    oled_write_cmd(0xD5);    //设置显示时钟分频比/振荡器频率
    oled_write_cmd(0x80);    //0x00~0xFF

    oled_write_cmd(0xA8);    //设置多路复用率
    oled_write_cmd(0x3F);    //0x0E~0x3F

    oled_write_cmd(0xD3);    //设置显示偏移
    oled_write_cmd(0x00);    //0x00~0x7F

    oled_write_cmd(0x40);    //设置显示开始行,0x40~0x7F

    oled_write_cmd(0xA1);    //设置左右方向,0xA1正常,0xA0左右反置

    oled_write_cmd(0xC8);    //设置上下方向,0xC8正常,0xC0上下反置

    oled_write_cmd(0xDA);    //设置COM引脚硬件配置
    oled_write_cmd(0x12);

    oled_write_cmd(0x81);    //设置对比度
    oled_write_cmd(0xCF);    //0x00~0xFF

    oled_write_cmd(0xD9);    //设置预充电周期
    oled_write_cmd(0xF1);

    oled_write_cmd(0xDB);    //设置VCOMH取消选择级别
    oled_write_cmd(0x30);

    oled_write_cmd(0xA4);    //设置整个显示打开/关闭

    oled_write_cmd(0xA6);    //设置正常/反色显示,0xA6正常,0xA7反色

    oled_write_cmd(0x8D);    //设置充电泵
    oled_write_cmd(0x14);

    oled_write_cmd(0xAF);    //开启显示
    
    oled_fill(0x00);         //及时清空避免出现雪花现象

}
void oled_set_cursor(uint8_t x, uint8_t y)              //设置写的位置在哪里  y为page x为列
{
    oled_write_cmd(0xB0 + y);    //设置page
    /*设置哪一列*/
    oled_write_cmd(( x & 0x0F) | 0x00);
    oled_write_cmd((x & 0xF0) >> 4 | 0x10 );

}
void oled_fill(uint8_t data)            //注意oled_set_cursor(0, i);  的位置是因为这里的寻址模式采用的是页地址的寻址模式
{
    uint8_t i, j;
    for(i = 0; i < 8; i++)
    {
        oled_set_cursor(0, i);
        for(j = 0; j < 128; j++)
        {
            
            oled_write_data(data);
        }
    }
}
void oled_show_char(uint8_t x,uint8_t y ,uint8_t num,uint8_t size)     //y为哪一行  x为哪一列,num为ascii值,size为高度  设置了三个高度 12 16 24 
{
    uint8_t i,j,page;
    num=num-' ';
    
    page =size / 8;
    if(size % 8 != 0)
        page++;
    
    for(j= 0;j<page;j++)
    {
        oled_set_cursor(x,y + j);
        for( i = size / 2 * j;  i < size / 2 * ( j + 1 ) ; i++)
        {
        if(size == 12)
            oled_write_data(ascii_6X12[num][i]);
        else if(size == 16)
            oled_write_data(ascii_8X16[num][i]);
        else if(size == 24)
            oled_write_data(ascii_12X24[num][i]);
        
        
        }
    
    }
  

}

void oled_show_string(uint8_t x,uint8_t y,char *p, uint8_t size)            //第三个参数为字符串的内容
{

    while(*p != '\0')
    {
        oled_show_char(x, y,*p,size);
        x +=size/2;
        p++;
    
    
    }

}

//void oled_show_chinese(uint8_t x, uint8_t y, uint8_t N, uint8_t size)       //N为汉字的位数
//{
//    uint16_t i, j;
//    for(j = 0; j < size/8; j++)
//    {
//        oled_set_cursor(x, y + j);
//        for(i = size *j; i < size * (j + 1); i++)
//        {
//            if(size == 16)
//                oled_write_data(chinese_16x16[N][i]);
//            else if(size == 24)
//                oled_write_data(chinese_24x24[N][i]);
//        }
//    }
//}

void oled_show_chinese(uint8_t x, uint8_t y, uint8_t N, uint8_t message_type)       //N为汉字的位数
{
    uint16_t i, j;
    for(j = 0; j < 2; j++)
    {
        oled_set_cursor(x, y + j);
        for(i = 16 *j; i < 16 * (j + 1); i++)
        {
            switch(message_type)
            {
                case SHOW_INPUT_PWD:
                    oled_write_data(chinese_enter_password[N][i]);
                    break;
                
                case SHOW_PWD_RIGHT:
                    oled_write_data(chinese_password_right[N][i]);
                    break;
                
                case SHOW_PWD_WRONG:
                    oled_write_data(chinese_password_wrong[N][i]);
                    break;
                
                case SHOW_INPUT_OLD_PWD:
                    oled_write_data( chinese_enter_old_password[N][i]);
                    break;
                
                case SHOW_INPUT_NEW_PWD:
                    oled_write_data(chinese_enter_new_password[N][i]);
                    break;
                
                case SHOWPWD_CHANGED:
                    oled_write_data(chinese_password_changed[N][i]);
                    break;
                
                case SHOW_SET_PWD:
                    oled_write_data(chinese_set_password[N][i]);
                    break;
                
             
                                
                default:
                    break;
                
            
            
            }
        }
    }
}

//请输入密码
void oled_show_input(void)
{
   oled_fill(0x00);
    oled_show_chinese(10,1,0,SHOW_INPUT_PWD);
    oled_show_chinese(30,1,1,SHOW_INPUT_PWD);
    oled_show_chinese(50,1,2,SHOW_INPUT_PWD);
    oled_show_chinese(70,1,3,SHOW_INPUT_PWD);
    oled_show_chinese(90,1,4,SHOW_INPUT_PWD);
    oled_show_char(110,1,':',16);

}
//密码正确
void oled_show_right(void)
{
   oled_fill(0x00);
    oled_show_chinese(10,1,0,SHOW_PWD_RIGHT);
    oled_show_chinese(30,1,1,SHOW_PWD_RIGHT);
    oled_show_chinese(50,1,2,SHOW_PWD_RIGHT);
    oled_show_chinese(70,1,3,SHOW_PWD_RIGHT);
    oled_show_char(90,1,'!',16);

}
//密码错误
void oled_show_wrong(void)
{
   oled_fill(0x00);
    oled_show_chinese(10,1,0,SHOW_PWD_WRONG);
    oled_show_chinese(30,1,1,SHOW_PWD_WRONG);
    oled_show_chinese(50,1,2,SHOW_PWD_WRONG);
    oled_show_chinese(70,1,3,SHOW_PWD_WRONG);
    oled_show_char(90,1,'!',16);

}
//请输入旧密码
void oled_show_old(void)
{
   oled_fill(0x00);
    oled_show_chinese(0,1,0,SHOW_INPUT_OLD_PWD);
    oled_show_chinese(20,1,1,SHOW_INPUT_OLD_PWD);
    oled_show_chinese(40,1,2,SHOW_INPUT_OLD_PWD);
    oled_show_chinese(60,1,3,SHOW_INPUT_OLD_PWD);
    oled_show_chinese(80,1,4,SHOW_INPUT_OLD_PWD);
    oled_show_chinese(100,1,5,SHOW_INPUT_OLD_PWD);
    oled_show_char(120,1,':',16);

}
//请输入新密码
void oled_show_new(void)
{
   oled_fill(0x00);
    oled_show_chinese(0,1,0,SHOW_INPUT_NEW_PWD);
    oled_show_chinese(20,1,1,SHOW_INPUT_NEW_PWD);
    oled_show_chinese(40,1,2,SHOW_INPUT_NEW_PWD);
    oled_show_chinese(60,1,3,SHOW_INPUT_NEW_PWD);
    oled_show_chinese(80,1,4,SHOW_INPUT_NEW_PWD);
    oled_show_chinese(100,1,5,SHOW_INPUT_NEW_PWD);
    oled_show_char(120,1,':',16);

}
//密码修改成功
void oled_show_changed(void)
{
   oled_fill(0x00);
    oled_show_chinese(0,1,0,SHOWPWD_CHANGED);
    oled_show_chinese(20,1,1,SHOWPWD_CHANGED);
    oled_show_chinese(40,1,2,SHOWPWD_CHANGED);
    oled_show_chinese(60,1,3,SHOWPWD_CHANGED);
    oled_show_chinese(80,1,4,SHOWPWD_CHANGED);
    oled_show_chinese(100,1,5,SHOWPWD_CHANGED);
    oled_show_char(120,1,'!',16);

}
//请设定密码
void oled_show_set(void)
{
   oled_fill(0x00);
    oled_show_chinese(10,1,0,SHOW_SET_PWD);
    oled_show_chinese(30,1,1,SHOW_SET_PWD);
    oled_show_chinese(50,1,2,SHOW_SET_PWD);
    oled_show_chinese(70,1,3,SHOW_SET_PWD);
    oled_show_chinese(90,1,4,SHOW_SET_PWD);
    oled_show_char(110,1,':',16);

}


void oled_show_image(uint8_t x,uint8_t y,uint8_t width,uint8_t height,uint8_t *bmp)            //其中参数bmp为指针
{
    uint8_t i,j;
    for(j=0;j<height;j++)
    {
        oled_set_cursor(x,y+j);
        for(i=0;i<width;i++)
        oled_write_data(bmp[width * j +i]);
    
    }



}


网站公告

今日签到

点亮在社区的每一天
去签到