打印

DS18B20关中断时,扫描LED段码闪烁处理

[复制链接]
9081|22
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
sjg_mcu|  楼主 | 2009-10-16 22:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我使用DS18B20测温,因时序严格,中断要关,而8段LED使用中断动态扫描,关掉中断后LED有屏闪,不关中断DS18B20读数不准.
以下为源程序.
18B20部分:已调试通过
//=================================================================================================
//ds18b20专用延时子程序
//=================================================================================================
void delayll(uint x){ for(;x>0;x--);}
//=================================================================================================
//ds18b20复位函数
//=================================================================================================
void ow_reset(void)
{ uchar presence=1; uint temp;
GIE=0;                //在DS18B20读出温度数据时最好关闭中断               
while(presence==1)          //标志位为1一直循环,该位会在DS18B20复位成功后归0退出循环
  { TRISA2=0;asm("nop");asm("nop");  //接DS18B20信号线的IO设置为输出,并稳定一段小时间
   DQ=1;asm("nop");asm("nop");DQ=0; //开始产生低电平
   delayll(50);            //持续550us
   DQ=1;               //撤销低电平
   delayll(6);             //等待66us
   TRISA2=1;asm("nop");asm("nop");  //将IO设置为输入开始检测复位成功的低电平信号出现
   presence=DQ;           //读取信号,如果该信号为0说明复位成功,并退出循环
   //以下小部分是附加功能,非驱动部分,功能是探头拔下或损坏报警-----------------------------------
   temp++;if(temp>2000){GIE=1;disp_add=2;disp_menu();} //goto loop;探头异常 显示Err,并有报警声
  } temp=0;
  while(DQ==0)           //DS18B20复位成功后的低电平时间会持续几百us时间,等待低电平消失
  {//以下小部分是附加功能,非驱动部分,功能是探头拔下或损坏报警
   temp++;if(temp>2000){GIE=1;disp_add=2;disp_menu();}   //goto loop;探头异常,显示Err,并有报警声
  }
//   loop: ;
   GIE=1;              //打开中断,不然数码管会闪烁
}
//=================================================================================================
//DS18B20写命令函数 向总线上写一字节
//=================================================================================================
void write_byte(uchar val)      //参数:向总线上定一个字节
{ uchar i;
GIE=0;                   //在DS18B20读出温度数据时最好关闭中断
TRISA2=0;asm("nop");asm("nop");   //IO脚设置为输出,并稳定一会儿时间
for(i=8;i>0;i--)          //一个字节8个bit位
{ DQ=1;asm("nop");asm("nop");    //
  DQ=0;asm("nop");asm("nop");    //
  asm("nop");asm("nop");asm("nop"); //
  DQ=val&0x01;           //
  delayll(6);             //等待6us
  val=val/2;            //
}                  //
DQ=1;delayll(1);           //
GIE=1;               //打开中断,不然数码管会闪烁  
}
//=================================================================================================
//DS18B20从总线上读一字节函数
//=================================================================================================
uchar read_byte(void)
{ uchar i,value=0;
GIE=0;                   //在DS18B20读出温度数据时最好关闭中断
for(i=8;i>0;i--)               //一个字节共8个bit位,全部要读完整
{ TRISA2=0; asm("nop");asm("nop");      //数据口置输出状态,稍微延时一会儿等待稳定下来
  DQ=1;asm("nop");asm("nop");         //数据口置高,稍微延时一会儿
  value>>=1;                  //
  DQ=0;                    //
  asm("nop");asm("nop");asm("nop");asm("nop");//
  DQ=1;                    //
  asm("nop");asm("nop");asm("nop");asm("nop");//
  TRISA2=1;asm("nop");asm("nop");       //
  if(DQ)value|=0x80;             //
  delayll(6);
}
DQ=1;GIE=1;
return(value);           //打开中断,不然数码管会闪烁
                   //
}
//=================================================================================================
//读出温度函数
//=================================================================================================
void read_temp(void)
{ uchar x;
  ow_reset();           //ds18b20复位程序
  write_byte(0xcc);        //发skip ROM命令
  write_byte(0xbe);        //发读命令
  readdata[0]=read_byte();    //温度低8位
  readdata[1]=read_byte();    //温度高8位
  ow_reset();
  write_byte(0xcc);        //发skip ROM命令
  write_byte(0x44);        //发转换命令
//温度数据处理----------------------------------------------------------------------
  sflag=0;
  if((readdata[1] & 0xf8)!=0x00)   //负数处理,取补码
   {
    sflag=1;
    readdata[1]=~readdata[1];
    readdata[0]=~readdata[0];
    result=readdata[0]+1;
    readdata[0]=result;
    if(result>255)
    {readdata[1]++;}
   }
   //整数处理--------------------------------------------------------------
  readdata[1]=readdata[1]<<4;     //左移去掉高位数据
  readdata[1]=readdata[1] & 0x70;   //去掉最高位和低位数据
  x=readdata[0];
  x=x>>4;               //右移4位去掉小数部分的数据
  x=x & 0x0f;             //去掉高位数据
  readdata[1]=readdata[1] | x;    //完整的整数部分数据
  result=readdata[1];         //数据赋值给缓存
  //小数处理-----------------------------------------------------------------
  x=readdata[0] & 0x0f;
  x=x<<1;
  //displaybuf[0]=(dotcode[x])%10;  //小数低位
  result1=(dotcode[x])/10;      //小数高位
}
//***************************************************************************************************
//       DS18B20读出的温度数据,滤波算法(DS18B20偶尔会读出错误数据)
//***************************************************************************************************
void wd_pj(void)
{  uchar i,temm;uchar wdaa[6];
  //------------------连续读出6次DS18B20温度数据---------------------------------------------
  for(i=0;i<6;i++)      
   {  read_temp();                                  //读出温度数据,数据在display[4]里
     wdaa[i]=result;                //依次临时存放6次读出的温度数据
     //delayy(1);                                   //间隔一会儿再读
   }
//-------------------冒泡排列,从大到小排列,去掉最高的和最小的,取中间的平均数------------------
for(i=6;i>0;i--)   
  { if(wdaa[0]<wdaa[1]){temm=wdaa[0];wdaa[0]=wdaa[1];wdaa[1]=temm;}
    if(wdaa[1]<wdaa[2]){temm=wdaa[1];wdaa[1]=wdaa[2];wdaa[2]=temm;}
    if(wdaa[2]<wdaa[3]){temm=wdaa[2];wdaa[2]=wdaa[3];wdaa[3]=temm;}
    if(wdaa[3]<wdaa[4]){temm=wdaa[3];wdaa[3]=wdaa[4];wdaa[4]=temm;}
    if(wdaa[4]<wdaa[5]){temm=wdaa[4];wdaa[4]=wdaa[5];wdaa[5]=temm;}
  }
  result=(wdaa[2]+wdaa[3])/2;                                        //                                
}
//=================================================================================================
//温度显示处理数据处理函数
//=================================================================================================
void disp_wd(void)
{  
  uchar x=3;
  //显示数据循环------------------------------------------------------------
  while(result/10)          //数据不为0 带高位消隐
  {
   displaybuf[x]=result%10;     //数据按位直到为0
   result=result/10;
   x++;
  }
  displaybuf[x]=result;        //数据为0
  //负号显示----------------------------------------------------------------
  if(sflag==1)            //在最高位前加负号
   {displaybuf[x+1]=17;}
  else{displaybuf[x+1]=16;}      //否则消隐      
  
// displaybuf[0]=2;
  displaybuf[1]=18;          //符号c
  displaybuf[2]=result1;       //小数位
}
//================================================================================================= 
//定时器中断扫描部分
//=================================================================================================  
void interrupt time0()
{
uchar displaycount,tmp;
  
  //动态扫描子程序------------------------------------------------------------
  tmp=PORTC&0X07;                //保留低3位数据不受影响,高5位才是扫描字
  led_dm=0x00;                 //清余辉
  led_smz=tmp|displaybit[displaycount];     //根据计数器取出扫描字点亮数码管
  tmp=displaybuf[displaycount];         //根据当前计数值,取显示缓冲待显示值
  if((displaycount==3)&&(xiaoshud==1))     //第3位显示小数点
   { tmp=displaycode[displaybuf[displaycount]]|0x80; }  //显示小数点
  else{ tmp=displaycode[displaybuf[displaycount]];}    //不显示小数点
  led_dm=0x00; PORTD=tmp;                 //清余辉,送自行码
  displaycount++; if(displaycount>4){displaycount=0;}   //计数值等于5就归0
  //---------------------------------------------------------------------------------
  TMR0=150;       //定时器0每中断一次重新置初值
}
}

相关帖子

沙发
踢球老越位| | 2009-10-16 23:21 | 只看该作者
在读写DS18B20的过程中,需要延时的地方,顺便扫描一下数码管。。。

使用特权

评论回复
板凳
awmc_m| | 2009-10-16 23:29 | 只看该作者
不要在中断服务程序中做显示,可以置标志位,然后在主程序中显示。定时器可以定为1ms。

使用特权

评论回复
地板
原野之狼| | 2009-10-16 23:57 | 只看该作者
18B20的临界区才多长时间呢,以几个毫秒的量级来动态扫描个数码管是不存在问题的。

使用特权

评论回复
5
sjg_mcu|  楼主 | 2009-10-17 09:03 | 只看该作者
这个项目是个多任务的系统,如果在主程序中显示,程序等于报废.以上的程序只是轻微的闪烁,不注意是看不出来的..但做产品要做到完美.所以请教高手怎么去掉那个轻微的闪烁.

使用特权

评论回复
6
原野之狼| | 2009-10-17 09:12 | 只看该作者
任务节拍多少?

使用特权

评论回复
7
machunshui| | 2009-10-17 09:51 | 只看该作者
这个项目是个多任务的系统,如果在主程序中显示,程序等于报废.以上的程序只是轻微的闪烁,不注意是看不出来的..但做产品要做到完美.所以请教高手怎么去掉那个轻微的闪烁. ...
sjg_mcu 发表于 2009-10-17 09:03


不知楼主用的啥MCU?

我用LPC2103,用DS18B20测温度,数码管在主程序动态扫描(而且还不是直接管脚驱动,基于SPI口驱动595实现),甚至一边进行PWM语音输出,数码管都不闪烁。

使用特权

评论回复
8
machunshui| | 2009-10-17 09:56 | 只看该作者
只要不是MCU特别慢,
即使多个任务放在主程序里面也没有关系。

可以一轮循环里面,执行多次动态扫描。

TASK1,
SCANLED,
TASK2,
SCANLED,
TASK3,
SCANLED,
TASK4,
SCANLED,

当然MCU不能太慢,否则用太慢的MCU执行多个任务+LED动态扫描,本身就是设计上欠考虑

使用特权

评论回复
9
lhj200304| | 2009-10-17 10:09 | 只看该作者
用状态机把把18b20的读数过程打断,每次都2个字节,分5次读完就行了。18b20的时序并不要求一次全部读完的

使用特权

评论回复
10
sjg_mcu|  楼主 | 2009-10-17 10:28 | 只看该作者
UCOS我还是刚看,操作系统还不是很熟,
我是用中断片轮多任务的,使用PIC16F877芯片,过星期一我把这部分做个proteus文件.再发上来.

使用特权

评论回复
11
sjg_mcu|  楼主 | 2009-10-17 10:30 | 只看该作者
PIC单片机,有时一个任务还套着另一个任务,有时每个任务都是分开.51的RTOS是用不上的

使用特权

评论回复
12
sjg_mcu|  楼主 | 2009-10-17 10:32 | 只看该作者
在读写DS18B20的过程中,需要延时的地方,顺便扫描一下数码管。。。


这个办法DS18B20时序不好控制.

使用特权

评论回复
13
sjg_mcu|  楼主 | 2009-10-17 10:44 | 只看该作者
这个程序我用51(STC和ATMEL)单片机不闪烁,但我做的是机电设备,干扰大,且公司产品一直用PIC,不敢用51单片机.

使用特权

评论回复
14
machunshui| | 2009-10-17 10:55 | 只看该作者
即使是PIC16也比普通ATMEL的51快。

怎么会51没事,PIC反而慢呢?

使用特权

评论回复
15
救火车| | 2009-10-17 11:09 | 只看该作者
在18B20时间不敏感的地方打开中断。
18B20对时序要求极严的地方时间是很短的,不影响显示。时序要求不严的地方打开中断。
我已经在我的学习板上实现数码管不闪的效果。

使用特权

评论回复
16
sjg_mcu|  楼主 | 2009-10-17 11:10 | 只看该作者
想起来了,51是个温度计,我在主序程里扫描的.使用的教科书通用方法.

使用特权

评论回复
17
machunshui| | 2009-10-17 11:29 | 只看该作者
LED扫描放到中断里面还是不好。

使用特权

评论回复
18
awmc_m| | 2009-10-17 12:38 | 只看该作者
这个项目是个多任务的系统,如果在主程序中显示,程序等于报废.以上的程序只是轻微的闪烁,不注意是看不出来的..但做产品要做到完美.所以请教高手怎么去掉那个轻微的闪烁. ...
sjg_mcu 发表于 2009-10-17 09:03


现在就是因为你在中断里显示,所以关中断即无法刷新显示,使得显示闪烁。
就是因为你在中断里显示,所以中断耗时较长,不关中断就无**确读取ds18b20
我不理解为什么在主程序做显示会报废,只是定时时间一到刷新显示而已,只是瞬间的事情,又不是占着所有时间只做显示,怎么会报废。

使用特权

评论回复
19
sjg_mcu|  楼主 | 2009-10-17 18:44 | 只看该作者
因为有的按键是点触长按的,长按后松开又要执行别的任务,有的按键是中断后执行的,有按键是点触的.如果在每个按键里,等键释放时扫描显示,程序罗索不说,还会影响别的功能执行.且与我们以前做的成熟产品程序不太兼容,因为我们现在这个产品是个过渡产品,但是个独立的产品,以后要兼容到成熟产品里去.

使用特权

评论回复
20
awmc_m| | 2009-10-17 19:09 | 只看该作者
那你试试将定时时间加长,定成几个ms看看。那样的ds18b20就有足够的操作时间。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

150

帖子

1

粉丝