ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

MIniCH32V103EVB学习手册

2022-06-07 15:05:53  阅读:239  来源: 互联网

标签:IRQHandler MIniCH32V103EVB USART 手册 学习 InitStructure GPIO USART2 RCC


MIniCH32V103EVB学习手册

第一部分、硬件概述

1.1 MIniCH32V103EVB实物图

1.1.1仿真图

shiwu1.png

1.1.2实物图

1.2 MIniCH32V103EVB原理图

MIniCH32V103EVB原理图下图所示,如看不清可打开Hardware目录下Sch的PDF文档查阅

MIniCH32V103EVB_Sch.png

第二部分、软件工具

2.1 软件概述

在 /Software 目录下是常用的工具软件:

  1.  MounRiver: 编译器;

2.2 MounRiver软件入门

大家访问以下链接:http://mounriver.com/help

2.3 新建工程

  • 打开MounRiver Studio;

  • 点击File->New->MounRiver Project后出现下图,键入Project Name,芯片选择CH32V103C8T6后点击Finish;

    Proj1.png

  • 完成工程创建后出现下图:

    Tree.png
    其中:

    • Includes: 包含的头文件;
    • __Core:__内核文件,存放core_riscv内核文件;
    • Debug: 存放串口打印和延迟函数相关的文件;
    • Ld: 链接文件;
    • Peripheral: 这是MCU厂商提供外设相关驱动;
    • Startup: ch32v103的启动文件;
    • __User: __ch32v103的配置文件,中断相关文件,main函数等;

至此,工程创建完成。

第三部分、实战训练

本节我们目标是实现两颗LED的循环闪烁效果;

3.1.1 硬件设计

如下图是板载LED原理图,其中LED2连接到PB0,LED3则与PB1相连;由于以上LED是共阳极接法,所以,PB0输出高电平,则灯灭,输出低电平则点亮;

LED.png

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时钟相关寄存器,

RCC-R.png

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振荡器;

RCC-R1.png

其他寄存器也同理;

在代码种,定义了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;

pa23.png

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个停止位,无奇偶校验,无硬件流控;然后发送任意字符串,串口终端回显相同字符串;

ssc.png

3.3 实例Eg3_DHT11

本节我们在上一节的基础上,目标是实现读取DHT11温湿度模块的温湿度数据并通过串口打印出来

3.3.1 硬件设计

如下图是DHT11模块原理图,我们将用PB3作为去读取DHT11的数据,这里用到单总线协议,详细资料请观看视频并打开

“Document\电子模块数据资料\DHT11 使用‌说明书”目录下的说明书;

DHT11.png

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,并上电;

ssc.png

标签:IRQHandler,MIniCH32V103EVB,USART,手册,学习,InitStructure,GPIO,USART2,RCC
来源: https://www.cnblogs.com/Li-Share/p/16351820.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有