asp网站后台上传不了图片,wordpress怎么用模板,软件开发服务合同,商业网站建设方案由于DS18B20数字温度传感器是单总线接口#xff0c;所以需要使用51单片机的一个IO口模拟单总线时序与DS18B20通信#xff0c;将检测的环境温度读取出来
1、DS18B20模块电路 传感器接口的单总线管脚接至单片机P3.7IO口上
2、DS18B20介绍
2.1 DS18B20外观实物图 管脚1为GN… 由于DS18B20数字温度传感器是单总线接口所以需要使用51单片机的一个IO口模拟单总线时序与DS18B20通信将检测的环境温度读取出来
1、DS18B20模块电路 传感器接口的单总线管脚接至单片机P3.7IO口上
2、DS18B20介绍
2.1 DS18B20外观实物图 管脚1为GND管脚2为数据DQ管脚3为VDD
2.2 DS18B20内部结构图 2.2.1 64位光刻ROM 64位光刻ROM中的64位序列号是出厂前被光刻好的它可以看作是该DS18B20的地址序列号。 64位光刻 ROM的排列是开始8位28H是产品类型标号接着的48位是该DS18B20自身的序列号最后 8位是前面56位的循环冗余校验码。 光刻ROM的作用是使每一个DS18B20都各不相同这样就可以实现一根总线上挂接多个DS18B20的目的
2.2.2 高速缓存存储器 DS18B20温度传感器的内部存储器包括一个高速的暂存器RAM和一个非易失性的可电擦除的 EEPROM后者存放高温度和低温度触发器TH、TL和配置寄存器
2.2.2.1 配置寄存器 配置寄存器是配置不同的位数来确定温度和数字的转化配置寄存器结构如下图所示 1低五位一直都是“1”
2TM是测试模式位用于设置DS18B20在工作模式还是在测试模式。在 DS18B20出厂时该位被设置为0用户不需要去改动
3R1和R0用来设置DS18B20的精度分辨率精度可设置为91011或12位对应的分辨率温度是 0.5℃0.25℃0.125℃和0.0625℃。R0和R1配置如下图所示 在初始状态下默认的精度是12位即R01、R11
2.2.2.2 高速暂存存储器 1高速暂存存储器由9个字节组成其分配如下图所示 当温度转换命令44H发布后经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节 2存储的两个字节高字节的前5位是符号位S单片机可通过单线接口读到该数据读取时低位在前高位在后数据格式如下 如果测得的温度大于0这5位为“0”只要将测到的数值乘以0.0625默认精度是12位即可得到实际温度
如果温度小于0这5位为“1” 测到的数值需要取反加1再乘以0.0625即可得到实际温度。
温度与数据对应关系如下图所示 2.3 DS18B20时序
DS18B20时序包括如下几种初始化时序、写0和1时序、 读0和1时序
DS18B20发送所有的命令和数据都是字节的低位在前 2.3.1 初始化时序 主机输出低电平保持低电平至少480us该时间范围480-960us以产生复位脉冲。接着主机释放总线外部的上拉电阻将单总线拉高延时15-60us并进入接收模式 接着DS18B20拉低总线60-240us以产生低电平应答脉冲若为低电平还要做延时其延时的时间从外部上拉电阻将单总线拉高算起最少要480us //初始化时序图13的左半段复位脉冲时序 void ds18b20_reset(){ DS18B20_PORT0; //拉低DQ线单总线 主机输出低电平 delay_10us(75); //750us480us-960us 保持低电平至少480us DS18B20_PORT1; //拉高DQ线 主机释放总线外部的上拉电阻将单总线拉高 delay_10us(2); //20us(15us-60us) 延时15-60us } //初始化时序图13的右半段检测DS18B20是否存在返回值0存在返回值1不存在 u8 ds18b20_check(){ u8 time_temp0; while(DS18B20_PORTtime_temp20){ //DS18B20_PORT1 time_temp; delay_10us(1); //10us要循环20次相当于200us(60-240us) } if(time_temp20){ return 1; //超时了仍没有等到低电平 }else{ time_temp0; } //如果等到了低电平DS18B20_PORT变为0 while((!DS18B20_PORT)time_temp20){ //DS18B20_PORT0 time_temp; delay_10us(1); } if(time_temp20){ return 1; //超时了仍没有等到高电平 } return 0; } 2.3.2 写时序 写时序包括写0时序和写1时序。所有写时序至少需要60us且在2次独立的写时序之间至少需要1us的恢复时间两种写时序均起始于主机拉低总线 写1时序主机输出低电平延时2us然后释放总线延时60us 写0时序主机输出低电平延时60us然后释放总线延时2us //写时序写一个字节到ds18b20中提前准备好数据 void ds18b20_write_byte(u8 dat){ u8 i0; u8 temp0; //从低位向高位写 eg1001 0011 for(i0;i8;i){ tempdat0x01; //拿到dat中低位的数据 dat1; if(temp){ //写1时序 DS18B20_PORT0; 主机输出低电平 _nop_(); //1us 延时2us _nop_(); DS18B20_PORT1; 释放总线 delay_10us(10); //100us(60-120us) 延时60us }else{ //写0时序 DS18B20_PORT0; 主机输出低电平 delay_10us(6); 延时60us DS18B20_PORT1; 释放总线 _nop_(); //1us 延时2us _nop_(); } } } 2.3.3 读时序 所有读时序至少需要60us且在2次独立的读时序之间至少需要1us的恢复时间。每个读时序都由主机发起至少拉低总线1us。主机在读时序期间必须释放总线并且在时序起始后的15us之内采样总线状态 典型的读时序过程为主机输出低电平延时2us然后主机转入输入模式延时12us然后读取单总线当前的电平然后延时50us //读一位 u8 ds18b20_read_bit(){ u8 dat0; //存的是某一位0或1 //主机输出低电平 DS18B20_PORT0; //延时2us _nop_(); //1us _nop_(); DS18B20_PORT1; 主机转入输入模式 //延时2us时间不能过长必须在15us内读到数据 延时12us _nop_(); //1us _nop_(); if(DS18B20_PORT){ 读取单总线当前的电平 dat1; }else{ dat0; } delay_10us(5); 延时50us return dat; } //读一个字节 u8 ds18b20_read_byte(){ u8 i0; u8 dat0; u8 temp0; for(i0;i8;i){ tempds18b20_read_bit(); //i0时temp1i1时temp1 dat1; //i0时dat000 0000i1时dat0100 0000 dat|temp7; //i0时dat1000 0000i1时dat1100 0000 } return dat; } 2.3.4 DS18B20的典型温度读取过程
复位→发SKIPROM命令0XCC→发开始转换命令0X44→延时→复位→发送SKIPROM命令0XCC→发读存储器命令0XBE→连续读出两个字节数据即温度→结束 /* DS18B20 的典型温度读取过程为 复位→发SKIPROM命令0XCC→发开始转换命令0X44 →延时→ 复位→发送SKIPROM命令0XCC→发读存储器命令0XBE→连续读出两个字节数据(即温度)→结束。 */ //开始温度转换 void ds18b20_start(){ ds18b20_init(); //初始化复位和检查 ds18b20_write_byte(0xcc); //发SKIPROM命令0XCC ds18b20_write_byte(0x44); //发开始转换命令0X44 } //从ds18b20得到温度值 double ds18b20_read_temperture(){ double temp; u8 dath0; u8 datl0; u16 value0; ds18b20_start(); ds18b20_init(); //初始化复位和检查 ds18b20_write_byte(0xcc); //发送SKIPROM命令0XCC ds18b20_write_byte(0xbe); //发读存储器命令0XBE //连续读出两个字节数据(即温度) datlds18b20_read_byte(); //低8位 dathds18b20_read_byte(); //高8位 //高8位和低8位连接起来拼成16位 value(dath8)datl; //判断是正温度还是负温度 if((value0xf800)0xf800){ //负温度 value(~value)1; tempvalue*(-0.0625); }else{ //正温度 tempvalue*0.0625; } return temp; } 3、实验
要实现的功能是插上DS18B20温度传感器数码管显示检测的温度值
如果不知道怎么进行多文件编程51单片机——I2C-EEPROM-CSDN博客中有
3.1 Public文件
3.1.1 public.h //头文件中放置函数的声明、全局变量的定义 #ifndef _public_H #define _public_H #include reg52.h //全局变量 typedef unsigned int u16; typedef unsigned char u8; //两个延迟函数声明 void delay_10us(u16 us); void delay_ms(u16 ms); #endif 3.1.2 public.c #include public.h void delay_10us(u16 us){ while(us--); } void delay_ms(u16 ms){ u16 i0,j0; for(i0;ims;i){ for(j0;j110;j); } } 3.2 动态数码管
3.2.1 smg.h #ifndef _smg_H #define _smg_H #include public.h sbit LSAP2^2; sbit LSBP2^3; sbit LSCP2^4; #define SMG_A_DP_PORT P0 extern u8 gsmg_code[]; void smg_display(u8 save_buff[],u8 pos); #endif 3.2.2 smg.c #include smg.h u8 gsmg_code[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; //save_buff是一个u8类型的数组方便外部传入要显示的数据 //pos是数码管从左开始第几个位置开始显示取值范围是1-8 void smg_display(u8 save_buff[],u8 pos){ u16 i0; u16 pos_temppos-1; for(ipos_temp;i8;i){ //位选 switch(i){ case 0: LSC1,LSB1,LSA1; //7 break; case 1: LSC1,LSB1,LSA0; //6 break; case 2: LSC1,LSB0,LSA1; //5 break; case 3: LSC1,LSB0,LSA0; //4 break; case 4: LSC0,LSB1,LSA1; //3 break; case 5: LSC0,LSB1,LSA0; //2 break; case 6: LSC0,LSB0,LSA1; //1 break; case 7: LSC0,LSB0,LSA0; //0 break; } SMG_A_DP_PORTsave_buff[i-pos_temp]; delay_10us(100); SMG_A_DP_PORT0x00; //消隐 } } 3.3 DS18B20
3.3.1 ds18b20.h #ifndef _ds18b20_H #define _ds18b20_H #include public.h #include intrins.h //_nop_()1us sbit DS18B20_PORTP3^7; //DQ //初始化时序图13的左半段复位脉冲时序 void ds18b20_reset(); //初始化时序图13的右半段检测DS18B20是否存在返回值0存在返回值1不存在 u8 ds18b20_check(); //初始化时序 u8 ds18b20_init(); //写时序写一个字节到ds18b20中提前准备好数据 void ds18b20_write_byte(u8 dat); //读一位 u8 ds18b20_read_bit(); //读一个字节 u8 ds18b20_read_byte(); //开始温度转换 void ds18b20_start(); //从ds18b20得到温度值 double ds18b20_read_temperture(); #endif 3.3.2 ds18b20.c #include ds18b20.h //协议层 //初始化时序图13的左半段复位脉冲时序 void ds18b20_reset(){ DS18B20_PORT0; //拉低DQ线单总线 delay_10us(75); //750us480us-960us DS18B20_PORT1; //拉高DQ线 delay_10us(2); //20us(15us-60us) } //初始化时序图13的右半段检测DS18B20是否存在返回值0存在返回值1不存在 u8 ds18b20_check(){ u8 time_temp0; while(DS18B20_PORTtime_temp20){ //DS18B20_PORT1 time_temp; delay_10us(1); //10us要循环20次相当于200us(60-240us) } if(time_temp20){ return 1; //超时了仍没有等到低电平 }else{ time_temp0; } //如果等到了低电平DS18B20_PORT变为0 while((!DS18B20_PORT)time_temp20){ //DS18B20_PORT0 time_temp; delay_10us(1); } if(time_temp20){ return 1; //超时了仍没有等到高电平 } return 0; } //初始化时序将初始化时序图13的左半段和右半段连接起来 u8 ds18b20_init(){ ds18b20_reset(); return ds18b20_check(); } //ds18b20中读写操作 //写时序写一个字节到ds18b20中提前准备好数据 void ds18b20_write_byte(u8 dat){ u8 i0; u8 temp0; //从低位向高位写 1001 0011 for(i0;i8;i){ tempdat0x01; //拿到dat中低位的数据 dat1; if(temp){ //写1时序 DS18B20_PORT0; _nop_(); //1us _nop_(); DS18B20_PORT1; delay_10us(10); //100us(60-120us) }else{ //写0时序 DS18B20_PORT0; delay_10us(6); DS18B20_PORT1; _nop_(); //1us _nop_(); } } } //读时序读位、读字节 1001 0011 //读一位 u8 ds18b20_read_bit(){ u8 dat0; //存的是某一位0或1 //主机输出低电平 DS18B20_PORT0; //延时2us _nop_(); //1us _nop_(); DS18B20_PORT1; //延时2us时间不能过长必须在15us内读到数据 _nop_(); //1us _nop_(); if(DS18B20_PORT){ dat1; }else{ dat0; } delay_10us(5); return dat; } //读一个字节 u8 ds18b20_read_byte(){ u8 i0; u8 dat0; u8 temp0; for(i0;i8;i){ tempds18b20_read_bit(); //i0时temp1i1时temp1 dat1; //i0时dat000 0000i1时dat0100 0000 dat|temp7; //i0时dat1000 0000i1时dat1100 0000 } return dat; } /* DS18B20 的典型温度读取过程为 复位→发SKIPROM命令0XCC→发开始转换命令0X44 →延时→ 复位→发送SKIPROM命令0XCC→发读存储器命令0XBE→连续读出两个字节数据(即温度)→结束。 */ //开始温度转换 void ds18b20_start(){ ds18b20_init(); //初始化复位和检查 ds18b20_write_byte(0xcc); //发SKIPROM命令0XCC ds18b20_write_byte(0x44); //发开始转换命令0X44 } //从ds18b20得到温度值 double ds18b20_read_temperture(){ double temp; u8 dath0; u8 datl0; u16 value0; ds18b20_start(); ds18b20_init(); //初始化复位和检查 ds18b20_write_byte(0xcc); //发送SKIPROM命令0XCC ds18b20_write_byte(0xbe); //发读存储器命令0XBE //连续读出两个字节数据(即温度) datlds18b20_read_byte(); //低8位 dathds18b20_read_byte(); //高8位 //高8位和低8位连接起来拼成16位 value(dath8)datl; //判断是正温度还是负温度 if((value0xf800)0xf800){ //负温度 value(~value)1; tempvalue*(-0.0625); }else{ //正温度 tempvalue*0.0625; } return temp; } 3.4 main.c #include public.h #include smg.h #include ds18b20.h /* 下载程序后插上DS18B20温度传感器数码管显示检测的温度值 */ void main(){ u8 i0; int temp_value; //有负温度 u8 temp_buf[5]; ds18b20_init(); //起始信号检查ds18b20在不在要不要都可以 while(1){ i; if(i%500){ //减少读的频率750us转换一次 temp_valueds18b20_read_temperture()*10; } if(temp_value0){ //显示符号位 temp_value-temp_value; temp_buf[0]0x40; //显示负号 }else{ temp_buf[0]0x00; //不显示 } //读的温度要在数码管显示 temp_buf[1]gsmg_code[temp_value/1000]; temp_buf[2]gsmg_code[temp_value%1000/100]; temp_buf[3]gsmg_code[temp_value%1000%100/10]|0x80; temp_buf[4]gsmg_code[temp_value%1000%100%10]; smg_display(temp_buf,4); } }