找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2596|回复: 19
收起左侧

请问C51单片机两个延时函数互相干扰是什么原因?

  [复制链接]
ID:731755 发表于 2021-5-9 18:57 | 显示全部楼层 |阅读模式
各位大师,你们好,我是个小白,目前正在学习DS18B20测温度,根据学习板的程序,可以正常显示温度,我想做一个可以温度报警器,前面一个帖子,就是询问想要数码管显示H的帖子,我经过查询资料,解决了,温度超过30度,可以在数码管末尾上显示H,不过目前有个问题,我设定的是温度超过30度,数码管末尾也能显示H,并且指示灯闪烁,蜂鸣器鸣叫,但是数码管也会一直闪烁,当温度低于30度的时候,数码管显示就是正常的,我觉得,应该是延时函数干扰造成的,我又另外写了一个延时函数,还是一样的问题,请问各位大师,这是延时函数互相干扰吗?如果想要解决问题,一定要用中断吗?

温度.rar

32.42 KB, 下载次数: 4

回复

使用道具 举报

ID:731755 发表于 2021-5-9 18:59 | 显示全部楼层
#include"temp.h"
#include "intrins.h"
/*******************************************************************************
* 函 数 名         : Delay1ms
* 函数功能                   : 延时函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void DelayX10us(uchar t)
{
do {
   _nop_();
   _nop_();
   _nop_();
   _nop_();
   _nop_();
   _nop_();
   _nop_();
   _nop_();
   }
   while (--t);
}
void Delay1ms(uint y)
{
        uint x;
        for( ; y>0; y--)
        {
                for(x=110; x>0; x--);
        }
}
/*******************************************************************************
* 函 数 名         : Ds18b20Init
* 函数功能                   : 初始化
* 输    入         : 无
* 输    出         : 初始化成功返回1,失败返回0
*******************************************************************************/

uchar Ds18b20Init()
{
        uchar i;
        DSPORT = 0;                         //将总线拉低480us~960us
        DelayX10us(60);
        DSPORT = 1;                        //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低
    DelayX10us(6)        ;
        while(DSPORT)        //等待DS18B20拉低总线
        {
                Delay1ms(1);
                i++;
                if(i>5)//等待>5MS
                {
                        return 0;//初始化失败
                }
       
        }
        return 1;//初始化成功
}

/*******************************************************************************
* 函 数 名         : Ds18b20WriteByte
* 函数功能                   : 向18B20写入一个字节
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void Ds18b20WriteByte(uchar dat)
{
        uint  j;

        for(j=0; j<8; j++)
        {
                DSPORT = 0;                       //每写入一位数据之前先把总线拉低1us
                _nop_();
        _nop_();;
                DSPORT = dat & 0x01;  //然后写入一个数据,从最低位开始
                DelayX10us(6)        ;
                DSPORT = 1;        //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值
                dat >>= 1;
        }
}
/*******************************************************************************
* 函 数 名         : Ds18b20ReadByte
* 函数功能                   : 读取一个字节
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/


uchar Ds18b20ReadByte()
{
        uchar byte, bi;
        uint  j;       
        for(j=8; j>0; j--)
        {
                DSPORT = 0;//先将总线拉低1us
            _nop_();
        _nop_();;
                DSPORT = 1;//然后释放总线
                _nop_();
        _nop_();
                _nop_();
        _nop_();
                _nop_();
        _nop_();
                bi = DSPORT;         //读取数据,从最低位开始读取
                /*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/
                byte = (byte >> 1) | (bi << 7);                                                  
            DelayX10us(5)        ;       
        }                               
        return byte;
}

/*******************************************************************************
* 函 数 名         : Ds18b20ReadTemp
* 函数功能                   : 读取温度
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

int Ds18b20ReadTemp()
{
        int temp = 0;
        uchar tmh, tml;
        Ds18b20Init();
        Delay1ms(1);
        Ds18b20WriteByte(0xcc);                //跳过ROM操作命令                 
        Ds18b20WriteByte(0x44);
    Ds18b20Init();
    Delay1ms(1);
        Ds18b20WriteByte(0xcc);         //跳过ROM操作命令
        Ds18b20WriteByte(0xbe);         //发送读取温度命令               
        tml = Ds18b20ReadByte();                //读取温度值共16位,先读低字节
        tmh = Ds18b20ReadByte();                //再读高字节
        temp = tmh;
        temp <<= 8;
        temp |= tml;
        return temp;
}


回复

使用道具 举报

ID:731755 发表于 2021-5-9 19:00 | 显示全部楼层
#include "reg51.h"
#include "temp.h"
#define OVERTEMP 30 //定义超温报警数值
  typedef unsigned char u8;
  typedef unsigned int u16;
  sbit LEDA=P1^0;
  sbit LEDB=P1^1;
  sbit LEDC=P1^2;
  sbit beep=P2^7;
  sbit led= P2^6;
  u8 code shuma[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f };
  u8 shijian[8];
  
  void delay(u16 q)
  {
   while(q--);
  }
  void DelayMS(u16 x)
{
  u8 y;
  while(x--)
  {
    for(y=0;y<120;y++);
  }  
}
   void dongtai()
   {
             u8 i;
          for(i=0;i<8;i++)
          {
                  switch(i)
           {
                   case(0):LEDA=0;LEDB=0;LEDC=0; break;
                case(1):LEDA=1;LEDB=0;LEDC=0; break;
                case(2):LEDA=0;LEDB=1;LEDC=0; break;
                case(3):LEDA=1;LEDB=1;LEDC=0; break;
                case(4):LEDA=0;LEDB=0;LEDC=1; break;
                case(5):LEDA=1;LEDB=0;LEDC=1; break;
                case(6):LEDA=0;LEDB=1;LEDC=1; break;
                case(7):LEDA=1;LEDB=1;LEDC=1; break;
           }
           P0=shijian[i];
           delay(10);        
           P0=0x00;
          }
   }
   void datapros(int temp)
   {
          float tp;
          if(temp<0)
          {
                shijian[0] = 0x40;
                temp=temp-1;
                temp=~temp;
                tp=temp;
                temp=tp*0.0625*100+0.5;
          }
          else
          {
                  shijian[0] = 0x00;
                  tp=temp;
                temp=tp*0.0625*100+0.5;
          }
           shijian[1] = shuma[temp/ 10000];
              shijian[2] = shuma[temp % 10000 / 1000];
              shijian[3] = shuma[temp % 1000 / 100] | 0x80;
       shijian[4] = shuma[temp % 100 / 10];
           shijian[5] = shuma[temp % 10];
           shijian[6] = 0x00;
              shijian[7] = 0x00;
          if((temp/100)>OVERTEMP)
     {
            shijian[7]=0x76;//显示"H"
            beep=~beep;
            DelayMS(100);
            led=~led;
            DelayMS(10) ;
         }                     
   }  
  
   void main()
   {
            
            while(1)
         {
           datapros( Ds18b20ReadTemp());
           dongtai() ;          
         }         
   }
   
回复

使用道具 举报

ID:731755 发表于 2021-5-9 19:00 | 显示全部楼层
#ifndef __TEMP_H_
#define __TEMP_H_

#include<reg51.h>
//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint
#define uint unsigned int
#endif

//--定义使用的IO口--//
sbit DSPORT=P3^7;

//--声明全局函数--//
void Delay1ms(uint );
uchar Ds18b20Init();
void Ds18b20WriteByte(uchar com);
uchar Ds18b20ReadByte();
int Ds18b20ReadTemp();

#endif

回复

使用道具 举报

ID:569384 发表于 2021-5-10 09:18 | 显示全部楼层
程序是从上往下执行的,这样做延时程序都是一直在延时函数里面循环,那程序当时就不能执行其他代码。
回复

使用道具 举报

ID:824490 发表于 2021-5-10 11:37 | 显示全部楼层
haokey 发表于 2021-5-10 09:18
程序是从上往下执行的,这样做延时程序都是一直在延时函数里面循环,那程序当时就不能执行其他代码。

上电后是从main()开始动行的。其它的函数无所谓顺序。在main之后的函数在C文件的前端加入声明;
如果是多个文件,要包含对应的头文件
回复

使用道具 举报

ID:844772 发表于 2021-5-10 14:31 | 显示全部楼层
不是延时冲突问题,就是你程序写的问题,你延误了一百多毫秒显示一次就会闪烁.
            beep=~beep;
            DelayMS(100);  //主要这句导致
            led=~led;
            DelayMS(10) ;  
回复

使用道具 举报

ID:814525 发表于 2021-5-10 16:22 | 显示全部楼层
多看看如何利用用定时器管理时间方面的架构,才能提升水平。DelayMs()只会误事
回复

使用道具 举报

ID:213173 发表于 2021-5-10 16:27 | 显示全部楼层
与延时函数没有直接关系,关键是协调好读写DS18B20的时序与数码管动态扫描的时间关系。给你一个示例参考。

DS18B20温度上下限报警 仿真示例.zip (231.57 KB, 下载次数: 7)
回复

使用道具 举报

ID:919104 发表于 2021-5-11 09:15 | 显示全部楼层
如果感到迷糊,就点开调试模式,或者自己读程序,画一个时序图。你的这个程序做判断的时间太久了
回复

使用道具 举报

ID:889094 发表于 2021-5-11 11:17 | 显示全部楼层
单片机程序都是顺序执行,从main函数 开始 ,你的程序结构挺好,先读取温度,转换格式 ,显示,问题在于你的动态显示里面用到了delay100ms,视觉不闪烁起码要显示频率大于24,而你的显示频率小于10了,可以把LED控制和显示数码管分开。
前几天看到大神的贴子,能不用delay尽量不用,因为delay的时候CPU没有闲着,它一直在忙,别的程序就没法执行,除非像读取DS18B20这种需要具体延时多少us或ms的时候用delay,其实显示控制之类的可以用定时器来控制时间。在定时器中设置一个或几个变量累加,到某个值之后置0,在主程序中判断范围显示或是关闭
回复

使用道具 举报

ID:731755 发表于 2021-5-13 07:31 | 显示全部楼层
名字不是重点 发表于 2021-5-10 11:37
上电后是从main()开始动行的。其它的函数无所谓顺序。在main之后的函数在C文件的前端加入声明;
如果是多 ...

好的,感谢,我在搜集别人的程序中,发现有人的程序确如师傅说的那样。
回复

使用道具 举报

ID:731755 发表于 2021-5-13 07:33 | 显示全部楼层
glinfei 发表于 2021-5-10 14:31
不是延时冲突问题,就是你程序写的问题,你延误了一百多毫秒显示一次就会闪烁.
            beep=~beep;
...

你好,我在网上找到类似的程序,把显示的那个地方的延时给换了,现在的就不闪了,谢谢
回复

使用道具 举报

ID:731755 发表于 2021-5-13 07:33 | 显示全部楼层
张天师 发表于 2021-5-10 16:22
多看看如何利用用定时器管理时间方面的架构,才能提升水平。DelayMs()只会误事

好的,感谢
回复

使用道具 举报

ID:731755 发表于 2021-5-13 07:34 | 显示全部楼层
wulin 发表于 2021-5-10 16:27
与延时函数没有直接关系,关键是协调好读写DS18B20的时序与数码管动态扫描的时间关系。给你一个示例参考。
...

好的,感谢,文件已下载
回复

使用道具 举报

ID:731755 发表于 2021-5-13 07:39 | 显示全部楼层
birdzhyli 发表于 2021-5-11 11:17
单片机程序都是顺序执行,从main函数 开始 ,你的程序结构挺好,先读取温度,转换格式 ,显示,问题在于你 ...

你好,师傅,前几天我用定时中断来写数码显示,可是效果不好,可以看到数码管一位位的在跳变,温度可以正常显示,问题是时间填充,我已经设置的很低了,1us一次跳动显示数码管八位,
回复

使用道具 举报

ID:65956 发表于 2021-5-13 08:16 | 显示全部楼层
如果你显示加蜂鸣器报警声都放在主函数中,当报警时显示肯定会闪。解决办法是,把显示改用定时器驱动显示,或是把蜂鸣器报警放在定时器中驱动,这样影响就比较小了,就看你定时器如何用了
回复

使用道具 举报

ID:883031 发表于 2021-5-13 11:29 | 显示全部楼层
先进行位选,再送数据。
回复

使用道具 举报

ID:731755 发表于 2021-5-13 21:32 | 显示全部楼层
aking991 发表于 2021-5-13 08:16
如果你显示加蜂鸣器报警声都放在主函数中,当报警时显示肯定会闪。解决办法是,把显示改用定时器驱动显示, ...

感谢师傅提点,我目前把显示那里的延时改成其他的延时,目前不闪了,不过,用定时器来显示数码管,没有写成功,可以看到数码管一位位的在闪烁,定时时间是1us,
回复

使用道具 举报

ID:731755 发表于 2021-5-13 21:33 | 显示全部楼层
cn_zhx 发表于 2021-5-13 11:29
先进行位选,再送数据。

好的,感谢,提点
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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