MIniCH32V103EVB学习手册
作者:互联网
MIniCH32V103EVB学习手册
第一部分、硬件概述
1.1 MIniCH32V103EVB实物图
1.1.1仿真图
1.1.2实物图
1.2 MIniCH32V103EVB原理图
MIniCH32V103EVB原理图下图所示,如看不清可打开Hardware目录下Sch的PDF文档查阅
第二部分、软件工具
2.1 软件概述
在 /Software 目录下是常用的工具软件:
1. MounRiver: 编译器;
2.2 MounRiver软件入门
大家访问以下链接:http://mounriver.com/help
2.3 新建工程
-
打开MounRiver Studio;
-
点击File->New->MounRiver Project后出现下图,键入Project Name,芯片选择CH32V103C8T6后点击Finish;
-
完成工程创建后出现下图:
其中:- Includes: 包含的头文件;
- __Core:__内核文件,存放core_riscv内核文件;
- Debug: 存放串口打印和延迟函数相关的文件;
- Ld: 链接文件;
- Peripheral: 这是MCU厂商提供外设相关驱动;
- Startup: ch32v103的启动文件;
- __User: __ch32v103的配置文件,中断相关文件,main函数等;
至此,工程创建完成。
第三部分、实战训练
3.1 实例Eg1_Blink
本节我们目标是实现两颗LED的循环闪烁效果;
3.1.1 硬件设计
如下图是板载LED原理图,其中LED2连接到PB0,LED3则与PB1相连;由于以上LED是共阳极接法,所以,PB0输出高电平,则灯灭,输出低电平则点亮;
3.1.2 软件设计
3.1.2.1 启动代码
我们先打开startup_ch32v10x.S启动文件,我们大概看一下我们能理解的部分,其中NMI_Handler是不可屏蔽中断的处理器;HardFault_Handler是硬件异常中断(死机),在工程目录User下的ch32v10x_it.c种实现;SysTick_Handler是系统滴答中断函数;SW_handler是软件中断;
j NMI_Handler /* NMI Handler */
j HardFault_Handler /* Hard Fault Handler */
j SysTick_Handler /* SysTick Handler */
j SW_handler /* SW Handler */
然后是一堆的外部中断;
/* External Interrupts */
j WWDG_IRQHandler /* Window Watchdog */
j PVD_IRQHandler /* PVD through EXTI Line detect */
j TAMPER_IRQHandler /* TAMPER */
j RTC_IRQHandler /* RTC */
j FLASH_IRQHandler /* Flash */
j RCC_IRQHandler /* RCC */
j EXTI0_IRQHandler /* EXTI Line 0 */
j EXTI1_IRQHandler /* EXTI Line 1 */
j EXTI2_IRQHandler /* EXTI Line 2 */
j EXTI3_IRQHandler /* EXTI Line 3 */
j EXTI4_IRQHandler /* EXTI Line 4 */
j DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */
j DMA1_Channel2_IRQHandler /* DMA1 Channel 2 */
j DMA1_Channel3_IRQHandler /* DMA1 Channel 3 */
j DMA1_Channel4_IRQHandler /* DMA1 Channel 4 */
j DMA1_Channel5_IRQHandler /* DMA1 Channel 5 */
j DMA1_Channel6_IRQHandler /* DMA1 Channel 6 */
j DMA1_Channel7_IRQHandler /* DMA1 Channel 7 */
j ADC1_2_IRQHandler /* ADC1_2 */
.word 0
.word 0
.word 0
.word 0
j EXTI9_5_IRQHandler /* EXTI Line 9..5 */
j TIM1_BRK_IRQHandler /* TIM1 Break */
j TIM1_UP_IRQHandler /* TIM1 Update */
j TIM1_TRG_COM_IRQHandler /* TIM1 Trigger and Commutation */
j TIM1_CC_IRQHandler /* TIM1 Capture Compare */
j TIM2_IRQHandler /* TIM2 */
j TIM3_IRQHandler /* TIM3 */
j TIM4_IRQHandler /* TIM4 */
j I2C1_EV_IRQHandler /* I2C1 Event */
j I2C1_ER_IRQHandler /* I2C1 Error */
j I2C2_EV_IRQHandler /* I2C2 Event */
j I2C2_ER_IRQHandler /* I2C2 Error */
j SPI1_IRQHandler /* SPI1 */
j SPI2_IRQHandler /* SPI2 */
j USART1_IRQHandler /* USART1 */
j USART2_IRQHandler /* USART2 */
j USART3_IRQHandler /* USART3 */
j EXTI15_10_IRQHandler /* EXTI Line 15..10 */
j RTCAlarm_IRQHandler /* RTC Alarm through EXTI Line */
j USBWakeUp_IRQHandler /* USB Wakeup from suspend */
j USBHD_IRQHandler /* USBHD */
并且继续往下,可以看到,这些中断都是弱定义的,也就是说,你可以重新定义并实现;
.weak NMI_Handler
.weak HardFault_Handler
.weak SysTick_Handler
.weak SW_handler
.weak WWDG_IRQHandler
.weak PVD_IRQHandler
3.1.2.2 系统时钟配置
最后是系统初始化和main函数,通过以下语句加载系统时钟初始化和main函数
jal SystemInit
la t0, main
我们先看SystemInit,操作RCC相关的寄存器是进行初始化,具体的定义请打开\MIniCH32V103EVB\Document\ch32v103手册\CH32xRM.PDF 的3.5小节 寄存器描述;
R32表示32位的寄存器,RCC表示RCC时钟相关寄存器,
void SystemInit (void)
{
RCC->CTLR |= (uint32_t)0x00000001;
RCC->CFGR0 &= (uint32_t)0xF8FF0000;
RCC->CTLR &= (uint32_t)0xFEF6FFFF;
RCC->CTLR &= (uint32_t)0xFFFBFFFF;
RCC->CFGR0 &= (uint32_t)0xFF80FFFF;
RCC->INTR = 0x009F0000;
SetSysClock();
}
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
SetSysClockTo24();
#elif defined SYSCLK_FREQ_48MHz
SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz
SetSysClockTo72();
#endif
/* If none of the define above is enabled, the HSI is used as System clock
* source (default after reset)
*/
}
这里我们以CTLR寄存器为例,讲解一些C语言操作寄存器的情况,RCC->CTLR |= (uint32_t)0x00000001;这段代码是CTLR最后一位置位,而该寄存器的最后一位如下图所示,为1,就是使能HSI振荡器;
其他寄存器也同理;
在代码种,定义了SYSCLK_FREQ_72MHz,所以SetSysClockTo72()这个函数吧系统时钟设置为72MHz;
3.1.2.3 main函数实现
接下来我们来看看main函数,如下
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Delay_Init();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n", SystemCoreClock);
printf("Blink TEST\r\n");
LED_GPIO_INIT();
while(1)
{
LED2_ON();
LED3_OFF();
printf("LED2_ON,LED3_OFF\r\n");
Delay_Ms(250);
LED2_OFF();
LED3_ON();
printf("LED2_OFF,LED3_ON\r\n");
Delay_Ms(250);
}
}
NVIC_PriorityGroupConfig是配置优先级分组的,Delay_Init初始化延迟函数;USART2_Printf_Init初始化串口打印,在使用printf之前,需要做声明并实现以下函数以支持printf函数
__attribute__((used))
int _write(int fd, char *buf, int size)
{
int i;
for(i = 0; i < size; i++){
#if(DEBUG == DEBUG_UART1)
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
USART_SendData(USART1, *buf++);
#elif(DEBUG == DEBUG_UART2)
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
USART_SendData(USART2, *buf++);
#elif(DEBUG == DEBUG_UART3)
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
USART_SendData(USART3, *buf++);
#endif
}
return size;
}
3.1.2.3 LED模块代码
LED_GPIO_INIT是对LED对应的PB0与PB1进行初始化,我们可以跳转到RCC_APB2PeriphClockCmd,不难发现RCC->APB2PCENR实际上这些库函数的本质就操作寄存器;GPIO_Init也是如此,即操作GPIOx->CFGLR和GPIOx->CFGHR寄存器,关于这些寄存器请直接参考参考手册;
void LED_GPIO_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
最后是LED的亮灭操作,LED2_ON()这个宏是亮灯,由于LED是共阳极接法,故低电平点亮GPIO_ResetBits(GPIOB,GPIO_Pin_0)使得PB0输出低电平,反之,LED2_OFF输出高电平,其他IO口同理可得;
#define LED2_ON() GPIO_ResetBits(GPIOB,GPIO_Pin_0)
#define LED2_OFF() GPIO_SetBits(GPIOB,GPIO_Pin_0)
#define LED3_ON() GPIO_ResetBits(GPIOB,GPIO_Pin_1)
#define LED3_OFF() GPIO_SetBits(GPIOB,GPIO_Pin_1)
while(1)
{
LED2_ON();
LED3_OFF();
Delay_Ms(250);
LED2_OFF();
LED3_ON();
Delay_Ms(250);
}
3.1.3 下载验证
我们把固件程序下载进去可以,可以看到板载的LED2和LED3交替点亮熄灭;
3.2 实例Eg2_USART
本节我们目标是实现串口2接收并回传数据;
3.1.1 硬件设计
如下图是板载排针,我们用到PA2作为USART2的TX,PA3作为USART2的RX;
3.1.2 软件设计
3.1.2.1 串口2初始化配置
我们配置USART2串口接收中断,一般的我们需要先进行GPIO Init,USART Init,NVIC Init;GPIO 配置为TX复用推挽模式RX为IN_FLOATING,USART波特率配置为115200,字长8位,1个停止位,无奇偶校验,无硬件流控,发送和接收模式;NVIC优先级配置为PreemptionPriority = 1,SubPriority = 1;
void USART2_CFG(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
USART_InitTypeDef USART_InitStructure = {0};
NVIC_InitTypeDef NVIC_InitStructure = {0};
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* USART2 TX-->A.2 RX-->A.3 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_Init(USART2, &USART_InitStructure);
USART2->STATR = 0x00C0;
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART2, ENABLE);
}
3.1.2.3 USART2全局中断请求
串口2全局中断请求回调函数声明与实现如下,在回调函数中USART_GetITStatus获取接收中断标志,USART_ClearITPendingBit清除中断标志,USART_ReceiveData接收数据,USART_SendData发送数据;
void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志
USART_SendData(USART2,USART_ReceiveData(USART2));
}
}
3.1.3 下载验证
我们把固件程序下载进去可以,可以看到板载的LED2和LED3交替点亮熄灭,连接PA2到USB转TTL串口调试工具上(如CH340、Wch-link)的RX,PA3接到串口工具的TX;打开串口调试工具;配置串口USART波特率配置为115200,字长8位,1个停止位,无奇偶校验,无硬件流控;然后发送任意字符串,串口终端回显相同字符串;
3.3 实例Eg3_DHT11
本节我们在上一节的基础上,目标是实现读取DHT11温湿度模块的温湿度数据并通过串口打印出来
3.3.1 硬件设计
如下图是DHT11模块原理图,我们将用PB3作为去读取DHT11的数据,这里用到单总线协议,详细资料请观看视频并打开
“Document\电子模块数据资料\DHT11 使用说明书”目录下的说明书;
3.3.2 软件设计
3.3.2.1 初始化DHT11
我们配置PB3为推挽输出模式,并复位DHT11后等待其响应,代码如下;
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在
u8 DHT11_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //PB3端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化IO口
GPIO_SetBits(GPIOB,GPIO_Pin_3); //PG11 输出高
DHT11_Rst(); //复位DHT11
return DHT11_Check();//等待DHT11的回应
}
3.1.2.3 DHT11数据处理
查阅DHT11 使用说明书可知:
一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据
+8bi温度整数数据+8bit温度小数数据
+8bit校验和
数据传送正确时校验和数据等于“ 8bit 湿度整数数据 +8bit 湿度小数数据+8bi 温度整数数据 +8bit 温度小数数据 ”所得结果的末8位。
根据以上数据格式实现如下代码:
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
u8 DHT11_Read_Data(u8 *temp,u8 *humi)
{
u8 buf[5];
u8 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;
}
3.1.3 下载验证
我们把固件程序下载进去可以,可以看到板载的LED2和LED3交替点亮熄灭,连接PA2到USB转TTL串口调试工具上(如CH340、Wch-link)的RX,PA3接到串口工具的TX;打开串口调试工具;配置串口USART波特率配置为115200,字长8位,1个停止位,无奇偶校验,无硬件流控;
紧接着我们把PB3连接到DHT模块的DATA,并上电;
标签:IRQHandler,MIniCH32V103EVB,USART,手册,学习,InitStructure,GPIO,USART2,RCC 来源: https://www.cnblogs.com/Li-Share/p/16351820.html