一.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时钟源,并设置分频系数为6
RCC_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和PB9
int32_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); // 初始化GPIOB
while (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();
}
}
}
关键功能说明
时钟使能:必须先启用GPIOA的时钟才能操作对应外设。
初始化结构体:通过GPIO_InitTypeDef统一配置引脚模式、速度等参数。
模式选择:
GPIO_MODE_OUTPUT_PP表示推挽输出
GPIO_MODE_INPUT_PULLUP表示内部上拉输入
两种操作方式:
标准库函数(如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)的状态
}
}
关键功能说明
中断配置:按键引脚配置为双沿触发中断,LED引脚为输出模式。
滤波设置:GPIO_ConfigFilter用于消除按键抖动(150K RC滤波)。
中断处理:在回调函数中通过ISR_f.PINx检测具体中断源,并清除对应标志位。
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;
}
代码功能说明:
系统启动后先进行2秒延时确保稳定
将调试用的SWD引脚转换为GPIO功能
进行10秒的GPIO电平切换测试
最终将引脚配置为UART通信功能
系统滴答定时器中断服务程序维护全局计时器
案例七.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位输出唤醒次数,便于调试观测
————————————————
版权声明:本文为CSDN博主「brave and determined」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43260261/article/details/148913921
|