stm32密码锁(矩阵键盘,数码管)
·
可以先看一下上面的文章熟悉一下,代码都是一样的
目录
密码锁实现的功能
按键1-10输入0-9数字
三个功能键,按键11——清零(取消),按键12——确认密码,按键13——更换密码
当输入密码与设定密码一致时,蜂鸣器响,不一致时,则清零,重新输入
更换密码时,先输入要更改的密码,按下按键13,更改密码成功led亮
按键只用到了13个,可以增加其他功能键

代码实现
矩阵按键
按键10不是数字0,因为返回的按按键值是10,需要数字0的话,更改一下扫描按键的函数,把key_value=10更改为key_value=0即可
#include "key.h"
#include "Delay.h"
void key_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
uint16_t key_scan(void)
{
uint16_t key_value=0;
uint16_t temp=0;
//向配置为输入的引脚写入数据是无效的,真正改变配置为输出的引脚(PC0-PC3)的状态。
//扫描第一行,置PC0为低电平,其余行高电平
GPIO_Write(GPIOC,0X00);
GPIO_Write(GPIOC,0XF7);
/*
为什么是 0xf0 ,不是其他值
GPIO设置为上拉输入,其IDR寄存器会将该位置1,默认为0,
如PC4,5,6,7为上拉,则读取到的寄存器值为0xf0,
GPIO_ReadInputData这个函数会读取整个GPIOC端口的所有引脚的状态(我们只关心低8位),
所以会读取到输出状态下的io口状态
*/
if((GPIO_ReadInputData(GPIOC)&0XF0)!=0XF0)
//如果没有按键按下,则相等,跳过此判断,如果有按键按下,则进入判断
{
Delay_ms(50);
if((GPIO_ReadInputData(GPIOC)& 0XF0)!=0XF0)
{
//读取GPIOC寄存器IDR,进行与操作
//如果按键1按下 0111 0111 & 1111 0111
temp=(GPIO_ReadInputData(GPIOC)&0XF7);
switch(temp)
{
case 0xE7: key_value=1; break;
case 0xD7: key_value=2; break;
case 0xB7: key_value=3; break;
case 0x77: key_value=4; break;
default: key_value=0; break; //无效值
}
}
}
GPIO_Write(GPIOC,0X00);
GPIO_Write(GPIOC,0XFB);
if((GPIO_ReadInputData(GPIOC)&0XF0)!=0XF0)
{
Delay_ms(50);
if((GPIO_ReadInputData(GPIOC) & 0XF0)!=0XF0)
{
temp=(GPIO_ReadInputData(GPIOC)&0XFB);
switch(temp)
{
case 0xEB: key_value=5; break;
case 0xDB: key_value=6; break;
case 0xBB: key_value=7; break;
case 0x7B: key_value=8; break;
default: key_value=0; break;
}
}
}
GPIO_Write(GPIOC,0X00);
GPIO_Write(GPIOC,0XFD);
if((GPIO_ReadInputData(GPIOC)&0XF0)!=0XF0)
{
Delay_ms(50);
if((GPIO_ReadInputData(GPIOC) & 0XF0)!=0XF0)
{
temp=(GPIO_ReadInputData(GPIOC)&0XFD);
switch(temp)
{
case 0xED: key_value=9; break;
case 0xDD: key_value=10; break;
case 0xBD: key_value=11; break;
case 0x7D: key_value=12; break;
default: key_value=0; break;
}
}
}
GPIO_Write(GPIOC,0X00);
GPIO_Write(GPIOC,0XFE);
if((GPIO_ReadInputData(GPIOC)&0XF0)!=0XF0)
{
Delay_ms(50);
if((GPIO_ReadInputData(GPIOC) & 0XF0)!=0XF0)
{
temp=(GPIO_ReadInputData(GPIOC)&0XFE);
switch(temp)
{
case 0xEE: key_value=13; break;
case 0xDE: key_value=14; break;
case 0xBE: key_value=15; break;
case 0x7E: key_value=16; break;
default: key_value=0; break;
}
}
}
return key_value;
}
#ifndef __KEY_H
#define __KEY_H
#include "stm32f10x.h" // Device header
void key_init(void);
uint16_t key_scan(void);
#endif
数码管
#include "74HC595.h"
#include "Delay.h"
uint8_t table[]={
0xc0,//0
0xf9,//1
0xa4,//2
0xb0,//3
0x99,//4
0x92,//5
0x82,//6
0xf8,//7
0x80,//8
0x90,//9
0x88,//A
0x83,//B
0xc6,//C
0xa1,//D
0x86,//E
0x8e, //F
0x8c, //P
0xc1,//U
0x91,//Y
0x7c,//L 20
0x00,//全亮
0xff //熄灭
};
uint8_t weixuan[4]={0x80,0x40,0x20,0x10};
// 四 三 二 一 数码管位选——看级联的输出脚接哪四个
//初始化
void hc595_init(void)
{
RCC_APB2PeriphClockCmd(HC595_CLK, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = HC595_DS_PIN|HC595_SH_CP_PIN|HC595_ST_CP_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(HC595_GPIO, &GPIO_InitStructure);
GPIO_ResetBits(HC595_GPIO,HC595_DS_PIN|HC595_SH_CP_PIN|HC595_ST_CP_PIN);
}
//发送16位数据 前8位是要显示的数字 后8位是要显示在哪个数码管
后8位只用到前4位——看级联的输出脚接哪四个
void hc595_send(uint16_t data)
{
int i=0;
for(i =0;i<16;i++) //扫16位数据
{
HC595_SH_CP_RESET; //拉低移位寄存器时钟
if( data & (0x8000>>i))//与操作
{
HC595_DS_SET; //拉高串行输入引脚,置1
Delay_us(5);
}
else
{
HC595_DS_RESET; //拉低串行输入引脚,置0
Delay_us(5);
}
HC595_SH_CP_SET; //拉高移位寄存器时钟 每一位输入就拉高一次移位寄存器时钟引脚——才能把数据放到8位寄存器里
}
HC595_ST_CP_SET; // 拉高存储寄存器时钟,读取移位寄存器的数据
HC595_ST_CP_RESET; //读取完数据就拉低
}
/*
num 显示的数字
weixuan1 显示在第几个数码管
*/
void hc595_display(uint8_t num,uint8_t weixuan1)
{
hc595_send(table[num]<<8 | weixuan[weixuan1]);//将两个8位数据合成16位数据再发送
}
#ifndef __74HC595_H
#define __74HC595_H
#include "stm32f10x.h"
//引脚初始化
#define HC595_CLK RCC_APB2Periph_GPIOB //时钟
#define HC595_GPIO GPIOB //最好用同属引脚,不然得再定义
#define HC595_DS_PORT GPIOB
#define HC595_DS_PIN GPIO_Pin_1 //输入引脚
#define HC595_SH_CP_PORT GPIOB
#define HC595_SH_CP_PIN GPIO_Pin_0 //移位寄存器引脚
#define HC595_ST_CP_PORT GPIOB
#define HC595_ST_CP_PIN GPIO_Pin_2 //存储寄存器引脚
//74HC595口线高低电平宏定义
#define HC595_DS_SET GPIO_SetBits(HC595_DS_PORT,HC595_DS_PIN) //拉高
#define HC595_DS_RESET GPIO_ResetBits(HC595_DS_PORT,HC595_DS_PIN) //拉低
#define HC595_SH_CP_SET GPIO_SetBits(HC595_SH_CP_PORT,HC595_SH_CP_PIN)
#define HC595_SH_CP_RESET GPIO_ResetBits(HC595_SH_CP_PORT,HC595_SH_CP_PIN)
#define HC595_ST_CP_SET GPIO_SetBits(HC595_ST_CP_PORT,HC595_ST_CP_PIN)
#define HC595_ST_CP_RESET GPIO_ResetBits(HC595_ST_CP_PORT,HC595_ST_CP_PIN)
void hc595_init(void);//初始化引脚
void hc595_send(uint16_t data);//发送数据
void hc595_display(uint8_t num,uint8_t weixuan1);//显示
#endif
led,蜂鸣器
#include "led.h"
void led_buzzer_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_1);//低电平触发,先不要发声
}
void led_on(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_0);
}
void led_off(void)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
}
void buzzer_on(void)//低电平触发
{
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
}
void buzzer_off(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_1);
}
#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h" // Device header
void led_buzzer_init(void);
void led_on(void);
void led_off(void);
void buzzer_on(void);
void buzzer_off(void);
#endif
主函数
#include "stm32f10x.h" // Device header
#include "74HC595.h"
#include "Delay.h"
#include "key.h"
#include "led.h"
uint16_t keynum,num,flag;//获取按键值,输入密码的位数,正确密码标志位
uint8_t key1[4]={0,0,0,0};//输入密码
uint8_t key2[4]={1,2,3,4}; //初始密码
int main(void)
{
key_init();
hc595_init();
led_buzzer_init();
while(1)
{
hc595_display(key1[0]%10,0);
hc595_display(key1[1]%10,1);
hc595_display(key1[2]%10,2);
hc595_display(key1[3]%10,3);
keynum=keyboard_scan();//读取按键值
led_off();
buzzer_off();
if(keynum!=0)
{
if(keynum<=10)//按键1-10,
{
if(num<4)//输入密码的位数
{
key1[num]=keynum;
num++;
if(num==4)//如果输入密码超过4位,会覆盖第一个输入的数字
{
num=0;
}
switch(num)//显示密码
{
case 0:hc595_display(key1[0]%10,0);
break;
case 1:hc595_display(key1[1]%10,1);
break;
case 2:hc595_display(key1[2]%10,2);
break;
case 3:hc595_display(key1[3]%10,3);
break;
default:
break;
}
}
}
if(keynum==11)//清零
{
num=0;
for(uint8_t i;i<4;i++)
{
key1[i]=0;
}
}
if(keynum==12)//确认密码
{
num=0;
//输入密码与设定密码一致,置标志位
if(key1[0]==key2[0]&key1[1]==key2[1]&key1[2]==key2[2]&key1[3]==key2[3])
{
flag=1;
}
//输入密码不一致,清零,重新输入
for(uint8_t i;i<4;i++)
{
key1[i]=0;
}
}
if(keynum==13)//更改密码
{
num=0;
//更新初始密码并清零
for(uint8_t i;i<4;i++)
{
key2[i]=key1[i];
key1[i]=0;
}
led_on();//更换密码成功
}
}
//输入密码一致,执行操作
if(flag)
{
buzzer_on();
flag=0;
}
}
}
更多推荐



所有评论(0)