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

发布于:2025-06-27 ⋅ 阅读:(18) ⋅ 点赞:(0)

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

目录

一.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时钟源,并设置分频系数为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();
        }
    }
}

关键功能说明

  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位输出唤醒次数,便于调试观测

 


网站公告

今日签到

点亮在社区的每一天
去签到