我使用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每中断一次重新置初值
}
} |