传感器
单片机 测温芯片 18B20 是一款常用的IC,优势特点不多说,这里主要讨论温度值的处理,尤其是负温度。
18B20片内有一个9Byte的 SRAM 和一个3Byte的 EEPROM。如下图:
其中我们需要使用的就是SRAM中的前两个字节,这里储存的就是我们要的温度值。这两个字节的结构如下:
我们可以看到,LS(低字节)的高四位 和 MS(高字节)的低四位共8个字节构成了实际的一个带符号位的字节数据可以表示(-128~127)足够表示18B20的温度范围。MS的高四位为符号为的扩展,当温度值为正时MS高5位(图中S的五位)全为0,温度值为负时全为1。LS的低四位为小数部分,不是要求太高的话可以忽略。我们这里暂不套路小数部分的处理方法。
整数部分我们实际只要高字节的第四位和低字节的高四位。首先通过移位求或后生成一个无符号位的字节。然后判断这个无符号的值是否大于127,如果大于128说明是个负温度需要处理,否则就可以直接返回。
18B20的负温度使用补码形式输出,我们只需要对这个字节进行取反加1后就是这个负温度的绝对值,这时候我们需要一个符号标记告诉输出函数这是个负温度需要显示负号即可。
uchar readtemp() //读取温度
{
uchar temp = 0;
uchar tmp[2]
reset();
writebyte(0xCC); // 跳过序列号
writebyte(0x44); // 启动温度转换
delayms(1000);
reset();
writebyte(0xCC);
writebyte(0xBE); //读9个寄存器,前两个为温度
tmp[0]=readbyte(); //低位
tmp[1]=readbyte(); //高位
temp = ((tmp[1]《《4)&0xF0)|((tmp[0]》》4)&0x0F);
if(temp》127)
{
temp = ~temp + 1;
}
return (temp);
}
18b20的ram中,前两个字节放的是温度信息。其中第二个字节的高五位是符号位,当温度为正的时候,高五位的字节是0,当温度为负的时候,高五位字节为一。当温度为正的时候,只需要将两个字节的数合到一个字节,然后乘以0.0625就是实际的温度。
那么,当温度为负的时候,该怎么读取温度呢?是将两个字节合为一个字节,然后先取反,再加一,最后再和0.0625相乘吗?这样得出的结果就是实际的负温度值吗?
判断是否是负,就是取高几位的读取值采用与的方式判断,比如(000) 11111 00001000,那么高5位可以这样弄,tempH&0x1f,如果这个值=1;说明是负的,否则就是正的啊,不过有一点,取反是对的,还要加1啊,记得哦。
至于在LCD中显示的,确实是按你说的那样,直接写上一个符号即可。
DS18b20 输出的负温度数据是定点补码(小数点后固定二进制四位),符号可由最高位判定(0为正,1为负)。若是负数,则求其补码即可,具体为“取反加一”或 0x10000 - T (T为度出来的补码)。
把读出来的数temperaturebuffer定义成16位的带符号整形,进行带符号的移位,直接转成浮点数,正负号就在里面了,用下面的表达式,你不用判断正负。
((float)(temperaturebuffer》》4))+((temperaturebuffer&0x0F)/16.0)
其内有两个温度上下限寄存器TH和TL,所采温度若超过此温度范围后会置相应的报警标志位。至于那个校验,是CRC-8,这并不太复杂,可以找些相关资料了解一下便知。
//main.c
#include
#include
#include “18B20.h”
#include“disp.h”
#define uint unsigned int
#define uchar unsigned char
const uchar shu[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,
0x82,0xF8,0x80,0x90};
const uchar bshu[3]={0xff,0xf9,0xbf};
//延时函数在4M时延时1ms
void s_1ms(unsigned int ms)
{
unsigned int aa;
for(;ms》=1;ms--)
{
for(aa=0;aa《=800;aa++)
{;}
}
}
void main()
{
uint wendu,xiao,ge,shi,bai;
uchar fh;
DDRA = 0xff;
PORTA = 0xff;
s_1ms(200); //延时200ms
ds1820_reset(); //DS18B20复位
while (1)
{
ds1820_start();
wendu = ds1820_read_temp(); //读取温度数值
fh=ds1820_fh();
if(fh)
{
wendu=~(wendu)+1;
wendu = (wendu * 10)/ 16; //数值处理
wendu = wendu % 1000;
shi= wendu / 100; //显示第2位
wendu = wendu % 100;
ge= wendu / 10; //显示ge位
xiao=wendu % 10; // 显示小数位
display(0,shu[xiao]); //小数位
display(1,shu[ge]&0x7f); //个位
display(2,shu[shi]); //shi
display(3,bshu[2]); //bai位,0不显示
}
else
{
wendu = (wendu * 10) / 16; //数值处理
bai = wendu / 1000; //bai位
wendu = wendu % 1000;
shi= wendu / 100; //显示第2位
wendu = wendu % 100;
ge= wendu / 10; //显示ge位
xiao=wendu % 10; // 显示小数位
display(0,shu[xiao]); //小数位
display(1,shu[ge]&0x7f); //个位
display(2,shu[shi]); //shi
display(3,bshu[bai]); //bai位,0不显示
}
}
}
//18B20.h
#define uchar unsigned char
#define uint unsigned int
//设置成输入
#define DQ_INPUT DDRC &= ~BIT(7)
//设置成输出
#define DQ_OUT DDRC |= BIT(7)
//设置成低电平
#define DQ_LO PORTC &= ~BIT(7)
//设置成高电平
#define DQ_HI PORTC |= BIT(7)
//读出
#define DQ_R PINC & BIT(7)
//中断标志
uchar init_f;
//延时函数
void delay_us(uint ms)
{
uchar tm;
while(ms--)
{
for(tm=0;tm《2;tm++);
}
}
//DS18B20复位
void ds1820_reset(void)
{
uchar i;
//中断保护
init_f = SREG;
//关中断
CLI();
DQ_OUT;
DQ_LO;
delay_us(80); //延时500us
DQ_HI;
DQ_INPUT;
delay_us(10); //延时80us
i = DQ_R;
delay_us(80); //延时500us
if (init_f & 0x80) //恢复中断状态
{
SEI();
}
}
//DS18B20字节读取
uchar ds1820_read_byte(void)
{
uchar i;
uchar value = 0;
//中断保护
init_f = SREG;
//关中断
CLI();
for (i = 8; i != 0; i--) {
value 》》= 1;
DQ_OUT;
DQ_LO;
delay_us(2);
DQ_HI;
DQ_INPUT;
if (DQ_R)
{
value|=0x80;
}
delay_us(10); //延时60us
}
if (init_f&&0x80) //恢复中断状态
{
SEI();
}
return(value);
}
//DS18B20字节写入
void ds1820_write_byte(unsigned char value)
{
uchar i;
init_f = SREG;
CLI();
for (i = 8; i 》 0; i--)
{
DQ_OUT;
DQ_LO;
if (value & 0x01)
{
DQ_HI;
}
delay_us(10); //延时80us
DQ_HI;
value 》》= 1;
}
if (init_f & 0x80)//恢复中断状态
{
SEI();
}
}
//启动ds1820转换
void ds1820_start(void)
{
ds1820_reset();
ds1820_write_byte(0xCC); //勿略ROM
ds1820_write_byte(0x44); //启动转换
}
//读温度
uint ds1820_read_temp(void)
{
uint i,wendu;
uchar buf[2];
ds1820_reset();
ds1820_write_byte(0xCC); //勿略ROM
ds1820_write_byte(0xBE); //读温度
for (i = 0; i 《 2; i++)
{
buf[i] = ds1820_read_byte();
}
wendu = (buf[1]《《8)|buf[0];
return wendu;
}
uint ds1820_fh(void) //读正负温度符号
{
uint i,bb;
uchar buf[2];
ds1820_reset();
ds1820_write_byte(0xCC); //勿略ROM
ds1820_write_byte(0xBE); //读温度
for (i = 0; i 《 2; i++)
{
buf[i] = ds1820_read_byte();
}
bb=buf[1]&0xf0;
return bb;
}
//disp.h
#define uchar unsigned char
#define uint unsigned int
#define SHCP_0 PORTA&=~BIT(1)
#define SHCP_1 PORTA|=BIT(1)
#define DS_0 PORTA&=~BIT(3)
#define DS_1 PORTA|=BIT(3)
#define STCP_0 PORTA&=~BIT(2)
#define STCP_1 PORTA|=BIT(2)
void CKin()
{
SHCP_0;
NOP();
SHCP_1;
}
void Dataout() //并行输出
{
STCP_0;
NOP();
STCP_1;
}
void Datein( uchar date ) //数据串行输入
{
uchar i,mod;
DDRA=0xff;
for(i=0;i《8;i++)
{
mod=date&0x80;
if(mod==0x80)
{DS_1;}
else
{DS_0;}
CKin();
date《《=1;
}
Dataout(); //并行输出
}
void weihao(uchar add)
{
DDRA=0xff;
switch(add)
{
case 0:PORTA=0x1f;break;
case 1:PORTA=0x1f|0x80;break;
case 2:PORTA=0x1f|0x40;break;
case 3:PORTA=0x1f|0xc0;break;
case 4:PORTA=0x1f|0x20;break;
case 5:PORTA=0x1f|0xA0;break;
case 6:PORTA=0x1f|0x60;break;
case 7:PORTA=0x1f|0xE0;break;
default:break;
}
}
void DELAY(uint tt)
{
uint mm;
while(tt--)
{
for(mm=30;mm》0;mm--);
}
}
void display(uchar wei,uchar data)
{
weihao(wei);
Datein(data);
DELAY(20);
weihao(wei);
Datein(0xff);
}
全部0条评论
快来发表一下你的评论吧 !