注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
lvxinn2006的个人空间 https://home.eeworld.com.cn/space-uid-757599.html [收藏] [复制] [分享] [RSS]
日志

【 ST NUCLEO-G071RB测评】_06_

已有 349 次阅读2019-1-17 10:54 |个人分类:MCU

本次活动测评开发板ST NUCLEO-G071RB由ST意法半导体提供,感谢意法半导体对EEWorld测评的支持!
【实验目的】
· 掌握DHT11的通信时序
· 掌握使用GPIO处理通信时序

【实验环境】
· NUCLEO-G071RB开发板
· DHT11温湿度模块
· Keil MDK-ARM(Keil uVision 5.25.2.0)
· Keil.STM32G0xx_DFP.1.0.0.pack
· 串口调试助手

【实验资料】
· NUCLEO-G071RB开发板原理图
· STM32G071x8/xB Data Sheet
· STM32G071芯片用户参考手册
· DHT11用户手册
【实验分析】
原理图:


连接如图所示,灰色线连接到电源的负极,黑色线连接到3.3V正极,白色是数据线,连接到了PC10引脚。
DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。DATA 用于微处理器与 DHT11 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先出。
数据格式:8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据+8bit 校验位。
校验位数据定义:“8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据”8bit 校验位等于所得结果的末 8 位。
数据时序图
用户主机(MCU)发送一次开始信号后,DHT11 从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11 发送响应信号,送出 40bit 的数据,幵触发一次信采集。
信号发送如图所示
外设读取步骤
主机和从机之间的通信可通过如下几个步骤完成(外设(如微处理器)读取 DHT11 的数据的步骤)。
步骤一:
DHT11 上电后(DHT11 上电后要等待 1S 以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,幵记录数据,同时 DHT11 DATA 数据线由上拉电阻拉高一直保持高电平;此时 DHT11 DATA 引脚处于输入状态,时刻检测外部信号。
步骤二:
微处理器的 I/O 设置为输出同时输出低电平,且低电平保持时间不能小于 18ms,然后微处理器的 I/O设置为输入状态,由于上拉电阻,微处理器的 I/O DHT11 DATA 数据线也随之变高,等待 DHT11 作出回答信号,发送信号如图所示:

步骤三:
DHT11 DATA 引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后 DHT11 DATA引脚处于输出状态,输出 80 微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据,微处理器的 I/O 此时处于输入状态,检测到 I/O 有低电平(DHT11 回应信号)后,等待 80 微秒的高电平后的数据接收,发送信号如图所示:
步骤四:
DHT11 DATA 引脚输出 40 位数据,微处理器根据 I/O 电平的变化接收 40 位数据,位数据“0”的格式为: 50 微秒的低电平和 26-28 微秒的高电平,位数据“1”的格式为: 50 微秒的低电平加 70微秒的高电平。位数据“0”“1”格式信号如图所示:

结束信号:
DHT11 DATA 引脚输出 40 位数据后,继续输出低电平 50 微秒后转为输入状态,由于上拉电阻随之变为高电平。但 DHT11 内部重测环境温湿度数据,幵记录数据,等待外部信号的到来。

实验代码
  1. #include "stm32g0xx.h"                  // Device header
  2. #include "uart.h"
  3. #include

  4. void mdelay(int ms)
  5. {
  6.         RCC->APBENR1 |= RCC_APBENR1_TIM6EN;        //使能TIM6
  7.         TIM6->PSC = SystemCoreClock / 1000 - 1;        //预分频 定时器时钟为1000Hz
  8.         TIM6->ARR = ms;        //周期数
  9.         TIM6->CR1 |= TIM_CR1_OPM;        //One Pulse mode
  10.         TIM6->CR1 |= TIM_CR1_CEN;        //启动定时器
  11.         while(TIM6->CR1 & TIM_CR1_CEN);        //等待定时器结束
  12. }

  13. void GPIOSetDir(GPIO_TypeDef *GPIO, int pin, int dir)
  14. {
  15.         if (dir == 0){
  16.                 GPIO->MODER        &= ~(0x3UL<<(pin * 2));
  17.                 GPIO->OTYPER &= ~(1<
  18.         }else{
  19.                 GPIO->MODER        &= ~(0x3UL<<(pin * 2));
  20.                 GPIO->MODER        |= (0x1UL<<(pin * 2));
  21.                 GPIO->OSPEEDR |= 0x3UL<<(pin * 2);
  22.                 GPIO->OTYPER &= ~(1<
  23.         }
  24. }

  25. void GPIOSetValue(GPIO_TypeDef *GPIO, int pin, int value)
  26. {
  27.         if (value == 0){
  28.                 GPIO->ODR &= ~(1<
  29.         }else{
  30.                 GPIO->ODR |= (1<
  31.         }
  32. }

  33. void GPIOSetToggle(GPIO_TypeDef *GPIO, int pin)
  34. {
  35.         GPIO->ODR ^= (1<
  36. }

  37. int GPIOGetValue(GPIO_TypeDef *GPIO, int pin)
  38. {
  39.         return GPIO->IDR & (1<
  40. }

  41. int DHT11_Read(char *temp, char *humd)
  42. {
  43.         int i;
  44.         int timeout = 0;
  45.         volatile int low_count, high_count;
  46.         char data[5];        //接收40位数据
  47.        
  48.         //步骤二
  49.         GPIOSetDir(GPIOC, 10, 1);
  50.         GPIOSetValue(GPIOC, 10, 0);        //输出低电平
  51.         mdelay(30);
  52.         GPIOSetDir(GPIOC, 10, 0);        //设置成输入模式
  53.         //步骤三
  54.         while(GPIOGetValue(GPIOC, 10)){ //等待响应信号
  55.                 timeout ++;
  56.                 if (timeout > 10000) return -1;
  57.         }
  58.         while(GPIOGetValue(GPIOC, 10) == 0);        //等待高电平
  59.         while(GPIOGetValue(GPIOC, 10) != 0);        //等待高电平结束
  60.         //步骤四
  61.         for (i = 0; i < 40; i ++){
  62.                 low_count = 0;
  63.                 high_count = 0;
  64.                 while(GPIOGetValue(GPIOC, 10) == 0){        //记录低电平
  65.                         low_count ++;
  66.                 }
  67.                 while(GPIOGetValue(GPIOC, 10) != 0){        //记录高电平
  68.                         high_count ++;
  69.                 }
  70.                 if (low_count > high_count){ //数据0
  71.                         data[i/8] &= ~(1<<(7-i%8));
  72.                 }else{//数据1
  73.                         data[i/8] |= (1<<(7-i%8));
  74.                 }
  75.         }
  76.         //步骤五
  77.         while(GPIOGetValue(GPIOC, 10) == 0);        //等待低电平结束
  78.        
  79.         if((data[0]+data[1]+data[2]+data[3]) == data[4]){//校验数据
  80.                 humd[0]=data[0];
  81.                 humd[1]=data[1];
  82.                 temp[0]=data[2];
  83.                 temp[1]=data[3];
  84.                 return 1;
  85.         }else{        //数据校验失败
  86.                 return 0;
  87.         }
  88. }

  89. /* 配置64MHz系统时钟 */
  90. void SystemClockConfig(void)
  91. {
  92.         //Fvco1 * 32 / 4 = 128
  93.         RCC->PLLCFGR = (0x2<<0)        //HSI16
  94.                         | (1<<4)                //M=1+1=2
  95.                         | (16<<8)                //N=16
  96.                         | (1<<28)                //使能PLLRCLK
  97.                         | (1<<29);        //R=1        PLLRCLK分频系数为2
  98.         RCC->CR |= (1<<24);        //使能PLL
  99.         while(!(RCC->CR & (1<<25)));        //等待PLL锁定
  100.        
  101.         FLASH->ACR |= (0x1<<0);        //设置Flash访问延迟
  102.         RCC->CFGR |= (0x2<<0);        //切换时钟源为PLLRCLK
  103.         while(!(RCC->CFGR & (0x2<<3)));        //等待时钟源切换完成
  104.         SystemCoreClockUpdate();        //更新SystemCoreClock全局变量
  105. }

  106. int main(void)
  107. {
  108.         int ret;
  109.         char temp[2]={0};        //保存温度数据
  110.         char humd[2]={0};        //保存湿度数据
  111.         SystemClockConfig();
  112.         RCC->IOPENR |= RCC_IOPENR_GPIOCEN;        //使能GPIOC
  113.         UART2_Init(115200);

  114.         GPIOSetDir(GPIOC, 13, 0);
  115.         GPIOSetDir(GPIOA, 5, 1);
  116.         while(1){
  117.                 ret = DHT11_Read(temp, humd);
  118.                 switch (ret){
  119.                         case -1:
  120.                                 printf("Timeout\n");
  121.                         break;
  122.                         case 0:
  123.                                 printf("Data Error\n");
  124.                         break;
  125.                         case 1:
  126.                                 printf("humd:%d.%d temp:%d.%d\n", humd[0], humd[1]
  127.                                                         , temp[0], temp[1]);
  128.                         break;
  129.                 }
  130.                 mdelay(1000);
  131.         }
  132. }
复制代码


【实验现象】
连接开发板,并打开串口调试工具,并使用115200的波特率连接开发板的串口,显示如下:




此内容由EEWORLD论坛网友lvxinn2006原创,如需转载或用于商业用途需征得作者同意并注明出处

本文来自论坛,点击查看完整帖子内容。

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章