矩阵键盘扫描原理与代码实现

74HC595驱动数码管与点阵屏

可以先看一下上面的文章熟悉一下,代码都是一样的

目录

密码锁实现的功能

代码实现

矩阵按键

数码管

led,蜂鸣器

主函数


密码锁实现的功能

按键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;
			}
			
	}
}


更多推荐