设计分享 | 51单片机与蜂鸣器实现摩斯电码转换

vx:【嵌入式工程师成长日记】

https://mp.weixin.qq.com/s?__biz=Mzg4Mzc3NDUxOQ==&mid=2247484142&idx=1&sn=e40b82983532fc4e8c8861d91b09a535&chksm=cf4307b6f8348ea01699b987e7c787009ef45fac791a49aeac3b397a9d74ef3e5e49d15ba26f&token=1580607796&lang=zh_CN#rdicon-default.png?t=M85Bhttps://mp.weixin.qq.com/s?__biz=Mzg4Mzc3NDUxOQ==&mid=2247484142&idx=1&sn=e40b82983532fc4e8c8861d91b09a535&chksm=cf4307b6f8348ea01699b987e7c787009ef45fac791a49aeac3b397a9d74ef3e5e49d15ba26f&token=1580607796&lang=zh_CN#rd

具体功能实现

当我们按下矩阵按键中不同的按键时,在LCD1602显示相应的内容,同时一个按键按下多次可以切换不同的字母或数字,并且LED灯会闪烁。最后当我们按下确认时,蜂鸣器会发出不同频率的声音。

器件

蜂鸣器,AT89C51,若干按键,LCD1602,两支LED灯,排阻

仿真展示图

仿真前

仿真后

知识介绍

矩阵按键控制原理

如果使用独立按键与单片机连接, 每一个按键都需要单片机的一个 I/O 口, 若某单片机系统需较多按键, 用独立按键便会占用过多的 I/O 口资源。 单片机系统中 I/O 口资源往往比较宝贵, 当用到多个按键时为了减少 I/O 口引脚, 引入了矩阵按键。

矩阵按键检测原理

按键检测一般通过扫描来实现,先使某一列变为低电平,其余几列为高电平,后检测每行是否出现低电平。若没有出现,则某行按键没有被按下,若出现则说明按键被按下,即可锁定位置。

矩阵按键控制方法

①行列式法:

上图将第一列全部置0,其余位置均为1

将第一行全部置0,其余位全部置1。

因此我们可以得出按键按下的正是第一行第一列的

②线翻转法:

首先使所有行置为0,然后检测列是否含有低电平,如果有,则记录列的位置;之后再翻转,使所有列置为0,检测行是否有低电平,如果有,则记录行的位置(本文采用的是线翻转法)

主函数代码(C语言)KEIL5实现

#include <reg51.h>
#include <intrins.h>
void delay(unsigned char ms);
void delay2(int i);
void lcd_wcmd(unsigned char cmd);
void lcd_pos(unsigned char pos);
void lcd_wdat(unsigned char dat);
void lcd_init();
void xianshi();
void KeyDown();
void la_ba();

sbit rs= P2^6;
sbit rw = P2^5;
sbit ep = P2^7;
sbit d=P3^0;
sbit d1=P3^1;
sbit lb=P3^2;
int b,c,s=0,q=0,w=0;
#define GPIO_KEY P1
unsigned char dis1[32];
unsigned char dis2[9]={',','A','D','G','J','M','P','T','W'};
unsigned char dis3[9]={'1','2','3','4','5','6','7','8','9'};
unsigned int code laba[36][5]={
1,2,3,3,3,//A
2,1,1,1,3,//B
2,1,2,1,3,//C
2,1,1,3,3,//D
1,3,3,3,3,//E
1,1,2,1,3,//F
2,2,1,3,3,//G
1,1,1,1,3,//H
1,1,3,3,3,//I
1,2,2,2,3,//J
2,1,2,3,3,//K
1,2,1,1,3,//L
2,2,3,3,3,//M
2,1,3,3,3,//N
2,2,2,3,3,//0
1,2,2,1,3,//P
2,2,1,2,3,//Q
1,2,1,3,3,//R
1,1,1,3,3,//S
2,3,3,3,3,//T
1,1,2,3,3,//U
1,1,1,2,3,//V
1,2,2,3,3,//W
2,1,1,2,3,//X
2,1,2,2,3,//Y
2,2,1,1,3,//Z
2,2,2,2,2,//0
1,2,2,2,2,//1
1,1,2,2,2,//2
1,1,1,2,2,//3
1,1,1,1,2,//4
1,1,1,1,1,//5
2,1,1,1,1,//6
2,2,1,1,1,//7
2,2,2,1,1,//8
2,2,2,2,1,//9
};
// LCD1602代码开始
bit lcd_bz()
{
bit result;
rs = 0;
rw = 1;
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
result = (bit)(P0 & 0x80);
ep = 0;
return result;
}
void lcd_wcmd(unsigned char cmd)
{
while(lcd_bz());//判断LCD是否忙碌
rs = 0;
rw = 0;
ep = 0;
_nop_();
_nop_();
P0 = cmd;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 0;
}
void lcd_pos(unsigned char pos)
{
lcd_wcmd(pos | 0x80);
}
void lcd_wdat(unsigned char dat)
{
while(lcd_bz());//判断LCD是否忙碌
rs = 1;
rw = 0;
ep = 0;
P0 = dat;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 0;
}
void lcd_init()
{
lcd_wcmd(0x38);
delay(1);
lcd_wcmd(0x0c);
delay(1);
lcd_wcmd(0x06);
delay(1);
lcd_wcmd(0x01);
delay(1);
}
void xianshi()
{
int i=0,j=1,n=0;
while(dis1[i] != '\0')
{
lcd_pos(0x00);//设置显示位置
while(j!=0&&dis1[i] != '\0')
{
lcd_wdat(dis1[i]);//显示字符
i++;
j=i%16;
}
lcd_pos(0x40);// 设置显示位置
j=1;
while(j!=0&&dis1[i] != '\0')
{
lcd_wdat(dis1[i]);// 显示字符
i++;
j=i%16;
}
j=1;
if(dis1[i] != '\0')
i-=16;
}
i=0;
}
//LCD1602代码结束
void delay(unsigned char ms)
{
unsigned char i;
while(ms--)
{
for(i = 0; i< 250; i++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
void delay2(int i)
{
while(i--);
}
//按下按键
void KeyDown()
{
int KeyValue=0;
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f)
{
delay(5);  //消抖
if(GPIO_KEY!=0x0f)
{
GPIO_KEY=0X0F;
switch(GPIO_KEY)
{
case(0X07): KeyValue=0;break;
case(0X0b): KeyValue=1;break;
case(0X0d): KeyValue=2;break;
case(0X0e): KeyValue=12;break;
}
}
GPIO_KEY=0XF0;
switch(GPIO_KEY)
{
case(0X70): KeyValue=KeyValue;break;
case(0Xb0): KeyValue=KeyValue+3;break;
case(0Xd0): KeyValue=KeyValue+6;break;
case(0Xe0): KeyValue=KeyValue+9;break;
}
while(GPIO_KEY!=0xf0);
if(KeyValue!=c&&dis1[w]!='\0')
{b=0;w++;}
if(KeyValue<=8&&s==0)
{
if(c==12||c==15)w--;
dis1[w]=dis2[KeyValue]+b;
d=0;delay(25);d=1;delay(25);
}
else if(KeyValue<=8&&s==1)
{
if(c==12||c==15)w--;
dis1[w]=dis3[KeyValue];
d=0;delay(25);d=1;delay(25);
}
else if(KeyValue==12)
{
//当按键为12时,删除一位(退格)
if(w>0)
{
w--;
dis1[w]=' ';
}
else
{
dis1[w]=' ';
}
d1=0;delay(25);d1=1;delay(25);
}
else if(KeyValue==15)
{
//当按下15时,添加一个空格
while(w!=0)
{
w--;
dis1[w]=' ';
}
}
else if(KeyValue==9)
{
//显示数字7
q++;
s=q%2;
if(c==12||c==15)w-=2;
}
else if(KeyValue==10)
{
//显示数字8
if(s==0)
dis1[w]=' ';
else
dis1[w]='0';
}
else if(KeyValue==11)
{
//显示数字9
dis1[w]=' ';
}
else if(KeyValue==18)
{
dis1[w]=' ';
w--;
}
else if(KeyValue==21)
{
la_ba();
}
b++;
if(b==3)b=0;
c=KeyValue;
}
}
//蜂鸣器
void la_ba()
{
int i,j,t;
for(i=0;dis1[i]!='\0';i++)
{
if(dis1[i]>=65&&dis1[i]<=90)
{
d1=0;delay(25);d1=1;delay(25);
for(j=0;laba[dis1[i]-65][j]!=3;j++)
{
if(laba[dis1[i]-65][j]==1)
{
t=100;
while(t--)
{
lb=~lb;
delay2(70);
}
delay(50);
}
if(laba[dis1[i]-65][j]==2)
{
t=300;
while(t--)
{
lb=~lb;
delay2(70);
}
delay(50);
}
if(laba[dis1[i]-65][j+1]==3)
{
delay(100);
}
}
}
if(dis1[i]>=48&&dis1[i]<=57)
{
d=0;delay(25);d=1;delay(25);
for(j=0;j<5;j++)
{
if(laba[dis1[i]-22][j]==1)
{
t=100;
while(t--)
{
lb=~lb;
delay2(70);
}
delay(50);
}
if(laba[dis1[i]-22][j]==2)
{
t=300;
while(t--)
{
lb=~lb;
delay2(70);
}
delay(50);
}
if(j==4)
{
delay(100);
}
}
}
}
}
void main()
{
lcd_init();// 初始化LCD
delay(10);
while(1)
{
KeyDown();
xianshi();
}
}

vx:【嵌入式工程师成长日记】 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值