CH582M开发板使用的是芯片是CH582M,是集成 BLE 无线通讯的 RISC-V MCU 微控制器(SoC)。片上集成 2Mbps 低功耗蓝牙 BLE 通讯模块、2 个全速 USB 主机和设备控制器及收发器、2 个 SPI、4 个串口、14 路 ADC、触摸按键检测模块、RTC 等丰富的外设资源。本帖学习最基本的通用IO方面的知识。
CH582M提供了两组GPIO端口:PA和PB。其中PA提供了PA0 ~ PA15共16个端口,PB提供了PB0 ~ PA23共24 个端口。均可作为输入输出使用,使用时必须按照8位、16位或者32位方式访问。每个GPIO口都可以配置为5种模式。

做外部中断使用时,需要配置为输入模式,提供4种触发方式:上升沿、下降沿、高电平、低电平。需要睡眠唤醒功能时,需要打开端口位的中断使能位R16_Px_INT_EN,并开启寄存器 R8_SLP_WAKE_CTRL 中的 GPIO唤醒控制位 RB_SLP_GPIO_WAKE。
PA和PB累计40个GPIO口均在开发板上引出,但其中PB23作为复位使用、PB22作为BOOT使用。PB12、PB13作为TypeA口的D+、D-用,PA4、PA5用于TypeC口,PA8、PA9用于串口、PB14、PB15用于WCH-Link调试口,使用时要注意。
接下来,用一个GPIO口作为输出,演示Blink功能。根据电路原理图,

PB4已经连接了蓝色LED。
测试使用MounRiver Studio Ⅱ开发。在标准库支持下,控制PB4连接的LED亮灭的程序如下:
#include "CH58x_common.h"
// 假设 LED 接在 PB4(开发板常见位置,若实际接法不同请修改)
#define LED_PIN GPIO_Pin_4
int main(void)
{
// 1. 设置系统时钟为 60MHz(必须)
SetSysClock(CLK_SOURCE_PLL_60MHz);
// 2. 初始化 GPIO
// 先置高电平(LED 灭,假设低电平点亮),再配置为推挽输出
GPIOB_SetBits(LED_PIN);
GPIOB_ModeCfg(LED_PIN, GPIO_ModeOut_PP_5mA);
while(1)
{
// 翻转 LED 电平
GPIOB_InverseBits(LED_PIN);
// 延时 500ms
DelayMs(500);
}
}有没有感觉到,代码超级简练,有Arduino那样的简练。在底层代码中:
#define GPIOA_SetBits(pin) (R32_PA_OUT |= pin)
#define GPIOA_InverseBits(pin) (R32_PA_OUT ^= pin)
/*********************************************************************
* @fn GPIOB_ModeCfg
*
* @brief GPIOB端口引脚模式配置
*
* @param pin - PB0-PB23
* @param mode - 输入输出类型
*
* @return none
*/
void GPIOB_ModeCfg(uint32_t pin, GPIOModeTypeDef mode)
{
switch(mode)
{
case GPIO_ModeIN_Floating:
R32_PB_PD_DRV &= ~pin;
R32_PB_PU &= ~pin;
R32_PB_DIR &= ~pin;
break;
case GPIO_ModeIN_PU:
R32_PB_PD_DRV &= ~pin;
R32_PB_PU |= pin;
R32_PB_DIR &= ~pin;
break;
case GPIO_ModeIN_PD:
R32_PB_PD_DRV |= pin;
R32_PB_PU &= ~pin;
R32_PB_DIR &= ~pin;
break;
case GPIO_ModeOut_PP_5mA:
R32_PB_PD_DRV &= ~pin;
R32_PB_DIR |= pin;
break;
case GPIO_ModeOut_PP_20mA:
R32_PB_PD_DRV |= pin;
R32_PB_DIR |= pin;
break;
default:
break;
}
}就是直接操作寄存器,非常容易搞懂,也没有那么多一层层的封装定义,非常好理解。和IO口有关的寄存器,我随后贴介绍,这里可以先体验下它的超级方便的编程风格。
延时函数的定义:
#define DelayMs(x) mDelaymS(x) #define DelayUs(x) mDelayuS(x)
底层是根据系统工作时钟提供的延时处理。
void mDelaymS(uint16_t t)
{
uint16_t i;
for(i = 0; i < t; i++)
{
mDelayuS(1000);
}
}
void mDelayuS(uint16_t t)
{
uint32_t i;
i = t * 15;
do
{
__nop();
} while(--i);
}
我要赚赏金
