嵌入式——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);
		}
	}	
 }
}

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值