打印

【试用】 国产MCU神作GD207ZE—ADC+DHT11+UART

[复制链接]
2267|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jjlink|  楼主 | 2016-4-9 11:22 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
     首先,再次感谢21IC给了我关于GDF207ZE的试用机会,关于GD32F207的详细介绍,详情可以参照我的上一个帖子:
   【试用】 国产MCU神作GD207ZE——开箱篇!
https://bbs.21ic.com/forum.php?mo ... amp;fromuid=1428042
    好了,废话不多说,接下来开始我们关于GD32F207的第一程序的开发吧。

    参考了关于这颗芯片的相关手册,发现跟STM32的很多架构,寄存器都很通用,因此,希望对于以前关于stm32的例程就很容易可以移植了,这里,我借用了以前写过的驱动,在GD板子上进行一些简易的移植,这里,主要用的是DHT11跟ADC模块,然后主要通过串口输出信息,以看到相关的测量结果~
   
     简单描述一下实现过程:
1.数字温湿度传感器DHT11采用单总线输出数据,单次数据包共5Byte(40bit),包括先发送高位,数据格式为:湿度整数+湿度小数+温度整数+温度小数+校验和,各占1 Byte,校验和为前4个Byte相加,由此可计算出温湿度的数值。
DHT11通讯过程的时序图如下图所示,空闲状态时总线为高电平,MCU发送开始信号,拉低总线等待DHT11响应(至少18ms),之后拉高总线20~40μs;DHT11接收到开始信号,在其结束后发送80μs的低电平响应信号,之后拉高总线40~50μs,再拉低40~50μs,接着输出数据;主机读取到响应信号后开始接收数据;一次数据传输完成,DHT11拉低总线50μs,之后总线进入空闲状态。    相关的操作手册在DHT11的数据手册里面已经详细提及到了,感兴趣的朋友可以去下载来看看,这里不再多说了!
    下面请上我们的驱动代码:
#include "dht11.h"

void DHT11_IO_IN(void)
{
        GPIO_InitPara GPIO_InitStructure;
        RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_GPIOG,ENABLE);         //使能PF端口时钟
        GPIO_InitStructure.GPIO_Pin = DHT11_Pin;                                 //端口配置
        GPIO_InitStructure.GPIO_Mode = GPIO_MODE_IPU;
        GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStructure);                                 //初始化IO口
}

void DHT11_IO_OUT(void)
{
        GPIO_InitPara GPIO_InitStructure;
        RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_GPIOG,ENABLE);         //使能PF端口时钟
        GPIO_InitStructure.GPIO_Pin = DHT11_Pin;                                 //端口配置
        GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;                  //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_10MHZ;
        GPIO_Init(DHT11_GPIO_Port, &GPIO_InitStructure);                                 //初始化IO口
}

//复位DHT11
void DHT11_Rst(void)
{                 
        DHT11_IO_OUT();
        CLR_DHT11();         //拉低DQ
  delay_ms(20); //拉低至少18ms
  SET_DHT11();         //DQ=1
        delay_us(30); //主机拉高20~40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
uint8_t DHT11_Check(void)
{   
        uint8_t retry=0;
        DHT11_IO_IN();//SET INPUT         
  while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
        {
                retry++;
                delay_us(1);
        };         
        if(retry>=100)return 1;
        else retry=0;
  while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
        {
                retry++;
                delay_us(1);
        };
        if(retry>=100)return 1;            
        return 0;
}
//从DHT11读取一个位
//返回值:1/0
uint8_t DHT11_Read_Bit(void)                          
{
        uint8_t retry=0;
        while(DHT11_DQ_IN&&retry<100)//等待变为低电平
        {
                retry++;
                delay_us(1);
        }
        retry=0;
        while(!DHT11_DQ_IN&&retry<100)//等待变高电平
        {
                retry++;
                delay_us(1);
        }
        delay_us(40);//等待40us
        if(DHT11_DQ_IN)return 1;
        else return 0;                  
}
//从DHT11读取一个字节
//返回值:读到的数据
uint8_t DHT11_Read_Byte(void)   
{        
  uint8_t i,dat;
  dat=0;
        for (i=0;i<8;i++)
        {
           dat<<=1;
          dat|=DHT11_Read_Bit();
  }                                                    
    return dat;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
uint8_t DHT11_Read_Data(uint8_t *temp,uint8_t *humi)   
{        
        uint8_t buf[5];
        uint8_t i;
        DHT11_Rst();
        if(DHT11_Check()==0)
        {
                for(i=0;i<5;i++)//读取40位数据
                {
                        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;            
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在             
uint8_t DHT11_Init(void)
{
        DHT11_IO_OUT();
        SET_DHT11();
        DHT11_Rst();  //复位DHT11
        return DHT11_Check();//等待DHT11的回应
}

相关的驱动相信大家也很熟悉啦,这里是引用了原子哥的驱动来移植的,感谢原子哥~
同时,还有ADC 部分的驱动代码:
 #include "adc.h"
#include "delay.h"

//初始化ADC                                                                                                                          
void  Adc_Init(void)
{        
        ADC_InitPara ADC_InitStructure;
        GPIO_InitPara GPIO_InitStructure;

        RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_GPIOA | RCC_APB2PERIPH_ADC1, ENABLE );          //使能ADC1通道时钟
        RCC_ADCCLKConfig(RCC_ADCCLK_APB2_DIV6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

        //PA1、PA2作为模拟通道输入引脚                        
        GPIO_InitStructure.GPIO_Pin = GPIO_PIN_1 | GPIO_PIN_2;
        GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AIN;                //模拟输入引脚
        GPIO_Init(GPIOA, &GPIO_InitStructure);       

        ADC_InitStructure.ADC_Mode = ADC_MODE_INDEPENDENT;        //ADC工作模式:ADC1工作在独立模式
        ADC_InitStructure.ADC_Mode_Scan = DISABLE;        //模数转换工作在单通道模式
        ADC_InitStructure.ADC_Mode_Continuous = DISABLE;        //模数转换工作在单次转换模式
        ADC_InitStructure.ADC_Trig_External = ADC_EXTERNAL_TRIGGER_MODE_NONE;        //转换由软件而不是外部触发启动
        ADC_InitStructure.ADC_Data_Align = ADC_DATAALIGN_RIGHT;        //ADC数据右对齐
        ADC_InitStructure.ADC_Channel_Number = 2;        //顺序进行规则转换的ADC通道的数目
        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   
       
        ADC_Enable(ADC1,ENABLE);
        ADC_Calibration(ADC1);

}                                  
//获得ADC值
//ch:通道值 0~3
uint16_t Get_Adc(uint8_t ch)   
{
          //设置指定ADC的规则组通道,一个序列,采样时间
        ADC_RegularChannel_Config(ADC1,ch,1,ADC_SAMPLETIME_239POINT5);        //ADC1,ADC通道,采样时间为239.5周期                                      
  
        ADC_SoftwareStartConv_Enable(ADC1,ENABLE);                //使能指定的ADC1的软件转换启动功能       
         
        while(ADC_GetBitState(ADC1,ADC_FLAG_EOC)!=SET);//等待转换结束

        return ADC_GetConversionValue(ADC1);        //返回最近一次ADC1规则组的转换结果
}

float Get_Adc_Average(uint8_t ch,uint8_t times)
{
        uint32_t temp_val=0;
        uint8_t t;
        for(t=0;t<times;t++)
        {
                temp_val+=Get_Adc(ch);
                delay_ms(5);
        }
        return (float)temp_val/times* (3.3 / 4096.0);
}
分别读取ADC1的ADC_IN1和ADC_IN2的转换值,取3次的平均值后转换为0-3.3V电压值发送到PC。
USART发送程序采用colibri_bsp_uart.c中的EvbUart1Printf(char* fmt, ...)函数,该函数实现了printf()的功能,按照printf()的格式调用即可。
硬件接线如下:
                          PG8:DHT11 DATA
                          PA1:电位器1
                          PA2:电位器2
                          PB6:USART1 TX

其次,在对于DHT11的操作中,最为重要的还是延时函数的精确性:
其中用到的延时函数采用cortex-M3内核中的跟踪组件DWT的时钟周期计数CYCCNT实现:
#include "delay.h"

#define  DWT_CR      *(volatile u32 *)0xE0001000
#define  DWT_CYCCNT  *(volatile u32 *)0xE0001004
#define  DEM_CR      *(volatile u32 *)0xE000EDFC
#define  DEM_CR_TRCENA                   (1 << 24)
#define  DWT_CR_CYCCNTENA                (1 <<  0)
static uint32_t cpuclkfeq;

void delay_init(uint32_t clk)
{
    cpuclkfeq = clk;
    DEM_CR |= DEM_CR_TRCENA;
//    DWT_CYCCNT      = 0u;
    DWT_CR |= DWT_CR_CYCCNTENA;
}
void delay_us(uint32_t us)
{
    uint32_t temp;
    temp= DWT_CYCCNT;
    us *=  SystemCoreClock/1000000;
    while((uint32_t)( DWT_CYCCNT - temp)< us);
}
//void delay_us(uint32_t value)
//{
//        uint32_t i;
//        i = value * 15;
//        while(i--);
//}

void delay_ms(uint32_t ms)
{
        uint32_t temp;
        temp= DWT_CYCCNT;
        ms *=  SystemCoreClock/1000;
        while((uint32_t)( DWT_CYCCNT - temp)< ms);
}

综上,将代码工程编译通后,通过GD-LINK连接到电脑进行下载:
运行结果如下:


下面再附上代码文件,请大家轻喷~

GD32F207.zip (3.97 MB)





沙发
jjlink|  楼主 | 2016-4-9 11:23 | 只看该作者
前排占座~

使用特权

评论回复
板凳
comeon201208| | 2016-4-17 13:00 | 只看该作者
这个还是采集温湿度及电压的程序设计的。

使用特权

评论回复
地板
jjlink|  楼主 | 2016-4-17 19:17 | 只看该作者
comeon201208 发表于 2016-4-17 13:00
这个还是采集温湿度及电压的程序设计的。

嗯。就是温湿度采集加上ADC转换的。有兴趣欢迎下载代码来看看

使用特权

评论回复
5
shenmu2012| | 2016-4-18 21:01 | 只看该作者
数字温湿度传感器DHT11采用单总线输出数据,单次数据包共5Byte(40bit),包括先发送高位,数据格式为:湿度整数+湿度小数+温度整数+温度小数+校验和,各占1 Byte,校验和为前4个Byte相加,由此可计算出温湿度的数值。
这个是很费心了

使用特权

评论回复
6
LXBYUN| | 2022-4-1 11:29 | 只看该作者
你好!这个版本的LIB库,定时器能否正常工作?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

73

帖子

0

粉丝