智能门禁的项目

项目需求

  1. 矩阵键盘输入密码,正确开锁,错误提示,三次错误后蜂鸣器响三秒;
  2. 按下#号确认输入,按下*号修改密码;
  3. 密码保存在W25Q128里;
  4. OLED屏幕显示信息。

硬件清单

|------|---------|---------|-----|------------|
| 矩阵键盘 | OLED显示屏 | 继电器 | 蜂鸣器 | W25Q128存储器 |
| 开发板 | ST-Link | USB转TTL | 杜邦线 | ------ |

其中,OLED显示器利用的是I2C的通信协议,W25Q128用的是SPI的通信协议 ;

矩阵键盘这节课进行介绍。

硬件接线

简图:

模块:矩阵键盘(原理+驱动)

学了了独立按键之后,发现使用一个按键就要浪费一个IO口。那有没有一种节约GPIO的方法,比如要用16个按键,怎么样才能节省IO口?那我们就可以用矩阵键盘。16个按键,只需8个IO口。

矩阵键盘介绍

我们矩阵键盘的型号多种多样,有 1x4、3x3、3x4、4x4,甚至是 8x8 的;有薄膜的,有按键的

矩阵键盘常见用途:

  1. 电子密码锁

  2. ATM 的键盘

  3. POS机 的键盘

  4. 家用电器的控制面板(微波炉、洗衣机等)

工作参数及引脚介绍

引脚介绍:

  • 按键式的有的有引脚标识,**R 是行,**C 是列。有的没有引脚标识,可以找商家问下,或者自己看原理图。
  • 薄膜式的都没有引脚标识。键盘正对自己,引脚是先行后列,从小到大。

矩阵键盘工作原理

这是矩阵键盘(4x4)内部电路示意图:

矩阵键盘识别常用------逐行逐列扫描法

  1. 使列线连接的I/O引脚输出低电平,四条行线所连接的I/O引脚输出高电平,当没有按键按下时,四条行线所连接的I/O引脚读取的将全部是高电平;当按键按下时,由于按键所在的行线与列线相通,行线将被下拉到低电阻。此时读取行线所连接的引脚,将不再是高电平。
  2. 逐列将列线依次置低电平,读取行线,如果某一条行线为低电平,则说明该行线与当前的行线为低电平的列线交叉点处的按键被按下,从判断按键按下。

中断来实现识别

  1. 把所有行引脚设成中断引脚,默认是上拉输入,下降沿触发,GPIO引脚输出高电平。
  2. 把所有列引脚连接的GPIO引脚 设成输入内部下拉。(GPIO引脚输入,默认是下拉)
  3. 当有中断触发 的时候就可以知道哪一行有按键按下 ,再逐列看哪一列变成高电平,就是哪个按键被触发了。

小实验:串口输出矩阵键盘按下的按键

硬件清单:

STM32F103C8T6、矩阵键盘(3x4,薄膜)、USB转TTL、ST-Link

硬件接线:

文件代码:

  • keyboard.c
cs 复制代码
#include "keyboard.h"
#include "delay.h"

uint8_t key_value;

void keyboard_init(void){
    
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    //调用GPIO的初始化函数
    GPIO_InitTypeDef GPIO_Initstruct;
    
    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_PIN_14;
    GPIO_Initstruct.Mode = GPIO_MODE_INPUT;
    GPIO_Initstruct.Pull = GPIO_PULLDOWN;    //配置成下拉模式,当导通时,会变成高电平
    GPIO_Initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_Initstruct); 
    
    HAL_NVIC_SetPriority(EXTI0_IRQn,2,2);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
    
    HAL_NVIC_SetPriority(EXTI1_IRQn,2,2);
    HAL_NVIC_EnableIRQ(EXTI1_IRQn);
    
    HAL_NVIC_SetPriority(EXTI2_IRQn,2,2);
    HAL_NVIC_EnableIRQ(EXTI2_IRQn);
    
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,2,2);
    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) == GPIO_PIN_SET);
        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) == GPIO_PIN_SET);
        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) == GPIO_PIN_SET);
        column = 0x03;
    }
     else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14) == GPIO_PIN_SET){
        delay_ms(10);
        while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14) == GPIO_PIN_SET);
        column = 0x04;
    }
     
    if(row != 0 && column != 0)
        key_value = row | column;    //按位与进行拼接
}

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 == 0x14) ch = 'A';
        
        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 == 0x24) ch = 'B';
        
        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 == 0x34) ch = 'C';
        
        else if(key_value == 0x41) ch = '*';
        else if(key_value == 0x42) ch = '0';
        else if(key_value == 0x43) ch = '#';
        else if(key_value == 0x44) ch = 'D';
        delay_ms(400);
        key_value = 0x00;
    }
    return ch;
}
  • keyboard.h
cs 复制代码
#ifndef __KEYBOARD_H__
#define __KEYBOARD_H__
#include "stm32f1xx.h"

void keyboard_init(void);
uint8_t keyboard_get_value(void);

#endif
  • main.c文件代码
cs 复制代码
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "keyboard.h"


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    uart1_init(115200);
    printf("hello,world");
    keyboard_init();
    
    uint8_t key_value = 0;
    
    while(1)
    { 
        key_value = keyboard_get_value();
        if(key_value != 0){
            printf("按下了:%c \r\n",key_value);
            key_value = 0;
        }
    }
}

**注意:**这个代码采用的是配置中断来实现,要回顾关于中断的配置流程。

项目框图

(要养成习惯,在做项目的时候一定要配置流程图)

项目代码

输出设备

OLED

oled.c文件代码:

cs 复制代码
#include "oled.h"
#include "delay.h"
#include "font.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;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_OD;
    gpio_initstruct.Pull = GPIO_PULLUP;
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(OLED_I2C_SCL_PORT,&gpio_initstruct);
    
    gpio_initstruct.Pin = OLED_I2C_SDA_PIN;
    HAL_GPIO_Init(OLED_I2C_SDA_PORT,&gpio_initstruct);
    
}

/**
* @breif 配置I2C协议的时序图:开始,读写,应答,结束。
* @note     在配置读写时序的时候,要注意。。。。。
*
*/
void oled_i2c_start(void){
    OLED_SCL_SET();
    OLED_SDA_SET();
    OLED_SDA_RESET();
    OLED_SCL_RESET();
}

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

void oled_i2c_write_byte(uint8_t data){
    uint8_t i,temp;
    temp = data;
    for(i = 0;i < 8 ;i++){
        if((temp & 0x80) == 0x80)
            OLED_SDA_SET();
        else
            OLED_SDA_RESET();
        temp = temp << 1;
        OLED_SCL_SET();
        OLED_SCL_RESET();
    }
}


/**
* @breif    利用I2C的时序图,配置OLED相关的写命令和写指令的函数
* @note     
*
*/
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_date(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();
    
}


/**
* @breif    初始化OLED显示屏的函数
* @note     包括初始化GPIO引脚和初始化OLED的1相关命令
*
*/
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);
    
}

/**
* @breif    设置oled显示屏显示的坐标
* @note     
*/
void oled_set_cursor(uint8_t x,uint8_t y){
    oled_write_cmd(0xB0 + x);
    oled_write_cmd((y & 0x0F) | 0x00);   //取x的低位
    oled_write_cmd(((y & 0xF0) >> 4) | 0x10);  //取高位
}


/**
* @breif    设置oled显示屏清屏函数
* @note     
*/
void oled_fill(uint8_t data){
    uint8_t i,j;
    for (i = 0;i < 8 ;i++){
        oled_set_cursor(i,0);
        for(j = 0;j < 128;j++)
            oled_write_date(data);
    } 
}

/**
* @breif    封装oled显示屏显示字符、字符串、汉字、图像的函数
* @note     
*/

void oled_show_char(uint8_t x ,uint8_t y,uint8_t number ,uint8_t size){         //size代表的是高度
    
    number = number - ' ';
    uint8_t i,j,page;                       //page:表示输入的字符总共需要的PAGE
    
    page = size / 8;
    if(size % 8 != 0)
        page ++;
 
    for (i = 0;i < page; i++)
    {
        oled_set_cursor(x+i,y);
        for (j = size / 2 * i;j < size / 2 * (i + 1); j++){              //size/2:高度的一半是宽度
            if(size == 16)
                oled_write_date(ascii_8X16[number][j]);                   
        }
    }
}

//显示字符串
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);      //*p:取出数组中的首元素
        y += size / 2;
        p++;                               //p++:代表的是数组指针递增,指向下一个元素地址。
    }
}

//void oled_show_chinese(uint8_t x,uint8_t y, uint8_t N ,uint8_t size){

//    uint8_t i,j;
//    for (i = 0 ; i < size / 8 ;i++){
//        oled_set_cursor(x+i,y);
//        for(j = size * i;j < size * (i + 1);j++){
//            if(size == 16)
//                oled_write_date(chinese_16X16[N][j]);
            if(size == 24)
                oled_write_date(chinese_24X24[N][j]);
//        }
//    }
//}

//显示汉字的函数
void oled_show_chinese(uint8_t x,uint8_t y, uint8_t N ,uint8_t message_type){

    uint8_t i,j;
    for (i = 0 ; i < 2 ;i++){
        oled_set_cursor(x+i,y);
        for(j = 16 * i;j < 16 * (i + 1);j++){
            switch (message_type){
                case SHOW_INPUT_PWD:
                    oled_write_date(chinese_enter_password[N][j]);
                    break;
                
                case SHOW_PWD_RIGHT:
                    oled_write_date(chinese_password_right[N][j]);
                    break;
                
                case SHOW_PWD_ERROR:
                    oled_write_date(chinese_password_error[N][j]);
                    break;
                
                case SHOW_INPUT_OLD_PWD:
                    oled_write_date(chinese_enter_oldPassword[N][j]);
                    break;
                
                case SHOW_INPUT_NEW_PWD:
                    oled_write_date(chinese_enter_newPassword[N][j]);
                    break;
                
                case SHOW_PWD_CHANGE:
                    oled_write_date(modify_passWord_complete[N][j]);
                    break;
                
                case SHOW_SET_PWD:
                    oled_write_date(set_passWord[N][j]);
                    break;
                
                default:
                    break;  
            }
        }
    }
}

//请输入密码
void oled_show_input(void){
    oled_fill(0x00);
    oled_show_chinese(1,10,0,SHOW_INPUT_PWD);
    oled_show_chinese(1,30,1,SHOW_INPUT_PWD);
    oled_show_chinese(1,50,2,SHOW_INPUT_PWD);
    oled_show_chinese(1,70,3,SHOW_INPUT_PWD);
    oled_show_chinese(1,90,4,SHOW_INPUT_PWD);
    oled_show_char(1,110,':',16);
}
//密码正确
void oled_pwd_right(void){
    oled_fill(0x00);
    oled_show_chinese(1,10,0,SHOW_PWD_RIGHT);
    oled_show_chinese(1,30,1,SHOW_PWD_RIGHT);
    oled_show_chinese(1,50,2,SHOW_PWD_RIGHT);
    oled_show_chinese(1,70,3,SHOW_PWD_RIGHT);
    oled_show_char(1,90,':',16);
}
//密码错误
void oled_pwd_error(void){
    oled_fill(0x00);
    oled_show_chinese(1,10,0,SHOW_PWD_ERROR);
    oled_show_chinese(1,30,1,SHOW_PWD_ERROR);
    oled_show_chinese(1,50,2,SHOW_PWD_ERROR);
    oled_show_chinese(1,70,3,SHOW_PWD_ERROR);
    oled_show_char(1,110,':',16);
}
//请输入旧密码
void oled_input_old_pwd(void){
    oled_fill(0x00);
    oled_show_chinese(1,10,0,SHOW_INPUT_OLD_PWD);
    oled_show_chinese(1,26,1,SHOW_INPUT_OLD_PWD);
    oled_show_chinese(1,42,2,SHOW_INPUT_OLD_PWD);
    oled_show_chinese(1,58,3,SHOW_INPUT_OLD_PWD);
    oled_show_chinese(1,74,4,SHOW_INPUT_OLD_PWD);
    oled_show_chinese(1,90,5,SHOW_INPUT_OLD_PWD);
    oled_show_char(1,106,':',16);
}
//请输入新密码
void oled_input_new_pwd(void){
    oled_fill(0x00);
    oled_show_chinese(1,10,0,SHOW_INPUT_NEW_PWD);
    oled_show_chinese(1,26,1,SHOW_INPUT_NEW_PWD);
    oled_show_chinese(1,42,2,SHOW_INPUT_NEW_PWD);
    oled_show_chinese(1,58,3,SHOW_INPUT_NEW_PWD);
    oled_show_chinese(1,74,4,SHOW_INPUT_NEW_PWD);
    oled_show_chinese(1,90,4,SHOW_INPUT_NEW_PWD);
    oled_show_char(1,106,':',16);
}
//密码修改完成
void oled_modif_pwd_complete(void){
    oled_fill(0x00);
    oled_show_chinese(1,10,0,SHOW_PWD_CHANGE);
    oled_show_chinese(1,26,1,SHOW_PWD_CHANGE);
    oled_show_chinese(1,42,2,SHOW_PWD_CHANGE);
    oled_show_chinese(1,58,3,SHOW_PWD_CHANGE);
    oled_show_chinese(1,74,4,SHOW_PWD_CHANGE);
    oled_show_chinese(1,90,5,SHOW_PWD_CHANGE);
    oled_show_char(1,106,':',16);
}
//请设置密码
void oled_set_pwd(void){
    oled_fill(0x00);
    oled_show_chinese(1,10,0,SHOW_SET_PWD);
    oled_show_chinese(1,30,1,SHOW_SET_PWD);
    oled_show_chinese(1,50,2,SHOW_SET_PWD);
    oled_show_chinese(1,70,3,SHOW_SET_PWD);
    oled_show_chinese(1,90,4,SHOW_SET_PWD);
    oled_show_char(1,110,':',16);
}

//显示图像
 void oled_show_image(uint8_t x,uint8_t y, uint8_t width ,uint8_t highth ,uint8_t * bpm){
     uint8_t i,j;
     for(i = 0; i < highth ;i++)
     {
         oled_set_cursor(x+i,j);
         for(j = 0;j < width;j++)
            oled_write_date(bpm[ width * i + j ]);
     }
 }

oled.h文件代码:

cs 复制代码
#ifndef __OLED_H__
#define __OLED_H__
#include "stm32f1xx.h"

enum message{
    SHOW_INPUT_PWD = 0,
    SHOW_PWD_RIGHT,
    SHOW_PWD_ERROR,
    SHOW_INPUT_OLD_PWD,
    SHOW_INPUT_NEW_PWD,
    SHOW_PWD_CHANGE,
    SHOW_SET_PWD
    
};


#define OLED_I2C_SCL_CLK()       __HAL_RCC_GPIOB_CLK_ENABLE()
#define OLED_I2C_SCL_PORT       GPIOB
#define OLED_I2C_SCL_PIN        GPIO_PIN_8

#define OLED_I2C_SDA_CLK()      __HAL_RCC_GPIOB_CLK_ENABLE()
#define OLED_I2C_SDA_PORT       GPIOB
#define OLED_I2C_SDA_PIN        GPIO_PIN_9

#define OLED_SCL_RESET()          HAL_GPIO_WritePin(OLED_I2C_SCL_PORT,OLED_I2C_SCL_PIN,GPIO_PIN_RESET)
#define OLED_SCL_SET()            HAL_GPIO_WritePin(OLED_I2C_SCL_PORT,OLED_I2C_SCL_PIN,GPIO_PIN_SET)

#define OLED_SDA_RESET()          HAL_GPIO_WritePin(OLED_I2C_SDA_PORT,OLED_I2C_SDA_PIN,GPIO_PIN_RESET)
#define OLED_SDA_SET()            HAL_GPIO_WritePin(OLED_I2C_SDA_PORT,OLED_I2C_SDA_PIN,GPIO_PIN_SET)


void oled_init(void);
void oled_set_cursor(uint8_t x,uint8_t y);
void oled_fill(uint8_t data);
void oled_write_date(uint8_t data);
void oled_show_char(uint8_t x ,uint8_t y,uint8_t number ,uint8_t size);
void oled_show_string(uint8_t x,uint8_t y,char *p ,uint8_t size);
void oled_show_chinese(uint8_t x, uint8_t y, uint8_t N, uint8_t size);
void oled_show_image(uint8_t x,uint8_t y, uint8_t width ,uint8_t highth,uint8_t * bpm);

void oled_show_input(void);
void oled_pwd_right(void);
void oled_pwd_error(void);
void oled_input_old_pwd(void);
void oled_input_new_pwd(void);
void oled_modif_pwd_complete(void);
void oled_set_pwd(void);


#endif

font.h文件代码

cs 复制代码
#ifndef __FONT_H__
#define __FONT_H__

//请输入密码;
const unsigned char chinese_enter_password[][32] = {
    0x40,0x42,0xCC,0x00,0x00,0x44,0x54,0x54,0x54,0x7F,0x54,0x54,0x54,0x44,0x40,0x00,
    0x00,0x00,0x7F,0x20,0x10,0x00,0xFF,0x15,0x15,0x15,0x55,0x95,0x7F,0x00,0x00,0x00,/*"请",0*/
        
    0x88,0x68,0x1F,0xC8,0x08,0x10,0xC8,0x54,0x52,0xD1,0x12,0x94,0x08,0xD0,0x10,0x00,
    0x09,0x19,0x09,0xFF,0x05,0x00,0xFF,0x12,0x92,0xFF,0x00,0x5F,0x80,0x7F,0x00,0x00,/*"输",1*/
        
    0x00,0x00,0x00,0x00,0x00,0x01,0xE2,0x1C,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x80,0x40,0x20,0x10,0x0C,0x03,0x00,0x00,0x00,0x03,0x0C,0x30,0x40,0x80,0x80,0x00,/*"入",2*/
        
    0x10,0x8C,0x44,0x04,0xE4,0x04,0x95,0xA6,0x44,0x24,0x14,0x84,0x44,0x94,0x0C,0x00,
    0x02,0x02,0x7A,0x41,0x41,0x43,0x42,0x7E,0x42,0x42,0x42,0x43,0xF8,0x00,0x00,0x00,/*"密",3*/
        
    0x04,0x84,0xE4,0x5C,0x44,0xC4,0x00,0x02,0xF2,0x82,0x82,0x82,0xFE,0x80,0x80,0x00,
    0x02,0x01,0x7F,0x10,0x10,0x3F,0x00,0x08,0x08,0x08,0x08,0x48,0x88,0x40,0x3F,0x00,/*"码",4*/
};

//密码正确;
const unsigned char chinese_password_right[][32] = {
    0x10,0x8C,0x44,0x04,0xE4,0x04,0x95,0xA6,0x44,0x24,0x14,0x84,0x44,0x94,0x0C,0x00,
    0x02,0x02,0x7A,0x41,0x41,0x43,0x42,0x7E,0x42,0x42,0x42,0x43,0xF8,0x00,0x00,0x00,/*"密",0*/
    
    0x04,0x84,0xE4,0x5C,0x44,0xC4,0x00,0x02,0xF2,0x82,0x82,0x82,0xFE,0x80,0x80,0x00,
    0x02,0x01,0x7F,0x10,0x10,0x3F,0x00,0x08,0x08,0x08,0x08,0x48,0x88,0x40,0x3F,0x00,/*"码",1*/
    
    0x00,0x02,0x02,0xC2,0x02,0x02,0x02,0xFE,0x82,0x82,0x82,0x82,0x82,0x02,0x00,0x00,
    0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,/*"正",2*/
    
    0x04,0x84,0xE4,0x5C,0x44,0xC4,0x20,0x10,0xE8,0x27,0x24,0xE4,0x34,0x2C,0xE0,0x00,
    0x02,0x01,0x7F,0x10,0x10,0x3F,0x80,0x60,0x1F,0x09,0x09,0x3F,0x49,0x89,0x7F,0x00,/*"确",3*/
};
//密码错误;
const unsigned char chinese_password_error[][32] = {
    0x10,0x8C,0x44,0x04,0xE4,0x04,0x95,0xA6,0x44,0x24,0x14,0x84,0x44,0x94,0x0C,0x00,
    0x02,0x02,0x7A,0x41,0x41,0x43,0x42,0x7E,0x42,0x42,0x42,0x43,0xF8,0x00,0x00,0x00,/*"密",0*/
    
    0x04,0x84,0xE4,0x5C,0x44,0xC4,0x00,0x02,0xF2,0x82,0x82,0x82,0xFE,0x80,0x80,0x00,
    0x02,0x01,0x7F,0x10,0x10,0x3F,0x00,0x08,0x08,0x08,0x08,0x48,0x88,0x40,0x3F,0x00,/*"码",1*/
    
    0x40,0x30,0xEF,0x24,0x64,0x48,0x48,0x7F,0x48,0x48,0x48,0x7F,0x48,0x48,0x40,0x00,
    0x01,0x01,0x7F,0x21,0x11,0x00,0xFF,0x49,0x49,0x49,0x49,0x49,0xFF,0x00,0x00,0x00,/*"错",2*/
    
    0x40,0x42,0xCC,0x00,0x00,0x80,0x9E,0x92,0x92,0x92,0x92,0x92,0x9E,0x80,0x00,0x00,
    0x00,0x00,0x7F,0x20,0x94,0x84,0x44,0x24,0x14,0x0F,0x14,0x24,0x44,0x84,0x84,0x00,/*"误",3*/
};

//请输入旧密码;
const unsigned char chinese_enter_oldPassword[][32] = {
    0x40,0x42,0xCC,0x00,0x00,0x44,0x54,0x54,0x54,0x7F,0x54,0x54,0x54,0x44,0x40,0x00,
    0x00,0x00,0x7F,0x20,0x10,0x00,0xFF,0x15,0x15,0x15,0x55,0x95,0x7F,0x00,0x00,0x00,/*"请",0*/
    
    0x88,0x68,0x1F,0xC8,0x08,0x10,0xC8,0x54,0x52,0xD1,0x12,0x94,0x08,0xD0,0x10,0x00,
    0x09,0x19,0x09,0xFF,0x05,0x00,0xFF,0x12,0x92,0xFF,0x00,0x5F,0x80,0x7F,0x00,0x00,/*"输",1*/
    
    0x00,0x00,0x00,0x00,0x00,0x01,0xE2,0x1C,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x80,0x40,0x20,0x10,0x0C,0x03,0x00,0x00,0x00,0x03,0x0C,0x30,0x40,0x80,0x80,0x00,/*"入",2*/
    
    0x00,0x00,0xFF,0x00,0x00,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,0x00,
    0x00,0x00,0xFF,0x00,0x00,0x00,0x7F,0x20,0x20,0x20,0x20,0x20,0x20,0x7F,0x00,0x00,/*"旧",3*/
    
    0x10,0x8C,0x44,0x04,0xE4,0x04,0x95,0xA6,0x44,0x24,0x14,0x84,0x44,0x94,0x0C,0x00,
    0x02,0x02,0x7A,0x41,0x41,0x43,0x42,0x7E,0x42,0x42,0x42,0x43,0xF8,0x00,0x00,0x00,/*"密",4*/
    
    0x04,0x84,0xE4,0x5C,0x44,0xC4,0x00,0x02,0xF2,0x82,0x82,0x82,0xFE,0x80,0x80,0x00,
    0x02,0x01,0x7F,0x10,0x10,0x3F,0x00,0x08,0x08,0x08,0x08,0x48,0x88,0x40,0x3F,0x00,/*"码",5*/
};

//请输入新密码
const unsigned char chinese_enter_newPassword[][32] = {
    0x40,0x42,0xCC,0x00,0x00,0x44,0x54,0x54,0x54,0x7F,0x54,0x54,0x54,0x44,0x40,0x00,
    0x00,0x00,0x7F,0x20,0x10,0x00,0xFF,0x15,0x15,0x15,0x55,0x95,0x7F,0x00,0x00,0x00,/*"请",0*/
    0x88,0x68,0x1F,0xC8,0x08,0x10,0xC8,0x54,0x52,0xD1,0x12,0x94,0x08,0xD0,0x10,0x00,
    0x09,0x19,0x09,0xFF,0x05,0x00,0xFF,0x12,0x92,0xFF,0x00,0x5F,0x80,0x7F,0x00,0x00,/*"输",1*/
    0x00,0x00,0x00,0x00,0x00,0x01,0xE2,0x1C,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x80,0x40,0x20,0x10,0x0C,0x03,0x00,0x00,0x00,0x03,0x0C,0x30,0x40,0x80,0x80,0x00,/*"入",2*/
    0x40,0x44,0x54,0x65,0xC6,0x64,0x54,0x44,0x00,0xFC,0x44,0x44,0xC4,0x42,0x40,0x00,
    0x20,0x12,0x4A,0x82,0x7F,0x02,0x0A,0x92,0x60,0x1F,0x00,0x00,0xFF,0x00,0x00,0x00,/*"新",3*/
    0x10,0x8C,0x44,0x04,0xE4,0x04,0x95,0xA6,0x44,0x24,0x14,0x84,0x44,0x94,0x0C,0x00,
    0x02,0x02,0x7A,0x41,0x41,0x43,0x42,0x7E,0x42,0x42,0x42,0x43,0xF8,0x00,0x00,0x00,/*"密",4*/
    0x04,0x84,0xE4,0x5C,0x44,0xC4,0x00,0x02,0xF2,0x82,0x82,0x82,0xFE,0x80,0x80,0x00,
    0x02,0x01,0x7F,0x10,0x10,0x3F,0x00,0x08,0x08,0x08,0x08,0x48,0x88,0x40,0x3F,0x00,/*"码",5*/
};
//密码修改成功
const unsigned char modify_passWord_complete[][32] = {
   0x10,0x8C,0x44,0x04,0xE4,0x04,0x95,0xA6,0x44,0x24,0x14,0x84,0x44,0x94,0x0C,0x00,
    0x02,0x02,0x7A,0x41,0x41,0x43,0x42,0x7E,0x42,0x42,0x42,0x43,0xF8,0x00,0x00,0x00,/*"密",0*/
    0x04,0x84,0xE4,0x5C,0x44,0xC4,0x00,0x02,0xF2,0x82,0x82,0x82,0xFE,0x80,0x80,0x00,
    0x02,0x01,0x7F,0x10,0x10,0x3F,0x00,0x08,0x08,0x08,0x08,0x48,0x88,0x40,0x3F,0x00,/*"码",1*/
    0x40,0x20,0xF8,0x07,0xF0,0xA0,0x90,0x4C,0x57,0x24,0xA4,0x54,0x4C,0x80,0x80,0x00,
    0x00,0x00,0xFF,0x00,0x1F,0x80,0x92,0x52,0x49,0x29,0x24,0x12,0x08,0x00,0x00,0x00,/*"修",2*/
    0x04,0x84,0x84,0x84,0x84,0xFC,0x40,0x30,0xCC,0x0B,0x08,0x08,0xF8,0x08,0x08,0x00,
    0x00,0x7F,0x20,0x10,0x10,0x08,0x80,0x40,0x21,0x16,0x08,0x16,0x21,0x40,0x80,0x00,/*"改",3*/
    0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0x08,0x08,0xFF,0x08,0x09,0x0A,0xC8,0x08,0x00,
    0x80,0x60,0x1F,0x00,0x10,0x20,0x1F,0x80,0x40,0x21,0x16,0x18,0x26,0x41,0xF8,0x00,/*"成",4*/
    0x08,0x08,0x08,0xF8,0x08,0x08,0x08,0x10,0x10,0xFF,0x10,0x10,0x10,0xF0,0x00,0x00,
    0x10,0x30,0x10,0x1F,0x08,0x88,0x48,0x30,0x0E,0x01,0x40,0x80,0x40,0x3F,0x00,0x00,/*"功",5*/ 
};
//请设定密码
const unsigned char set_passWord[][32] = {
    0x40,0x42,0xCC,0x00,0x00,0x44,0x54,0x54,0x54,0x7F,0x54,0x54,0x54,0x44,0x40,0x00,
    0x00,0x00,0x7F,0x20,0x10,0x00,0xFF,0x15,0x15,0x15,0x55,0x95,0x7F,0x00,0x00,0x00,/*"请",0*/
    0x40,0x40,0x42,0xCC,0x00,0x40,0xA0,0x9E,0x82,0x82,0x82,0x9E,0xA0,0x20,0x20,0x00,
    0x00,0x00,0x00,0x3F,0x90,0x88,0x40,0x43,0x2C,0x10,0x28,0x46,0x41,0x80,0x80,0x00,/*"设",1*/
    0x10,0x0C,0x44,0x44,0x44,0x44,0x45,0xC6,0x44,0x44,0x44,0x44,0x44,0x14,0x0C,0x00,
    0x80,0x40,0x20,0x1E,0x20,0x40,0x40,0x7F,0x44,0x44,0x44,0x44,0x44,0x40,0x40,0x00,/*"定",2*/
    0x10,0x8C,0x44,0x04,0xE4,0x04,0x95,0xA6,0x44,0x24,0x14,0x84,0x44,0x94,0x0C,0x00,
    0x02,0x02,0x7A,0x41,0x41,0x43,0x42,0x7E,0x42,0x42,0x42,0x43,0xF8,0x00,0x00,0x00,/*"密",3*/
    0x04,0x84,0xE4,0x5C,0x44,0xC4,0x00,0x02,0xF2,0x82,0x82,0x82,0xFE,0x80,0x80,0x00,
    0x02,0x01,0x7F,0x10,0x10,0x3F,0x00,0x08,0x08,0x08,0x08,0x48,0x88,0x40,0x3F,0x00,/*"码",4*/
};

BEEP (蜂鸣器)

beep.c文件代码

cs 复制代码
#include "stm32f1xx.h"
#include "beep.h"

//初始化GPIO口
void beep_init(void){
    //打开时钟
    __HAL_RCC_GPIOC_CLK_ENABLE();
    //打开GPIO口
    GPIO_InitTypeDef GPIO_Initstruct;
    GPIO_Initstruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Initstruct.Pin = GPIO_PIN_13;
    GPIO_Initstruct.Pull = GPIO_NOPULL;
    GPIO_Initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOC,&GPIO_Initstruct);
    //关闭蜂鸣器
    beep_off();
}
//打开蜂鸣器函数
void beep_on(void){
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}
//关闭蜂鸣器
void beep_off(void){
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
}
//反转蜂鸣器
void beep_toggle(void){
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_13);  
}

SWITCH(开关)

switch.h文件代码

cs 复制代码
#include "alarm.h"
#include "stm32f1xx.h"                  // 外设的驱动函数


//初始化GPIO口

void alarm_init(void){
    
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    //调用GPIO的初始化函数
    GPIO_InitTypeDef GPIO_Initstruct;
    GPIO_Initstruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Initstruct.Pin = GPIO_PIN_7;
    GPIO_Initstruct.Pull = GPIO_PULLUP;
    GPIO_Initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_Initstruct);
    //关闭继电器
    alarm_off();
}
//接通继电器的函数
void alarm_on(void){   
    
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_RESET);   
}

//断开继电器的函数
void alarm_off(void){
    
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7,GPIO_PIN_SET);
    
}

//获取继电器的状态
uint8_t alarm_status_get(void){
    
    return (uint8_t)HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_7);
}

W25Q128(FLASH存储器)

w25q128.c文件代码

cs 复制代码
#include "w25q128.h"

SPI_HandleTypeDef spi_handle = {0};
void w25q128_spi_init(void){
    
    spi_handle.Instance = SPI1;
    spi_handle.Init.Mode = SPI_MODE_MASTER;    //配置成主模式还是从模式
    spi_handle.Init.Direction = SPI_DIRECTION_2LINES;                 //配置全双工还是半双工
    spi_handle.Init.DataSize = SPI_DATASIZE_8BIT;      //数据的长度:8bit
    spi_handle.Init.CLKPolarity = SPI_POLARITY_LOW;      //CPOL = 0
    spi_handle.Init.CLKPhase = SPI_PHASE_1EDGE;          //CPHA = 奇数边沿检测
    spi_handle.Init.NSS = SPI_NSS_SOFT;               //软件控制SS引脚配置
    spi_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;    //波特率分频 :256
    spi_handle.Init.FirstBit = SPI_FIRSTBIT_MSB;             //高位先行还是低位先行:高位先行
  
    //下面这三个先不需要考虑
    spi_handle.Init.TIMode = SPI_TIMODE_DISABLE;
    spi_handle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    spi_handle.Init.CRCPolynomial = 7;
    
    HAL_SPI_Init(&spi_handle);
}


void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi){
    if(hspi->Instance == SPI1){
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_SPI1_CLK_ENABLE();
        
        GPIO_InitTypeDef gpio_initstruct;
        
        //NSS引脚
        gpio_initstruct.Pin = GPIO_PIN_4;
        gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;
        gpio_initstruct.Pull = GPIO_PULLUP;
        gpio_initstruct.Speed  = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOA,&gpio_initstruct);
        
        //SCL引脚和输出引脚
        gpio_initstruct.Pin = GPIO_PIN_5 |GPIO_PIN_7;
        gpio_initstruct.Mode = GPIO_MODE_AF_PP;
        HAL_GPIO_Init(GPIOA,&gpio_initstruct);
        
        //输入引脚
        gpio_initstruct.Pin = GPIO_PIN_6;
        gpio_initstruct.Mode = GPIO_MODE_INPUT;
        HAL_GPIO_Init(GPIOA,&gpio_initstruct);
        
    } 
}

uint8_t w25q128_spi_swap_byte(uint8_t data){
    
    uint8_t recv_data = 0;
    HAL_SPI_TransmitReceive(&spi_handle,&data, &recv_data,1,1000);  ///size:尺寸代表是多少个字节
    return recv_data;
}

//初始化w25q128模块
void w25q128_init(void){
    w25q128_spi_init();
}

//测试:读ID
uint16_t w25q128_read_id(void){
    uint16_t device_id = 0;
    
    W25Q128_CS(0);
    
    w25q128_spi_swap_byte(FLASH_ManufactDeviceID);
    w25q128_spi_swap_byte(0x00);
    w25q128_spi_swap_byte(0x00);
    w25q128_spi_swap_byte(0x00);
    
    device_id = w25q128_spi_swap_byte(FLASH_DummyBtye) << 8;  /* 将数据放在高8位 */
    device_id |= w25q128_spi_swap_byte(FLASH_DummyBtye);      /* 利用 |= 将数据放在低8位,并保留高8位的数据 */
    
    W25Q128_CS(1);
    
    return device_id; 
}

//写使能

void w25q128_write_enable(void)
{
    W25Q128_CS(0);
    w25q128_spi_swap_byte(FLASH_WriteEable);
    W25Q128_CS(1);
}

//读SR1寄存器
uint8_t w25q128_read_sr1(void){
    
    uint8_t recv_data = 0;
    W25Q128_CS(0);
    w25q128_spi_swap_byte(FLASH_ReadStatusReg1);
    recv_data = w25q128_spi_swap_byte(FLASH_DummyBtye);
    W25Q128_CS(1);
    return recv_data;
}

//发送地址的函数
void w25q128_send_address(uint32_t address){   //地址是3个字节,先发送高位,在发送中位,最后发送低位
    
    w25q128_spi_swap_byte(address >> 16);//高位
    w25q128_spi_swap_byte(address >> 8);  //中位:由于函数是一个8位的,因此,移动后数据后,高位自动去掉。
    w25q128_spi_swap_byte(address);
}

//忙等待的函数
void w25q128_wait_busy(void){
    
    while ((w25q128_read_sr1() & 0x01) == 0x01);  //判断最后一位是不是1
}

//读数据
void w25q128_read_data(uint32_t address,uint8_t *data,uint32_t size){
    
    uint32_t i = 0;
    
    W25Q128_CS(0);
    w25q128_spi_swap_byte(FLASH_ReadDate);
    w25q128_send_address(address);
    
    for(i = 0;i< size; i++)
       data[i] =  w25q128_spi_swap_byte(FLASH_DummyBtye);
    W25Q128_CS(1);
    
}
//页写:写的是256个字节,
void w25q128_write_page(uint32_t address,uint8_t *data,uint16_t size){   //代表的是字节数量
    
    uint16_t i = 0;
    
    w25q128_write_enable();
    W25Q128_CS(0);
    w25q128_spi_swap_byte(FLASH_PageProgram);
    w25q128_send_address(address);
    
    for(i = 0;i < size; i++)
       w25q128_spi_swap_byte(data[i]);
    W25Q128_CS(1);
    
    //忙等待,写入数据是需要花费时间的;看状态寄存器的最后一位是0还是1
    w25q128_wait_busy();
}
//扇区擦除
void w25q128_erase_sector(uint32_t address){
    w25q128_write_enable();
    w25q128_wait_busy();
    W25Q128_CS(0);
    w25q128_spi_swap_byte(FLASH_SectorErase);
    w25q128_send_address(address);
    W25Q128_CS(1);
    w25q128_wait_busy();
}
//如何指定变量的数据类型是多少

w25q128.h文件代码

cs 复制代码
#ifndef __W25Q128_H__
#define __W25Q128_H__
#include "stm32f1xx.h"

#define W25Q128_CS(x)  do{x ? \
                            HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET): \
                            HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);\
                       }while(0)

/* 指令表 */
#define FLASH_ManufactDeviceID          0x90
#define FLASH_WriteEable                0x06
#define FLASH_ReadStatusReg1            0x05
#define FLASH_ReadDate                  0x03
#define FLASH_PageProgram               0x02
#define FLASH_SectorErase               0x20
#define FLASH_DummyBtye                 0xFF                       

void w25q128_init(void);
uint16_t w25q128_read_id(void);
void w25q128_read_data(uint32_t address,uint8_t *data,uint32_t size);
void w25q128_write_page(uint32_t address,uint8_t *data,uint16_t size);
void w25q128_erase_sector(uint32_t address);                       
#endif

输入设备

KEYBOARD(矩阵键盘

keyboard.c文件代码:

cs 复制代码
#include "keyboard.h"
#include "delay.h"

static uint8_t key_value;

void keyboard_init(void){
    
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    //调用GPIO的初始化函数
    GPIO_InitTypeDef GPIO_Initstruct;
    
    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_PIN_14;
    GPIO_Initstruct.Mode = GPIO_MODE_INPUT;
    GPIO_Initstruct.Pull = GPIO_PULLDOWN;    //配置成下拉模式,当导通时,会变成高电平
    GPIO_Initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_Initstruct); 
    
    HAL_NVIC_SetPriority(EXTI0_IRQn,2,2);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
    
    HAL_NVIC_SetPriority(EXTI1_IRQn,2,2);
    HAL_NVIC_EnableIRQ(EXTI1_IRQn);
    
    HAL_NVIC_SetPriority(EXTI2_IRQn,2,2);
    HAL_NVIC_EnableIRQ(EXTI2_IRQn);
    
    HAL_NVIC_SetPriority(EXTI15_10_IRQn,2,2);
    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) == GPIO_PIN_SET);
        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) == GPIO_PIN_SET);
        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) == GPIO_PIN_SET);
        column = 0x03;
    }
     else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14) == GPIO_PIN_SET){
        delay_ms(10);
        while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_14) == GPIO_PIN_SET);
        column = 0x04;
    }
     
    if(row != 0 && column != 0)
        key_value = row | column;    //按位与进行拼接
}

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 == 0x14) ch = 'A';
        
        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 == 0x24) ch = 'B';
        
        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 == 0x34) ch = 'C';
        
        else if(key_value == 0x41) ch = '*';
        else if(key_value == 0x42) ch = '0';
        else if(key_value == 0x43) ch = '#';
        else if(key_value == 0x44) ch = 'D';
        delay_ms(400);
        key_value = 0x00;
    }
    return ch;
}

PASSWORD(配置密码)

password.c文件代码:

cs 复制代码
#include "password.h"
#include "w25q128.h"
#include "oled.h"
#include "keyboard.h"
#include "string.h"
#include "stdio.h"
#include "alarm.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,key_value = 0,try_times = 0;

                    /********** 1 *********/

//初始化函数
void password_init(void){
    w25q128_init();   
}
//读取密码:读取的是w25Q128_read_data();

//保存密码
void password_save(void){
    w25q128_erase_sector(0x000000);
    w25q128_write_page(0x000000,pwd_input,PASSWORD_SIZE);
    oled_modif_pwd_complete();
}
//清空输入缓存
void password_input_clear(void){
    memset(pwd_input, 0 ,PASSWORD_SIZE);
    i = 0;
}

//获取键盘输入:将按键输入(数字、字母)存到一个字符串数组当中,而"#","*"则进行返回。
uint8_t password_get_input(void){
   password_input_clear();                                  /*清除 字符数组 中的值 */
    
   while(1){
      key_value =  keyboard_get_value();
       if(key_value == '#'){
           printf("按下了 %c 键 \r\n", key_value);
           return POUND_KEY;
       }
       else if(key_value == '*'){
           printf("按下了 %c 键 \r\n", key_value);
           return STAR_KEY;
       }
       else if(key_value != 0){
           printf("按下了 %c 键 \r\n", key_value);
           oled_show_char(3,i * 10,key_value,16);  //字符的尺寸。
           pwd_input[i++] = key_value;
       }
   }
    
}
                    /********** 2 *********/
//密码比对:长度和元素。返回值:TURE和FLASE
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_pwd_right();
    alarm_on();
    beep_on();
    delay_ms(500);
    beep_off();
    delay_s(1);
    alarm_off();
    try_times = 0;
    
}
//密码输入错误的操作
void password_input_error_action(void){
    oled_pwd_error();
    try_times ++;
    if(try_times >= 3){
        beep_on();
        delay_ms(1000);
        beep_off();
        try_times = 0;
    }
    delay_s(1);
}

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

//旧密码输入错误的操作
void password_old_error_action(void){
    oled_pwd_error();
    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_set_pwd();
        password_get_input();
        password_save();
    }
}

password.h文件代码

cs 复制代码
#ifndef __PASSWORD_H__
#define __PASSWPRD_H__
#include "stm32f1xx.h"

#define FALSE               0
#define TRUE                1

#define POUND_KEY   '#'
#define STAR_KEY    '*'

void password_init(void);

void password_check(void);
void password_save(void);
uint8_t password_get_input(void);
uint8_t password_compare(void);

void password_input_right_action(void);
void password_input_error_action(void);

void password_old_right_action(void);
void password_old_error_action(void);


#endif

主函数

main.c文件代码:

cs 复制代码
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "oled.h"
#include "beep.h"
#include "alarm.h"
#include "w25q128.h"
#include "keyboard.h"
#include "password.h"


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    uart1_init(115200);
    printf("hello,world!!!\r\n");
    
    beep_init();
    alarm_init();
    oled_init();
    keyboard_init();
    password_init();
//    w25q128_init();
    
    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_error_action();
       }
       else if(key_last == STAR_KEY){
           oled_input_old_pwd();
           password_get_input();
           if(password_compare() == TRUE)
               password_old_right_action();
           else
               password_old_error_action();
       }
    }
}
相关推荐
森焱森30 分钟前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白34 分钟前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D1 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术4 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt5 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘5 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang5 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c
几个几个n7 小时前
STM32-第二节-GPIO输入(按键,传感器)
单片机·嵌入式硬件
Despacito0o10 小时前
ESP32-s3摄像头驱动开发实战:从零搭建实时图像显示系统
人工智能·驱动开发·嵌入式硬件·音视频·嵌入式实时数据库
门思科技11 小时前
设计可靠 LoRaWAN 设备时需要考虑的关键能力
运维·服务器·网络·嵌入式硬件·物联网