CH32V307环境参数在线监测系统是以CH32V307VCT6为核心,由ESP8266模块、DHT11温湿度传感器模块、TFT LCD显示屏组成。系统实物图如下所示:
系统功能主要有RTC实时时钟、WIFI网络授时、DHT11温度测量、温湿度数据实时上传到onenet平台、屏幕定时刷新等功能。本例程主要用到CH32V307的GPIO、串口、AD转换、定时器、RTC功能。今天先来看一下GPIO端口操作。
CH32V307官方例程提供了GPIO应用的基本案例。官方案例代码主函数如下:
主程序首先是通过NVIC_PriorityGroupConfig配置优先级分组-抢占优先级和次优先级,然后根据时钟寄存器值更新系统核心时钟变量,官方例程默认采用外部高速时钟作为时钟源,倍频至96MHZ。Delay_Init为ms级延时函数。初始化串口,用于输出调试信息。然后就是通过初始化函数初始PD0。在while循环中,通过GPIO_WriteBit函数对PD0进行写操作。 一般而言,嵌入式系统在正式工作前,都要进行一些初始化工作,比如GPIO使用前,先进行GPIO的初始化,如官方例程GPIO_Toggle_INIT函数,一般我们写成一个函数的形式。GPIO初始化函数如下图所示,
这里GPIO初始化函数首先定义了一个GPIO_InitTypeDef类型的结构体变量。右键打开其声明可以看到这个结构变量的成员如下:有GPIO_Pin、GPIO_Speed和GPIO_Mode三个成员变量。
这里GPIO_Pin就是需要配置的引脚。在ch32v30x_gpio.h的头文件中可以看到其预定义,如下图所示
GPIO_Speed为所选择的初始化引脚的输出响应速度(这个速度是指I/O口驱动电路的响应速度而不是输出信号的速度,输出信号的速度与程序有关),芯片内部在I/O口的输出部分安排了多个响应速度不同的输出驱动电路,可以根据需要选择合适的驱动电路。在输出模式时可选速度如下:10MHz、2MHz、50MHz。
这里需要注意:高频的驱动电路,噪声也高,当不需要高的输出频率时,请选用低频驱动电路,这个非常有利于提高系统的电磁干扰(EMI)性能。当然如果要输出较高频率的信号,但却选用了较低频率的驱动模块,很可能会得到失真的输出信号。关键是GPIO的引脚速度跟应用匹配,推荐10倍以上。对于串口,假如最大波特率只需要115.2K,那么用2M的GPIO的引脚速度就够了,既省电也噪声小;对于IIC接口,假如用400K的传输速率,若想把余量留大些,那么用2M的GPIO的引脚速度或许不够。这时可以选择10M的GPIO引脚速度;对于SPI通信,假如使用18M或9M的传输速率,用10M的GPIO的引脚速度显然不够,需要选用50M的GPIO的引脚速度。
GPIO_Mode所选择引脚的操作模式,CH32V307系列的MCU的输入/输出引脚可配置为一下8种模式(4种输入模式+2种输出模式+2种复用输出模式)。
GPIO_Mode_AIN为模拟输入,ADC对应的引脚配置引脚为模拟输入
GPIO_Mode_IN_FLOATING为浮空输入
GPIO_Mode_IPD带下拉输入
GPIO_Mode_IPU带上拉输入
GPIO_Mode_Out_OD开漏输出,要得到高电平状态需要上拉电阻才行如果引脚不连接外部的上拉电阻,则只能输出低电平。
1.开漏输出的这一特性一个明显的优势就是可以很方便的调节输出的电平,因为输出电平完全由上拉电阻连接的电源电平决定。所以在需要进行电平转换的地方,非常适合使用开漏输出。
2.开漏输出的这一特性另一个好处在于可以实现"线与"功能,所谓的"线与"指的是多个信号线直接连接在一起,只有当所有信号全部为高电平时,合在一起的总线为高电平;只要有任意一个或者多个信号为低电平,则总线为低电平。而推挽输出就不行,如果高电平和低电平连在一起,会出现电流倒灌,损坏器件。
GPIO_Mode_Out_PP推免输出,推挽输出结构是由两个MOS或者三极管收到互补控制的信号控制,两个管子始终一个在导通,一个在截止,如下图所示:
推挽输出的最大特点是可以真正能真正的输出高电平和低电平,在两种电平下都具有驱动能力。所谓的驱动能力,就是指输出电流的能力。推免式输出既可以提高电路的负载能力,又能提高开关速度,且导通损耗小效率高。输出既可以向负载灌电流(作为输出),也可以从负载抽取电流(作为输入)。
GPIO_Mode_AF_OD复用功能的推免输出
GPIO_Mode_AF_PP复用功能的开漏输出
GPIO_Toggle_INIT初始化代码功能就是初始化PD0为普通推免输出模式,通过PD0控制LED灯闪烁。其中GPIO_Init(GPIOA, &GPIO_InitStructure);这个函数的第一个参数GPIOD为宏定义,其相关的宏定义如下:((GPIO_TypeDef *) GPIOD_BASE),
GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
对照官方手册寄存器映射表如下图所示,可以看到这里宏定义其实为GPIOD寄存器组的首地址。而第二个参数就是定义的结构变量是用户对GPIOD端口的参数设置的首地址,就是上面我们介绍的端口号、模式和速度。CH32单片机使用固件库函数完成对外设初始化都是采用这种规范。
另外在初始化代码中还有一句语句是RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
这句代码是开启GPIOD的时钟输出功能,CH32系列单片机和STM32系列单片机一样外设带有时钟输出使能控制,如AHB总线时钟、内核时钟、各种外设APB1、APB2外设、ADC时钟等。因此要使用GPIOD模块时,必须先使能对应的时钟。这里GPIO(GPIOA、GPIOB、GPIOC、GPIOD)连接外设总线上APB2上,如下图所示。因此通过以下代码使能其时钟。RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
在while循环中,通过GPIO_WriteBit函数对PD0进行写操作。
在ch32v30x_gpio.c文件中我们看到GPIO_WriteBit的源代码,看芯片手册,可知这里BSHR和BCR分别为端口置位/复位寄存器。注意这两个寄存器写0没有影响,写1则会置为或者复位。
对于上面的代码,我们也可以直接对寄存器访问来编写程序,寄存器直接操作如下:
本编文章对GPIO操作代码分析就到这里。本项目用到IO口配置如下:
1.串口通信引脚配置
这里串口通信引脚使用的是PA2作为发送,PA3作为接收。所以PA2这个引脚配置为功能复用推免输出。PA3作为接收引脚属于输入,这里配置为浮空输入模式。
2.LED指示灯引脚配置
3.LCD显示屏接口引脚
4.DHT11相关引脚初始化