今天,给大家分享的是自己弄着玩的一个矩阵键盘控制控制舵机模拟一个智能门锁的功能。
用到的硬件: 开发板我用的是原子哥的精英板(杀鸡用宰牛刀了)。
矩阵键盘(宝上十几块买的):
外加一个舵机和一个0.96的oled显示屏。
矩阵键盘:有VCC,GND,SCL,SDO四条线,这个矩阵键盘的驱动原理和i2c类似,
从SDO发送一个100微秒的高电平为读取信号,读取数据的流程为:
? ? 1.SDO设置为输出模式
? ? 2.SDO拉高
? ? 3.延时100微秒
? ? 4.SDO拉低
? ? 5.SDO设置为输入模式
接下来就会接收一个16位的数据,上代码:
u16 TOUCHKEY_READ(void)
{
u8 i;
u16 re_val=0;
SDO_OUT();//设置sdo为输出
SD0_Set(1);//sdo拉高
delay_us(100);
SD0_Set(0);//sd0拉低
SDO_IN();//设置sdo为输入
for(i=0;i<16;i++)
{
SCL_Set(1);//拉高scl
delay_us(200);
SCL_Set(0);//拉低scl
if(Read_SDO)//读SDO是否为高
{
re_val |=(1<<i);//为真就把1向左移i位与re_val做或运算
}
}
delay_ms(2);
return re_val;
}
这是我配置的.h文件配合上面一起看
#define SCL_Set(EN) (EN)? GPIO_SetBits(GPIOB,GPIO_Pin_6):GPIO_ResetBits(GPIOB,GPIO_Pin_6)//问号表达式 EN值位真就执行前面 为假相反
#define SD0_Set(EN) (EN)? GPIO_SetBits(GPIOB,GPIO_Pin_7):GPIO_ResetBits(GPIOB,GPIO_Pin_7)
#define Read_SDO GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7)//读取输入的数据
//IO 方向设置
#define SDO_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDO_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
然后就是数据的处理,我自己写的数据处理老是有点小毛病,是在网上找的:
u8 Get_KeyNum(void)
{
u8 key_num;
NowKeyNum=TOUCHKEY_READ();
if((NowKeyNum & 0x0001)&& !(PreKeyNum & 0x0001))
{
key_num='1';
}
if((NowKeyNum & 0x0002)&& !(PreKeyNum & 0x0002))
{
key_num='2';
}
if((NowKeyNum & 0x0004)&& !(PreKeyNum & 0x0004))
{
key_num='3';
}
if((NowKeyNum & 0x0008)&& !(PreKeyNum & 0x0008))
{
key_num='A';
}
if((NowKeyNum & 0x0010)&& !(PreKeyNum & 0x0010))
{
key_num='4';
}
if((NowKeyNum & 0x0020)&& !(PreKeyNum & 0x0020))
{
key_num='5';
}
if((NowKeyNum & 0x0040)&& !(PreKeyNum & 0x0040))
{
key_num='6';
}
if((NowKeyNum & 0x0080)&& !(PreKeyNum & 0x0080))
{
key_num='B';
}
if((NowKeyNum & 0x0100)&& !(PreKeyNum & 0x0100))
{
key_num='7';
}
if((NowKeyNum & 0x0200)&& !(PreKeyNum & 0x0200))
{
key_num='8';
}
if((NowKeyNum & 0x0400)&& !(PreKeyNum & 0x0400))
{
key_num='9';
}
if((NowKeyNum & 0x0800)&& !(PreKeyNum & 0x0800))
{
key_num='C';
}
if((NowKeyNum & 0x1000)&& !(PreKeyNum & 0x1000))
{
key_num='*';
}
if((NowKeyNum & 0x2000)&& !(PreKeyNum & 0x2000))
{
key_num='0';
}
if((NowKeyNum & 0x4000)&& !(PreKeyNum & 0x4000))
{
key_num='#';
}
if((NowKeyNum & 0x8000)&& !(PreKeyNum & 0x8000))
{
key_num='D';
}
PreKeyNum=NowKeyNum;
return key_num;
}
舵机的驱动我之前也有介绍过这里就不介绍了,需要的可以看一下。http://t.csdn.cn/NQsqk
这是判断密码是否正确函数以及oled显示内容函数:
char configpw[10]="1010#";//密码
void Judgement(void)
{
int n=0;
for(;1;n++)
{
if(password[n]==configpw[n])
{
if(password[n]=='#'&&configpw[n]=='#')
{
Open_Lock();
break;//密码输入成功
}
}
else
{
Password_Mistake();
break;//密码输入错误
}
}
i=0;//i清除标志位
}
void Open_Lock(void)//密码正确执行效果
{
OLED_Clear(0); //显示屏显示
OLED_ShowCHinese(26,4,4);//密
OLED_ShowCHinese(46,4,5);//码
OLED_ShowCHinese(66,4,6);//正
OLED_ShowCHinese(86,4,7);//确
SG90_set();//舵机驱动函数
}
void Password_Mistake()//密码错误执行效果
{
//显示屏显示函数
OLED_Clear(0);
OLED_ShowCHinese(26,4,4);//密
OLED_ShowCHinese(46,4,5);//码
OLED_ShowCHinese(66,4,8);//错
OLED_ShowCHinese(86,4,9);//误
}
最后就是主函数? (我这里的#include "include.h" 是定义了一个include.h里面包含了其他所有的.h文件)
#include "include.h"
char password[10];
int i=0,I;
int main(void)
{
char mun='D';
char MUN;
Init();
OLED_Clear(0);
OLED_ShowCHinese(26,0,0);//王
OLED_ShowCHinese(46,0,1);//某
OLED_ShowCHinese(66,0,2);//科
OLED_ShowCHinese(86,0,3);//技
while(1)
{
delay_ms(50);
MUN=Get_KeyNum();//获取矩阵键盘的数据
if(mun!=MUN)//密码的不重复 其作用是不让一直进入执行
{
mun=Get_KeyNum();//获取矩阵键盘的数据
password[i++]=mun;
BEEP_OPEN;//输入成功 蜂鸣器驱动
delay_ms(100);
BEEP_CLOSE;
if(password[i-1]=='#')//'#'为结束
{
Judgement();//判断密码是否正确
}//'#'为结束,在这里进入函数判断密码是否正确
else
{
OLED_ShowChar(i*20,6,password[i-1],16);//oled显示输入数字 ’#‘(结束符)不显示
}
}
}
}
至于为什么num初始化为’D‘呢 ?
我测试多次发现一上电过后不经过任何操作读取到的初始值就是’D‘至于是什么原因没找到,所以就将就它初始化一个D,就不会一上电就执行if里面的代码。
能力有限 不喜勿喷 ——来自喜欢分享的小王
链接:https://pan.baidu.com/s/15GbKBrs46HZy5kSqT55iQQ?pwd=6hzi? 提取码:6hzi
|