51单片机一个开关控制两个程序

当开关接高电平时,做霹雳灯,当接低电平时做奇偶灯变换,有没有人帮看一下代码有什么问题吗?```

#include
#include
#define uchar unsigned char
#define uint unsigned int
uchar tab[]={0x7e,0xbd,0xdb,0xe7,0xdb,0xbd};
sbit key=P0^7;
uchar a;
void delay(uint b)
{
uchar t;
while (b--)
{
for(t=0;t<120;t++);
}
}
void main()
{
unsigned char zt=0;
while(1)
{
if(key==1){zt=0;}
if(key==0){zt=1;}
switch(zt)
{
case 0:
P1=0x55;
while(1)
{
delay(500);
P1=crol(P1,1);
}
break;
case 1:
while(1)
{
for(a=0;a<6;a++)
{
P1=tab[a];
delay(500);
}
}
break;
}
}
}

```

这么改,供参考:

#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint  unsigned int
uchar tab[] = { 0x7e,0xbd,0xdb,0xe7,0xdb,0xbd };
sbit key = P0 ^ 7;
uchar a;
void delay(uint b)
{
    uchar t;
    while (b--)
    {
        for (t = 0; t < 120; t++);
    }
}
void main()
{
    unsigned char zt = 0;
    P1 = 0x55;
    while (1)
    {
        if (key == 0) { 
            delay(100);   //消抖
            if (key == 0) {
                zt = !zt; //状态翻转
                if (zt == 0) P1 = 0x55;
            }
            while (!key); //判断是否放开按键
        }
        switch (zt)
        {
        case 0:
            delay(500);
            P1 = crol(P1, 1);
            break;
        case 1:
            for (a = 0; a < 6; a++)
            {
                P1 = tab[a];
                delay(500);
            }
            break;
        }
    }
}

代码的逻辑看起来是可以实现需求的,但是在具体实现上存在一些问题:

  1. 在延时函数 delay() 中,使用了一个空循环来实现精确延时,但是空循环的具体延时时间并不稳定,且受到不同的编译器、芯片型号、频率等因素的影响,因此不太建议这种方式来实现延时。

  2. 在按键的检测中,使用了简单的消抖方式(当按键松开后才重新置状态),虽然可以防止误触,但如果按键在短时间内反复按下,则可能会因为状态未及时置位而导致问题。

下面是对代码进行改进的建议:

  1. 延时函数可以使用定时器来实现精确延时,这样能够避免使用空循环的问题。例如,使用定时器 0 可以实现毫秒级的延时功能。具体实现可参考以下代码:

    void delay(uint ms) {
        while (ms--) {
            TH0 = (65536 - 1000) / 256;  // 定时器初值
            TL0 = (65536 - 1000) % 256;
            TF0 = 0;  // 清除定时器中断标志
            TR0 = 1;  // 开始计时
            while (!TF0);  // 等待计时结束
            TR0 = 0;  // 停止计时
            TF0 = 0;  // 清除定时器中断标志
        }
    }
    
  2. 建议在按键检测中增加消抖的处理,可以通过对按键状态的连续检测来实现。例如,可以对按键状态做一个计数器,只有在按键状态连续稳定一段时间(如 10 次检测)之后才认为按键状态是有效的。代码示例如下:

    void scan_key() {
        static uint cnt = 0;
        static uchar state = 1;
        if (key == 0) {
            cnt++;
            if (cnt >= 10) {
                state = 0;
                cnt = 0;
            }
        } else {
            cnt = 0;
            state = 1;
        }
        if (state == 0) {
            zt = 1;
        } else {
            zt = 0;  // 当按键状态没变化时保持前一个状态
        }
    }
    
  3. 当按键状态发生变化时,可以增加一个短暂的延时,以防止按键反复触发导致状态切换不及时。例如,可以在状态切换之后延时 50ms 左右再进行后续操作。

  • 你可以看下这个问题的回答https://ask.csdn.net/questions/750922
  • 这篇博客你也可以参考下:用51单片机测电容容值的方法原理及一些问题的解决方案
  • 除此之外, 这篇博客: 51单片机舵机控制中的 硬件设计 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 这次的小系统电路都由洞洞板搭建,主要包括51单片机最小系统,矩阵按键,数码管驱动和舵机四个部分。Protues仿真电路图如下
    在这里插入图片描述

    • 数码管驱动
      仿真测试程序数码管时可以直接用IO口驱动,但是实物搭建电路需要再接驱动电路,这次选择了74HC245芯片来驱动。这款芯片使用非常简单,在驱动显示屏,做隔离芯片时应用都非常多。它有A0-A7,B0-B7两组输入输出口,可以DIR管脚选择数据传输方向,在使用时如果不需要转换传输方向可以直接将此管脚接到芯片VCC或者GND。
      在这里插入图片描述

    • 矩阵按键
      4*4的矩阵按键每一行每一列接在一个口上,通过行列扫描确定哪一个按键被按下,也就是导通。

    • 舵机
      舵机一般分为数字舵机和模拟电机。它们都由马达,减速齿轮组和控制电路组成。主要区别是数字电机有微处理器和晶振,能产生一周期为20ms,占空比为7.5%(即1.5ms高电平)的基准信号,通过输入与信号比较确定打角。而模拟电机则通过电位器产生的差分电压驱动电机正反转从而改变角度。这次选用的是SG90 180度的模拟舵机,价格低,带动一个激光头绰绰有余。通过单片机输出的周期为20ms的PWM波控制,在宽度从0.5ms到2.5ms,每一个占空比对应一个角度,示意图如下
      在这里插入图片描述