OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4415|回复: 10

用51单片机同时测温度(DS18B20)和频率(外部中断测),单独运行两程序时没问题,同时显示时出现频率测量不准的情况

[复制链接]

4

主题

7

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2016-5-16
在线时间
7 小时
发表于 2016-5-26 16:12:42 | 显示全部楼层 |阅读模式
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

7

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2016-5-16
在线时间
7 小时
 楼主| 发表于 2016-5-26 16:15:05 | 显示全部楼层
void main()//主函数
{          
    delay1ms(1000);     
        lcd_init();//液晶显示初始化
        init_play();
                
while(1)
{       
     EA=0; //因DS18B20对时序要求高且受中断影响,故先关闭总中断
     read_temp();//读取温度
     ds1820disp();//显示
     CT_init();//定时计数器初始化     
     EA=1;//开总中断
         EX0=1;//允许外部中断
         IT0=1;//设置外部中断方式为下降沿触发
         P3=0xff;                                                        
         t0=(u*65536+x)*(12/22.1);//计算脉冲时间宽度(单位:ms)
         f=1000000/(2*t0);//计算频率                        
         if(f>8000&&tflag==1)          
          init_play1();         //显示Frozen
   else init_play2(); //显示Not frozen
}
}
这是主函数,初步怀疑是中断测频率时和温度传感器读取数据相影响,怎么解决 ?
回复

使用道具 举报

2

主题

16

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
258
金钱
258
注册时间
2013-5-27
在线时间
68 小时
发表于 2016-5-26 16:24:34 | 显示全部楼层
读频率实时性要求不高的话,就开这个关那个,轮流来,其他没招了
回复

使用道具 举报

4

主题

7

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2016-5-16
在线时间
7 小时
 楼主| 发表于 2016-5-26 16:34:51 | 显示全部楼层
yanyinzhong 发表于 2016-5-26 16:24
读频率实时性要求不高的话,就开这个关那个,轮流来,其他没招了

先测1秒温度,然后测1秒频率,再测一秒温度?
回复

使用道具 举报

0

主题

79

帖子

0

精华

高级会员

Rank: 4

积分
726
金钱
726
注册时间
2016-5-27
在线时间
91 小时
发表于 2016-5-27 14:46:00 | 显示全部楼层
我不知道你用的什么51单片机,根据我的经验就这两句
     t0=(u*65536+x)*(12/22.1);//计算脉冲时间宽度(单位:ms)
     f=1000000/(2*t0);//计算频率
速度低点的单片机拿来测频率就有问题。
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2016-5-28
在线时间
1 小时
发表于 2016-5-28 06:54:19 | 显示全部楼层
我给你个参考程序,也是单总线的数据采集(时钟11.0592)。
在你的主循环中不要关闭中断,调用读温度时,有校验码确定数据的有效性(如果读温度程序中间有中断,数据可能会是无效的)。
#include <INTRINS.H>
#include "public.h"

sbit DS2401Bus  = P3^5;

//DS2401.c
//  首先对单总线发复位:
//        总线保持低电平超过480us;总线上的所有器件将复位
//        主机释放总线,并进入接收模式
//        从机等待15-60us,接着拉低总线60-240us,以产生应答脉冲
//    写0x33H命令: 仅适合于单节点(读ROM[0x33]命令)
//                  所有写(0或1)时隙至少需要60us 且在两次独立的写时隙之间至少需要1us的恢复时间
//                  两种写时隙均起始于主机拉低总线
//                          写1时隙: 主机在拉低总线后接着必须在15us之内释放总线,由5k上拉电阻将总线拉至高电平
//                           写0时隙: 主机拉低总线后只需在整个时隙期间保持低电平即可至少60us
//                           -- 在写时隙起始后15-60us期间,单总线器件采样总线电平状态(0或1)
//           读时隙
//                   器件仅在主机发出读时隙时才向主机传输数据。所以在主机发出读数据命令后必须马上产生读时隙
//                  所有读时隙至少需要60us 且在两次独立的读时隙之间至少需要1us的恢复时间
//                  每个读时隙都由主机发起,至少拉低总线1us
//                  在主机发起读时隙之后单总线器件才开始在总线上发送0或1
//                  从机发出的数据在起始时隙之后保持有效时间15us
//                  因而,主机在读时隙期间必须释放总线并且在时隙起始后的15us之内采样总线状态
//
#pragma ot(4,SPEED)

void delay_500us(void)   
{   
    unsigned char data i;         
    for(i = 0; i < 56; i++) ;   
}   
void delay_250us(void)   
{   
    unsigned char data i;         
    for(i = 0; i < 28; i++) ;   
}   
void delay_90us(void)   
{   
    unsigned char data i;         
    for(i = 0; i < 9; i++) ;   
}   
void delay_60us(void)   
{   
    unsigned char data i;         
    for(i = 0; i < 6; i++) ;   
}   

unsigned char InitDS2401(void)  //复位DS2401
{
        unsigned char tmp;
        DS2401Bus = 0;                   // 输出:0;总线保持低电平超过480us
        delay_500us();                  // 498us
        DS2401Bus = 1;                   // 释放总线,由5k上拉电阻将总线拉至高电平
        delay_60us();            // 64us,等待器件发出应答脉冲
        tmp = DS2401Bus;        // 检查应答脉冲
        delay_250us();                // 255us,延时240us以上
        if(tmp)                                // 读取数据
                return 0;
        else
                return 1;
}

void WriteDS2401(unsigned char d)//写2401命令
{
        unsigned char i;
        for(i=0;i<8;i++) {
                DS2401Bus = 0;                   // 主机在拉低总线后接着必须在15us之内释放总线
                _nop_(); _nop_(); _nop_();        // 每个nop估计耗时 1.085us
                if(d & 1) {                           // 输出:数据位
                        DS2401Bus = 1;
                }
                d >>= 1;
                delay_60us();                // 至少保持60us
                DS2401Bus = 1;            // 将总线拉至高电平, 至少需要1us的恢复时间
                _nop_();_nop_();_nop_();                  
        }
}

unsigned char ReadDS2401()         //读2401数据
{
        unsigned char i,d;
        for(i=0;i<8;i++) {
                d >>= 1;
                DS2401Bus = 0;                    // 至少拉低总线1us
                _nop_();_nop_();_nop_();             
                DS2401Bus = 1;            // 释放总线
                _nop_();_nop_();_nop_();_nop_();_nop_();
                if(DS2401Bus == 1) d |= 0x80;           // 读取数据
                delay_90us();                // 90us
        }
        return d;
}

unsigned char crctest()         //进行CRC校验
{
        unsigned char i1, i2, crc=0;
        for(i1=0; i1<8; i1++) {
                crc ^= DS2401IDBuf[i1];
                for(i2=0; i2<8; i2++) {
                        if (crc & 0x01)
                                crc = (crc >> 1) ^ 0x8C;
                        else
                                crc >>= 1;
                }
        }
        return (crc);
}

unsigned char ReadRS2401ID()         //读出DS2401的
{
        unsigned char i;
        if (!InitDS2401()) return(0);
        WriteDS2401(0x33);
        for(i=0;i<8;i++) DS2401IDBuf[i]=ReadDS2401();
        if (crctest() != 0) return(0);
        return(1);         //CRC校验成功
}
回复

使用道具 举报

5

主题

168

帖子

0

精华

高级会员

Rank: 4

积分
780
金钱
780
注册时间
2016-5-28
在线时间
64 小时
发表于 2016-5-29 10:00:07 | 显示全部楼层
用速度高一点的单片机,最好是单周期指令的,在中断里面处理频率测量和扫描显示(显示也可以在主程序中处理),读取DS18B20不要关闭中断,这样应该可以的,最好这两部分不要使用同一组寄存器,减少中端开销,应该没有问题。
回复

使用道具 举报

50

主题

1805

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
6661
金钱
6661
注册时间
2016-5-29
在线时间
909 小时
发表于 2016-5-29 13:40:09 | 显示全部楼层
本帖最后由 操作系统 于 2016-5-29 13:41 编辑

单任务正常.多任务不正常.分明是代码架构没有做好.要把CPU当超人使唤.从来不要让CPU休息,做无用的空指令.除非所有任务完成,多使用事件触发,函数回调.
回复

使用道具 举报

36

主题

249

帖子

0

精华

高级会员

Rank: 4

积分
680
金钱
680
注册时间
2015-12-13
在线时间
243 小时
发表于 2016-6-9 20:11:37 | 显示全部楼层
DS18B20 有很多空延时,你想办法把这些浪费的资源合理利用就能解决问题了!!    我用一个stc15w4k48s4同时驱动液晶彩屏,同时输出几路独立的PWM,18B20温度,还有脉冲捕获等等…… 关键的是,你尽量不让单片机做些空延时这种浪费资源的东西……http://www.openedv.com/thread-67777-1-1.html
回复

使用道具 举报

2

主题

171

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3792
金钱
3792
注册时间
2016-6-26
在线时间
276 小时
发表于 2016-6-27 06:53:48 | 显示全部楼层
延时尽量不要用,最好使用定时器。
回复

使用道具 举报

2

主题

16

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
258
金钱
258
注册时间
2013-5-27
在线时间
68 小时
发表于 2016-8-13 09:23:20 | 显示全部楼层
liuyimao485812 发表于 2016-6-27 06:53
延时尽量不要用,最好使用定时器。

有US级的要求,定时器有这么快吗
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-27 09:07

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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