courses:embedded_system:ds18b20_温度测量
DS18B20温度测量
实验目的
学习DS18B20的操作。
实验内容
学习使用单总线技术,通过它来实现STM32和外部温度传感器(DS18B20)的通信,并把从温度传感器得到的温度数据通过LCD1602显示出来。
实验说明
在既有框架下,主要编写 main.c 和 ds18b20.c 程序,完成相应的功能。
- main.c
/******************************************************************************* * -------------------------------------------------------------------------------- * 实 验 名 : DS18B20温度传感器实验 * 实验说明 : 通过LCD1602显示 * 连接方式 : * 注 意 : 所用函数在头文件.c文件内 *******************************************************************************/ #include "public.h" #include "Lcd1602.h" #include "ds18b20.h" #include "systick.h" /**************************************************************************** * Function Name : main * Description : Main program. * Input : None * Output : None * Return : None ****************************************************************************/ int main() { u16 wd; double temp; LCD1602_GPIO_Init(); LCD1602_Init(); //LCD1602初始化 ds18b20_init(); //DS18B20初始化 while(1) { temp=readtemp(); //读取温度 wd=temp*100; //显示二位小数 LCD1602_MoveToPosition(0,0); LCD1602_DisplayString("wendu"); LCD1602_MoveToPosition(1,0); LCD1602_DisplayOneCharOnAddr(0,9,wd/1000+0x30);//显示十位 LCD1602_DisplayOneCharOnAddr(0,10,wd%1000/100+0x30);//显示个位 LCD1602_DisplayOneCharOnAddr(0,11,'.');//显示. LCD1602_DisplayOneCharOnAddr(0,12,wd%1000%100/10+0x30);//显示小数1位 LCD1602_DisplayOneCharOnAddr(0,13,wd%1000%100%10+0x30);//显示小数2位 LCD1602_DisplayOneCharOnAddr(0,14,0xdf); //℃ LCD1602_DisplayOneCharOnAddr(0,15,'C');//显示C } }
- ds18b20.c
#include "ds18b20.h" /******************************************************************************* * 函 数 名 : ds18b20_init * 函数功能 : IO端口时钟初始化函数 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void ds18b20_init() { GPIO_InitTypeDef GPIO_InitStructure; // 初始化结构体类型 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); // 连接端口 GPIOB 时钟 GPIO_InitStructure.GPIO_Pin=dq; // 端口连接 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; // 初始化为推挽式输出 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // 端口速率 GPIO_Init(GPIO_ds18b20,&GPIO_InitStructure); // 端口初始化 } /******************************************************************************* * 函 数 名 : DQININT * 函数功能 : 输入配置 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void DQININT() //输入配置 { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin=dq; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIO_ds18b20,&GPIO_InitStructure); } /******************************************************************************* * 函 数 名 : DQOUTINT * 函数功能 : 输出配置 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void DQOUTINT() //输出配置 { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin=dq; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIO_ds18b20,&GPIO_InitStructure); } /******************************************************************************* * 函 数 名 : ds18b20init * 函数功能 : DS18B20初始化时序 * 输 入 : 无 * 输 出 : 无 *******************************************************************************/ void ds18b20init() { DQOUTINT();//输出 ds18b20_dq_L; delay_us(480);//延时480微妙 ds18b20_dq_H; delay_us(480);//延时480微妙 } /******************************************************************************* * 函 数 名 : ds18b20wr * 函数功能 : DS18B20写数据时序 * 输 入 : dat * 输 出 : 无 *******************************************************************************/ void ds18b20wr(u8 dat) { u8 i=0; DQOUTINT();//输出 for(i=0;i<8;i++) // 一次8位,即1字节 { ds18b20_dq_L; //拉低 delay_us(15); //延时15微妙 if((dat&0x01)==1) // 判断最低位 { ds18b20_dq_H; } else { ds18b20_dq_L; } delay_us(60);//延时60微妙 ds18b20_dq_H; dat>>=1; // 右移一位,准备下一位数据的发送 } } /******************************************************************************* * 函 数 名 : DS18b20rd * 函数功能 : DS18B20读数据时序 * 输 入 : 无 * 输 出 : value *******************************************************************************/ u8 DS18b20rd() { u8 i=0,value=0; for(i=0;i<8;i++) { value>>=1; // 右移一位,留出最高位 DQOUTINT(); //输出 ds18b20_dq_L; //拉低 delay_us(4); //延时4微妙 ds18b20_dq_H; delay_us(10); //延时10微妙 DQININT(); //输入配置 if(GPIO_ReadInputDataBit(GPIO_ds18b20,dq)==1) { value|=0x80; // value和最高位比较,如果是1就读进去,8次移位之后高位变低位;读数据 从低位开始 } delay_us(45); //延时45微妙 } return value; } /******************************************************************************* * 函 数 名 : readtemp * 函数功能 : DS18B2温度寄存器配置,温度读取 * 输 入 : 无 * 输 出 : value *******************************************************************************/ double readtemp() //读取温度内需要复位的 { u16 temp; u8 a,b; double value; ds18b20init(); //初始化 ds18b20wr(0xcc); //发送忽略ROM指令 ds18b20wr(0x44); //发送温度转换指令 delay_ms(800); // 12位分辨率时,转换时间需大于750ms ds18b20init(); //初始化 ds18b20wr(0xcc); //发送忽略ROM指令 ds18b20wr(0xbe); //发读暂存器指令 a=DS18b20rd(); //温度的低八位 b=DS18b20rd(); //温度的高八位 temp=b; temp=(temp<<8)+a; // temp是16位,先把temp中b左移8为,放到temp的高8位;再+a即将a放到temp的低8位 // 使用 temp=(temp<<8)|a 也一样 if((temp&0xf800)==0xf800) // 如果前5为是1,表示温度是负值(根据数据存储表),用负数的补码公式:取反+1 { temp=(~temp)+1; value=temp*(-0.0625); } else { value=temp*0.0625; } return value; }
实验步骤
1. 使用1根1P杜邦线连接核心板PB8与“两路温度传感器”单元JP35(WD1)相连。 2. 使用1根8P杜邦线连接核心板PA0~PA7与“LCD1602液晶”单元JP33(D0~D7)。 3. 使用3根1P线连接PA8~PA11与“LCD1602液晶”单元JP31(RS,RW,EN)。 4. 在KEIL软件中调试运行“DS18B20温度测量”工程文件。 5. 实验现象:在液晶上显示“wendu xx.xx℃”。
实验任务
1. 按上述步骤调试出结果; 2. 显示器上的“wendu”改为“Temperature”,设置温度显示范围为小数点后4位; 3. 改变测量温度的分辨率为10位,即最小刻度变化为0.25°C,此时可以观察到温度显示的4位小数中最后两位始终为0。
任务解答
- 任务1.c
int main() { u32 wd; // 这里要改为 u32,因为u16最多表示2^16=65536 double temp; LCD1602_GPIO_Init(); LCD1602_Init(); ds18b20_init(); //DS18B20初始化 while(1) { temp=readtemp(); //读取温度 wd=temp*10000; //显示四位小数 LCD1602_MoveToPosition(0,0); LCD1602_DisplayString("Temperature:"); LCD1602_MoveToPosition(1,0); LCD1602_DisplayOneCharOnAddr(1,7,wd/100000+0x30);//显示十位 LCD1602_DisplayOneCharOnAddr(1,8,wd%100000/10000+0x30);//显示个位 LCD1602_DisplayOneCharOnAddr(1,9,'.');//显示. 用ox2e效果一样 LCD1602_DisplayOneCharOnAddr(1,10,wd%100000%10000/1000+0x30);//显示小数1位 LCD1602_DisplayOneCharOnAddr(1,11,wd%100000%10000%1000/100+0x30);//显示小数2位 LCD1602_DisplayOneCharOnAddr(1,12,wd%100000%10000%1000%100/10+0x30);//显示小数3位 LCD1602_DisplayOneCharOnAddr(1,13,wd%100000%10000%1000%100%10+0x30);//显示小数4位 LCD1602_DisplayOneCharOnAddr(1,14,0xdf); //显示°,对照LCD1602的字符表查询 LCD1602_DisplayOneCharOnAddr(1,15,'C');//显示C } }
- 任务2.m
/* 第1步:在 ds18b20.c 中添加配置函数修改分辨率 */ void resolution_conf() { ds18b20init(); ds18b20wr(0xcc); // 发送忽略ROM指令 ds18b20wr(0x4e); // 发送写寄存器指令 ds18b20wr(0x7D); // 配置触发寄存器最高125° ds18b20wr(0xc9); // 配置触发寄存器最低-55° ds18b20wr(0x3f); // 配置分辨率9位1f,即 0 00 11111,默认12位为7f,即 0 11 11111 // ds18b20wr(0x48); // 写入非易失性的EEPROM } /* 第2步:在 ds18b20.h 中声明定义的配置函数 */ void resolution_conf(void); /* 第3步:在 main.c 中调用 resolution_conf() */ ds18b20_init(); //DS18B20初始化 resolution_conf(); // 调用 /* 第4步:在 readtemp() 中修改温度转换时间为 delay_ms(200);