嵌入式系统中利用C51控制按键、流水灯和电机
一、按键、单片机驱动蜂鸣器
任务:用K1、K2、K3、K4控制无源蜂鸣器。单片机上机后,按键K1,无源蜂鸣器“滴、滴、滴”的响三声;按键K2,响四声;按键K3,响五声;按键K4,响六声。
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit BEEP = P2^5; //定义无源蜂鸣器和四个按脚的口
sbit K1 = P3^1;
sbit K2 = P3^0;
sbit K3 = P3^2;
sbit K4 = P3^3;
void delay(uint i){ //延时函数
uint x,y;
for(x=i;x>0;x--)
for(y=100;y>0;y--);
}
void buzzer(uchar i){ //使无源蜂鸣器响,间隔500ms,i为响的次数。
uchar time;
while(i--){
for(time = 250;time>0;time--){
BEEP = 0;
delay(2);
BEEP = 1;
}
delay(500);
}
}
main(){
while(1){
if(K1 == 0){ //第一次检测按的是哪个键
delay(8); //延时8ms,进行消抖
if(K1 == 0){ //第二次检测按键,证明确实是改键按下了
buzzer(3); //使蜂鸣器响3下
}
}else if(K2 == 0){
delay(8);
if(K2 == 0){
buzzer(4);
}
}else if(K3 == 0){
delay(8);
if(K3 == 0){
buzzer(5);
}
}else if(K4 == 0){
delay(8);
if(K4 == 0){
buzzer(6);
}
}else{}
}
}
二、矩阵按键的应用
任务:使用矩阵键盘,实现当某个按键按下时,用LED灯来表示,低四位LED灯为行,高四位LED灯为列。
1、扫描法获取矩阵键盘按键
#include<reg51.h>
sbit D1 = P2^0; //D1到D8定义LED灯引脚
sbit D2 = P2^1;
sbit D3 = P2^2;
sbit D4 = P2^3;
sbit D5 = P2^4;
sbit D6 = P2^5;
sbit D7 = P2^6;
sbit D8 = P2^7;
sbit h1 = P1^7; //h1~h4,定义矩阵键盘的行
sbit h2 = P1^6;
sbit h3 = P1^5;
sbit h4 = P1^4;
sbit lie1 = P1^3; //lie1~lie4,定义矩阵键盘的列
sbit lie2 = P1^2;
sbit lie3 = P1^1;
sbit lie4 = P1^0;
void key(){ //按键检测按钮
h1=h2=h3=h4=lie1=lie2=lie3=lie4=1; //先将所有行列都变成高电位
h1 = 0; //将第一行全置低电位
if(lie1==0){P2=0xff;D4=D5=0;} //将第一行置为低电位了,若按键第一行第一列的键,将导通线路,即连第一列的线将会变为低电位;P2=0xff为灯管显示前,显示前先清空之前显示的灯管
else if(lie2==0){P2=0xff;D4=D6=0;} //同理,若按键第一行第二列的键,导通线路,即连第二列的线变为低电位
else if(lie3==0){P2=0xff;D4=D7=0;}
else if(lie4==0){P2=0xff;D4=D8=0;}
else{}
h1 = 1; //将第一行恢复高电位
h2 = 0;
if(lie1==0){P2=0xff;D3=D5=0;}
else if(lie2==0){P2=0xff;D3=D6=0;}
else if(lie3==0){P2=0xff;D3=D7=0;}
else if(lie4==0){P2=0xff;D3=D8=0;}
else{}
h2 = 1;
h3 = 0;
if(lie1==0){P2=0xff;D2=D5=0;}
else if(lie2==0){P2=0xff;D2=D6=0;}
else if(lie3==0){P2=0xff;D2=D7=0;}
else if(lie4==0){P2=0xff;D2=D8=0;}
else{}
h3 = 1;
h4 = 0;
if(lie1==0){P2=0xff;D1=D5=0;}
else if(lie2==0){P2=0xff;D1=D6=0;}
else if(lie3==0){P2=0xff;D1=D7=0;}
else if(lie4==0){P2=0xff;D1=D8=0;}
else{}
h4 = 1;
}
void main(){
while(1){
key();
}
}
2、利用二维数组存储键值
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
uchar code ka[4][4] = {0xee,0xed,0xeb,0xe7, //将每一个按键赋一个值,按哪一个键,将会获取哪一个值,这值可以按需求设置,我这里需要的是亮两个灯(行灯和列灯),故设置十六进制代码作为值
0xde,0xdd,0xdb,0xd7,
0xbe,0xbd,0xbb,0xb7,
0x7e,0x7d,0x7b,0x77};
void key_get() //键值获取函数,单片机开启,就循环执行这个函数
{
uchar i,j;
for(i=0;i<4;i++){ //进行列循环
P1 = _cror_(0x7f,i); //0x7f为0111 1111,_cror_进行循环右移,赋值给P1
for(j=0;j<4;j++){ //若按键,P1的低四位会相应的改变
if((P1&_cror_(0x08,j))==0){ //若按第一键将会是0111 0111与0000 1000移按位与,按的键不同低四位的0的位置不同,所需循环次数也不同;若没按键,将会是0111 1111与0000 1000即它的右移四位按位与,将永得不为0
P2 = 0xff;
P2 = ka[j][i];}
}
}
}
void main(){
while(1){
key_get();
}
}
三、按键控制直流电机的启动和停止
任务:设K3为启动按钮,K4为停止按钮。点按K3,直流电机就转动;点按K4,直流电机就停止。
#include<reg51.h>
sbit DJ = P1^0; //定义控制电机的开关
sbit K3 = P3^2;
sbit K4 = P3^3;
void main(){
DJ=0;
while(1){
if(K3 == 0)DJ=1;
if(K4 == 0)DJ=0;
}
}
四、数码管的静态显示
任务:使用共阴极数码管,间隔0.5秒依次循环显示:1~9~0~.~A~F
#include<reg51.h>
char LED[] = {0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x3f,0x80,0x77,0x7C,0x39,0x5e,0x79,0x71},k;
void delay(){
int i,j;
for(i=500;i>0;i--)
for(j=120;j>0;j--);
}
void main(){
while(1){
for(k=0;k<17;k++){ //使用数组存储数字的信息,for循环依次将值赋值给P0口从而点亮相应的管灯
P0 = LED[k];
delay();
}
/* 基础方法,将每一个数字按顺序都写上
P0 = 0x06;delay(); //1
P0 = 0x5b;delay(); //2
P0 = 0x4f;delay(); //3
P0 = 0x66;delay(); //4
P0 = 0x6d;delay(); //5
P0 = 0x7d;delay(); //6
P0 = 0x07;delay(); //7
P0 = 0x7f;delay(); //8
P0 = 0x6f;delay(); //9
P0 = 0x3f;delay(); //0
P0 = 0x80;delay(); //.
P0 = 0x77;delay(); //A
P0 = 0x7C;delay(); //B
P0 = 0x39;delay(); //C
P0 = 0x5e;delay(); //D
P0 = 0x79;delay(); //E
P0 = 0x71;delay(); //F*/
}
}
五、数码管的动态显示
任务1:8个数码管,从左到右,肉眼能看见的显示3.1415926
#include<reg51.h>
sbit A1 = P2^2;
sbit A2 = P2^3;
sbit A3 = P2^4;
char LED[] = {0x3f,0x06,0x5b,0xcf,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //0 1 2 3. 4 5 6 7 8 9
void delay(int h){
int i,j;
for(i=h;i>0;i--)
for(j=120;j>0;j--);
}
void main(){
while(1){
A1=0;A2=0;A3=0;P0 = LED[6];delay(1); //8管
A1=0;A2=1;A3=0;P0 = LED[9];delay(1); //6管
A1=1;A2=0;A3=0;P0 = LED[2];delay(1); //7管
A1=1;A2=1;A3=0;P0 = LED[5];delay(1); //5管
A1=0;A2=0;A3=1;P0 = LED[1];delay(1); //4管
A1=0;A2=1;A3=1;P0 = LED[1];delay(1); //2管
A1=1;A2=0;A3=1;P0 = LED[4];delay(1); //3管
A1=1;A2=1;A3=1;P0 = LED[3];delay(1); //1管
}
}
六、步进电机控制
任务:通过ULN2003驱动模块控制28BYJ48步进电机运行方向及速度,按K1键转向,K2键提速,K3键减速,K4键停止与启动(暂停)。
#include<reg51.h>
typedef unsigned int uint;
typedef unsigned char uchar;
//定义ULN2003控制步进电机管脚
sbit IN1_A = P1^0;
sbit IN2_B = P1^1;
sbit IN3_C = P1^2;
sbit IN4_D = P1^3;
//定义独立按键控制脚
sbit K1 = P3^1;
sbit K2 = P3^0;
sbit K3 = P3^2;
sbit K4 = P3^3;
//定义步进电机速度,值越小,速度越快
//最小不小于1
#define MAX_SPEED 1
#define MIN_SPEED 5
//延时函数
void delay_10us(uint ten_us){ //当ten_us=1时,大约延时10us
while(ten_us--);
}
void delay_ms(uint ms) //当ms=1时,大约延时1ms
{
uint i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
/*****************************************************************
**********
* 函 数 名 : send_pulse
* 函数功能 : 输入一个数据给ULN2003从而实现向步进电机发送一个脉冲
* 输 入 : step:指定步进信号,可选值0~7
dir:方向选择,1:顺时针,0:逆时针
* 输 出 : 无
******************************************************************
*********/
void send_pulse(uchar step,uchar dir)
{
uchar temp = step;
if(dir==0) //如果为逆时针旋转
temp = 7 - step; //调换节拍信号
switch(temp)//8个节拍控制
{
case 0: IN1_A=1;IN2_B=0;IN3_C=0;IN4_D=0;break;
case 1: IN1_A=1;IN2_B=1;IN3_C=0;IN4_D=0;break;
case 2: IN1_A=0;IN2_B=1;IN3_C=0;IN4_D=0;break;
case 3: IN1_A=0;IN2_B=1;IN3_C=1;IN4_D=0;break;
case 4: IN1_A=0;IN2_B=0;IN3_C=1;IN4_D=0;break;
case 5: IN1_A=0;IN2_B=0;IN3_C=1;IN4_D=1;break;
case 6: IN1_A=0;IN2_B=0;IN3_C=0;IN4_D=1;break;
case 7: IN1_A=1;IN2_B=0;IN3_C=0;IN4_D=1;break;
}
}
/*****************************************************************
*********
* 函 数 名 :key_scan
* 函数功能 :检测独立按键是否按下,按下则返回对应键值
* 输 入 :mode=0: 单次扫描按键
mdde=1: 连续扫描按键
* 输 出 :1:K1按下
2:K2按下
3:K3按下
4:k4按下
0:没有按下
******************************************************************
********/
uchar key_scan()
{
if(K1==0||K2==0||K3==0||K4==0) //任意按键按下
{
delay_10us(1000); //消抖
if(K1==0) return 1;
else if(K2==0) return 2;
else if(K3==0) return 3;
else if(K4==0) return 4;
else if(K1==1&&K2==1&&K3==1&&K4==1) //无按键按下
{
return 0;
}
return 0;
}
}
void main()
{
uchar key=0;
uchar speed=MAX_SPEED;
uchar step=0;
uchar dir = 1;
while(1){
if(key_scan() == 4){
delay_ms(1000);
while(1){
key=key_scan();
if(key==1){dir=!dir;key=0;}
else if(key==2){
if(speed>MAX_SPEED){speed--;}
key = 0;
}
else if(key==3){
if(speed<MIN_SPEED){speed++;}
key = 0;
}
else if(key==4){
delay_ms(500);
break;
}
send_pulse(step++,dir);
if(step==8)step=0;
delay_ms(speed);
}
}
}
}
作者:小强不秃头