国产MCU学习Day2——CW32F030C8T6:GPIO配置全攻略

每日更新教程,评论区答疑解惑,小白也能变大神!"

目录

一.GPIO概述

GPIO主要特性

GPIO寄存器配置

示例代码(配置GPIO为推挽输出):

二.案例 

案例一.LED灯交替闪烁

案例二.时钟输出与GPIO翻转

案例三.GPIO输入功能测试

案例四.GPIO中断功能测试

案例五.GPIO按键中断滤波

案例六.SWD引脚转换为GPIO

案例七.GPIO中断唤醒


一.GPIO概述

CW32F030C8T6是武汉芯源半导体推出的32位微控制器,基于ARM Cortex-M0内核。其GPIO(通用输入输出)模块支持多种功能配置,包括输入模式、输出模式、复用功能及模拟模式,适用于多种应用场景。


GPIO主要特性

  • 工作电压:1.8V至5.5V,兼容宽电压范围。
  • 驱动能力:每个IO口可配置为推挽或开漏输出,支持最大20mA sink/source电流。
  • 模式配置
    • 输入模式(浮空、上拉、下拉)。
    • 输出模式(推挽、开漏)。
    • 复用功能(UART、SPI、I2C等外设映射)。
    • 模拟模式(ADC输入)。
  • 中断支持:所有GPIO均可配置为外部中断触发源。

GPIO寄存器配置

  • GPIOx_DIR:控制方向(输入/输出)。
  • GPIOx_AF:配置复用功能。
  • GPIOx_PUPD:设置上拉/下拉电阻。
  • GPIOx_OD:开漏输出使能。

示例代码(配置GPIO为推挽输出):

#include "cw32f030_gpio.h"  // 包含CW32F030 GPIO模块的头文件void GPIO_Init() {// 定义GPIO初始化结构体变量GPIO_InitTypeDef GPIO_InitStruct;// 启用HSI时钟源,并设置分频系数为6RCC_HSI_Enable(RCC_HSIOSC_DIV6);// 使能GPIOB的时钟__RCC_GPIOB_CLK_ENABLE();// 配置GPIO初始化参数GPIO_InitStruct.IT = GPIO_IT_NONE;       // 不启用中断功能GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 设置为推挽输出模式GPIO_InitStruct.Pins = LED_GPIO_PINS;    // 指定需要初始化的GPIO引脚GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 设置GPIO输出速度为高速// 初始化指定的GPIO端口(LED_GPIO_PORT)和引脚GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);
}

二.案例 

案例一.LED灯交替闪烁

解析

代码实现LED闪烁程序,主要包含主函数main()和延时函数Delay()两部分。

主函数

/******************************************************************************** \brief  Main function of project**** \return uint32_t return value, if needed**** LED1, LED2闪烁********************************************************************************/
#define LED_GPIO_PORT CW_GPIOB  // 定义LED连接的GPIO端口为GPIOB
#define LED_GPIO_PINS GPIO_PIN_8 | GPIO_PIN_9  // 定义LED连接的引脚为PB8和PB9int32_t main(void)
{GPIO_InitTypeDef GPIO_InitStruct;  // 定义GPIO初始化结构体RCC_HSI_Enable(RCC_HSIOSC_DIV6);   // 启用HSI时钟,分频系数为6__RCC_GPIOB_CLK_ENABLE();          // 使能GPIOB时钟// 配置GPIO初始化参数GPIO_InitStruct.IT = GPIO_IT_NONE;        // 无中断触发GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出模式GPIO_InitStruct.Pins = LED_GPIO_PINS;     // 控制PB8和PB9引脚GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;  // GPIO高速模式GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct); // 初始化GPIOBwhile (1)  // 主循环{GPIO_TogglePin(LED_GPIO_PORT, LED_GPIO_PINS); // 翻转PB8和PB9引脚电平Delay(0xFFFF);  // 延时约65535个时钟周期}
}

延时函数

/******************************************************************************* @brief 循环延时** @param nCount 延时循环次数,值越大延时越长******************************************************************************/
void Delay(__IO uint16_t nCount)
{/* 递减nCount值直至为0 */while (nCount != 0){nCount--;  // 每次循环减少nCount}
}

案例二.时钟输出与GPIO翻转

解析:

代码实现从PA03/PA04输出系统时钟(HCLK/PCLK),并通过PA05管脚周期性电平翻转的功能。

/********************************************************************************** \brief  Main function of project**** \return uint32_t return value, if needed**** 从PA03/PA04输出HCLK及PCLK,并翻转PA05管脚********************************************************************************/
int32_t main(void)
{CW_SYSCTRL->AHBEN_f.GPIOA = 1;    // 使能GPIOA模块的时钟(AHB总线时钟)// 配置PA3、PA4、PA5为数字输出模式(关闭模拟功能)REGBITS_CLR(CW_GPIOA->ANALOG, bv3 | bv4 | bv5); // 清除ANALOG寄存器中的bv3/bv4/bv5位,关闭模拟功能// 配置PA3、PA4、PA5为输出方向(GPIO模式)REGBITS_CLR(CW_GPIOA->DIR, bv3 | bv4 | bv5);    // 清除DIR寄存器中的bv3/bv4/bv5位,设置为输出模式PA03_AFx_PCLKOUT();    // 将PA03复用为PCLK(外设时钟)输出功能PA04_AFx_HCLKOUT();    // 将PA04复用为HCLK(系统时钟)输出功能while (1){CW_GPIOA->TOG = bv5;    // 翻转PA05的输出电平(高变低/低变高)}
}

关键功能说明

  • 时钟使能CW_SYSCTRL->AHBEN_f.GPIOA = 1启用GPIOA模块的AHB总线时钟,确保GPIOA可以正常工作。

  • GPIO模式配置

    • ANALOG寄存器操作:关闭PA3/PA4/PA5的模拟功能,使其作为数字引脚。
    • DIR寄存器操作:设置PA3/PA4/PA5为输出方向。
  • 引脚复用

    • PA03_AFx_PCLKOUT():配置PA03为PCLK(外设时钟)输出引脚。
    • PA04_AFx_HCLKOUT():配置PA04为HCLK(系统主时钟)输出引脚。
  • 主循环:通过TOG寄存器持续翻转PA05的电平,产生周期性信号。

案例三.GPIO输入功能测试

解析

当PA08输入高电平时,PA0和PA1输出高电平,否则输出低电平。

当PA09输入高电平时,PA2固定输出高电平且PA3状态翻转,否则PA2输出低电平。

int32_t main(void)
{GPIO_InitTypeDef GPIO_InitStruct;  // 定义GPIO初始化结构体,用于配置引脚参数// 使能GPIOA时钟(AHB总线)CW_SYSCTRL->AHBEN_f.GPIOA = 1;    // 配置PA00-PA03为推挽输出模式(高速)GPIO_InitStruct.Pins = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;GPIO_Init(CW_GPIOA, &GPIO_InitStruct);// 配置PA08-PA09为上拉输入模式(无中断)GPIO_InitStruct.Pins = GPIO_PIN_8 | GPIO_PIN_9;GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP;GPIO_InitStruct.IT   = GPIO_IT_NONE;GPIO_Init(CW_GPIOA, &GPIO_InitStruct);while (1){//-----------------------------------------------------------------------// 函数调用方式实现GPIO控制// 检测PA08输入状态if (GPIO_ReadPin(CW_GPIOA, GPIO_PIN_8)) {// PA08为高电平时,设置PA0和PA1为高电平GPIO_WritePin(CW_GPIOA, GPIO_PIN_0 | GPIO_PIN_1, GPIO_Pin_SET); }else{// PA08为低电平时,清除PA0和PA1的电平GPIO_WritePin(CW_GPIOA, GPIO_PIN_0 | GPIO_PIN_1, GPIO_Pin_RESET);}//-----------------------------------------------------------------------// 宏定义方式实现GPIO控制// 检测PA09输入状态if (PA09_GETVALUE()) {// PA09为高电平时,设置PA02为高电平并切换PA03状态PA02_SETHIGH();PA03_TOG();  // TOG表示电平翻转(Toggle)}else{// PA09为低电平时,设置PA02为低电平PA02_SETLOW();}}
}

关键功能说明

  1. 时钟使能:必须先启用GPIOA的时钟才能操作对应外设。
  2. 初始化结构体:通过GPIO_InitTypeDef统一配置引脚模式、速度等参数。
  3. 模式选择
    • GPIO_MODE_OUTPUT_PP表示推挽输出
    • GPIO_MODE_INPUT_PULLUP表示内部上拉输入
  4. 两种操作方式
    • 标准库函数(如GPIO_WritePin
    • 封装宏(如PA02_SETHIGH()


案例四.GPIO中断功能测试

解析

代码实现按键控制LED开关,每次按键触发中断时对应LED状态切换。

宏定义部分

#define LED_GPIO_PORT CW_GPIOB  // LED连接的GPIO端口为B组  
#define LED_GPIO_PINS GPIO_PIN_8 | GPIO_PIN_9  // LED使用的具体引脚为PB8和PB9  
#define KEY_GPIO_PORT CW_GPIOA  // 按键连接的GPIO端口为A组  
#define KEY_GPIO_PINS GPIO_PIN_1 | GPIO_PIN_2  // 按键使用的具体引脚为PA1和PA2  

主函数初始化

int32_t main(void)  
{  GPIO_InitTypeDef GPIO_InitStruct;  // 定义GPIO配置结构体  __RCC_GPIOA_CLK_ENABLE();  // 使能GPIOA时钟  __RCC_GPIOB_CLK_ENABLE();  // 使能GPIOB时钟  // 配置按键引脚为输入模式  GPIO_InitStruct.IT = GPIO_IT_RISING | GPIO_IT_FALLING;  // 中断触发方式:上升沿和下降沿  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;  // 输入模式  GPIO_InitStruct.Pins = KEY_GPIO_PINS;  // 指定引脚PA1和PA2  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;  // 速度配置(输入模式下通常无效)  GPIO_Init(KEY_GPIO_PORT, &GPIO_InitStruct);  // 应用配置到GPIOA  // 配置LED引脚为输出模式  GPIO_InitStruct.IT = GPIO_IT_NONE;  // 无中断功能  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;  // 推挽输出模式  GPIO_InitStruct.Pins = LED_GPIO_PINS;  // 指定引脚PB8和PB9  GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);  // 应用配置到GPIOB  GPIOA_INTFLAG_CLR(bv1 | bv2);  // 清除GPIOA中断标志位(bv1/bv2代表具体引脚位)  NVIC_EnableIRQ(GPIOA_IRQn);  // 使能GPIOA中断向量  while (1) {}  // 主循环空转,实际逻辑在中断中处理  
}

中断服务函数

void GPIOA_IRQHandlerCallback(void)  
{  // 检测PA1是否触发中断  if (CW_GPIOA->ISR_f.PIN1) {  GPIOA_INTFLAG_CLR(bv1);  // 清除PA1中断标志  PB09_TOG();  // 翻转PB9引脚状态(控制LED)  }  // 检测PA2是否触发中断  if (CW_GPIOA->ISR_f.PIN2) {  GPIOA_INTFLAG_CLR(bv2);  // 清除PA2中断标志  PB08_TOG();  // 翻转PB8引脚状态(控制LED)  }  
}

关键功能说明

  • GPIO初始化:通过结构体配置引脚模式(输入/输出)、中断类型、速度等参数。
  • 中断配置:按键引脚设置为双边沿触发,LED引脚无中断。
  • 中断处理:检测具体引脚中断标志,清除标志后执行LED状态翻转(PB08_TOG()PB09_TOG()为宏定义的翻转操作)。
  • 硬件依赖:代码基于特定硬件库(如CW_GPIO),需确认库文件是否包含相关宏和函数。

案例五.GPIO按键中断滤波

解析

程序加入硬件中断滤波(150KHZ ,RC滤波) ,用于消除按键抖动(150K RC滤波)。

硬件定义

#define LED_GPIO_PORT CW_GPIOB       // LED连接的GPIO端口B
#define LED_GPIO_PINS GPIO_PIN_8 | GPIO_PIN_9  // LED使用的引脚8和9
#define KEY_GPIO_PORT CW_GPIOA       // 按键连接的GPIO端口A
#define KEY_GPIO_PINS GPIO_PIN_1 | GPIO_PIN_2  // 按键使用的引脚1和2

主函数初始化

int32_t main(void)
{GPIO_InitTypeDef GPIO_InitStruct;  // GPIO配置结构体// 启用GPIOA和GPIOB的时钟__RCC_GPIOA_CLK_ENABLE();__RCC_GPIOB_CLK_ENABLE();// 配置按键引脚为输入模式,启用上升沿和下降沿中断GPIO_InitStruct.IT = GPIO_IT_RISING | GPIO_IT_FALLING;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pins = KEY_GPIO_PINS;GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;GPIO_Init(KEY_GPIO_PORT, &GPIO_InitStruct);// 配置LED引脚为推挽输出模式,无中断GPIO_InitStruct.IT = GPIO_IT_NONE;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pins = LED_GPIO_PINS;GPIO_Init(LED_GPIO_PORT, &GPIO_InitStruct);// 配置GPIOA中断滤波(使用150K RC滤波)GPIO_ConfigFilter(CW_GPIOA, bv1, GPIO_FLTCLK_RC150K);// 清除PA1和PA2的中断标志,并启用NVIC中断GPIOA_INTFLAG_CLR(bv1 | bv2);NVIC_EnableIRQ(GPIOA_IRQn);while (1)  // 主循环保持空转,实际逻辑在中断中处理{}
}

中断回调函数

void GPIOA_IRQHandlerCallback(void)
{// 检测PA1是否触发中断(按键1动作)if (CW_GPIOA->ISR_f.PIN1){GPIOA_INTFLAG_CLR(bv1);  // 清除PA1中断标志PB09_TOG();              // 切换PB9(LED1)的状态}// 检测PA2是否触发中断(按键2动作)if (CW_GPIOA->ISR_f.PIN2){GPIOA_INTFLAG_CLR(bv2);  // 清除PA2中断标志PB08_TOG();              // 切换PB8(LED2)的状态}
}

关键功能说明

  1. 中断配置:按键引脚配置为双沿触发中断,LED引脚为输出模式。
  2. 滤波设置GPIO_ConfigFilter用于消除按键抖动(150K RC滤波)。
  3. 中断处理:在回调函数中通过ISR_f.PINx检测具体中断源,并清除对应标志位。
  4. LED控制PB08_TOG()PB09_TOG()直接切换对应引脚电平。

案例六.SWD引脚转换为GPIO

主函数实现

int32_t main(void)
{uint32_t tmp32; // 用于存储临时时间戳的变量// 初始化系统滴答定时器,设置频率为8MHz,每毫秒中断一次InitTick(8000000); // 延时2000毫秒(2秒),确保系统稳定后再操作SWD引脚SysTickDelay(2000);// 启用GPIOA的时钟CW_SYSCTRL->AHBEN_f.GPIOA = 1;// 将PA13和PA14从SWD功能切换为普通GPIO功能GPIO_SWD2GPIO();// 配置PA13和PA14为数字模式(非模拟)REGBITS_CLR(CW_GPIOA->ANALOG, bv13 | bv14);// 配置PA13和PA14为输出模式REGBITS_CLR(CW_GPIOA->DIR, bv13 | bv14);// 设置10秒超时时间点tmp32 = GetTick() + 10000;// 在10秒内循环操作GPIO引脚while (GetTick() < tmp32){PA13_SETHIGH(); // PA13输出高电平PA14_SETHIGH(); // PA14输出高电平PA14_SETLOW();  // PA14输出低电平PA13_SETLOW();  // PA13输出低电平PA14_SETHIGH(); // PA14输出高电平PA14_SETLOW();  // PA14输出低电平}// 重新配置PA13和PA14为UART功能REGBITS_CLR(CW_GPIOA->ANALOG, bv13 | bv14);       // 确保数字模式REGBITS_MODIFY(CW_GPIOA->DIR, bv13 | bv14, bv13); // PA13输入,PA14输出PA13_AFx_UART1RXD();                              // PA13映射为UART1接收PA14_AFx_UART1TXD();                              // PA14映射为UART1发送// 主循环(空操作)while (1){;}
}

系统滴答中断处理

void SysTick_Handler(void)
{/* 系统时钟计数器递增 */uwTick += uwTickFreq;
}

代码功能说明:

  1. 系统启动后先进行2秒延时确保稳定
  2. 将调试用的SWD引脚转换为GPIO功能
  3. 进行10秒的GPIO电平切换测试
  4. 最终将引脚配置为UART通信功能
  5. 系统滴答定时器中断服务程序维护全局计时器

案例七.GPIO中断唤醒

解析

程序默认配置进入睡眠模式,由按键(GPIO下降沿)中断唤醒,输出唤醒次数

增加:LSI时钟滤波防止按键误触发

GPIO初始化配置

#define KEY_GPIO_PORT CW_GPIOA          // 定义按键使用的GPIO端口为GPIOA
#define KEY_GPIO_PINS GPIO_PIN_1 | GPIO_PIN_2  // 定义按键使用的引脚为PA1和PA2
int32_t main(void)
{uint8_t tmp8;                      // 用于计数唤醒次数的临时变量GPIO_InitTypeDef GPIO_InitStruct;  // GPIO初始化结构体__RCC_GPIOA_CLK_ENABLE();         // 使能GPIOA时钟__RCC_GPIOB_CLK_ENABLE();         // 使能GPIOB时钟// 配置PA1和PA2为输入模式,下降沿触发中断GPIO_InitStruct.IT = GPIO_IT_FALLING;  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pins = KEY_GPIO_PINS;GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;GPIO_Init(KEY_GPIO_PORT, &GPIO_InitStruct);// 配置GPIOB高8位为推挽输出模式GPIO_InitStruct.IT = GPIO_IT_NONE;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pins = 0xFF00;GPIO_Init(CW_GPIOB, &GPIO_InitStruct);

中断配置与唤醒逻辑

    // 配置GPIOA中断滤波为LSI时钟,抑制短脉冲干扰GPIO_ConfigFilter(CW_GPIOA, bv1 | bv2, GPIO_FLTCLK_LSI);PB09_SETHIGH();                   // 设置PB9输出高电平(具体用途取决于硬件设计)// 等待PA1引脚变为低电平,防止直接进入深度睡眠导致调试锁死while (PA01_GETVALUE());GPIO_HighByte_Write(CW_GPIOB, 0); // 初始化GPIOB高8位输出为0// 清除PA1和PA2的中断标志位,并开启NVIC中断GPIOA_INTFLAG_CLR(bv1 | bv2);NVIC_EnableIRQ(GPIOA_IRQn);tmp8 = 0x00;                      // 唤醒计数器清零

主循环与低功耗处理

    while (1){SCB->SCR = 0x04;             // 设置系统控制寄存器,允许深度睡眠__WFI();                     // 进入睡眠模式,等待中断唤醒tmp8++;                      // 唤醒后计数器递增GPIO_HighByte_Write(CW_GPIOB, tmp8); // 输出唤醒次数到GPIOB高8位}
}

中断服务函数

void GPIOA_IRQHandlerCallback(void)
{if (CW_GPIOA->ISR_f.PIN1)       // 检查PA1中断标志{GPIOA_INTFLAG_CLR(bv1);     // 清除PA1中断标志}if (CW_GPIOA->ISR_f.PIN2)       // 检查PA2中断标志{GPIOA_INTFLAG_CLR(bv2);     // 清除PA2中断标志}
}

关键功能说明

  • 低功耗设计:通过__WFI()指令进入睡眠模式
  • 抗干扰处理:使用LSI时钟滤波防止误触发
  • 调试保护:进入深度睡眠前检查GPIO状态避免锁死
  • 状态指示:GPIOB高8位输出唤醒次数,便于调试观测