找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 577|回复: 12
收起左侧

STC单片机开关点灯这个代码哪里由问题?

[复制链接]
ID:72649 发表于 2024-1-6 14:46 | 显示全部楼层 |阅读模式
/*一、上电后故障灯和加水灯点亮,加热灯熄灭;
二、开关低电平后,延时5s加热灯亮,加水灯灭 ,故障灯熄灭。
三、开关高电平后 ,加水灯点亮,故障灯和加热灯熄灭。
四、保护功能两个:1、开机后六分钟如果开关一直处于高电平,则:故障灯1秒闪烁,加热灯加水灯熄灭。
2、在开关由低电平转为高电平后,加水灯加热灯都点亮,延时30秒,开关电平没有转换,则:故障灯闪烁,加水灯加热灯熄灭 */

电路原理图如下:
51hei图片_20240106144544.png
单片机源程序如下:
#include <STC8H.h>


#define uchar unsigned char
#define uint unsigned int

sbit LD3 = P3^3;
sbit LD2 = P5^5;

sbit KEY1 = P3^2;
sbit ERR_LED = P5^4;
bit t0zd0b=0;
bit t1zd0b=0;

uchar count;
char sec,min;

uint  i=0,j=0;
uchar t0IntCnt = 0; //T0中断计数变量
uint ledFlashCnt = 0;        //ERR_LED指示灯闪烁周期计数
uchar Flag2ms = 0;      //2MS到标志
uchar u8Flag6min = 0;        //6分钟到标志

void Timer0_Init(void);
void Timer1_Init(void);
void delay_1ms(void);
void delay_ms(uint var);
void IO_init();

void Timer0_Init(void)                //5毫秒@11.0592MHz
{
                                AUXR &= 0x7F;                        //定时器时钟12T模式
                                TMOD &= 0xF0;                        //设置定时器模式
                                TL0 = 0x00;                                //设置定时初始值
                                TH0 = 0xEE;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时
        ET0 = 1;                                //使能定时器0中断   
}


void Timer1_Init(void)                //250微秒@11.0592MHz
{
                                AUXR &= 0xBF;                        //定时器时钟12T模式
                                TMOD &= 0x0F;                        //设置定时器模式
                                TL1 = 0x1A;                                //设置定时初始值
                                TH1 = 0xFF;                                //设置定时初始值        
        TF1 = 0;                                //清除TF1标志
        TR1 = 1;                                //定时器1开始计时
         ET1 = 1;      //开T0中断     
}

/*
必须开启T0中断,延时函数才起作用
*/
void delay_1ms(void)
{
        uchar i = 4; //每次256us,1ms中断4次
        while (i) {
                if (t1zd0b)
                {
                       t1zd0b = 0; //清除时间中断标志
                        --i;
                }
        }
}

void delay_ms(uint var)//延时单位为毫秒,最多延时65.535秒(65535mS)
{
        while (var--)
        {
                delay_1ms();
        }
}


#define d_s(s) delay_ms((s)*1000ul)//延时单位为秒


void IO_init()
                {                 
                                P3M0 = 0x08; P3M1 = 0x00;
                                P5M0 = 0x30; P5M1 = 0x00;
                        ERR_LED = 0;
                        LD2 = 1;
                        LD3 = 0;                       
                }


void TM0_Isr() interrupt 1    //5毫秒
        {  
//                                        ERR_LED ^= 1;                            //测试是否进入中断
           if(TF0)        //定时器 0 上溢中断
        {  
                TF0 = 0;
                t0zd0b = 1;
                t0IntCnt++;
                if(t0IntCnt>=8)        //8*250 = 2ms
                {
                        t0IntCnt = 0;
                        Flag2ms=1;
                        ledFlashCnt ++;
                }      
        }
        }

void TM1_Isr() interrupt 3            //250微秒
        {      
//                                          ERR_LED ^= 1;                        //测试是否进入中断
                if(TF1)
                TF1=0;
                t1zd0b=1;
        }      


void main()
{                     
    Timer0_Init();
          Timer1_Init();
           EA = 1;       //开总中断
    IO_init();
    delay_ms(80);
    while (1)
     {
                                                        if(KEY1 == 1 )     //缺水时
                         {                                                                                                                                                                                                                                                                                                                                               
                                                        ERR_LED = 1;
                                                        LD2 = 1;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
                                                        LD3 = 0;               
                                                         
                                if(!u8Flag6min)
                                {
                                        if(Flag2ms)
                                         {
                                                Flag2ms=0;

                                                if(i<0xFFFF)
                                                        i++;
                                                if(i>=30000)   //60000ms,1分钟
                                                {
                                                        i=0;
                                                        j++;
                                                }
                                                if(j>=2)  
                                                {
                                                        u8Flag6min = 1;
                                                        LD2 = 0;
                                                        LD3 = 0;
                                                }
                                    }
                                }
                                else        //15分钟到,执行LED闪烁   3、如果第一个动作水位一直不能到,
                                                            //也就是开关一直断开高电平,则故障灯闪烁,
                                                            //加水加热电磁阀灯全部熄灭。
                                {
                                        if (ledFlashCnt>=500) //500*2=1000ms
                                        {
                                                ledFlashCnt = 0;
                                                 ERR_LED ^= 1;
                                        }
                                }
                        }
                        else if(KEY1==0)    //b、第二步只要水位到了,也就是开关接通低电平,延时一秒
                                            //加热灯点亮,延时五秒后,电磁阀灯熄灭,又过一秒,加水灯熄灭。
                                {
                                u8Flag6min = 0;
                                
               
                        ERR_LED = 0;

               
                                LD3 = 1;

                                LD2 = 0;                                                                                       
                        }

        }
}




回复

使用道具 举报

ID:235200 发表于 2024-1-6 19:21 | 显示全部楼层
开启了定时中断,在进入中断程序后硬件自动清除标志TF0,而进入中断后又来判断该标志,条件永远不成立 if(TF0)        //定时器 0 上溢中断
回复

使用道具 举报

ID:72649 发表于 2024-1-6 23:53 来自手机 | 显示全部楼层
csmyldl 发表于 2024-1-6 19:21
开启了定时中断,在进入中断程序后硬件自动清除标志TF0,而进入中断后又来判断该标志,条件永远不成立 if(T ...

    if(TF1)
                TF1=0进入中断,硬件自动清零,这局不要吗?
回复

使用道具 举报

ID:72649 发表于 2024-1-7 00:20 | 显示全部楼层
csmyldl 发表于 2024-1-6 19:21
开启了定时中断,在进入中断程序后硬件自动清除标志TF0,而进入中断后又来判断该标志,条件永远不成立 if(T ...

#include <STC8H.h>

#define uchar unsigned char
#define uint unsigned int
      
sbit LD3 = P3^3;
sbit LD2 = P5^5;

sbit KEY1 = P3^2;
sbit ERR_LED = P5^4;
bit t0zd0b=0;
bit t1zd0b=0;

uchar count;
char sec,min;

uint  i=0,j=0;
uchar t0IntCnt = 0; //T0中断计数变量
uint ledFlashCnt = 0;        //ERR_LED指示灯闪烁周期计数
uchar Flag2ms = 0;      //2MS到标志
uchar u8Flag6min = 0;        //6分钟到标志

void Timer0_Init(void);
void Timer1_Init(void);
void delay_1ms(void);
void delay_ms(uint var);
void IO_init();

/*
必须开启T0中断,延时函数才起作用
*/
void delay_1ms(void)
{
        uchar i = 4; //每次250us,1ms中断4次
        while (i) {
                if (t1zd0b)
                {
                       t1zd0b = 0; //清除时间中断标志
                        --i;
                }
        }
}

void delay_ms(uint var)//延时单位为毫秒,最多延时65.535秒(65535mS)
{
        while (var--)
        {
                delay_1ms();
        }
}


#define d_s(s) delay_ms((s)*1000ul)//延时单位为秒


void IO_init()
                {                 
                        P3M0 = 0x08; P3M1 = 0x00;
                        P5M0 = 0x30; P5M1 = 0x00;
                        ERR_LED = 0;
                        LD2 = 1;
                        LD3 = 0;                       
                }

void Timer0_Init(void)                //250微秒@11.0592MHz
{
        AUXR &= 0x7F;                        //定时器时钟12T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TL0 = 0x1A;                                //设置定时初始值
        TH0 = 0xFF;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                                //定时器0开始计时
        ET0 = 1;                                //使能定时器0中断
}


void Timer1_Init(void)                //250微秒@11.0592MHz
{
        AUXR |= 0x40;                        //定时器时钟1T模式
        TMOD &= 0x0F;                        //设置定时器模式
        TL1 = 0x33;                                //设置定时初始值
        TH1 = 0xF5;                                //设置定时初始值
        TF1 = 0;                                //清除TF1标志
        TR1 = 1;                                //定时器1开始计时
        ET1 = 1;      //开T0中断
}
                                                               
void TM0_Isr() interrupt 1    //250微秒
        {  
//                                        ERR_LED ^= 1;                            //测试是否进入中断
                t0zd0b = 1;
                t0IntCnt++;
                if(t0IntCnt>=8)        //8*250 = 2ms
                {
                        t0IntCnt = 0;
                        Flag2ms=1;
                        ledFlashCnt ++;                       
                }      
        }
      
void TM1_Isr() interrupt 3            //250微秒
        {      
//                                          ERR_LED ^= 1;                        //测试是否进入中断
              t1zd0b=1;
        }      

void main()
{                     
    Timer0_Init();
          Timer1_Init();
           EA = 1;       //开总中断
    IO_init();
    delay_ms(80);
    while (1)
     {
                                                        if(KEY1 == 1 )     //缺水时
                         {                                                                                                                                                                                                                                                                                                                                              
                                                        ERR_LED = 0;
                                                        LD2 = 1;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
                                                        LD3 = 0;               
                               
                                if(!u8Flag6min)   //6分钟没到
                                        {
                                        if(Flag2ms)     //2ms
                                         {
                                                Flag2ms=0;
                                                if(i<0xFFFF)
                                                        i++;
                                                if(i>=30000)   //60000ms,1分钟
                                                {
                                                        i=0;
                                                        j++;
                                                }
                                                if(j>=1)       //方便调试改为1分钟
                                                {  
                                                        u8Flag6min = 1;
                                                        LD2 = 0;
                                                        LD3 = 0;
                                                }
                                    }
                                }
                                else        //6分钟到,执行LED闪烁   3、如果第一个动作水位开关一直高电平,
                                                            //也就是开关一直断开高电平,则故障灯闪烁,
                                                            //加水加热电磁阀灯全部熄灭。
                                {
                                        if (ledFlashCnt>=500) //500*2=1000ms
                                        {
                                                ledFlashCnt = 0;
                                                 ERR_LED ^= 1;
                                        }
                                }
                        }
                        else if(KEY1==0)    //b、第二步只要水位到了,也就是开关接通低电平,延时一秒
                                            //加热灯点亮,延时五秒后,电磁阀灯熄灭,又过一秒,加水灯熄灭。
                                {
                                u8Flag6min = 0;
                    ERR_LED = 0;
                          LD3 = 1;
                                LD2 = 0;                                                                                       
                        }
        }
}


//这样修改对吗?
回复

使用道具 举报

ID:72649 发表于 2024-1-7 09:01 来自手机 | 显示全部楼层
csmyldl 发表于 2024-1-6 19:21
开启了定时中断,在进入中断程序后硬件自动清除标志TF0,而进入中断后又来判断该标志,条件永远不成立 if(T ...

把这个取消了,程序在贴上了,但是故障指示灯闪烁太暗了,几乎看不到,而且时间到了LD2也不能进入低电平。
回复

使用道具 举报

ID:235200 发表于 2024-1-7 09:43 | 显示全部楼层
hjx5548 发表于 2024-1-7 09:01
把这个取消了,程序在贴上了,但是故障指示灯闪烁太暗了,几乎看不到,而且时间到了LD2也不能进入低电平 ...

闪烁太暗是因为闪烁间隔时间太短,或者减少串联电阻
回复

使用道具 举报

ID:213173 发表于 2024-1-7 09:52 | 显示全部楼层
hjx5548 发表于 2024-1-7 00:20
#include

#define uchar unsigned char

你的硬件电路和软件设计都有严重问题,延时功能也不是你这么个玩法。给你彻底改写,有详细注释,看不明白就反复测试反复看,理清逻辑关系。
  1. #include <STC8G.h>
  2. #define uchar unsigned char
  3. #define uint unsigned int

  4. sbit KEY1 = P3^2;//开关
  5. //所有LED必须加限流电阻
  6. sbit LED1 = P3^3;//加热
  7. sbit LED2 = P5^4;//加水
  8. sbit LED3 = P5^5;//故障

  9. uint  count1=0,count2=0;//计数变量
  10. uchar temp=0;//计数变量
  11. bit   sign=0;//开关状态标志
  12. bit   flag=0;//初始状态标志
  13. bit   B_50ms;//50ms标志

  14. //Timer0 50ms中断服务函数
  15. void timer0 (void) interrupt 1
  16. {//自动重装
  17.         B_50ms = 1;      //50ms标志
  18. }
  19. //初始化定时器0
  20. void Timer0_Init(void)                //50毫秒@11.0592MHz
  21. {
  22.         AUXR &= 0x7F;                        //定时器时钟12T模式
  23.         TMOD &= 0xF0;                        //设置定时器模式
  24.         TL0 = 0x00;                                //设置定时初始值
  25.         TH0 = 0x4C;                                //设置定时初始值
  26.         TF0 = 0;                                //清除TF0标志
  27.         TR0 = 1;                                //定时器0开始计时
  28.         ET0 = 1;                                //使能定时器0中断
  29.         EA  = 1;          //使能总中断
  30. }

  31. void main()
  32. {
  33.         uint i=0xffff;
  34.         P3M0 = 0x08; P3M1 = 0x00;
  35.         P5M0 = 0x30; P5M1 = 0x00;
  36. //一、上电后故障灯和加水灯点亮,加热灯熄灭;
  37.         LED1 = 0;
  38.         LED2 = 1;
  39.         LED3 = 1;
  40.         while(i--);//延时等待系统稳定
  41.         Timer0_Init();
  42.         while(1)
  43.         {
  44.                 if(B_50ms)        //定时器周期50ms
  45.                 {  
  46.                         B_50ms = 0;

  47. //二、开关低电平后,延时5s加热灯亮,加水灯灭 ,故障灯熄灭。
  48.                         if(KEY1==0)
  49.                         {
  50. //                                if(++count1>=100 && sign==0)//延时5s
  51.                                 if(++count1>=10 && sign==0)//延时0.5s 用于快速调试
  52.                                 {
  53.                                         sign=1;
  54.                                         flag=1;
  55.                                         LED1=1;//加热灯亮
  56.                                         LED2=0;//加水灯灭
  57.                                         LED3=0;//故障灯灭
  58.                                 }
  59.                                 count2=0;//清0计数2
  60.                                 temp=0;//清0计数
  61.                         }
  62.                        
  63.                         if(KEY1==1)
  64.                         {
  65.                                 count1=0;//清0计数1
  66.                                 sign=0;//清0开关状态标志
  67. //四、保护功能两个之一:开机后六分钟如果开关一直处于高电平,则:故障灯1秒闪烁,加热灯加水灯熄灭。
  68.                                 if(flag==0)//KEY1开关初始高电平
  69.                                 {
  70.                                         count2++;
  71. //                                        if(count2<7200)//小于6分钟
  72.                                         if(count2<300)//小于15秒 用于快速调试
  73.                                         {
  74.                                                 LED1=0;//加热灯灭
  75.                                                 LED2=1;//加水灯亮
  76.                                                 LED3=0;//故障灯灭
  77.                                         }
  78. //                                        if(count2>=7200) //大于6分钟
  79.                                         if(count2>=300) //大于15秒
  80.                                         {
  81. //                                                count2=7200;//防止溢出
  82.                                                 count2=300;//防止溢出
  83.                                                 LED1=0;//加热灯灭
  84.                                                 LED2=0;//加水灯灭
  85.                                                 if(++temp>=10)//500ms
  86.                                                 {
  87.                                                         temp=0;
  88.                                                         LED3=~LED3;//故障灯闪烁
  89.                                                 }
  90.                                         }
  91.                                 }
  92.                                 if(flag==1)//KEY1开关低电平后恢复高电平
  93.                                 {
  94.                                         count2++;
  95. //三、开关高电平后 ,加水灯点亮,故障灯和加热灯熄灭(此条与保护功能之二相悖)只能取1
  96. //                                        if(count2<600)//30秒内
  97.                                         if(count2<60)//3秒内 用于快速调试
  98.                                         {
  99.                                                 LED1=0;//加热灯灭
  100.                                                 LED2=1;//加水灯亮
  101.                                                 LED3=0;//故障灯灭
  102.                                         }
  103. //四、保护功能两个之二:在开关由低电平转为高电平后,加水灯加热灯都点亮,延时30秒,开
  104. //关电平没有转换,则:故障灯闪烁,加水灯加热灯熄灭
  105. //                                        if(count2>=600)//超过30秒没有再次低电平
  106.                                         if(count2>=60)//3秒 用于快速调试
  107.                                         {
  108. //                                                count2=600;//防止溢出
  109.                                                 count2=60;//防止溢出
  110.                                                 LED1=0;//加热灯灭
  111.                                                 LED2=0;//加水灯灭
  112.                                                 if(++temp>=10)//500ms
  113.                                                 {
  114.                                                         temp=0;
  115.                                                         LED3=~LED3;//故障灯闪烁
  116.                                                 }
  117.                                         }
  118.                                 }
  119.                         }
  120.                 }
  121.         }
  122. }
复制代码
回复

使用道具 举报

ID:72649 发表于 2024-1-7 20:10 来自手机 | 显示全部楼层
wulin 发表于 2024-1-7 09:52
你的硬件电路和软件设计都有严重问题,延时功能也不是你这么个玩法。给你彻底改写,有详细注释,看不明白 ...

只要LED3闪烁 LED1和LED2始终为低电平。不管KEY电平怎么变化,LED1和LED2始终为低电平,保护闪烁了,只有重新上电才能恢复,应该怎样修改?
回复

使用道具 举报

ID:72649 发表于 2024-1-7 20:49 来自手机 | 显示全部楼层
wulin 发表于 2024-1-7 09:52
你的硬件电路和软件设计都有严重问题,延时功能也不是你这么个玩法。给你彻底改写,有详细注释,看不明白 ...

保护后,不需要恢复现场,一定重启电源,才能工作,否则一直保护。应该怎样修改?
回复

使用道具 举报

ID:213173 发表于 2024-1-8 10:22 | 显示全部楼层
hjx5548 发表于 2024-1-7 20:49
保护后,不需要恢复现场,一定重启电源,才能工作,否则一直保护。应该怎样修改?

写一个死循环报警函数替换闪烁代码

void Alarm()
{
        unsigned long i;
        while(1)
        {
                LED3=~LED3;//故障灯闪烁
                i=50000L;
                while(i--);
        }
}

       
        if(count2>=600)//超过30秒没有再次低电平
        {
                LED1=0;//加热灯灭
                LED2=0;//加水灯灭
                Alarm();//故障灯闪烁
        }
回复

使用道具 举报

ID:72649 发表于 2024-1-8 21:12 | 显示全部楼层
wulin 发表于 2024-1-8 10:22
写一个死循环报警函数替换闪烁代码

void Alarm()

//一、上电后故障灯和加水灯点亮,加热灯熄灭;这段代码如果修改为://一、上电后故障灯和加水灯点亮,延时1秒后,加热灯熄灭;这样应该怎么修改?
回复

使用道具 举报

ID:275826 发表于 2024-1-9 11:23 | 显示全部楼层
问题第三点与保护的第二点逻辑矛盾
回复

使用道具 举报

ID:72649 发表于 2024-1-14 18:14 来自手机 | 显示全部楼层
wulin 发表于 2024-1-8 10:22
写一个死循环报警函数替换闪烁代码

void Alarm()

/*一、上电后故障灯和加水灯点亮,加热灯熄灭;
二、第一次开关低电平后,延时5s加热灯亮,加水灯灭 ,故障灯熄灭。第二次之后一直延时3s加热灯亮,加水灯灭 ,故障灯熄灭。
三、开关高电平后 ,加水灯点亮,故障灯和加热灯熄灭。
四、保护功能两个:1、开机后六分钟如果开关一直处于高电平,则:故障灯1秒闪烁,加热灯加水灯熄灭。
2、在开关由低电平转为高电平后,加水灯加热灯都点亮,延时30秒,开关电平没有转换,则:故障灯闪烁,加水灯加热灯熄灭 */

第二条修改了一下延时动作,分第一次延时动作5s,第二次后面的延时动作3s,应该怎样修改程序?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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