作者共发了1篇帖子。 内容转换:不转换▼
 
点击 回复
692 0
【程序】STM32读取DHT11温湿度传感器的数据并在1602液晶上显示
一派护法 十九级
1楼 发表于:2017-3-5 18:18
#include <stdio.h>
#include <stm32f10x.h>

#define RS_0 (GPIOA->BRR = GPIO_BRR_BR0)
#define RS_1 (GPIOA->BSRR = GPIO_BSRR_BS0)
#define RW_0 (GPIOA->BRR = GPIO_BRR_BR1)
#define RW_1 (GPIOA->BSRR = GPIO_BSRR_BS1)
#define E_0 (GPIOA->BRR = GPIO_BRR_BR2)
#define E_1 (GPIOA->BSRR = GPIO_BSRR_BS2)

#define DHT11_W0 (GPIOB->BRR = GPIO_BRR_BR0)
#define DHT11_W1 (GPIOB->BSRR = GPIO_BSRR_BS0)
#define DHT11_R ((GPIOB->IDR & GPIO_IDR_IDR0) != 0)

#define MANTISSA(n) ((uint8_t)((n) * 390625 / 1e6)) // 保留两位小数

// 延时n毫秒(0<n<6553)
void delay_ms(uint16_t nms)
{
    TIM1->ARR = nms * 10 - 1; // 从0计数到9为1ms, UIF在CNT=0时置位
    TIM1->PSC = 7199; // 72000kHz/7200=10kHz -> 0.1ms
    
    TIM1->EGR = TIM_EGR_UG; // 保存上面的设置
    TIM1->SR &= ~TIM_SR_UIF; // 清UIF
    
    TIM1->CR1 = TIM_CR1_OPM | TIM_CR1_CEN; // 开定时器, 使用非循环模式
    while ((TIM1->SR & TIM_SR_UIF) == 0); // 等待UIF置位
    // 返回时保留UIF=1, 下次延时时再清除
}

// 延时n微秒(0<n<65536)
void delay_us(uint16_t nus)
{
    TIM1->ARR = nus - 1;
    TIM1->PSC = 71; // 72MHz/72=1MHz -> 1us
    
    TIM1->EGR = TIM_EGR_UG;
    TIM1->SR &= ~TIM_SR_UIF;
    
    TIM1->CR1 = TIM_CR1_OPM | TIM_CR1_CEN;
    while ((TIM1->SR & TIM_SR_UIF) == 0);
}

// 用于延长1602液晶E信号的高电平持续时间
void delay_short(void)
{
    uint8_t i;
    for (i = 0; i < 10; i++);
}

void LCD1602_BusyWait(void)
{
    RS_0;
    RW_1;
    E_1;
    GPIOC->CRL = 0x44444444; // 读端口
    while (GPIOC->IDR & GPIO_IDR_IDR7);
    GPIOC->CRL = 0x33333333;
    E_0;
}

void LCD1602_WriteCmd(uint8_t cmd)
{
    LCD1602_BusyWait();
    RS_0;
    RW_0;
    GPIOC->ODR = cmd;
    E_1;
    delay_short();
    E_0;
}

void LCD1602_WriteData(uint8_t data)
{
    LCD1602_BusyWait();
    RS_1;
    RW_0;
    GPIOC->ODR = data;
    E_1;
    delay_short();
    E_0;
}

void LCD1602_Init(void)
{
    LCD1602_WriteCmd(0x38);
    LCD1602_WriteCmd(0x01);
    LCD1602_WriteCmd(0x0c);
    
    DAC->CR = DAC_CR_EN1 | DAC_CR_EN2;
    DAC->DHR8R1 = 69; // 对比度电压: 约1.0V, 端口: PA4
    DAC->DHR8R2 = DAC->DHR8R1; // PA5输出同样大小的电压
}

// printf内容往液晶上显示
// 工程属性里的Use MicroLIB必须打勾
int fputc(int ch, FILE *fp)
{
    LCD1602_WriteData(ch);
    return ch;
}

int8_t DHT11_Read(uint8_t data[])
{
    uint8_t i, j;
    DHT11_W1;
    GPIOB->CRL = (GPIOB->CRL & 0xfffffff0) | 7; // 开漏输出50MHz
    
    DHT11_W0;
    delay_ms(18);
    DHT11_W1;
    delay_us(30);
    
    GPIOB->CRL = (GPIOB->CRL & 0xfffffff0) | 4; // 浮空输入
    if (!DHT11_R)
    {
        delay_us(80);
        if (DHT11_R)
        {
            for (i = 0; i < 5; i++)
            {
                data[i] = 0;
                for (j = 0; j < 8; j++)
                {
                    while (!DHT11_R); // 等待低电平
                    
                    // 对高电平计时
                    TIM1->ARR = TIM_ARR_ARR; // 最大超时时间65.536ms
                    TIM1->PSC = 71;
                    TIM1->EGR = TIM_EGR_UG; // UG=1会自动将CNT清零, 但会把UIF置1
                    TIM1->SR &= ~TIM_SR_UIF;
                    TIM1->CR1 = TIM_CR1_OPM | TIM_CR1_CEN;
                    while (DHT11_R) // 等待高电平
                    {
                        if (TIM1->SR & TIM_SR_UIF)
                            return i; // 高电平超时, 返回实际读取的数据个数
                    }
                    data[i] <<= 1;
                    if (TIM1->CNT >= 50) // CNT+1为测出的us数
                        data[i] |= 1;
                }
            }
            while (!DHT11_R);
            
            // 数据检验
            if (((data[0] + data[1] + data[2] + data[3]) & 0xff) != data[4])
                return -2; // 数据校验出错
            
            return i; // 成功
        }
    }
    return -1; // 传感器出错, 未读到数据
}

int main(void)
{
    int8_t n;
    uint8_t data[5];
    RCC->APB1ENR = RCC_APB1ENR_DACEN;
    RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_TIM1EN;
    
    GPIOA->CRL = 0x00000333;
    GPIOB->CRL = 0x00000004;
    GPIOC->CRL = 0x33333333;
    
    LCD1602_Init();
    while (1)
    {
        LCD1602_WriteCmd(0x80); // 跳到第一行
        n = DHT11_Read(data);
        if (n == 5 || n == -2)
        {
            // 以小数方式显示湿度(百分数*256=小数)
            //printf("H:%d.%02d T:%d.%02d          ", data[0], MANTISSA(data[1]), (int8_t)data[2], MANTISSA(data[3]));
            // 以百分数方式显示湿度
            printf("H:%d%% T:%d.%02d          ", data[0] * 100 / 256, (int8_t)data[2], MANTISSA(data[3]));
            
            LCD1602_WriteCmd(0xc0); // 换行
            printf("Sum:%d Recv:%d%c           ", (data[0] + data[1] + data[2] + data[3]) & 0xff, data[4], (n == -2) ? '!' : ' ');
            // 感叹号表示校验错误
            // 校验错误一般可忽略,因为得到的温湿度值是正确的
        }
        else
        {
            // 读数据时出错
            printf("Error!            ");
            LCD1602_WriteCmd(0xc0);
            printf("n=%d              ", n);
        }
        delay_ms(1000);
    }
}

回复帖子

内容:
用户名: 您目前是匿名发表
验证码:
(快捷键:Ctrl+Enter)
 

本帖信息

点击数:692 回复数:0
评论数: ?
作者:巨大八爪鱼
最后回复:巨大八爪鱼
最后回复时间:2017-3-5 18:18
 
©2010-2024 Arslanbar Ver2.0
除非另有声明,本站采用知识共享署名-相同方式共享 3.0 Unported许可协议进行许可。