C51单片机,实现LED灯循环点亮的程序所出现的问题

为什么我增大对计数器的赋值,LED灯循环间隔反而减小,而我减小计数器赋值,LED循环间隔反而增大


     ORG  0000H
      LJMP MAIN
      ORG  0003H
      LJMP INTER
      ORG  0020H
MAIN: MOV  SP,#60H
      MOV  TMOD,#01H
      SETB EA
      CLR  IT0
      SETB IE0
      SETB EX0
      SETB TR0
      CLR  C
      MOV  A,#01H
      MOV  P1,A
      MOV  R0,#14H
TIM1: MOV  TH0,#0E8H
      MOV  TL0,#0ECH
      JNB  TF0,$
      CLR  TF0
      DJNZ R0,TIM1
      JNC  RL0
RR0:  RR A
      MOV  P1,A
      LJMP TIM1
RL0:  RL A
      MOV  P1,A
      LJMP TIM1
INTER:CPL C
      RETI
      END


TMOD=1时是计数方式1:计数位数是16位,由TL0作为低8位、TH0作为高8位,组成了16位加1计数器
计数个数与计数初值的关系为:X=2^16-N
通俗来讲,就是TH0和TL0设置了初值为10000,那么51芯片会从10000+1,也就是10001、10002这样累加,知道65535中断,所以TH0和TL0初值越大,累加值越小,才会有你跑马灯的效果。你可以看看C51计时器的教程(https://www.cnblogs.com/Poppings/p/14556300.html)

如果您想要减小LED灯循环间隔,可以尝试减小计数器的赋值;如果您想要增大LED灯循环间隔,可以尝试增大计数器的赋值。同时,您需要注意计数器的范围和定时器的精度,确保赋值在合适的范围内,并且定时器能够精确地控制LED灯循环间隔。

  • 你可以参考下这个问题的回答, 看看是否对你有帮助, 链接: https://ask.csdn.net/questions/644318
  • 除此之外, 这篇博客: 2021年4月10日-粤嵌智能小车兴趣课笔记(2)中的 3、C51单片机实现独立按键点亮LED灯 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 实验目的
    实现在按动单片机上的独立按键时,会有一个对应的led灯改变当前状态(若当前未亮则亮起,若已亮起则熄灭)
    实验过程
    注:本段是我的探索过程,包含大量不成熟的代码,如果想直接查看最终代码,可点击此处跳转查看
    project>>new uVision project>>Atmel>>AT89C52>>右键options for target "target1">>output>>Create Hex File,建立并设置工程;
    点击File>>new建立文件;
    根据CPU引脚图找出四个独立按键对应的引脚(注:其实一共有五个独立按键,但其中一个名为“rst”的按键是重置状态按键,不可再定义)
    在这里插入图片描述
    由于四个独立按键的引脚命名十分直白,可看出它们分别对应P33P34P36P37号引脚。
    可定义变量:

    sbit key1=P3^3;
    sbit key2=P3^4;
    sbit key3=P3^6;
    sbit 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<z;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<intrins.h>			   
    #define bara unsigned int
    
    sbit led1=P1^0;//四个led灯
    sbit led2=P1^1;
    sbit led3=P1^2;
    sbit led4=P1^3;
     
    sbit key1=P3^3;//四个开关
    sbit key2=P3^4;
    sbit key3=P3^6;
    sbit key4=P3^7;
    
    void sleep(bara z)//休眠函数
    {
      bara i;
      for(i=0;i<z;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;
    }