温湿度采集实验

描述

11.1 实验简介

11.1.1 温度采集方案概述

本实验采用三种方式来获取温湿度值,一种是STM32芯片内部自带的温度传感器,一种是基于单总线协议的DS18B20温度传感器,还有一种就是温湿度传感器DHT11或者DHT22,但是在成本上DHT22比较高,所以实验仅使用DHT11,DS18B20和内部温度传感器进行。

11.1.2 单线协议

单总线协议是美国的达拉斯公司推出的一款总线通信协议,所谓单线协议,就是通过一根线传输所有的数据,通俗地讲就是根据低电平的时间来判断总线上的数据是0还是1,比如拉低总线10us,就认为发送的是1,拉低总线50us,就认为发送的是0,单总线协议中,有3种时序,即写时序,读时序和检测时序。我们在51单片机开发中已经尝试用51单片机通过单总线协议读取DS18B20的温度值,故这里不再详细描述协议的具体内容。

11.2 传感器介绍

11.2.1 内部温度传感器

STM32F103有一个内部温度传感器,可以用于测量CPU以及周围的温度,这个温度传感器在内部和ADC模块的通道16相连,这个通道用于将传感器输出的电压值转换为数字编码,根据手册得到推荐的采样时间是17.1us,STM32内部温度传感器支持的温度范围为-40~+125℃,精度在±1.5℃左右。

   根据手册提供的电压与温度转换公式如下所示。

温度传感器

其中V25代表传感器在25℃时候的数值,典型值为1.43

K代表温度与Vsense曲线的平均斜率,典型值为4.3mV/℃

Vsense代表实际温度传感器输出的数值。

通过上面的公式,我们就可以方便地计算出当前的实际温度。

11.2.2 DS18B20温度传感器

DS18B20是一款测温范围在-55~+125℃,精度在±0.5℃的高精度数字式温度传感器,可以通过单线接口直接读取出被测物体的温度,测温精度可以通过编程实现,工作电压3~5.5V。值得一提的是,DS18B20内部具有64位序列号是出厂就被设定的,每一个DS18B20的序列号均不相同,其中前8位是产品家族码,中间48位是序列号,最后8位是CEC校验码,这就可以实现1根总线上挂接多个DS18B20

(1)复位与应答脉冲

单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少480us,以产生复位脉冲。接着主机释放总线,4.7K的上拉电阻将单总线拉高,延时1560us,并进入接收模式。接着从设备拉低总线60~240us,以产生低电平应答脉冲,若为低电平,再延时480us

(2)写时序

写时序包括写0时序和写1时序。所有写时序至少需要60us,且在2次独立的写时序之间至少需要1us的恢复时间,两种写时序均起始于主机拉低总线。写1时序:主机输出低电平,延时2us,然后释放总线,延时60us。写0时序:主机输出低电平,延时60us,然后释放总线,延时2us。

(3)读时序

必须马上产生读时序,以便从机能够传输数据。所有读时序至少需要60us,且在2次独立的读时序之间至少需要1us的恢复时间。每个读时序都由主机发起,至少拉低总线1us。主机在读时序期间必须释放总线,并且在时序起始后的15us之内采样总线状态。典型的读时序过程为:主机输出低电平延时2us,然后主机转入输入模式延时12us,然后读取单总线当前的电平,然后延时50us。

(4)DS18B20测温时序

DS18B20的典型温度读取过程为:复位->发送跳过ROM读取命令(0XCC)->发开始转换命令(0X44)->延时复位->发送跳过ROM读取命令(0XCC)->发读存储器命令(0XBE)->连续读出两个字节温度->结束。

11.2.3 DHT11温湿度传感器

DHT11是一款湿温度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。通过单片机等微处理器简单的威廉希尔官方网站
连接就能够实时的采集本地湿度和温度。DHT11与单片机之间能采用简单的单总线进行通信,仅仅需要一个I/O口。传感器内部湿度和温度数据40Bit的数据一次性传给单片机,数据采用校验和方式进行校验,有效的保证数据传输的准确性。DHT11功耗很低,5V电源电压下,工作平均最大电流0.5mA。

   DHT11的电参数如下所示。

(1)工作电压:3.3V~5.5V

(2)工作电流:平均0.5mA

(3)测量范围:湿度2090%RH,温度050℃

(4)测量精度:湿度±5%,温度±2%℃

(5)分辨率:湿度1%,温度1℃

DHT11数字式温湿度传感器采用单总线数据格式。即,单个数据引脚端口完成输入输出双向传输。其数据包由5个字节组成。数据分小数部分和整数部分,一次完整的数据传输为40bit,高位先出。DHT11的数据格式为:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和。其中校验和数据为前四个字节相加。传感器数据输出的是未编码的二进制数据。数据(湿度、温度、整数、小数)之间应该分开处理。

   DHT11的 **开始时序** ,即:拉低数据线,保持至少18ms,然后拉高数据线20~40us,然后读取DHT11的响应,正常的话,DHT11会拉低数据线,保持40~50us,作为响应信号,然后DHT11拉高数据线,保持40~50us后,开始输出数据。

11.3 STM32片内ADC简介

11.3.1 内部ADC概述

STM32F103拥有1~3个ADC,这些ADC可以独立使用,也可以使用双重模式(提高采样率)。STM32的ADC是12位逐次逼近型的模拟数字转换器。它有18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。STM32F103系列最少都拥有2个ADC,我们选择的STM32F103ZET包含有3个ADC。

   STM32的ADC最大的转换速率为1Mhz,也就是转换时间为1us(在ADCCLK=14M,采样周期为1.5个ADC时钟下得到),不要让ADC的时钟超过14M,否则将导致结果准确度下降。STM32将ADC的转换分为2个通道组:规则通道组和注入通道组。规则通道相当于你正常运行的程序,而注入通道就相当于中断。在程序正常执行的时候,中断是可以打断执行的。同这个类似,注入通道的转换可以打断规则通道的转换,在注入通道被转换完成之后,规则通道才得以继续转换。

11.3.2 ADC相关寄存器

(1)ADC控制寄存器1:ADC_CR1

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
- AWDEN AWDENJ - FUALMOD[3:0]
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
DISCNUM[2:0] DISCENJ DISCEN JAUTO AWDSGL SCAN JEOCIE AWDIE EOCIE AWDCH[4:0]

Bit 23:在规则通道上开启模拟看门狗

0:在规则通道上禁用模拟看门狗

   1:在规则通道上使用模拟看门狗

Bit 22:在注入通道上开启模拟看门狗

0:在注入通道上禁用模拟看门狗

   1:在注入通道上使用模拟看门狗

Bit 19~Bit16:双模式选择

0000:独立模式

   0001:混合的同步规则+注入同步模式

   0010:混合的同步规则+交替触发模式

   0011:混合同步注入+快速交叉模式

   0100:混合同步注入+慢速交叉模式

   0101:注入同步模式

   0110:规则同步模式

   0111:快速交叉模式

   1000:慢速交叉模式

   1001:交替触发模式

Bit 15~Bit 13:间断模式通道计数

000:1个通道

   001:2个通道

   ……

   111:8个通道

Bit 12:在注入通道上的间断模式

0:注入通道组上禁用间断模式

   1:注入通道组上使用间断模式

Bit 11:在规则通道上的间断模式

0:规则通道组上禁用间断模式

   1:规则通道组上使用间断模式

Bit 10:自动的注入通道组转换

0:关闭自动的注入通道组转换

   1:开启自动的注入通道组转换

Bit 9:扫描模式中在一个单一的通道上使用看门狗

0:在所有的通道上使用模拟看门狗

   1:在单一通道上使用模拟看门狗

Bit 8:扫描模式

0:关闭扫描模式

   1:使用扫描模式

Bit 7:允许产生注入通道转换结束中断

0:禁止JEOC中断

   1:允许JEOC中断

Bit 6:允许产生模拟看门狗中断

0:禁止模拟看门狗中断

   1:允许模拟看门狗中断

Bit 5:允许产生EOC中断

0:禁止EOC中断

   1:允许EOC中断

Bit 4~Bit 0:模拟看门狗通道选择位

00000:ADC模拟输入通道0

   00001:ADC模拟输入通道1

   ……

   01111:ADC模拟输入通道15

   10000:ADC模拟输入通道16

   10001:ADC模拟输入通道17

(2)ADC控制寄存器2:ADC_CR2

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
- TSVREF SWSTART SWSTARTJ EXTTRIG EXTSEL[2:0] -
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
JEXTTRIG JEXTSEL[2:0] ALIGN - DMA - RSTCAL CAL CONT ADON

Bit 23:温度传感器和VREFINT使能

0:禁止温度传感器和VREFINT

   1:启用温度传感器和VREFINT

Bit 22:开始转换规则通道

0:复位状态

   1:开始转换规则通道

Bit 21:开始转换注入通道

0:复位状态

   1:开始转换注入通道

Bit 20:规则通道的外部触发转换模式

0:不用外部事件启动转换

   1:使用外部事件启动转换

Bit 19~Bit 17:选择启动规则通道组转换的外部事件

ADC1和ADC2的触发配置如下

   000:定时器1的CC1事件

   001:定时器1的CC2事件

   010:定时器1的CC3事件

   011:定时器2的CC2事件

   100:定时器3的TRGO事件

   101:定时器4的CC4事件

   110:EXTI线11/TIM8_TRGO事件,仅大容量产品具有TIM8_TRGO功能

   111:SWSTART

   ADC3的触发配置如下

   000:定时器3的CC1事件

   001:定时器2的CC3事件

   010:定时器1的CC3事件

   011:定时器8的CC1事件

   100:定时器8的TRGO事件

   101:定时器5的CC1事件

   110:定时器5的CC3事件

   111:SWSTART

Bit 15:注入通道的外部触发转换模式

0:不用外部事件启动转换;

1:使用外部事件启动转换。

Bit 14~Bit 12:选择启动注入通道组转换的外部事件

ADC1和ADC2的触发配置如下

   000:定时器1的TRGO事件

   001:定时器1的CC4事件

   010:定时器2的TRGO事件

   011:定时器2的CC1事件

   100:定时器3的CC4事件

   101:定时器4的TRGO事件

   110:EXTI线15/TIM8_CC4事件,仅大容量产品具有TIM8_CC4

   111:JSWSTART

   ADC3的触发配置如下

   000:定时器1的TRGO事件

   001:定时器1的CC4事件

   010:定时器4的CC3事件

   011:定时器8的CC2事件

   100:定时器8的CC4事件

   101:定时器5的TRGO事件

   110:定时器5的CC4事件

   111:JSWSTART

Bit 11:数据对齐

0:右对齐

   1:左对齐

Bit 8:直接存储器访问模式

0:不使用DMA模式

   1:使用DMA模式

Bit 3:复位校准

0:校准寄存器已初始化

   1:初始化校准寄存器

Bit 2:A/D校准

0:校准完成

   1:开始校准

Bit 1:连续转换

0:单次转换模式

   1:连续转换模式

Bit 0:开/关A/D转换器

0:关闭ADC转换/校准,并进入断电模式

   1:开启ADC并启动转换

(3)ADC采样事件寄存器1:ADC_SMPR1

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
- SMP17[2:0] SMP16[2:0] SMP15[2:1]
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
SMP15_0 SMP14[2:0] SMP13[2:0] SMP12[2:0] SMP11[2:0] SMP10[2:0]

SMPx[2:0]:选择通道x的采样时间

0001.5周期

   0017.5周期

   01013.5周期

   01128.5周期

   10041.5周期

   10155.5周期

   11071.5周期

   111239.5周期

(4)ADC采样事件寄存器2:ADC_SMPR2

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
- SMP9[2:0] SMP8[2:0] SMP7[2:0] SMP6[2:0] SMP5[2:1]
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
SMP5_0 SMP4[2:0] SMP3[2:0] SMP2[2:0] SMP1[2:0] SMP0[2:0]

SMPx[2:0]:选择通道x的采样时间

0001.5周期

   0017.5周期

   01013.5周期

   01128.5周期

   10041.5周期

   10155.5周期

   11071.5周期

   111239.5周期

(5)ADC规则序列寄存器1:ADC_SQR1

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
- L[3:0] SQ16[4:1]
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
SQ16_0 SQ15[4:0] SQ14[4:0] SQ13[4:0]

Bit 23~Bit 20:规则通道序列长度

0000:1个转换

   0001:2个转换

   ……

   1111:16个转换

Bit 19Bit 15:规则序列中的第16个转换,这些位由软件定义转换序列中的第16个转换通道的编号(017)

Bit 14~Bit 10:规则序列中的第15个转换

Bit 9~Bit 5:规则序列中的第14个转换

Bit 4~Bit 0:规则序列中的第13个转换

(6)ADC规则序列寄存器2:ADC_SQR2

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
- SQ12[4:0] SQ11[4:0] SQ10[4:0]
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
SQ10_0 SQ9[4:0] SQ8[4:0] SQ7[4:0]

Bit 29~Bit 25:规则序列中的第12个转换

Bit 24~Bit 20:规则序列中的第11个转换

Bit 19~Bit 15:规则序列中的第10个转换

Bit 14~Bit 10:规则序列中的第9个转换

Bit 9~Bit 5:规则序列中的第8个转换

Bit 4~Bit 0:规则序列中的第7个转换

(7)ADC规则序列寄存器3:ADC_SQR3

31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
- SQ6[4:0] SQ5[4:0] SQ4[4:0]
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
SQ4_0 SQ3[4:0] SQ2[4:0] SQ1[4:0]

Bit 29~Bit 25:规则序列中的第6个转换

Bit 24~Bit 20:规则序列中的第5个转换

Bit 19~Bit 15:规则序列中的第4个转换

Bit 14~Bit 10:规则序列中的第3个转换

Bit 9~Bit 5:规则序列中的第2个转换

Bit 4~Bit 0:规则序列中的第1个转换

(8)ADC数据寄存器:ADC_DR和ADC_JDR

数据寄存器分为DR和JDR,其中DR中存储的是规则序列转换后的值,JDR存储的则是注入序列转换后的值。其中ADC_DR寄存器的结构如下图所示。
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
ADC2_DATA[15:0]
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
DATA[15:0]

Bit 31~Bit16:ADC2转换的数据,在ADC1中:双模式下,这些位包含了ADC2转换的规则通道数据

Bit 15~Bit 0:规则转换的数据:包含了规则通道的转换结果,数据是左对齐或右对齐

(9)ADC状态寄存器:ADC_SR

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- STRT JSTART JEOC EOC AWD

Bit 4:规则通道开始位

0:规则通道转换未开始

   1:规则通道转换已开始

Bit 3:注入通道开始位

0:注入通道组转换未开始

   1:注入通道组转换已开始

Bit 2:注入通道转换结束位

0:转换未完成

   1:转换完成

Bit 1:转换结束位

0:转换未完成

   1:转换完成

Bit 0:模拟看门狗标志位

0:没有发生模拟看门狗事件

   1:发生模拟看门狗事件

11.4 内部温度传感器例程

功能实现:采用内部温度传感器读取温度显示在TFTLCD上。

(1)创建adc.h文件,并输入以下代码。

#ifndef _ADC_H_
#define _ADC_H_


#include "sys.h"
/*********************************************************************************************************
                    函    数    列    表
*********************************************************************************************************/
void ADC_Init( void ) ;                                          //初始化ADC1
u16 Get_Adc_Average( u8 ch, u8 times ) ;                                //获取通道ch的转换均值
short Get_Temprate( void ) ;                                      //获取温度值


#endif

(2)创建adc.c文件,并输入以下代码。

#include "adc.h"
#include "delay.h"
/***************************************************
Name    :ADC_Init
Function  :初始化ADC1
Paramater  :None
Return    :None
***************************************************/
void ADC_Init()
{
  //先初始化IO口
   RCC->APB2ENR |= 1<<2 ;                                        //使能PORTA口时钟
  GPIOA->CRL &= 0XFFFFFF0F ;                                      //PA1 anolog输入
  RCC->APB2ENR |= 1<<9 ;                                        //ADC1时钟使能
  RCC->APB2RSTR |= 1<<9 ;                                        //ADC1复位
  RCC->APB2RSTR &= ~( 1<<9 ) ;                                    //复位结束
  RCC->CFGR &= ~( 3<<14 ) ;                                      //分频因子清零
  //SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M
  RCC->CFGR |= 2<<14 ;
  ADC1->CR1 &= 0xF0FFFF ;                                        //工作模式清零
  ADC1->CR1 |= 0<<16 ;                                        //独立工作模式
  ADC1->CR1 &= ~( 1<<8 ) ;                                      //非扫描模式
  ADC1->CR2 &= ~( 1<<1 ) ;                                      //单次转换模式
  ADC1->CR2 &= ~( 7<<17 ) ;
  ADC1->CR2 |= 7<<17 ;                                        //软件控制转换
  ADC1->CR2 |= 1<<20 ;                                        //使用用外部触发
  ADC1->CR2 &= ~( 1<<11 ) ;                                      //右对齐
  ADC1->CR2 |= 1<<23 ;                                        //使能温度传感器
  ADC1->SQR1 &= ~( 0xF<<20 ) ;
  ADC1->SQR1 &= ~( 1<<20 ) ;                                      //1个转换在规则序列中
  //设置通道1的采样时间
  ADC1->SMPR2 &= ~( 3<<0 ) ;                                      //通道1采样时间清空
   ADC1->SMPR2 |= 7<<3 ;                                        //通道1 239.5周期,提高采样时间可以提高精确度
  ADC1->SMPR1 &= ~( 7<<18 ) ;                                      //清除通道16原来的设置
  ADC1->SMPR1 |= 7<<18 ;                                        //通道16 239.5周期,提高采样时间可以提高精确度
  ADC1->CR2 |= 1<<0 ;                                          //开启AD转换器
  ADC1->CR2 |= 1<<3 ;                                          //使能复位校准
  while( ( ADC1->CR2&0x08 )==0x08 ) ;                                  //等待校准结束
  ADC1->CR2 |= 1<<2 ;                                          //开启AD校准
  while( ( ADC1->CR2&0x04 )==0x04 ) ;                                  //等待校准结束
}
/***************************************************
Name    :ADC_Init
Function  :获取通道ch的转换均值
Paramater  :
      ch:通道编号
      times:获取次数
Return    :通道ch的转换均值
***************************************************/
u16 Get_Adc_Average( u8 ch, u8 times )
{
  u32 temp_val=0 ;
  u8 t ;
  for( t=0; t

(3)创建main文件,并输入以下代码。

#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "adc.h"


int main()
{
  short Temp ;
  u8 Str[] = "Temperature:+000.00 'C" ;
  STM32_Clock_Init( 9 ) ;                                        //STM32时钟初始化
  SysTick_Init( 72 ) ;                                        //SysTick初始化
  USART1_Init( 72, 115200 ) ;                                      //初始化串口1波特率115200
  LCD_Init() ;                                            //LCD初始化
  ADC_Init() ;                                            //ADC初始化
  while( 1 )
  {
    Temp = Get_Temprate() ;
    if( Temp<0 )
    {
      Temp = -Temp ;
      Str[ 12 ] = '-' ;                                      //显示负号
    }
    else
      Str[ 12 ] = ' ' ;                                      //无符号    
    Str[ 13 ] = 0x30+Temp/10000 ;
    Str[ 14 ] = 0x30+Temp%10000/1000 ;
    Str[ 15 ] = 0x30+Temp%1000/100 ;
    Str[ 17 ] = 0x30+Temp%100/10 ;
    Str[ 18 ] = 0x30+Temp%10 ;
    LCD_ShowString( 100, 100, Str ) ;                                //显示温度值
    delay_ms( 500 ) ;
  }
}

11.5 DS18B20例程

功能实现:读取DS18B20的温度显示在TFTLCD上。

(1)创建ds18b20.h文件,并输入以下代码。

#ifndef _DS18B20_H_
#define _DS18B20_H_


#include "sys.h"
/*********************************************************************************************************
                    端    口    分    配
*********************************************************************************************************/
#define  DS18B20_DQ_OUT  PGout( 11 )                                    //数据端口
#define  DS18B20_DQ_IN  PGin( 11 )
/*********************************************************************************************************
                    函    数    列    表
*********************************************************************************************************/
void DS18B20_Init( void ) ;                                        //初始化DS18B20
short DS18B20_Get_Temp( void ) ;                                    //获取温度


#endif

(2)创建ds18b20.c文件,并输入以下代码。

#include "ds18b20.h"
#include "delay.h"
/***************************************************
Name    :DS18B20_Write_Byte
Function  :发送1个字节
Paramater  :
      Byte:发送的字节
Return    :None
***************************************************/
void DS18B20_Write_Byte( u8 Byte )
{
    u8 i ;
  GPIOG->CRH &= 0xFFFF0FFF ;
  GPIOG->CRH |= 0x00003000 ;
  for( i=0; i<8; i++ )
  {
    if( ( Byte&0x01 )==0x01 )
    {
      DS18B20_DQ_OUT = 0;
      delay_us( 2 ) ;
      DS18B20_DQ_OUT = 1 ;
      delay_us( 60 ) ;
    }
    else
    {
      DS18B20_DQ_OUT = 0 ;
      delay_us( 60 ) ;
      DS18B20_DQ_OUT = 1 ;
      delay_us( 2 ) ;
    }
    Byte >>= 1 ;
  }
}
/***************************************************
Name    :DS18B20_Read_Byte
Function  :读取1个字节
Paramater  :None
Return    :读取的字节
***************************************************/
u8 DS18B20_Read_Byte()
{
  u8 i, Byte=0 ;
  for( i=0; i<8; i++ )
  {
    Byte >>= 1 ;
    GPIOG->CRH &= 0xFFFF0FFF ;
    GPIOG->CRH |= 0x00003000 ;
    DS18B20_DQ_OUT = 0 ; 
    delay_us( 2 ) ;
    DS18B20_DQ_OUT = 1 ; 
    GPIOG->CRH &= 0xFFFF0FFF ;
    GPIOG->CRH |= 0x00008000 ;
    delay_us( 12 ) ;
    if( DS18B20_DQ_IN )
      Byte |= 0x80 ;
    delay_us( 50 ) ;
  }
  return Byte ;
}
/***************************************************
Name    :DS18B20_Check
Function  :等待DS18B20的回应
Paramater  :None
Return    :None
***************************************************/
void DS18B20_Check()      
{
  GPIOG->CRH &= 0xFFFF0FFF ;
  GPIOG->CRH |= 0x00003000 ;
  DS18B20_DQ_OUT = 0 ;                                        //拉低DQ
  delay_us( 750 );                                          //拉低750us
  DS18B20_DQ_OUT = 1 ;                                        //DQ=1
  delay_us( 15 ) ;                                          //15us
  GPIOG->CRH &= 0xFFFF0FFF ;
  GPIOG->CRH |= 0x00008000 ;
  while( DS18B20_DQ_IN ) ;                                      //等待应答
  while( DS18B20_DQ_IN==0 );                                      //等待应答结束
}
/***************************************************
Name    :DS18B20_Init
Function  :初始化DS18B20
Paramater  :None
Return    :None
***************************************************/
void DS18B20_Init()
{
  RCC->APB2ENR |= 1<<8 ;                                        //使能PORTG口时钟 
  GPIOG->CRH &= 0xFFFF0FFF ;                                      //PORTG.11 推挽输出
  GPIOG->CRH |= 0x00003000 ;
  GPIOG->ODR |= 1<<11 ;                                        //输出1
  DS18B20_Check() ;
}
/***************************************************
Name    :DS18B20_Get_Temp
Function  :得到温度值
Paramater  :None
Return    :温度值
***************************************************/
short DS18B20_Get_Temp()
{
  u8 TL,TH;
  short temp ;
  DS18B20_Check() ;
  DS18B20_Write_Byte( 0xCC ) ;                                    //跳过ROM读取
  DS18B20_Write_Byte( 0x44 ) ;                                    //开启转换
  DS18B20_Check() ;   
  DS18B20_Write_Byte( 0xCC ) ;                                    //跳过ROM读取
  DS18B20_Write_Byte( 0xBE ) ;                                    //开始转换
  TL = DS18B20_Read_Byte() ;                                      //LSB
  TH = DS18B20_Read_Byte() ;                                      //MSB
  if( TH>7 )
  {
    TH = ~TH ;
    TL = ~TL ;
  }
  temp = TH ;                                              //获得高八位
  temp <<= 8 ;    
  temp += TL ;                                            //获得低八位
  temp = ( float )temp*0.625 ;                                    //转换     
  if( TH>7 )
    return temp ;                                          //返回温度值
  else
    return -temp ;
}

(3)创建1.c文件,并输入以下代码。

#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "ds18b20.h"


int main()
{
  short Temp ;
  u8 Str[] = "Temperature:+000.00 'C" ;
  STM32_Clock_Init( 9 ) ;                                        //STM32时钟初始化
  SysTick_Init( 72 ) ;                                        //SysTick初始化
  USART1_Init( 72, 115200 ) ;                                      //初始化串口1波特率115200
  LCD_Init() ;                                            //LCD初始化
  DS18B20_Init() ;                                          //DS18B20初始化
  while( 1 )
  {
    Temp = DS18B20_Get_Temp();                                    //读取温度
    if( Temp<0 )
    {
      Temp = -Temp ;
      Str[ 12 ] = '-' ;                                      //显示负号
    }
    else
      Str[ 12 ] = ' ' ;                                      //无符号    
    Str[ 13 ] = 0x30+Temp/10000 ;
    Str[ 14 ] = 0x30+Temp%10000/1000 ;
    Str[ 15 ] = 0x30+Temp%1000/100 ;
    Str[ 17 ] = 0x30+Temp%100/10 ;
    Str[ 18 ] = 0x30+Temp%10 ;
    LCD_ShowString( 100, 100, Str ) ;                                //显示温度值
    delay_ms( 500 ) ;
  }
}

11.6 DHT11例程

功能实现:读取DHT11的温度与湿度数据显示在TFTLCD上。

(1)创建dht11.h文件,并输入以下代码。

#ifndef _DHT11_H_
#define _DHT11_H_


#include "sys.h"
/*********************************************************************************************************
                    端    口    分    配
*********************************************************************************************************/
#define  DHT11_DQ_OUT  PGout( 11 )                                    //数据端口
#define  DHT11_DQ_IN    PGin( 11 )
/*********************************************************************************************************
                    函    数    列    表
*********************************************************************************************************/
u8 DHT11_Init( void ) ;                                          //初始化DHT11
u8 DHT11_Get_Data( u8 *temp, u8 *humi ) ;                                //获取温湿度


#endif

(2)创建dht11.c文件,并输入以下代码。

#include "dht11.h"
#include "delay.h"
/***************************************************
Name    :DHT11_Check
Function  :检查DHT11
Paramater  :None
Return    :
      0:存在
      1:不存在
***************************************************/
u8 DHT11_Check()      
{
  u8 retry ;
  GPIOG->CRH &= 0xFFFF0FFF ;                                      //PG11推挽输出
  GPIOG->CRH |= 0x00003000 ;
  DHT11_DQ_OUT = 0 ;                                          //拉低DQ
  delay_ms( 20 ) ;                                          //拉低至少18ms
  DHT11_DQ_OUT = 1 ;                                          //DQ=1
  delay_us( 30 );                                            //主机拉高20~40us
  GPIOG->CRH &= 0xFFFF0FFF;                                      //PG11上拉输入
  GPIOG->CRH |= 0x00008000;
  //DHT11会拉低40~80us
  retry = 0 ;
  while( ( DHT11_DQ_IN==1 )&&( retry<100 ) )
  {
    retry ++ ;
    delay_us( 1 ) ;
  };
  if( retry>=100 )
    return 1 ;
  else
    retry = 0 ;
  //DHT11拉低后会再次拉高40~80us
  while( ( DHT11_DQ_IN==0 )&&( retry<100 ) )
  {
    retry ++ ;
    delay_us( 1 ) ;
  };
  if( retry>=100 )
    return 1 ;
  return 0 ;
}
/***************************************************
Name    :DHT11_Read_Byte
Function  :读取1个字节
Paramater  :None
Return    :读取的字节
***************************************************/
u8 DHT11_Read_Byte()
{
  u8 i, Byte=0;
  for (i=0;i<8;i++)
  {
    Byte <<= 1 ;
    while( DHT11_DQ_IN ) ;                                      //等待变为低电平
    while( DHT11_DQ_IN==0 ) ;                                    //等待变高电平
    delay_us( 40 ) ;                                        //等待40us
    if( DHT11_DQ_IN )
      Byte |= 0x01 ;
  }
  return Byte ;
}
/***************************************************
Name    :DHT11_Get_Data
Function  :获取温湿度
Paramater  :
      temp:温度值(范围:0~50°)
      humi:湿度值(范围:20%~90%)
Return    :
      0:正常
      1:读取失败
***************************************************/
u8 DHT11_Get_Data( u8 *temp, u8 *humi )
{        
  u8 i, buf[ 5 ] ;
  if( DHT11_Check()==0 )
  {
    //读取40位数据
    for( i=0; i<5; i++ )
      buf[ i ] = DHT11_Read_Byte() ;
    if( ( buf[ 0 ]+buf[ 1 ]+buf[ 2 ]+buf[ 3 ] )==buf[ 4 ] )
    {
      *humi = buf[ 0 ] ;
      *temp = buf[ 2 ] ;
    }
  }
  else
    return 1 ;
  return 0 ;
}
/***************************************************
Name    :DHT11_Init
Function  :初始化DHT11
Paramater  :None
Return    :
      0:存在
      1:不存在
***************************************************/
u8 DHT11_Init()
{
  RCC->APB2ENR |= 1<<8 ;                                        //使能PG时钟
  GPIOG->CRH &= 0xFFFF0FFF ;                                      //PG11推挽输出
  GPIOG->CRH |= 0x00003000 ;
  GPIOG->ODR |= 1<<11 ;                                        //输出1
  if( DHT11_Check() )
    return 1 ;
  return 0 ;
}

(3)创建1.c文件,并输入以下代码。

#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "dht11.h"


int main()
{
  u8 Temp, Humi;
  u8 Str1[ 20 ] ;
  u8 Str2[ 20 ] ;
  STM32_Clock_Init( 9 ) ;                                        //STM32时钟初始化
  SysTick_Init( 72 ) ;                                        //SysTick初始化
  USART1_Init( 72, 115200 ) ;                                      //初始化串口1波特率115200
  LCD_Init() ;                                            //LCD初始化
  while( DHT11_Init() )                                        //DHT11初始化
  {
    LCD_ShowString( 100, 100, "DHT11 Error!!!" ) ;
    delay_ms( 200 ) ;
    LCD_ShowString( 100, 100, "              " ) ;
    delay_ms( 200 ) ;
  }
  while( 1 )
  {
    //读取温湿度
    if( DHT11_Get_Data( &Temp, &Humi )==0 )
    {
      sprintf( ( char * )Str1, "Temperature:%02d C", Temp ) ;
      LCD_ShowString( 100, 100, Str1 ) ;                              //显示温度值
      sprintf( ( char * )Str2, "Humidity:%02d RH%%", Temp ) ;
      LCD_ShowString( 100, 116, Str2 ) ;                              //显示湿度值
    }
    delay_ms( 500 ) ;
  }
}
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分