沁恒ch32v307使用记录:gpio与exti(代码片段)

NaisuXu NaisuXu     2023-02-22     311

关键词:

文章目录

目的

GPIO是单片机最基础的功能,EXTI最常用的场景就是GPIO用于输入时使用。这篇文章将对CH32V307中相关内容进行说明。

本文使用沁恒官方的开发板 (CH32V307-EVT-R1沁恒RISC-V模块MCU赤兔评估板) 进行演示。

本文演示中需要用到开发板上的KEY和LED,默认只是引入接口到排针,并没有和芯片GPIO口相连,下文使用中需要手动用杜邦线连接。

GPIO(通用输入输出接口)

基础说明


CH32V307的GPIO和大部分单片机一样支持多种工作模式: 浮空输入 上拉输入 下拉输入 模拟输入 开漏输出 推挽输出 复用功能的输入和输出

复位后 ,GPIO口运行在初始状态,这时大多数IO口都是运行在浮空输入状态 ,但也有HSE等外设相关的引脚是运行在外设复用的功能上。

沁恒官方提供了库函数用于操作GPIO口,主要是 ch32v30x_gpio.hch32v30x_gpio.c 两个文件,前者中声明了提供给用户调用的函数以及相关的枚举和宏定义类型等。

下面只介绍些GPIO的基础使用,剩余的功能大多数是结合外设复用或是中断等进行的,会在包含在那些内中中进行介绍。需要详细了解也可以直接查看上面的库函数文件。

初始化

初始化GPIO只要配置需要使用的GPIO口和工作模式及其附加参数等,比如下面方式:

// 下面函数将初始化 PA0 为推挽输出模式
void GPIO_Toggle_INIT(void)

    GPIO_InitTypeDef GPIO_InitStructure = 0; // GPIO后初始化结构体
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //初始化GPIOA时钟
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 使用 Pin0
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 输出切换频率 // 这个通常在满足需求的情况下越低越好,比如使用 GPIO_Speed_2MHz 
    
    GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化GPIO口

上面代码中出现的 GPIOA GPIO_Pin_0 GPIO_Mode_Out_PP 等枚举和宏定义类型都可以在 ch32v30x_gpio.h 文件中找到,其中同一组的 GPIO_Pin 可以多个一起使用,比如下面这样:

// 同时使用 PIN 0、2、4
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2 | GPIO_Pin_4;

输出

这里以推挽输出模式进行介绍,这里直接以点亮控制控制开发板上的LED进行测试,用杜邦线将 LED1LED2 分别与 PC0PC1 相连接,然后使用 MounRiverStudio 新建 CH32V307VC 项目,将 main.c 中代码替换成如下即可:

#include "debug.h"

int main(void)

	Delay_Init();

	// 以下初始化 GPIOC 的 PIN0 和 PIN1
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure = 0;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

	while(1)
    
	    GPIO_SetBits(GPIOC, GPIO_Pin_0 | GPIO_Pin_1); // PC0 和 PC1 输出高电平,根据电路这将会熄灭LED
	    Delay_Ms(1000);
	    GPIO_ResetBits(GPIOC, GPIO_Pin_0 | GPIO_Pin_1); // PC0 和 PC1 输出低电平,根据电路这将会点亮LED
	    Delay_Ms(500);
	

编译程序下载到开发板就可以看到LED闪烁了。

输出相关操作库函数有下面一些:

// 指定IO口输出高电平
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
// 指定IO口输出低电平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
// 写指定IO口的电平值,BitAction可选Bit_RESET(0)和Bit_SET(1)
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal); 
// 写一组IO口的输出值
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

也可以使用调试器来查看GPIOC的输出寄存器状态了解输出情况:

上面的 OUTDR 就是输出数据寄存器了,该寄存器数据也可以通过下面库函数进行读取:

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

输入与电平读取

这里以下拉输入模式进行介绍,用杜邦线将 KEYPB2 相连接, PB2 设置为浮空输入模式,根据电路连接,当按键松开时读取到的输入电平为高,按键被按下时读取到的输入电平为低。

修改 main.c 代码如下:

#include "debug.h"

int main(void)

	Delay_Init();
    USART_Printf_Init(115200);

	// 以下初始化 PB2 为浮空输入模式
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure = 0;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

	while(1)
    
	    Delay_Ms(2000);
	    // 读取PB2输入电平值
	    printf("PB2 Input Data:%d\\r\\n", GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2));
	

输入数据读取相关操作库函数有下面一些:

// 读取指定IO口电平值
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
// 读取一组IO口电平值
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

锁定机制

锁定机制可以锁定IO口的配置,在一些可靠性要求高的场合下比较有用。经过特定的一个写序列后,选定的 IO 引脚配置将被锁定,在下
一个复位前无法更改。使用库函数的话只需要使用下面函数即可:

void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

EXTI(外部中断)

基础说明


CH32V307有二十多条外部中断线,大部分都是给GPIO用的,这里也只对这个进行介绍,其它的中断线都是用于特定功能了,会在那些功能下进行介绍。

GPIO使用外部中断通常用于输入模式下,根据中断配置当外部电平上升或下降变化时会触发中断。

GPIO上的外部中断使用时需要处理的内容如下:

  • 初始化GPIO;
  • 初始化EXTI;
  • 中断都受到中断控制器控制(NVIC),所以相应用能也需要初始化;
  • 编写外部中断触发时的回调函数;

外部中断的库函数主要位于 ch32v30x_exti.hch32v30x_exti.c 两个文件,前者中声明了提供给用户调用的函数以及相关的枚举和宏定义类型等。

使用演示

这里使用PB2触发外部中断,电路上保持 KEYPB2 的连接。将 main.c 代码改为如下:

#include "debug.h"

int main(void)

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 将外部中断配置为分组二,这样中断父优先级和子优先级取值都为0~3
	Delay_Init();
    USART_Printf_Init(115200);

	// 以下初始化 PB2 为浮空输入模式
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE); // 此处需要把复用时钟也打开
    GPIO_InitTypeDef GPIO_InitStructure = 0;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

//    EXTI_ClearITPendingBit(EXTI_Line2); // 推荐在使能中断前先清除一次中断,防止意外发生

    // 以下初始化外部中断
    EXTI_InitTypeDef EXTI_InitStructure = 0;
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource2); // 配置外部中断源为 PB2
    EXTI_InitStructure.EXTI_Line = EXTI_Line2; // 外部中断线2
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 配置为外部中断
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; // 配置上升沿下降沿都触发中断
    EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能外部中断
    EXTI_Init(&EXTI_InitStructure);

    // 以下初始化中断控制器
    NVIC_InitTypeDef NVIC_InitStructure = 0;
    NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; // 配置使用 EXTI2 通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 父优先级设置为1,数值越小优先级越高。父优先级高的中断会抢占优先级低的中断
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; // 子优先级设置为2,数值越小优先级越高,子优先级不会引起抢占
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断
    NVIC_Init(&NVIC_InitStructure);

	while(1)


// 下面是中断回调函数的声明,该函数名是在启动文件 startup_ch32v30x_D8C.S 中定义的
// 需要注意的是后面的 __attribute__((interrupt())); 是必须的这是 GCC For RISCV 对于中断的一种处理
// 另外也可以使用__attribute__((interrupt("WCH-Interrupt-fast"))); 这样可以使用沁恒RISCV的快速中断功能
void EXTI2_IRQHandler(void) __attribute__((interrupt()));

// 下面是中断回调函数的定义
void EXTI2_IRQHandler(void)

  if(EXTI_GetITStatus(EXTI_Line2)!=RESET) // 检查是否是中断线2的中断
  
    printf("PB2 Input Data:%d\\r\\n", GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2));
    EXTI_ClearITPendingBit(EXTI_Line2); // 清除中断标志,这样才能触发下次中断
  

这里特别需要注意的是这颗RISC-V内核的单片机使用时中断处理函数需要特殊的标识声明后才能正常使用,比如上面代码中使用 ( void EXTI2_IRQHandler(void) __attribute__((interrupt())); ) 方式进行声明,不然进一次中断后程序就跑飞了。

演示中读取到的数据异常是由于按键抖动引起的,实际使用中需要添加软件和硬件上的按键消抖功能。

总结

GPIO与EXTI虽然是使用频率比较高的功能,但总体使用比较简单,没有太多需要详细说明的地方。

沁恒ch32v307单片机入门(02):官方库与工程模板介绍(代码片段)

文章目录目的官方库工程模板使用例程总结目的现在开发单片机大多数时候都是面向库开发的,这里将简单介绍下CH32V307的官方库。在开发过程中新建项目时通常会从某些模板开始,模板包含了库和初始化代码等内容࿰... 查看详情

沁恒ch32v307单片机入门(02):官方库与工程模板介绍(代码片段)

...进行开发时的模板内容。一些基础的内容可以参考文章《沁恒CH32V307单片机入门(01):基础说明与流程体验》:https://blog.csdn.net/Naisu_kun/article/details/128734532官方库在前面文章提到的CH32V307评估板说明及参考应用例... 查看详情

沁恒ch32v307单片机入门(01):基础说明与流程体验(代码片段)

...试试国产的单片机。基础说明芯片介绍这里准备使用南京沁恒的CH32V307为基础进行介绍,这是一款RISC-V架构内核的单片机。我看中它的主要是自带高速USBPHY和ETHPHY,同时价格也很便宜,某宝上散买十块出头。图片是R的... 查看详情

沁恒ch32v208:ch32v208的储存结构,启动模式和时钟(代码片段)

...特点,以及通过SDK中的示例代码分析CH32V208的时钟设置目录沁恒CH32V208(一):CH32V208WBU6评估板上手报告和Win10环境配置沁恒CH32V208(二):CH32V208的储存结构,启动模式和时钟CH32V存储容量命名方式在介绍下面的内容前,先看一下CH32V系列和存... 查看详情

沁恒risc-vmcu为全国大学生智能汽车竞赛加速(代码片段)

 §01沁恒RISC-V  第十七届(2022年)全国大学生智能汽车竞赛规则已发布,沁恒微电子很荣幸继续为大赛提供赞助。其中多车编队组的头车限定使用沁恒微电子的MCU作为主控,跟随车之一可以选用沁恒微电子的MCU... 查看详情

第十七届全国大学生智能汽车竞赛沁恒微电子芯片推荐(代码片段)

简介:南京沁恒为电子公司继续赞助第十七届全国大学生智能车。今年他们不仅提供性能更加优越的RISV-VMCU芯片,同时也推荐使用公司具有特色的无线蓝牙芯片,用于运动智能车作品的调试与跟踪。关键词:沁恒&... 查看详情

沁恒risc-vmcu为全国大学生智能汽车竞赛加速(代码片段)

...f08;2023年)全国大学生智能汽车竞赛规则已发布,沁恒微电子很荣幸继续为大赛提供赞助。其中电能接力组限定使用沁恒微电子的MCU作为主控,单车越野组和完全模型组也可以选择使用沁恒微电子的单片机。为更好的... 查看详情

第十七届ch32v307多车组头尾双车摄像头传统扫线循迹

一.传统的扫线循迹,网上的资料繁杂,开源资料或者博客破碎化1.我于2021年10份正式接触摄像头,在到最终比赛期间,遇到了不少困难和迷惑的地方,接下来我会阐述摄像头小车整个从图像处理到实现循迹的... 查看详情

国产沁恒ch32f103c8t6使用指南

国产沁恒CH32F103C8T6使用指南前言:CH32F103芯片是由南京沁恒电子产品公司推出的国产ARM芯片,与STM32F103系列芯片相比,不仅管脚和寄存器全部兼容,而且还增强了USB功能,有2个USB,一个Host,一个Device&#x... 查看详情

沁恒ch552usb学习之旅

学习目标:学习单片机USB开发,了解USB底层前期准备:参考书籍和资料: 1、《圈圈教你玩USB》,绝对的经典,入门USB不二之选! 2、《圈圈教你玩USB》,绝对的经典,入门USB不二之选! 3、... 查看详情

stm32进入不了中断

...ENABLE;EXTI_Init(&EXTI_InitStructure);/*ConnectKeyButtonEXTILinetoKeyButtonGPIOPin*/GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource3);//将PA3连接到外部中断通道4/*Generatesoftwareinterrupt:simulateafallingedgeappliedonKeyButtonEXTIline*/EXTI_GenerateSWInterrupt(EXTI_Line3);  /*... 查看详情

stm32中exti和nvic的关系(代码片段)

...司在其STM32产品上扩展的外中断控制。它负责管理映射到GPIO引脚上的外中断和片内几个集成外设的中断(PVD,RTCalarm,USBwakeup,ethernetwakeup),以及软件中断。其输出最终被映射到NVIC的相应通道。因此,配置EXTI中断的过程必然包... 查看详情

沁恒ch32学习——risc-v架构学习笔记

作为新手第一次接触RISC-V架构时。我首先百度简单了解了ARM架构和RISC-V架构的区别,以我个人的理解是ARM架构代表之前的复杂指令集,而RISC-V架构代表着精简指令集。就比如说同样是一个舞蹈动作,复杂指令集可能会... 查看详情

risc-v指令学习笔记(基于ch32v103)(代码片段)

文章目录RISC-V指令学习笔记(基于CH32V103)一、指令结构分类二、寄存器功能三、加载存储指令四、算数运算指令五、移位指令六、逻辑操作指令七、跳转指令7.1条件跳转7.2无条件跳转八、比较判断九、CSR操作指令RISC-V指... 查看详情

risc-v指令学习笔记(基于ch32v103)(代码片段)

文章目录RISC-V指令学习笔记(基于CH32V103)一、指令结构分类二、寄存器功能三、加载存储指令四、算数运算指令五、移位指令六、逻辑操作指令七、跳转指令7.1条件跳转7.2无条件跳转八、比较判断九、CSR操作指令RISC-V指... 查看详情

外部中断(代码片段)

1.外部中断开启步骤  a.初始化IO口为输入    GPIO_Init();  b.使能IO复用功能时钟    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);  c.设置与中断线的映射关系        voidGPIO_EXTILineConfig();  d.初始化线上外部... 查看详情

stm32g0学习手册——使用hal库进行exti中断实验(代码片段)

目录G0外部中断框图中断来源GPIO中断线定义 EXTI类型外部中断实验代码讲解G0外部中断框图扩展中断和事件控制器可以生成中断和事件,并将处理器从停止模式唤醒。 中断来源可配置事件(Configurableevents)来自GPIO,PVD以及... 查看详情

《零死角玩转stm32》-17-exti外部中断/事件控制器

/**本文中的相关图片来自火哥的教程,只作为随笔记录,无侵权之意* 21:25:46,2017-04-08*/EXTI:外部中断/事件控制器。STM32F429共有23根,其中EXTI0~EXTI15,分别对应GPIO中的PX0~PX15,另外7根线有如下用途:(中间省略了EXTI1~EXTI15)&nb... 查看详情