找回密码
 立即注册

QQ登录

只需一步,快速开始

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

51单片机继电器控制程序

[复制链接]
跳转到指定楼层
楼主
ID:1104510 发表于 2026-1-12 10:43 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
各位大神,麻烦帮我看一下,用C语言写一个51单片机程序,实现如下功能:单片机型号为STC15W408AS,有四个输入口,两个输出口。4个输入口分别命名为key1~key4,2个输出继电器口分别命名为kt1~kt2;key1接入的是一个自复位按钮开关,key2,key3接入的是两个光电开关。key1主要实现按钮一键控制继电器kt1启停(不管key2和key3的状态),即按一下开,再按一下关。当kt1处于打开状态时,如果检测到key2和key3任意一个输入口没有输入信号时,关闭kt1;引脚定义:sbit key1 = P1^2;                        /*单片机1.2引脚检测key1是否动作*/
        sbit key2 = P1^3;                        /*单片机1.3引脚检测key2是否动作*/
        sbit key3 = P1^4;                        /*单片机1.4引脚检测key3是否动作*/
        sbit key4 = P1^5;                        /*单片机1.5引脚检测key4是否动作*/
           
        sbit kt1 = P3^7;                  /*单片机3.7引脚控制继电器kt1*/
        sbit kt2 = P3^6;                  /*单片机3.6引脚控制继电器kt2*/    输入口为0表示有信号输入;输入口为1表示无信号输入;输出口为0表示开启继电器,输出口为1表示关闭继电器;  我自己写了一些,然后又在deepseek上问了  写出来的都不对  麻烦各位大神看看怎么写
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:69038 发表于 2026-1-12 11:36 | 只看该作者
"我自己写了一些,然后又在deepseek上问了  写出来的都不对"...
DeepSeek也要训练的,不对就要提出来,让它完善啊。。。
回复

使用道具 举报

板凳
ID:230500 发表于 2026-1-12 11:45 | 只看该作者
key1主要实现按钮一键控制继电器kt1启停(不管key2和key3的状态),


KEY1  KEY2 KEY3 控制KT1   那KEY4 和KT2呢?   问题需求你都没描叙清楚
回复

使用道具 举报

地板
ID:1104510 发表于 2026-1-12 12:40 | 只看该作者
a399288395 发表于 2026-1-12 11:45
key1主要实现按钮一键控制继电器kt1启停(不管key2和key3的状态),

key4  kt2 暂时闲置
回复

使用道具 举报

5#
ID:1104510 发表于 2026-1-12 12:41 | 只看该作者
zhuls 发表于 2026-1-12 11:36
"我自己写了一些,然后又在deepseek上问了  写出来的都不对"...
DeepSeek也要训练的,不对就要提出来,让 ...

提了   改来改去都跟没改一样
回复

使用道具 举报

6#
ID:1104510 发表于 2026-1-12 12:45 | 只看该作者
a399288395 发表于 2026-1-12 11:45
key1主要实现按钮一键控制继电器kt1启停(不管key2和key3的状态),

在kt1是关闭状态时,不管key2和key3什么状态,只要按下key1,就打开kt1;在kt1是打开状态时,不管key2和key3什么状态,只要按下key1,就关闭kt1;在kt1处于打开状态时,key2或者key3任意一个输入点无信号,都关闭kt1;
回复

使用道具 举报

7#
ID:230500 发表于 2026-1-12 13:42 | 只看该作者
郑效桂 发表于 2026-1-12 12:45
在kt1是关闭状态时,不管key2和key3什么状态,只要按下key1,就打开kt1;在kt1是打开状态时,不管key2和k ...

1; 在kt1是关闭状态时,不管key2和key3什么状态,只要按下key1,就打开kt1;2; 在kt1是打开状态时,不管key2和key3什么状态,只要按下key1,就关闭kt1;
3; 在kt1处于打开状态时,key2或者key3任意一个输入点无信号,都关闭kt1;


上面1,2,3项是你的要求, 1,2 可以实现,对于1,2. 相当于KEY1是总开关,他的开和关 不受KEY2,KEY3 影响。 但是你第3项 和上面的1,2相冲突,(按下开关后 由于KEY2 KEY3 没信号, 继电器根本不会吸合,吸合马上又断开)  ;





回复

使用道具 举报

8#
ID:1104510 发表于 2026-1-12 15:32 | 只看该作者
a399288395 发表于 2026-1-12 13:42
1; 在kt1是关闭状态时,不管key2和key3什么状态,只要按下key1,就打开kt1;2; 在kt1是打开状态时,不 ...

对的   这就是问题所在
回复

使用道具 举报

9#
ID:592807 发表于 2026-1-12 16:15 | 只看该作者
郑效桂 发表于 2026-1-12 15:32
对的   这就是问题所在

你将K1换成普通开关,一般自恢复开关都有自锁功能你按下KEY1后,KEY1就会一直处于0状态(按键锁死),你不再按一次将状态解开,他就一直处于0状态。然后当按键KEY1处于0状态时(按下状态),你就必须开启继电器KIT1=0,你开启以后你要检测KEY2 和KEY3状态,如果KEY2 和KEY3没有信号(不为0状态),你要关闭继电器,但是你忘了吗,你的KEY1是自锁自恢复的按键,它锁着呢,你没松开它,他一直处于0状态,你关了继电器KEY1会立刻让你重新打开继电器,这矛盾了。除非你能让KEY1强制复位,不然你的逻辑就是死循环,就是错的。
回复

使用道具 举报

10#
ID:1133081 发表于 2026-1-12 16:32 | 只看该作者
郑效桂 发表于 2026-1-12 12:45
在kt1是关闭状态时,不管key2和key3什么状态,只要按下key1,就打开kt1;在kt1是打开状态时,不管key2和k ...

这种简单控制本身没有难度,问题是楼主提出的控制功能有逻辑问题。
既然“在kt1是关闭状态时,不管key2和key3什么状态,只要按下key1,就打开kt1;在kt1是打开状态时,不管key2和key3什么状态,只要按下key1,就关闭kt1;”
这段话就是key1点控kt1开关不受key2和key3状态限制。那么后面这段话就与前面的话是矛盾的:“在kt1处于打开状态时,key2或者key3任意一个输入点无信号,都关闭kt1;”

回复

使用道具 举报

11#
ID:1104510 发表于 2026-1-12 16:38 | 只看该作者
WL0123 发表于 2026-1-12 16:32
这种简单控制本身没有难度,问题是楼主提出的控制功能有逻辑问题。
既然“在kt1是关闭状态时,不管key2 ...

对的   这个逻辑有问题   我在尝试换另一种方案
回复

使用道具 举报

12#
ID:1109793 发表于 2026-1-13 07:41 | 只看该作者
if(!key1)kt1 = 0;
kt1 = key2|key3;
回复

使用道具 举报

13#
ID:227818 发表于 2026-1-13 08:00 | 只看该作者
http://www.51hei.com/bbs/dpj-195153-1.html
看看这篇文章,如果你把这些例程都搞懂,你就是大佬。
回复

使用道具 举报

14#
ID:592807 发表于 2026-1-13 10:54 | 只看该作者
郑效桂 发表于 2026-1-12 16:38
对的   这个逻辑有问题   我在尝试换另一种方案

有啥难得加个报警机制就行了,出错报警,复位KEY1取消报警
回复

使用道具 举报

15#
ID:161164 发表于 2026-1-13 11:44 | 只看该作者
郑效桂 发表于 2026-1-12 16:38
对的   这个逻辑有问题   我在尝试换另一种方案

按下Key1 切换手动模式,一键控制继电器kt1启停
按下Key4 切换自动模式,检测到key2和key3任意一个输入口没有输入信号时,关闭kt1
回复

使用道具 举报

16#
ID:1104510 发表于 2026-1-14 08:43 | 只看该作者
lkc8210 发表于 2026-1-13 11:44
按下Key1 切换手动模式,一键控制继电器kt1启停
按下Key4 切换自动模式,检测到key2和key3任意一个输入 ...

这样貌似还是不对,如果key4在触发状态,key2或者key3任意一个输入口无信号,kt1关闭了,此时,如果再按key1,就会出现kt1开启一下然后迅速关闭  就是kt1会闪烁一下  然后保持关闭状态
回复

使用道具 举报

17#
ID:1104510 发表于 2026-1-14 09:31 | 只看该作者
黄youhui 发表于 2026-1-13 10:54
有啥难得加个报警机制就行了,出错报警,复位KEY1取消报警

请问这个报警机制怎么写呢
回复

使用道具 举报

18#
ID:1133081 发表于 2026-1-14 11:02 | 只看该作者
郑效桂 发表于 2026-1-14 09:31
请问这个报警机制怎么写呢

楼主还处于编程初级阶段,这样问也问不出什么有用的结果。不如直接讲目的,坛友帮你捋清逻辑关系更可行。
回复

使用道具 举报

19#
ID:1104510 发表于 2026-1-14 11:59 | 只看该作者
WL0123 发表于 2026-1-14 11:02
楼主还处于编程初级阶段,这样问也问不出什么有用的结果。不如直接讲目的,坛友帮你捋清逻辑关系更可行。

好的   现在有3个输入口  key1~key3  一个输出继电器 kt1;key1是一个自复位按钮开关,key2~key3是两个光电开关;key1控制kt1的一键启停(无论key2和key3有没有输入信号);当kt1处于打开状态,此时key2或者key3任意一个输入口没有信号,将kt1关闭;此时再次按下key1,将kt1开启;就这样循环;
回复

使用道具 举报

20#
ID:427868 发表于 2026-1-14 12:11 | 只看该作者

楼主试试:

这个功能较为简单,写了个以STC8H1K08 为例,可以试试。

#include <stc8g.h>          //STC8H1K08  IRC内部时钟选12MHZ
typedef unsigned char u8;   //对数据类型进行定义声明
typedef unsigned int u16;   //对数据类型进行定义声明

sbit key1 = P1^2;           //按键输入
sbit key2 = P1^3;           //光电开关,0为有信号,1为无信号
sbit key3 = P1^4;           //光电开关,0为有信号,1为无信号
sbit key4 = P1^5;           //备用输入
sbit kt1 = P3^7;            //继电器控制,0开启,1关闭
sbit kt2 = P3^6;            //继电器控制,0开启,1关闭,备用
bit flag10ms = 0;           //10ms时间标志,按键扫描

/*********************触发扫描*************************/
void scan()
{
  static u8 i = 0;          //扫描次数

  kt1 = key2 | key3;     //key2和key3中有1路无信号,则关闭继电器1
  if(flag10ms)             //检测10ms时间标志
  {
    flag10ms = 0;         //清零10ms标志
    if(key1){i = 0;}
    else
      {
        i++;
        if(i == 2) {kt1 = ~kt1;}
        if(i == 250) {i = 3;}
      }
  }
}

/*************************主函数******************************/
void main()
{
  P1M0 = 0x00; P1M1 = 0x00;     //P3设置为准双向口
  P3M0 = 0x00; P3M1 = 0x00;     //P5设置为准双向口

  kt1 = 1;                      //关闭继电器1
  kt2 = 1;                      //关闭继电器2
  PT1 = 0;                      //设置Tim1中断为低级0 PT1=0
  IPH &= 0xF7;                //0xF7=11110111       PT1H=0
  ET1 = 1;                      //开启定时器1中断
  EA = 1;                       //开启总中断
  AUXR &= 0xBF;             //定时器时钟12T模式
  TMOD &= 0x0F;              //设置定时器模式16位自动重装
  TL1 = 0xF0;                   //设置定时初始值10ms
  TH1 = 0xD8;                  //设置定时初始值
  TF1 = 0;                       //清除TF1标志
  TR1 = 1;                      //定时器1开始计时
  WDT_CONTR = 0x24;    //使能看门狗,溢出时间约为1s

  while(1)      //主循环
  {
    WDT_CONTR = 0x34;    //清看门狗,否则系统复位
    scan();                        //调入继电器扫描函数
  }
}

/**********定时器Tim1中断 10ms  级别0***********/
void Time1() interrupt 3
{
  flag10ms = 1;              //产生10ms标志位,用于按键扫描
}
/**********Program Size: data=10.1 xdata=0 code=245***********/

回复

使用道具 举报

21#
ID:592807 发表于 2026-1-14 17:19 | 只看该作者
郑效桂 发表于 2026-1-14 11:59
好的   现在有3个输入口  key1~key3  一个输出继电器 kt1;key1是一个自复位按钮开关,key2~key3是两个光 ...

哥们,你这样做产品会被开除的。
|你现在需要时是报警机制,就是当按键KEY1按下后,如果光电开关没信号(这是故障来的,可能有哪些地方没接好,你必须控制你的继电器断开,且要告诉使用者有故障,你不能说还让他循环啊,继续工作啊,就像你家电路总闸都跳了,你还没事掰上去继续干,掰不上去就用东西强行撑上去)你需要提醒使用者重启机器(重新再按KEY1断开继电器检查故障,然后再次按下KEY1重启)。你要加个蜂鸣器或者LED灯,如果KEY1按下,光电信号没反应就闪灯就响蜂鸣器断开继电器(没有灯和蜂鸣器也可以,但是你要将继电器状态标记成故障,除非重启KEY1,不然无论如何都不能开继电器)
回复

使用道具 举报

22#
ID:1133081 发表于 2026-1-14 21:23 | 只看该作者
郑效桂 发表于 2026-1-14 11:59
好的   现在有3个输入口  key1~key3  一个输出继电器 kt1;key1是一个自复位按钮开关,key2~key3是两个光 ...

你这样描述与前面的描述基本相同没有意义。我给你举例:要设计制作一款声、光控楼道灯,晚间无光照,才能受楼道人活动的声音触发亮灯,并延时15秒熄灭。声控不能太灵敏,防止误动作。另设置一个按键强制开关,不论声、光条件是否满足,按下按键即触发亮灯,并延时15秒熄灭。
回复

使用道具 举报

23#
ID:584814 发表于 2026-1-16 12:40 | 只看该作者
楼主自己写的东西咋没看见 
回复

使用道具 举报

24#
ID:1104510 发表于 2026-1-17 16:31 | 只看该作者
刘佑红 发表于 2026-1-14 12:11
这个功能较为简单,写了个以STC8H1K08 为例,可以试试。

#include           //STC8H1K08  IRC内部时钟 ...

好的 谢谢大佬  马上我试一下
回复

使用道具 举报

25#
ID:230500 发表于 2026-1-18 08:49 | 只看该作者
郑效桂 发表于 2026-1-17 16:31
好的 谢谢大佬  马上我试一下

不用试了  他这个程序明显的逻辑不通。 kt1 = key2 | key3;  这句在大循环里会一直执行,  后面不管按键怎么扫描,  10毫秒后,KT1的最终结果只受  key2 | key3 控制。
回复

使用道具 举报

26#
ID:427868 发表于 2026-1-18 09:03 | 只看该作者
本帖最后由 刘佑红 于 2026-1-18 09:24 编辑
a399288395 发表于 2026-1-18 08:49
不用试了  他这个程序明显的逻辑不通。 kt1 = key2 | key3;  这句在大循环里会一直执行,  后面不管按键 ...

您说得对,确有逻辑错误,kt1会持续开启,可将kt1 = key2 |key3;这句改为if(kt1 == 0) {kt1 = key2 |key3;}试试,或者改为if(kt2 | ky3)  {kt1 = 1;},这句逻辑看着更直观。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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