发新帖本帖赏金 2.00元(功能说明)我要提问
返回列表
打印
[51单片机]

STC单片机测温度,控制继电器吸合不稳的情况

[复制链接]
2642|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wangpeng59|  楼主 | 2015-12-1 20:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
RT,用18B20采集室温并作实时显示。
同时可以设定温度。判断温度设定值与室温的大小,若设定值大于室温,就启动继电器,控制加热丝加热。
我想做的效果是用一个键,一个屏幕。平时显示室温,当按下一个键是,显示设定值,并闪烁3次,提醒注意现在是在设定温度。3次后自动回到室温显示。
现在问题是,我用的STC89C52RC的T2定时器,当按下设定键时,自动启动T2定时器定时1ms,当进入1ms中断3600次后,退出,继续显示室温。
可就是这个程序,会使得继电器吸合不稳,一直抖动。而延时时间到后,就会稳定吸合,不再抖动,不知道为什么?
不知道我表述清楚了没有,困扰我一天了,感觉脑袋木了。。求指教!!谢谢!

打赏榜单

21ic小管家 打赏了 2.00 元 2015-12-02

相关帖子

沙发
gmm2015| | 2015-12-1 21:03 | 只看该作者
软件的问题可能性很大。请发程序上来看看。

使用特权

评论回复
板凳
wangpeng59|  楼主 | 2015-12-1 21:49 | 只看该作者
我几乎肯定是定时的问题,我就是找不到原因,稍等。。

使用特权

评论回复
地板
wangpeng59|  楼主 | 2015-12-1 21:56 | 只看该作者
void timer2IntProc() interrupt 5
{
  TF2=0;  number++;  
  if(number==600)
   {
    liang = 1;
   }
     if(number==1200)
   {
    liang = 0;
   }
  if(number==1800)
   {
    liang = 1;
   }
  if(number==2400)
   {
    liang = 0;
   }
  if(number==3000)
   {
    liang = 1;
   }          
  if(number==3600)
    {
    FLAG = 0;
    TR2 = 0;
        number=0;
        liang = 0;
       
        }
}  

void initProg(void)
{
       
        EA = 1;
        RCAP2H=0xfc;    RCAP2L=0x66;
        TH2=RCAP2H; TL2=RCAP2L;
        T2CON=0;    T2MOD=0;
        ET2=1;               
}   


void Keyboard()       
{
if(adjust==0)
   Delay_ms(10);
   if(adjust==0)
   {
    while(!adjust);
        beep();
        FLAG = 1;
       
    setvalue+=7;
    if(setvalue == 42)
      setvalue = 7;

          TR2 = 1;       
    }
       
}
void GetTemperture(void)
{
uint8 i,temp;
uint16 real,setvalue1;  
Init_DS18B20();                                //DS18B20初始化
  if(yes0==0)                                         //若yes0为0,说明DS18B20正常
  {
          WriteOneByte(0xCC);                  // 跳过读序号列号的操作
             WriteOneByte(0x44);                  // 启动温度转换
        for(i=0;i<250;i++);//延时,等待A/D转换结束,分辨率为12位时需延时750ms以上
             Init_DS18B20();
            WriteOneByte(0xCC);                  //跳过读序号列号的操作
             WriteOneByte(0xBE);                  //读取温度寄存器
             temperature_sbuf[1] = ReadOneByte();          //温度低8位
             temperature_sbuf[0] = ReadOneByte();          //温度高8位
                temp=temperature_sbuf[1]&0x0f;                        //取出低4位的小数
        gewei = (temp *10/16);             //求出小数位的值
        temp=((temperature_sbuf[1]&0xf0)>>4)|((temperature_sbuf[0]&0x0f)<<4);// temp_data[0]高4位与temp_data[1]低4位组合成1字节整数
        baiwei =temp/10;                        //分离出整数部分十位
        shiwei =temp%10;                        //个位部分
            real = (uint16)100*baiwei+(uint16)10*shiwei+(uint16)gewei;
                setvalue1 = (uint16)setvalue*10;
                //Delay_ms(100);
                if(real < setvalue1)
                 Relay = 0;
                 if(real >= setvalue1)
                 Relay = 1;       
               
               

   }
}

/********以下是温度数据转换函数,将温度数据转换为适合LED数码管显示的数据********/
void TempConv()
{
  
  if(FLAG==0)  
   {
    disp_buf[0]=gewei;             //求出小数位的值
    disp_buf[2]=baiwei;                        //分离出整数部分十位
    disp_buf[1]=shiwei;                        //个位部分
    if(!disp_buf[2])            //若十位为0,不显示十位
    disp_buf[2]=10;
   }        
   if(FLAG==1)
    {
         if(liang == 0 )
         {
          
          disp_buf[2] = setvalue/10;
          disp_buf[1] = setvalue%10;
          disp_buf[0] = 0;
          if(!disp_buf[2])            //若十高位为0,不显示十位
      disp_buf[2]=10;
          }          
         if(liang == 1)
         {
          disp_buf[2]=10;
          disp_buf[1]=10;
          disp_buf[0]=10;
         }        
        }  
  }

/********以下是显示函数, 在前4位数码管上显示出温度值********/
void Display()
{
        P0 =seg_data[disp_buf[2]]; //显示十位
        P21 = 0;                           //开十位显示
        Delay_ms(2);                   //延时2ms
        P21=1;                                   //关十位显示
        P0 =seg_data[disp_buf[1]];                  //显示个位
        P22 = 0;
        DOT = 0;                //显示小数点
        if(liang==1)
        DOT = 1;                                       
        Delay_ms(2);
        P22=1;
        P0 =seg_data[disp_buf[0]] ;                  //显示小数位
        P23= 0;
        Delay_ms(2);
        P23=1;
       

}

void main(void)
{       
        initProg();                //整体初始化
    while(1)
        {                                                                       
            Keyboard();         
            GetTemperture();                //读取温度值
                TempConv();                //温度值转换
                Display();                //温度值显示
                 
               
        }
}

使用特权

评论回复
5
wangpeng59|  楼主 | 2015-12-1 21:59 | 只看该作者
有用的就是以上这些了。因为我试过,TR2不置1,也就是不启动T2定时,直接if(real < setvalue1)时,  Relay = 0;启动继电器,继电器是可以稳固吸合的。
只有在T2开始定时3600ms时,也就是设定值在3次闪烁时,继电器在频繁地断开和吸合。而在3次闪烁过后,将TR0清0后,继电器就可以稳定的吸合了。

使用特权

评论回复
6
wangpeng59|  楼主 | 2015-12-1 22:14 | 只看该作者
不知道我写的大家能不能看懂,我来解释一下:
1. void initProg(void)为初始化。是找的例程,感觉没什么问题。初值是0xfc66,1ms的初值。
2. void Keyboard()是键盘扫描程序,检测到唯一的那个按键adjust按下后,蜂鸣器响一声,将标志位FLAG置1,同时将设定值变量setvalue加7(温度设定为每7摄氏度1档)。当加到42摄氏度时,回到7摄氏度设定值。之后启动定时器T2。

使用特权

评论回复
7
wangpeng59|  楼主 | 2015-12-1 22:15 | 只看该作者
3. void GetTemperture(void)是获得18B20温度值的标准程序。我在后面加了一点儿,就是把获得的实时温度值存入变量real中,与设定值比较,从而确定是否给继电器上电,让其动作。
4. void TempConv(),将温度值转换为适合数码管显示的数据。根据FLAG标志位的状态判断,FLAG为0时,显示实时的室温值。FLAG为1时(也就是按键adjust按下后)显示设定值。其中,还根据变量liang的状态,决定显示还是熄灭,从而达到闪烁的效果
5. void Display(),就是一般的数码管显示函数。

使用特权

评论回复
8
wangpeng59|  楼主 | 2015-12-1 22:16 | 只看该作者
本帖最后由 wangpeng59 于 2015-12-1 22:24 编辑

6. 最关键的就是void timer2IntProc() interrupt 5,我觉得它由问题。我的想法是,每到1ms,就进入这个中断,将变量number加1.当加到600、1200、1800、2400等数时,将变量liang置1或清零,来确定void TempConv()显示的变化。(此时就是继电器不断抖动的时候)直到3600,即3.6秒,闪烁了6次后,清掉FLAG、TR0等标志位或变量。而由于FLAG=0,系统将会重新显示室温。(这个状态很想有的家用热水器的调温过程,我就是按照那种方式设计的程序)

使用特权

评论回复
9
dirtwillfly| | 2015-12-1 22:50 | 只看该作者
电路有没有问题?
建议把电路也发上来

使用特权

评论回复
10
wangpeng59|  楼主 | 2015-12-1 23:21 | 只看该作者
dirtwillfly 发表于 2015-12-1 22:50
电路有没有问题?
建议把电路也发上来

电路是单片机实验板,没有问题的。
况且我试过了,TR2不置1,也就是不启动定时器T2,继电器是可以稳定吸合的。
由于程序已经用了T0和T1了,我能想到的方法就是启用这个T2,可是只要一定时,就会频繁吸合分断

使用特权

评论回复
11
twtyxj| | 2015-12-2 09:46 | 只看该作者
T2中断影响了DS18B20的读数,有没有这种可能。

使用特权

评论回复
12
07611128| | 2015-12-2 09:52 | 只看该作者
感觉吸合频率太快

使用特权

评论回复
13
oufuqiang| | 2015-12-2 10:02 | 只看该作者
用一个定时器跑时间状态机驱动18B20,就不用管18B20的时序问题,专心做你的功能逻辑就好了。
https://bbs.21ic.com/forum.php?mo ... p;page=1#pid5432764

使用特权

评论回复
14
21ic小管家| | 2015-12-2 11:06 | 只看该作者
此打赏为十大热门打赏哦~继续努力

使用特权

评论回复
15
mylsf| | 2015-12-2 15:00 | 只看该作者
是不是因为你在SET状态时候,setvalue值不确定啊

使用特权

评论回复
16
duxinlng| | 2015-12-2 16:36 | 只看该作者
在读写DS18B20时,关闭中断,可能就没问题了

使用特权

评论回复
17
e_007| | 2015-12-2 18:03 | 只看该作者
本帖最后由 e_007 于 2015-12-2 18:22 编辑

当启动继电器阶段,T2中断了继电器的工作了,只有T2 完毕才不会,setvalue值Flashing :loveliness:?!你这个程序需要调整吧。。。。

使用特权

评论回复
18
风清扬mxz| | 2015-12-2 20:50 | 只看该作者
楼猪,你这个采集室温,然后加热电阻丝,对时间上的响应要求不高,你可以多次采集室温,放在一个缓冲区里面,然后求平均值,如果设定值低于室温,则闭合继电器加热,可以设定至少加热一分钟,在此期间无论采集的温度值是否高于设定值,都进行加热。可能是采集的速度太快,造成采集的值不稳定,造成继电器不停的开关闭合

使用特权

评论回复
19
tong1991海深| | 2015-12-2 22:18 | 只看该作者
您可以通过软件来模拟一个滞回比较器,这样的话继电器就可以很好的工作了!

使用特权

评论回复
20
wangpeng59|  楼主 | 2015-12-2 22:48 | 只看该作者
本帖最后由 wangpeng59 于 2015-12-2 22:52 编辑

感谢各位!本人的问题已解决,是定时器T2定时时间过短造成的!1ms进中断一次,我现在改成60ms进中断一次,也就是初值改成2800H,问题就解决了。谢谢各位的热心和耐心的解答,虽然不是都看得懂,但是谢谢了!!感觉e_007的解答最接近,给您了,同时谢谢其他人!!

使用特权

评论回复
发新帖 本帖赏金 2.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

39

主题

217

帖子

2

粉丝