找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2313|回复: 34
打印 上一主题 下一主题
收起左侧

自锁和非自锁开关在单片机程序中用法?

[复制链接]
跳转到指定楼层
楼主
10黑币
51单片机控制灯亮灭:用一个非自锁开关控制2个灯亮灭,当做总开关K总,再分别用2个自锁按键开关K1,K2控制这2个灯LED1,LED2亮灭。这种组合开关的用法程序怎么写呢?

K总合上,K1,K2才起作用。K总断开,K1,K2不起作用。K总合上时,2个灯都亮,然后K1,K2可以分别控制亮灭。K总断开后,K1,K2延时10秒灭。

最佳答案

查看完整内容

你一开始这么说就不用改那么多次
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:161164 发表于 2024-12-1 21:13 | 只看该作者
lch327 发表于 2024-12-2 22:15
K总开关触发后,2个灯就亮了,然后再用分开关K1,,K2按键控制亮灭,然后不管灯亮灭,只要关断K总,2个灯 ...

你一开始这么说就不用改那么多次
  1. #include <REG52.h>

  2. // 定义类型别名
  3. typedef unsigned char u8;  // 0 到 255
  4. typedef unsigned int u16;   // 0 到 65535

  5. // 延时函数,产生约 50 毫秒的延时
  6. void Delay50ms(void) //@11.0592MHz
  7. {
  8.     unsigned char data i, j; // 定义循环变量

  9.     i = 90;  // 外层循环次数
  10.     j = 163; // 内层循环次数
  11.     do
  12.     {
  13.         while (--j); // 内层循环
  14.     }
  15.     while (--i); // 外层循环
  16. }

  17. // 定义按键和 LED 引脚
  18. sbit Kzong = P3^1; // 总按键连接到 P3.1
  19. sbit K1 = P3^2;    // 按键 1 连接到 P3.2
  20. sbit K2 = P3^3;    // 按键 2 连接到 P3.3
  21. sbit LED1 = P2^0;  // LED1 连接到 P2.0
  22. sbit LED2 = P2^1;  // LED2 连接到 P2.1

  23. u8 Off_Delay = 0;  // 关灯延时计数器,初始化为 0

  24. void main()
  25. {
  26.     while(1) // 主循环
  27.     {
  28.         if(Kzong == 0) // 如果总按键被按下
  29.         {
  30.             if(Off_Delay == 0) // 如果延时计数器为 0
  31.             {
  32.                 LED1 = 0; // 开启 LED1
  33.                 LED2 = 0; // 开启 LED2
  34.             }
  35.             if(K1 == 0) // 如果按键 1 被按下
  36.             {
  37.                 Delay50ms(); // 延时 50ms
  38.                 if(K1 == 0) // 确认按键 1 仍被按下
  39.                 {
  40.                     LED1 = !LED1; // 切换 LED1 状态
  41.                     while(K1 == 0); // 等待按键 1 释放
  42.                 }
  43.             }
  44.             if(K2 == 0) // 如果按键 2 被按下
  45.             {
  46.                 Delay50ms(); // 延时 50ms
  47.                 if(K2 == 0) // 确认按键 2 仍被按下
  48.                 {
  49.                     LED2 = !LED2; // 切换 LED2 状态
  50.                     while(K2 == 0); // 等待按键 2 释放
  51.                 }
  52.             }
  53.             Off_Delay = 200; // 设置关灯延时计数器为 200
  54.         }
  55.         else // 如果总按键没有被按下
  56.         {
  57.             if(Off_Delay != 0) // 如果延时计数器不为 0
  58.             {
  59.                 Delay50ms(); // 延时 50ms
  60.                 Off_Delay = Off_Delay - 1; // 递减延时计数器
  61.                 if(Off_Delay == 0) // 如果计数器减到 0
  62.                 {
  63.                     LED1 = 1; // 熄灭 LED1
  64.                     LED2 = 1; // 熄灭 LED2
  65.                 }
  66.             }
  67.         }
  68.     }
  69. }
复制代码
回复

使用道具 举报

板凳
ID:624769 发表于 2024-12-1 22:03 | 只看该作者
delay 函数你应该自己会写吧?

bit  Off_Delay;
void  main()
{
     while(1)
     {
          if(Kzong == 0)
          {
                LED1 = K1;
                LED2 = K2;
                Off_Delay = 1;
          }
          else
         {
                 if(Off_Delay == 1)
                 {
                        Off_Delay  = 0;
                        delay_Sec(10);
                        LED1  = 1;
                        LED2  = 1;
                 }
         }
     }
}
回复

使用道具 举报

地板
ID:161164 发表于 2024-12-1 23:20 | 只看该作者
本帖最后由 lkc8210 于 2024-12-2 11:10 编辑

稍修一下
重开不用等10秒
  1. u8  Off_Delay = 0;
  2. void  main()
  3. {
  4.         while(1)
  5.         {
  6.                 if(Kzong == 0)
  7.                 {
  8.                         LED1 = K1;
  9.                         LED2 = K2;
  10.                         Off_Delay = 200;
  11.                 }
  12.                 else
  13.                 {
  14.                         if(Off_Delay)
  15.                         {
  16.                                 if(--Off_Delay==0)
  17.                                 {
  18.                                         LED1  = 1;
  19.                                         LED2  = 1;
  20.                                 }
  21.                                 delay_ms(50);
  22.                         }
  23.                 }
  24.         }
  25. }
复制代码
回复

使用道具 举报

5#
ID:1109793 发表于 2024-12-2 08:03 | 只看该作者
开关画的不太对吧,K1K2好像表示非自锁才比较合适吧
回复

使用道具 举报

6#
ID:584814 发表于 2024-12-2 08:47 | 只看该作者
“K总断开后,K1,K2延时10秒灭”是K总断开后,无论K1,K2是亮是灭都要亮起延时10秒灭 ?
回复

使用道具 举报

7#
ID:1009628 发表于 2024-12-2 10:11 | 只看该作者
man1234567 发表于 2024-12-2 08:47
“K总断开后,K1,K2延时10秒灭”是K总断开后,无论K1,K2是亮是灭都要亮起延时10秒灭 ?

不需要再亮起,只要给一个灭的指令就行,灭的 状态不管,保持原样,亮的 状态灭掉就行了。
回复

使用道具 举报

8#
ID:1009628 发表于 2024-12-2 10:16 | 只看该作者
xiaobendan001 发表于 2024-12-2 08:03
开关画的不太对吧,K1K2好像表示非自锁才比较合适吧

K1,K2就是按键开关,属于非自锁开关。我画的不好。
回复

使用道具 举报

9#
ID:1009628 发表于 2024-12-2 10:27 | 只看该作者
K总应该是自锁开关,K1,K2是非自锁按键开关,说错了。不好意思。
回复

使用道具 举报

10#
ID:1109793 发表于 2024-12-2 11:12 | 只看该作者
lch327 发表于 2024-12-2 10:27
K总应该是自锁开关,K1,K2是非自锁按键开关,说错了。不好意思。

原来是说反了,不是画反了
回复

使用道具 举报

11#
ID:1109793 发表于 2024-12-2 11:13 | 只看该作者
lch327 发表于 2024-12-2 10:27
K总应该是自锁开关,K1,K2是非自锁按键开关,说错了。不好意思。

那你这个延时是K总触发的,这不是没有啥意义了?平时K1K2都是断开的,灯也不亮啊
回复

使用道具 举报

12#
ID:1009628 发表于 2024-12-2 12:03 | 只看该作者
188610329 发表于 2024-12-1 22:03
delay 函数你应该自己会写吧?

bit  Off_Delay;

不好意思,开关表达错了,应该K总是自锁开关,K1,K2是非自锁按键开关。所以这个程序K1,K2按下时灯灭,可是抬起时灯又亮了。应该抬起是还保持灭的状态 ,再按一下灯亮,抬起时保持不变。
回复

使用道具 举报

13#
ID:1009628 发表于 2024-12-2 14:01 | 只看该作者
188610329 发表于 2024-12-1 22:03
delay 函数你应该自己会写吧?

bit  Off_Delay;

经过试验,还是不行。
回复

使用道具 举报

14#
ID:1109793 发表于 2024-12-2 17:37 | 只看该作者
描述不对,K1K2不是按下去灯亮,松开灯灭,而是在K总接通的情况下,按一下改变一下灯的状态。
K总断开后,如果灯亮就延时灭,不亮就不管了。
回复

使用道具 举报

15#
ID:161164 发表于 2024-12-2 21:01 | 只看该作者
lch327 发表于 2024-12-2 12:03
不好意思,开关表达错了,应该K总是自锁开关,K1,K2是非自锁按键开关。所以这个程序K1,K2按下时灯灭, ...
  1. u8  Off_Delay = 0;
  2. void  main()
  3. {
  4.         while(1)
  5.         {
  6.                 if(Kzong == 0)
  7.                 {
  8.                         if(!K1)
  9.                         {
  10.                                 delay_ms(50);
  11.                                 if(!K1)
  12.                                 {
  13.                                         LED1=!LED1;
  14.                                         while(!K1);
  15.                                 }
  16.                         }
  17.                         if(!K2)
  18.                         {
  19.                                 delay_ms(50);
  20.                                 if(!K2)
  21.                                 {
  22.                                         LED2=!LED2;
  23.                                         while(!K2);
  24.                                 }
  25.                         }
  26.                         Off_Delay = 200;
  27.                 }
  28.                 else
  29.                 {
  30.                         if(Off_Delay)
  31.                         {
  32.                                 if(--Off_Delay==0)
  33.                                 {
  34.                                         LED1  = 1;
  35.                                         LED2  = 1;
  36.                                 }
  37.                                 delay_ms(50);
  38.                         }
  39.                 }
  40.         }
  41. }
复制代码
回复

使用道具 举报

16#
ID:1009628 发表于 2024-12-2 21:40 | 只看该作者
xiaobendan001 发表于 2024-12-2 17:37
描述不对,K1K2不是按下去灯亮,松开灯灭,而是在K总接通的情况下,按一下改变一下灯的状态。
K总断开后, ...

对,对,对,感谢理解我的意思,就是您说的这样。我以为描述清楚了,实际容易误解,您说的准确。
回复

使用道具 举报

17#
ID:1009628 发表于 2024-12-2 22:15 | 只看该作者
xiaobendan001 发表于 2024-12-2 11:13
那你这个延时是K总触发的,这不是没有啥意义了?平时K1K2都是断开的,灯也不亮啊

K总开关触发后,2个灯就亮了,然后再用分开关K1,,K2按键控制亮灭,然后不管灯亮灭,只要关断K总,2个灯是灭的状态就行了。
回复

使用道具 举报

18#
ID:1009628 发表于 2024-12-2 22:28 | 只看该作者
lkc8210 发表于 2024-12-1 23:20
稍修一下
重开不用等10秒

能写一个完整的吗?U8是什么意思,(--off_Delay==0)是什么意思啊?看不懂,能注释一下吗?
回复

使用道具 举报

19#
ID:1009628 发表于 2024-12-2 23:25 | 只看该作者

能写一个完整的吗?U8是什么意思,(--off_Delay==0)是什么意思啊?看不懂,能注释一下吗?
回复

使用道具 举报

20#
ID:1109793 发表于 2024-12-3 07:25 | 只看该作者
lch327 发表于 2024-12-2 23:25
能写一个完整的吗?U8是什么意思,(--off_Delay==0)是什么意思啊?看不懂,能注释一下吗?

看起来C你是一点不懂啊,还是先看看书吧,代码都给你了你都看不懂啊
回复

使用道具 举报

21#
ID:624769 发表于 2024-12-3 21:32 | 只看该作者
lkc8210 发表于 2024-12-3 09:19
你一开始这么说就不用改那么多次

代码有个小漏洞,假定 K1 / K2 年久失修,容易按下后卡住,不一定能弹起, 此时 Kzong 会失效,建议,按下后,不要等待弹起,而是标记“未弹起”,在“未弹起”标记被清除前,不再判断按键按下。
没特别意思,属于职业习惯的强迫症。发现有漏洞,不说就难受。
回复

使用道具 举报

22#
ID:1009628 发表于 2024-12-4 17:07 | 只看该作者
188610329 发表于 2024-12-3 21:32
代码有个小漏洞,假定 K1 / K2 年久失修,容易按下后卡住,不一定能弹起, 此时 Kzong 会失效,建议,按下 ...

经过试验,确实有这个问题,假如常按K1或K2不松手,K总就不起作用了,一直在那里死循环了。可程序具体怎么改能实现呢?我看一些教学里,也不提K1,K2卡住的问题啊。那属于硬件故障吧。教学里没考虑这个问题。如果按键坏了,肯定就得换按键,保证它是完好的。
回复

使用道具 举报

23#
ID:1009628 发表于 2024-12-4 18:03 | 只看该作者
lkc8210 发表于 2024-12-1 21:13
你一开始这么说就不用改那么多次

感谢您的解答,困扰我多日的问题解决了。我是新手,单片机爱好者,望您以后多多指教。十分感谢!!!
回复

使用道具 举报

24#
ID:1109793 发表于 2024-12-4 18:18 | 只看该作者
lch327 发表于 2024-12-4 17:07
经过试验,确实有这个问题,假如常按K1或K2不松手,K总就不起作用了,一直在那里死循环了。可程序具体怎 ...

做个演示没问题,控制个灯光也不打紧,如果是涉及安全性问题,不能使用这种死等的方式了,做为实用产品,必须方方面面考虑到各种可能出现的情况。
回复

使用道具 举报

25#
ID:161164 发表于 2024-12-5 00:03 | 只看该作者
lch327 发表于 2024-12-4 17:07
经过试验,确实有这个问题,假如常按K1或K2不松手,K总就不起作用了,一直在那里死循环了。可程序具体怎 ...

非死等版本
  1. #include <REG52.h>

  2. // 定义类型别名
  3. typedef unsigned char u8;  // 0 到 255
  4. typedef unsigned int u16;   // 0 到 65535

  5. // 延时函数,产生约 50 毫秒的延时
  6. void Delay50ms(void) //@11.0592MHz
  7. {
  8.     unsigned char data i, j; // 定义循环变量

  9.     i = 90;  // 外层循环次数
  10.     j = 163; // 内层循环次数
  11.     do
  12.     {
  13.         while (--j); // 内层循环
  14.     }
  15.     while (--i); // 外层循环
  16. }

  17. // 定义按键和 LED 引脚
  18. sbit Kzong = P3^1; // 总按键连接到 P3.1
  19. sbit K1 = P3^2;    // 按键 1 连接到 P3.2
  20. sbit K2 = P3^3;    // 按键 2 连接到 P3.3
  21. sbit LED1 = P2^0;  // LED1 连接到 P2.0
  22. sbit LED2 = P2^1;  // LED2 连接到 P2.1

  23. u8 Off_Delay = 0;  // 关灯延时计数器,初始化为 0

  24. void main()
  25. {
  26.         bit K1_Lock = 1;
  27.         bit K2_Lock = 1;
  28.     while(1) // 主循环
  29.     {
  30.         if(Kzong == 0) // 如果总按键被按下
  31.         {
  32.             if(Off_Delay == 0) // 如果延时计数器为 0
  33.             {
  34.                 LED1 = 0; // 开启 LED1
  35.                 LED2 = 0; // 开启 LED2
  36.             }
  37.                         if(K1 == 0 && K1_Lock ==1) //下降沿触发
  38.                         {
  39.                                 LED1 = !LED1; // 切换 LED1 状态
  40.                         }
  41.                         K1_Lock = L1;
  42.                         if(K2 == 0 && K2_Lock ==1) //下降沿触发
  43.                         {
  44.                                 LED2 = !LED2; // 切换 LED1 状态
  45.                         }
  46.                         K2_Lock = L2;
  47.             Delay50ms(); // 延时 50ms
  48.             Off_Delay = 200; // 设置关灯延时计数器为 200
  49.         }
  50.         else // 如果总按键没有被按下
  51.         {
  52.             if(Off_Delay != 0) // 如果延时计数器不为 0
  53.             {
  54.                 Delay50ms(); // 延时 50ms
  55.                 Off_Delay = Off_Delay - 1; // 递减延时计数器
  56.                 if(Off_Delay == 0) // 如果计数器减到 0
  57.                 {
  58.                     LED1 = 1; // 熄灭 LED1
  59.                     LED2 = 1; // 熄灭 LED2
  60.                 }
  61.             }
  62.         }
  63.     }
  64. }
复制代码
回复

使用道具 举报

26#
ID:1009628 发表于 2024-12-6 14:31 | 只看该作者

这个程序解决了按键卡死的问题。我搭建一个电路,用单片机控制ULN2003驱动电路,单片机输出高电平给2003,2003反相后低电位驱动12V继电器,12V继电器再控制一个中间继电器,这时候,KZONG,K1,K2都不稳定,有时好使,有时不好使,K1和K2还互相干扰。可能接入中间继电器后,会受到电磁干扰。不接中间继电器没事。如果换用三极管驱动电路就没问题。(单片机低电位控制三极管驱动12V小继电器,再控制中间继电器)用2种电路做了试验。还没用灯泡做试验,等有了灯泡再试试。我想是不是加按键延时,会抵消干扰呢?下降沿触发没有延时,按键一瞬间会受到干扰吗?
回复

使用道具 举报

27#
ID:1009628 发表于 2024-12-6 14:42 | 只看该作者

这种接法单片机会受到干扰
回复

使用道具 举报

28#
ID:1109793 发表于 2024-12-6 16:05 | 只看该作者
lch327 发表于 2024-12-6 14:42
这种接法单片机会受到干扰

2003里面就是三极管吧
开关线不能太长,否则要增加上拉电阻,还有电容。再长就要加光耦隔离了
回复

使用道具 举报

29#
ID:69038 发表于 2024-12-6 17:23 | 只看该作者
自锁与非自锁,不就是逻辑关系吗?
请原谅我实话实说,连这么简单的逻辑都搞不定,代码也不用写了。
如果不考虑去抖的动作:
自锁就是按一下一个状态(比如连通),再按一下是另一个状态(断开);
非自锁就是按下时是一个状态(比如连通),放开时是另一个状态(断开);
简单地说,自锁开关按两下,相当于非自锁按一下而已。
搞不定自锁,就加标志,又不用占用太多的代码空间。。。

回复

使用道具 举报

30#
ID:161164 发表于 2024-12-6 17:44 | 只看该作者
lch327 发表于 2024-12-6 14:31
这个程序解决了按键卡死的问题。我搭建一个电路,用单片机控制ULN2003驱动电路,单片机输出高电平给2003, ...

试试这个
  1. #include <REG52.h>

  2. // 定义类型别名
  3. typedef unsigned char u8;  // 0 到 255
  4. typedef unsigned int u16;   // 0 到 65535

  5. // 延时函数,产生约 50 毫秒的延时
  6. void Delay50ms(void) //@11.0592MHz
  7. {
  8.         unsigned char data i, j; // 定义循环变量

  9.         i = 90;  // 外层循环次数
  10.         j = 163; // 内层循环次数
  11.         do
  12.         {
  13.                 while (--j); // 内层循环
  14.         }
  15.         while (--i); // 外层循环
  16. }

  17. // 定义按键和 LED 引脚
  18. sbit Kzong = P3^1; // 总按键连接到 P3.1
  19. sbit K1 = P3^2;    // 按键 1 连接到 P3.2
  20. sbit K2 = P3^3;    // 按键 2 连接到 P3.3
  21. sbit LED1 = P2^0;  // LED1 连接到 P2.0
  22. sbit LED2 = P2^1;  // LED2 连接到 P2.1

  23. u8 Off_Delay = 0;  // 关灯延时计数器,初始化为 0

  24. void main()
  25. {
  26.         bit K1_Lock = 1;
  27.         bit K2_Lock = 1;
  28.         while(1) // 主循环
  29.         {
  30.                 if(Kzong == 0) // 如果总按键被按下
  31.                 {
  32.                         if(Off_Delay == 0) // 如果延时计数器为 0
  33.                         {
  34.                                 LED1 = 0; // 开启 LED1
  35.                                 LED2 = 0; // 开启 LED2
  36.                         }
  37.                         if(K1 == 0)
  38.                         {
  39.                                 if(K1_Lock == 0)
  40.                                 {
  41.                                         LED1 = !LED1; // 切换 LED1 状态
  42.                                         K1_Lock = 1;
  43.                                 }
  44.                         }
  45.                         else
  46.                         {
  47.                                 K1_Lock = 0;
  48.                         }
  49.                         if(K2 == 0)
  50.                         {
  51.                                 if(K2_Lock == 0)
  52.                                 {
  53.                                         LED2 = !LED2; // 切换 LED2 状态
  54.                                         K2_Lock = 1;
  55.                                 }
  56.                         }
  57.                         else
  58.                         {
  59.                                 K2_Lock = 0;
  60.                         }
  61.                         Delay50ms(); // 延时 50ms
  62.                         Off_Delay = 200; // 设置关灯延时计数器为 200
  63.                 }
  64.                 else // 如果总按键没有被按下
  65.                 {
  66.                         if(Off_Delay != 0) // 如果延时计数器不为 0
  67.                         {
  68.                                 Delay50ms(); // 延时 50ms
  69.                                 Off_Delay = Off_Delay - 1; // 递减延时计数器
  70.                                 if(Off_Delay == 0) // 如果计数器减到 0
  71.                                 {
  72.                                         LED1 = 1; // 熄灭 LED1
  73.                                         LED2 = 1; // 熄灭 LED2
  74.                                 }
  75.                         }
  76.                 }
  77.         }
  78. }
复制代码
回复

使用道具 举报

31#
ID:1009628 发表于 2024-12-7 16:41 | 只看该作者

经过试验,这个程序和上面的效果差不多,也有干扰。接上照明灯没有问题。放弃ULN2003电路,使用三极管电路就行了。本来也是想控制照明用的。控制中间继电器有干扰,可能需要在硬件电路上改变。十分感谢您的帮助!
回复

使用道具 举报

32#
ID:624769 发表于 2024-12-8 00:15 | 只看该作者
lch327 发表于 2024-12-6 14:42
这种接法单片机会受到干扰

你这属于硬件问题了, 单片机电源这里 加大电容,开关到IO之间接个1K电阻,然后IO这里接104电容对地,应该会好很多。
回复

使用道具 举报

33#
ID:1109793 发表于 2024-12-8 14:54 | 只看该作者
只要没有被干扰到复位,就可以用软件处理
回复

使用道具 举报

34#
ID:1009628 发表于 2024-12-10 09:54 | 只看该作者
xiaobendan001 发表于 2024-12-8 14:54
只要没有被干扰到复位,就可以用软件处理

我看到网上教学里有这种套娃式接法,可是实际不行。不知道软件能否解决?
回复

使用道具 举报

35#
ID:1109793 发表于 2024-12-10 15:35 | 只看该作者
lch327 发表于 2024-12-10 09:54
我看到网上教学里有这种套娃式接法,可是实际不行。不知道软件能否解决?

你可以加一个上拉电阻,实际上我就不加。软件就是多次读取嘛
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表