单片机学习小组
直播中

萧蔼晨

7年用户 952经验值
私信 关注

如何利用C51单片机去实现一种独立按键点亮LED灯的设计呢

如何利用C51单片机去实现一种独立按键点亮LED灯的设计呢?其程序代码该怎样去实现呢?

回帖(1)

李文

2022-1-24 11:25:30
实验部分

1、单片机实现流水灯实验

实验目标:
实现一个基础的流水灯
实验过程
1、project>>new uVision project>>Atmel>>AT89C52>>右键options for target "target1">>output>>Create Hex File,建立并设置工程; 点击File>>new建立文件
2、查看单片机引脚图,了解到8个Led灯分别对应引脚为P10~P17,因此可定义变量

sfr p1= 0x90;
***it led1 = p1^0;
***it led2 = p1^1;
***it led3 = p1^2;
***it led4 = p1^3;
***it led5 = p1^4;
***it led6 = p1^5;
***it led7 = p1^6;
***it led8 = p1^7;
3、流水灯原理:即先点亮一个LED灯,让程序停滞一短时间后熄灭该LED灯点亮下一个LED灯,以此周而复始。根据以往的c语言知识,这个停滞可用sleep函数来实现,但现在我们并未引入stdio头文件,因此我们可以自己编写一个“sleep”函数

#define bara unsigned int//不能直接用int,所以给它改头换面一下再使用
void sleep(bara z)//加一个参数,可以控制停滞时间
{
bara i;
  for(i=0;i    }
}


4、根据流水灯原理实现流水灯
现在我们可以实现流水灯功能了

int main()
{
   while(1){//在通电情况下无限循环,“周而复始”
   led1=0;//点亮第一个LED
   sleep(10000);//停滞一段时间,让LED以肉眼可见的速度亮起而非一闪而过
   led1=1;//熄灭第一个LED
   led2=0;//点亮第二个LED
   sleep(10000);//之后的过程都与以上相同
   led2=1;
   led3=0;
   sleep(10000);
   led3=1;
   led4=0;
   sleep(10000);
   led4=1;
   led5=0;
   sleep(10000);
   led5=1;
   led6=0;
   sleep(10000);
   led6=1;
   led7=0;
   sleep(10000);
   led7=1;
   led8=0;
   sleep(10000);
   led8=1;


   }
   return 0;
}
因为时单独控制LED灯,因此对寄存器的bit位赋值(***it关键字)会更简单。
附上完整代码:

eg52.h>
#include                          
#define bara unsigned int         
sfr p1= 0x90;
***it led1 = p1^0;
***it led2 = p1^1;
***it led3 = p1^2;
***it led4 = p1^3;
***it led5 = p1^4;
***it led6 = p1^5;
***it led7 = p1^6;
***it led8 = p1^7;   
void sleep(bara z)
{
  bara i;
  for(i=0;i    }
}


int main()
{
   while(1){
   led1=0;
   sleep(10000);
   led1=1;
   led2=0;
   sleep(10000);
   led2=1;
   led3=0;
   sleep(10000);
   led3=1;
   led4=0;
   sleep(10000);
   led4=1;
   led5=0;
   sleep(10000);
   led5=1;
   led6=0;
   sleep(10000);
   led6=1;
   led7=0;
   sleep(10000);
   led7=1;
   led8=0;
   sleep(10000);
   led8=1;
   }
   return 0;
}
像不像网络差的时侯逛淘宝的那个加载进度条

2、自加:美化你的流水灯

这是我在上一个实验做完后的空余时间中自娱自乐的产物。如何美化流水灯?主要就是微微减少流水灯停滞时间使其看起来更流畅,以及增加流水灯流动方式。完整代码如下,大家有兴趣不妨烧录到单片机上让它博君一乐

#include
#include                          
#define bara unsigned int
sfr p1= 0x90;
***it led1 = p1^0;
***it led2 = p1^1;
***it led3 = p1^2;
***it led4 = p1^3;
***it led5 = p1^4;
***it led6 = p1^5;
***it led7 = p1^6;
***it led8 = p1^7;   
void sleep(bara z)
{
  bara i;
  for(i=0;i    }
}
//本流水灯能流畅的往返流动
int main()
{
   while(1){
   led1=0;
   sleep(10000);
   led1=1;
   led2=0;
   sleep(10000);
   led2=1;
   led3=0;
   sleep(10000);
   led3=1;
   led4=0;
   sleep(10000);
   led4=1;
   led5=0;
   sleep(10000);
   led5=1;
   led6=0;
   sleep(10000);
   led6=1;
   led7=0;
   sleep(10000);
   led7=1;
   led8=0;
   sleep(10000);
   led8=1;
   led7=0;
   sleep(10000);
   led7=1;
   led6=0;
   sleep(10000);
   led6=1;
   led5=0;
   sleep(10000);
   led5=1;
   led4=0;
   sleep(10000);
   led4=1;
   led3=0;
   sleep(10000);
   led3=1;
   led2=0;
   sleep(10000);
   led2=1;
   }
   return 0;
}
这回像是b站视频卡住时的加载进度条了
3、C51单片机实现独立按键点亮LED灯

实验目的
实现在按动单片机上的独立按键时,会有一个对应的led灯改变当前状态(若当前未亮则亮起,若已亮起则熄灭)
实验过程
注:本段是我的探索过程,包含大量不成熟的代码,如果想直接查看最终代码,可点击此处跳转查看
project>>new uVision project>>Atmel>>AT89C52>>右键options for target "target1">>output>>Create Hex File,建立并设置工程;
点击File>>new建立文件;
根据CPU引脚图找出四个独立按键对应的引脚(注:其实一共有五个独立按键,但其中一个名为“rst”的按键是重置状态按键,不可再定义)

由于四个独立按键的引脚命名十分直白,可看出它们分别对应P33、P34、P36、P37号引脚。
可定义变量:

***it key1=P3^3;
***it key2=P3^4;
***it key3=P3^6;
***it key4=P3^7;


先用KEY1按键连接·LED1·(对应引脚P10)试一下

int main()
{
   while(1){
   if(key1==0)        {//按键按下时
          led1=~led1;//led1的值取非,改变led状态
         }


   }                 
   return 0;
}


将代码烧录到文件上后,会发现:虽然是可以按按键key1改变led1状态,但是随机性极大,必须要反复、快速按动按键才能改变状态,有时甚至是长按按键能让led灯亮起,一松开按键led灯就灭了,这是为什么?
由于单片机的按键下有一个机械弹片,机械弹片虽然能改变按键当前状态,但会在短时间内造成一系列抖动,造成开关状态多次改变
因此我们程序中使用开关时需要对其进行防抖

  防抖分为软件防抖和硬件防抖,其中软件防抖为:检测到有开关按下时,先用软件延时(10~20ms),而后再确认键电平是否依旧维持闭合状态的电平,若是,则确认此键已经按下,消除按键抖动影响
——百度文库,《按键的消抖技术》
可看出,若想消除抖动影响,需要:判断按键电平>>延时>>再次判断按键电平。这一点也和老师在实验后的讲解相同
因此之前的主函数部分可改为:

void sleep(bara z)
{
  bara i;
  for(i=0;i    }
}


int main()
{
   while(1){
   if(key1==0)        {//判断按键电平
      sleep(1000);//延时
      if(key1==0){//再次判断按键电平
             led1=~led1;//led1的值取非,改变led状态
           }
         }


   }                 
   return 0;
}
这次的程序烧录到单片机上时,可以发现按键能稳定改变led灯状态,因此我们照葫芦画瓢,将四个按键与对应led灯全部加入while(1)循环中,却发现此时单片机的反应十分迟钝;根据老师后续的讲解,此时因为单片机需要将所有的按键状态都判断一次,因此总体需要有四倍的延时,极大影响操作流畅性,因此还需要对程序进行限定。

**以下附上最终的完整代码**(可完美实现按键控制led灯) #include              


#include                          
#define bara unsigned int


***it led1=P1^0;//四个led灯
***it led2=P1^1;
***it led3=P1^2;
***it led4=P1^3;

***it key1=P3^3;//四个开关
***it key2=P3^4;
***it key3=P3^6;
***it key4=P3^7;


void sleep(bara z)//休眠函数
{
  bara i;
  for(i=0;i    }
}


int main()
{
   while(1){
   if(key1==0)        {//判断按键电平
   sleep(1000);//延时
     if(key1==0)//再次判断
         {led1=~led1;}//改变led电平
         while(!key1);//增加:限定条件 ———— 当第一次检测到开关状态变化
         }            //这样就不需要每一次循环都判断四个按键的电平导致一次循环有四次延时
         if(key2==0)        {
   sleep(1000);
     if(key2==0)
         {led2=~led2;}
         while(!key2);
         }
         if(key3==0)        {
   sleep(1000);
     if(key3==0)
         {led3=~led3;}
         while(!key3);
         }
         if(key4==0)        {
   sleep(1000);
     if(key4==0)
         {led4=~led4;}
         while(!key4);
         }
   }                 
   return 0;
}


课程笔记部分


轮询

轮询是一种单片机的工作形式,也就是我们编写单片机程序时经常用到的while(1),这种方式实现简单,因此经常被用到,但是这种方式有非常明显的缺点:浪费CPU资源,同时易造成时间差(例如我实现独立按键点亮led灯实验那里,不小心就弄出四倍延时)。

中断

中断是一种与轮询相辅相成的工作形式,原理学习java时学到的中断一样(甚至用到的关键字也大致相同interrupt):控制CPU短暂的停止做A工作,转而去完成B、C等其他工作,做完后再继续转入A工作。

C51单片机的中断源以及中断的使用

共有五种中断源,每种中断源都有其对应编号
[tr]编号中断源(电平信号)[/tr]
0外部中断(0)
1定时器中断(0)
2外部中断(1)
3定时器中断(1)
4串口中断 (嘭)
中断的使用方法:
void 寄存器()interrupt n//其中n属于中断源编号{  //此处写需要进行的操作} 注:该函数只需在主函数外即可,不需要在主函数或其他函数中调用。
同时,编号为0~4的各个中断源优先级递减,因此当同时出现多个中断,会根据中断优先级来决定处理中断的顺序
第一次写笔记类的博客,笔法拙劣还望见谅。。。若文中有错误,也劳烦各位大神能指教!
举报

更多回帖

发帖
×
20
完善资料,
赚取积分