STM32获取DHT11温度传感器数据

准备物件

  • STM32F103C8T6核心板
  • ST-LINK V2
  • DHT11
  • 杜邦线若干

连接线

STM32F103C8T6芯片管脚图

管脚说明

连接仿真器

STM32 ST-LINKV2
VCC VCC
GND GND
SWCLK SWCLK
SWDIO SWDIO

创建工程

参考STM32F103X 开发环境搭建
可将其模板复制一份

添加延时功能

DRIVER/inc中添加timer.h

#ifndef __TIMER_H__
#define __TIMER_H__

#include "stm32f10x.h"

void systick_init(void);
void timing_delay_decrement(void);
void delay_us(__IO uint32_t n);

#endif

对应的在DRIVER/src中添加timer.c

#include "timer.h"

__IO uint32_t gTimingDelay;

/* SystemCoreClock / 1000    --> 1ms */
/* SystemCoreClock / 10000   --> 100us */
/* SystemCoreClock / 100000  --> 10us */
/* SystemCoreClock / 1000000 --> 1us */

void systick_init(void)
{
    while (SysTick_Config(SystemCoreClock / 1000000) == 1);
}

void timing_delay_decrement(void)
{
    if (gTimingDelay != 0x0)
    {
        gTimingDelay--;
    }
}

void SysTick_Handler(void)
{
    timing_delay_decrement();
}

void delay_us(__IO uint32_t n)
{
    gTimingDelay = n;
    while(gTimingDelay != 0);
}

点亮LED

可以看到核心板上有两个LED灯,PWR(电源)和PC13
修改USER/main.c

#include "stm32f10x.h"
#include "timer.h"

#define Led_On   GPIO_SetBits(GPIOC, GPIO_Pin_13)
#define Led_Off GPIO_ResetBits(GPIOC, GPIO_Pin_13)

void LED_Init()
{
    GPIO_InitTypeDef s;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    
    s.GPIO_Pin = GPIO_Pin_13;
    s.GPIO_Mode = GPIO_Mode_Out_PP;
    s.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &s);
}

int main()
{
    SystemInit();
    systick_init();

    LED_Init();
    while (1)
    {
        Led_On;
        delay_us(500000);
        Led_Off;
        delay_us(500000);
    }
}

<1> 由于timer.c已经实现SysTick_handler中断实现,需要编辑USER/stm32f10x_it.c,将SysTick_handler函数注释

<2> 右击工程名 -> Options -> C/C++ Compiler -> Preprocessor
在"Additional include directories:"中添加$PROJ_DIR$\USER\inc\

<3> 右击工程名 -> Options -> Debugger -> Setup
在Driver中选择ST-LINK

<4> 右击工程名 -> Options -> ST-LINK -> Setup
在Reset选择Connect during reset
在Interface中选择SWD

<5> 点击编译,然后Download and Debug -> Go

便可以看到PC13 LED灯均匀的闪烁。

串口发送数据

用于显示DHT11读取的数据

连线方式

USB-TTL STM32
VCC VCC
GND GND
RXD PA9(TXD)
TXD PA10(RXD)
如果是树莓派,可以查看GPIO管脚说明,按照上述连接即可。

添加DRIVER/inc/usart.h

#ifndef __USART_H_
#define __USART_H_


#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_usart.h"
#include <stdarg.h>

#define WAIT_TC while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)

void usart_config(void);
void usart_gpio_init(void);
void usart_param_config(void);

void usart_send_string(char *data);
void usart_printf(const char *fmt, ...);

#endif

添加DRIVER/src/usart.c

#include "usart.h"

void usart_config(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    usart_gpio_init();
    usart_param_config();
}

void usart_gpio_init(void)
{
    GPIO_InitTypeDef g;
    g.GPIO_Speed = GPIO_Speed_50MHz;
    
    g.GPIO_Pin = GPIO_Pin_9;
    g.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    GPIO_Init(GPIOA, &g);
    
    g.GPIO_Pin = GPIO_Pin_10;
    g.GPIO_Mode = GPIO_Mode_IN_FLOATING; //开漏输入
    GPIO_Init(GPIOA, &g);
}

void usart_param_config(void)
{
    USART_InitTypeDef u;
    
    u.USART_BaudRate = 9600;
    u.USART_WordLength = USART_WordLength_8b;   //数据位8位
    u.USART_StopBits = USART_StopBits_1;    //停止位1位
    u.USART_Parity = USART_Parity_No;   //无校验位
    u.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    u.USART_Mode = USART_Mode_Tx;
    
    USART_Init(USART1, &u);
    
    USART_Cmd(USART1, ENABLE);
}

void usart_send_string(char *data)
{
    char *p = data;
    while (p < data + strlen(data))
    {
        WAIT_TC;
        USART_SendData(USART1, *p++);
    }
}

void usart_printf(const char *fmt, ...)
{
    va_list ap;
    char string[64];
    
    va_start(ap, fmt);
    vsprintf(string, fmt, ap);
    va_end(ap);
    usart_send_string(string);
}

main.c添加如下细节

#include "usart.h"

int main()
{
    SystemInit();
    systick_init();

    usart_config();
    
    LED_Init();
    while (1)
    {
        Led_On;
        usart_printf("test usart\n");
        delay_us(2000000);
        Led_Off;
        delay_us(2000000);
    }
}

打开串口工具,linux下是minicom

minicom -b 9600 -D /dev/ttyUSB0

可以看到test usart字符,说明串口通信正常。

驱动DHT11

连线方式

DHT11 STM32
VCC VCC
GND GND
DATA PB11

添加DRIVER/inc/dht11.h

#ifndef __DHT11_H__
#define __DHT11_H__

#include "timer.h"
#include "stm32f10x_gpio.h"

#define DHT11_GPIO_TYPE  GPIOB
#define DHT11_GPIO_PIN   GPIO_Pin_11
#define DHT11_RCC        RCC_APB2Periph_GPIOB


#define DHT11_OUT_H GPIO_SetBits(DHT11_GPIO_TYPE, DHT11_GPIO_PIN)
#define DHT11_OUT_L GPIO_ResetBits(DHT11_GPIO_TYPE, DHT11_GPIO_PIN)
#define DHT11_IN    GPIO_ReadInputDataBit(DHT11_GPIO_TYPE, DHT11_GPIO_PIN)


void dht11_gpio_input(void);
void dht11_gpio_output(void);
u16 dht11_scan(void);
u16 dht11_read_bit(void);
u16 dht11_read_byte(void);
u16 dht11_read_data(u8 buffer[4]);

#endif

添加DRIVER/src/dht11.c

#include "dht11.h"

void dht11_gpio_input(void)
{
    GPIO_InitTypeDef g;
    
    RCC_APB2PeriphClockCmd(DHT11_RCC, ENABLE);
    
    g.GPIO_Pin = DHT11_GPIO_PIN;
    g.GPIO_Speed = GPIO_Speed_50MHz;
    g.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
    
    GPIO_Init(DHT11_GPIO_TYPE, &g);
}

void dht11_gpio_output(void)
{
    GPIO_InitTypeDef g;
    
    RCC_APB2PeriphClockCmd(DHT11_RCC, ENABLE);
    
    g.GPIO_Pin = DHT11_GPIO_PIN;
    g.GPIO_Speed = GPIO_Speed_50MHz;
    g.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出

    GPIO_Init(DHT11_GPIO_TYPE, &g);
}

void dht11_reset(void)
{
    // 按照DHT11手册步骤
    dht11_gpio_output();
    DHT11_OUT_L;
    delay_us(19000);
    DHT11_OUT_H;
    delay_us(30);
    dht11_gpio_input();
}

u16 dht11_scan(void)
{
    return DHT11_IN;
}

u16 dht11_read_bit(void)
{
    while (DHT11_IN == RESET);
    delay_us(40);
    if (DHT11_IN == SET)
    {
        while (DHT11_IN == SET);
        return 1;
    }
    else
    {
        return 0;
    }
}

u16 dht11_read_byte(void)
{
    u16 i;
    u16 data = 0;
    for (i = 0; i < 8; i++)
    {
        data <<= 1;
        data |= dht11_read_bit();
    }
    return data;
}

u16 dht11_read_data(u8 buffer[5])
{
    u16 i = 0;
    
    dht11_reset();
    if (dht11_scan() == RESET)
    {
        //检测到DHT11响应
        while (dht11_scan() == RESET);
        while (dht11_scan() == SET);
        for (i = 0; i < 5; i++)
        {
            buffer[i] = dht11_read_byte();
        }
        
        while (dht11_scan() == RESET);
        dht11_gpio_output();
        DHT11_OUT_H;
        
        u8 checksum = buffer[0] + buffer[1] + buffer[2] + buffer[3];
        if (checksum != buffer[4])
        {
            // checksum error
            return 1;
        }
    }
    
    return 0;
}

修改USER/main.c

#include "dht11.h"

int main()
{
    SystemInit();
    systick_init();

    usart_config();
    
    LED_Init();
    while (1)
    {
        Led_On;
        u8 buffer[5];
        double hum;
        double temp;
        if (dht11_read_data(buffer) == 0)
        {
            hum = buffer[0] + buffer[1] / 10.0;
            temp = buffer[2] + buffer[3] / 10.0;
        }
        usart_printf("___{\"temperature\": %.2f, \"humidness\": %.2f}___\n", temp, hum);
        delay_us(2000000);
        Led_Off;
        delay_us(2000000);
    }
}

编译、运行,发现串口可以收到温度信息。

minicom -b 9600 -D /dev/ttyUSB0

posted @ 2017-09-25 13:00  雨中尘埃  阅读(36613)  评论(6编辑  收藏  举报