公司动态

【飞控系列教程·③】GPIO入门与LED点亮:CH582F寄存器操作与SDK API编程详解

📅 2026/7/27 7:18:01
【飞控系列教程·③】GPIO入门与LED点亮:CH582F寄存器操作与SDK API编程详解
GPIOGeneral Purpose Input/Output通用输入/输出是微控制器最基本、最常用的外设功能。本章将以点亮控制板上的LED灯为切入点系统学习CH582F的GPIO工作原理、寄存器配置和编程方法。3.1 GPIO工作原理3.1.1 什么是GPIOGPIO是微控制器上可以软件配置为输入或输出模式的数字信号引脚。作为输出时GPIO引脚可以输出高电平通常为VCC如3.3V或低电平0V作为输入时GPIO引脚可以读取外部施加的电平信号。GPIO的应用非常广泛包括但不限于1控制LED的亮灭——输出模式。2读取按键状态——输入模式。3驱动蜂鸣器——输出模式产生方波。4与外部芯片通信——复用为UART/SPI/I2C等功能。3.1.2 GPIO输出模式GPIO作为输出使用时主要有两种驱动方式推挽输出Push-Pull Output推挽输出由两个MOSFET一个P-MOS和一个N-MOS组成。输出高电平时P-MOS导通输出低电平时N-MOS导通。推挽输出的优点是驱动能力强可以直接驱动LED等负载。CH582F的GPIO推挽输出可提供最大20mA的驱动电流。开漏输出Open-Drain Output开漏输出只有N-MOS管只能输出低电平高电平需要外接上拉电阻。开漏输出常用于I2C总线等需要线与逻辑的场合。3.1.3 GPIO输入模式GPIO作为输入使用时有以下几种配置方式浮空输入Floating Input引脚内部既不接上拉电阻也不接下拉电阻电平完全由外部电路决定。浮空输入模式下引脚容易受到干扰一般不推荐在按键等应用中使用。上拉输入Pull-Up Input引脚内部连接一个上拉电阻到VCC。无外部信号时引脚读取为高电平当外部将引脚拉低时读取为低电平。上拉输入常用于按键检测按键一端接地另一端接GPIO。下拉输入Pull-Down Input引脚内部连接一个下拉电阻到GND。无外部信号时引脚读取为低电平。适用于按键接VCC的场景。3.2 CH582F的GPIO寄存器详解CH582F有两组GPIO端口GPIOAPA0PA15共16个引脚和GPIOBPB0PB15共16个引脚。每组GPIO都有若干控制寄存器用于配置引脚的工作模式和读写引脚状态。3.2.1 方向寄存器DIR方向寄存器用于设置每个GPIO引脚是作为输入还是输出。寄存器名称R32_GPIOA_DIRGPIOA方向寄存器R32_GPIOB_DIRGPIOB方向寄存器。位宽每个位对应一个引脚。0 输入模式1 输出模式。寄存器地址偏移位域说明R32_GPIOA_DIRGPIOA基址0x00bit[15:0]PA15~PA0方向: 0输入, 1输出R32_GPIOB_DIRGPIOB基址0x00bit[15:0]PB15~PB0方向: 0输入, 1输出3.2.2 输出数据寄存器输出数据寄存器用于设置GPIO引脚的输出电平。操作寄存器/操作说明置位输出高电平R32_GPIOA_SET / GPIOA_SetBits()写1的位对应引脚输出高电平清零输出低电平R32_GPIOA_CLR / GPIOA_ResetBits()写1的位对应引脚输出低电平翻转输出R32_GPIOA_OUT ^ mask异或操作翻转指定位3.2.3 输入数据寄存器输入数据寄存器用于读取GPIO引脚当前的电平状态。寄存器名称R32_GPIOA_IN读取GPIOA输入R32_GPIOB_IN读取GPIOB输入。读取方式直接读取寄存器值对应位为1表示高电平为0表示低电平。3.2.4 上拉/下拉配置寄存器CH582F的GPIO支持内部上拉和下拉电阻的配置寄存器名称R32_GPIOA_PUGPIOA上拉使能R32_GPIOA_PDGPIOA下拉使能。位操作写1使能对应引脚的上拉/下拉电阻写0禁用。3.2.5 功能复用寄存器CH582F的许多GPIO引脚具有复用功能如UART TX/RX、SPI MOSI/MISO、PWM输出等。功能复用通过以下寄存器选择寄存器说明取值R32_GPIOA_FUN_MODEGPIOA引脚功能选择00GPIO, 01功能1, 10功能2, 11功能3R32_GPIOB_FUN_MODEGPIOB引脚功能选择00GPIO, 01功能1, 10功能2, 11功能3ℹ️**** 注意使用GPIO功能时需要确保引脚的功能复用寄存器设置为GPIO模式00。如果引脚被配置为其他功能如UART TX则GPIO输出操作将无效。3.2.6 SDK API函数总结CH582F的SDK提供了一系列封装好的GPIO操作函数简化了寄存器操作函数名称功能描述示例调用GPIOA_ModeCfg(pins, mode)配置GPIOA引脚工作模式GPIOA_ModeCfg(GPIO_Pin_12, GPIO_ModeOut_PP_20mA)GPIOB_ModeCfg(pins, mode)配置GPIOB引脚工作模式GPIOB_ModeCfg(GPIO_Pin_4, GPIO_ModeIN_PU)GPIOA_SetBits(pins)GPIOA指定引脚输出高电平GPIOA_SetBits(GPIO_Pin_12)GPIOA_ResetBits(pins)GPIOA指定引脚输出低电平GPIOA_ResetBits(GPIO_Pin_12)GPIOA_InvertBits(pins)GPIOA指定引脚输出翻转GPIOA_InvertBits(GPIO_Pin_12)GPIOA_ReadPortPin(pins)读取GPIOA指定引脚电平val GPIOA_ReadPortPin(GPIO_Pin_0)GPIOB_SetBits(pins)GPIOB指定引脚输出高电平GPIOB_SetBits(GPIO_Pin_10)GPIOB_ResetBits(pins)GPIOB指定引脚输出低电平GPIOB_ResetBits(GPIO_Pin_10)GPIOB_ReadPortPin(pins)读取GPIOB指定引脚电平val GPIOB_ReadPortPin(GPIO_Pin_4)GPIO模式常量模式常量名含义GPIO_ModeIN_Floating浮空输入无上下拉GPIO_ModeIN_PU上拉输入内部上拉电阻GPIO_ModeIN_PD下拉输入内部下拉电阻GPIO_ModeOut_PP_20mA推挽输出最大20mA驱动GPIO_ModeOut_PP_5mA推挽输出最大5mA驱动GPIO_ModeOut_OD_20mA开漏输出最大20mA3.3 电路原理分析3.3.1 LED驱动电路本控制板上的4个LED指示灯采用以下驱动方式GPIO引脚 → 限流电阻约1kΩ → LED阳极 → LED阴极 → GND这是一种高电平驱动Active High的接法当GPIO输出高电平时LED两端产生正向压降电流从GPIO经限流电阻和LED流向GNDLED点亮当GPIO输出低电平时LED两端无压差LED熄灭。限流电阻的计算假设LED正向压降VF 2.0V红色LEDGPIO输出电压VOH 3.3V期望LED电流IF 5mAR (VOH - VF) / IF (3.3V - 2.0V) / 5mA 260Ω实际电路中选用1kΩ电阻LED电流约1.3mA亮度适中且更加节能。3.3.2 LED对应的GPIO引脚根据1.3.5节的引脚分配表四个LED对应的GPIO引脚为LED编号位置GPIO引脚控制方式LED1前左PB15高电平点亮LED2前右PA11高电平点亮LED3后左PA14高电平点亮LED4后右PB4高电平点亮ℹ️**** 注意在后续代码中我们将使用这四个LED进行各种灯光效果的演示。掌握LED的控制是后续飞控状态指示功能的基础。3.4 代码实现LED闪烁下面我们将实现第一个完整的嵌入式程序——让控制板上的一个LED以固定频率闪烁。这是嵌入式开发中的Hello World程序。3.4.1 方法一使用SDK API函数推荐SDK提供了封装好的GPIO操作函数使用简单且代码可读性好。/*** LED闪烁实验 —— 使用SDK API* 目标让LED1PB15以500ms间隔交替亮灭* 硬件LED1阳极经1kΩ电阻接PA4阴极接GND*/#include “CH58x_common.h”int main(void){/* 第一步配置系统时钟为PLL 60MHz */SetSysClock(CLK_SOURCE_PLL_60MHz);/* 第二步配置PA4为推挽输出模式驱动能力20mA *//* GPIO_Pin_4 是SDK预定义的宏值为 (14) 0x0010 */GPIOA_ModeCfg(GPIO_Pin_4, GPIO_ModeOut_PP_20mA);/* 第三步初始状态——关闭LED输出低电平 */GPIOA_ResetBits(GPIO_Pin_4);/* 第四步进入主循环不断翻转LED状态 */while(1){/* 翻转PA4引脚的输出电平 */GPIOA_InvertBits(GPIO_Pin_4);/* 延时500毫秒 */DelayMs(500);}}代码逐行解析第1行#include “CH58x_common.h” 引入CH58x系列所有公共头文件包括GPIO、时钟、延时等函数声明。第8行SetSysClock() 函数配置系统主时钟。CLK_SOURCE_PLL_60MHz 表示使用PLL倍频到60MHz。时钟配置必须在所有外设操作之前完成。第12行GPIOA_ModeCfg() 函数配置指定引脚的工作模式。第一个参数GPIO_Pin_4指定要配置的引脚可以是多个引脚的或组合第二个参数GPIO_ModeOut_PP_20mA表示推挽输出、20mA驱动能力。第15行GPIOA_ResetBits() 将PA4引脚输出设置为低电平0VLED初始状态为关闭。第21行GPIOA_InvertBits() 翻转PA4的当前输出电平——如果当前是高电平则变为低电平反之亦然。第24行DelayMs(500) 软件延时500毫秒。该函数在SDK中实现通过循环计数产生近似延时。3.4.2 方法二直接操作寄存器为了深入理解GPIO的底层工作原理下面演示如何通过直接读写寄存器来控制LED。/*** LED闪烁实验 —— 直接寄存器操作* 通过直接读写GPIO寄存器来控制PA4*/#include “CH58x_common.h”/* 定义PA4的位掩码 */#define LED1_PIN (1 4) /* PA4对应bit4 */int main(void){SetSysClock(CLK_SOURCE_PLL_60MHz);/* 配置PA4为输出模式设置DIR寄存器bit4为1 */R32_GPIOA_DIR | LED1_PIN;/* 初始输出低电平使用CLR寄存器清零bit4 */R32_GPIOA_CLR LED1_PIN;while(1){/* 输出高电平LED点亮 */R32_GPIOA_SET LED1_PIN;DelayMs(500);/* 输出低电平LED熄灭 */R32_GPIOA_CLR LED1_PIN;DelayMs(500);}}寄存器操作解析R32_GPIOA_DIR | LED1_PIN将方向寄存器的bit4置1设置PA4为输出模式。使用或操作可以只修改目标位而不影响其他引脚的配置。R32_GPIOA_SET LED1_PINSET寄存器是写1置位类型向某位写1会将对应引脚的输出设为高电平写0无效果。因此可以直接赋值不需要或操作。R32_GPIOA_CLR LED1_PINCLR寄存器是写1清零类型向某位写1会将对应引脚的输出设为低电平。编程建议在实际项目中推荐使用SDK API函数进行GPIO操作代码可读性更好、可移植性更强。寄存器直接操作适用于对性能有极致要求的场合或者在调试底层问题时使用。3.4.3 同时控制多个LEDSDK API支持同时配置和操作多个引脚只需将引脚常量进行或运算/* 同时配置4个LED引脚为输出模式 */GPIOA_ModeCfg(GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_12 | GPIO_Pin_13,GPIO_ModeOut_PP_20mA);/* 同时点亮4个LED */GPIOA_SetBits(GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_12 | GPIO_Pin_13);/* 同时熄灭4个LED */GPIOA_ResetBits(GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_12 | GPIO_Pin_13);/* 同时翻转4个LED */GPIOA_InvertBits(GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_12 | GPIO_Pin_13);3.5 实验与练习实验一不同频率闪烁修改LED闪烁程序让LED以不同的频率闪烁观察并记录效果1快速闪烁亮灭各100ms。2中速闪烁亮灭各500ms示例代码中的默认频率。3慢速闪烁亮灭各1000ms1秒。4不均匀闪烁亮200ms、灭800ms类似心跳灯效果。/* 实验一参考代码不均匀闪烁心跳灯效果 */while(1){GPIOA_SetBits(GPIO_Pin_4); /* LED亮 */DelayMs(200); /* 亮200ms */GPIOA_ResetBits(GPIO_Pin_4); /* LED灭 */DelayMs(800); /* 灭800ms */}实验二交替闪烁编写程序让LED1PA4和LED2PA5交替闪烁当LED1亮时LED2灭当LED1灭时LED2亮。/* 实验二参考代码LED1和LED2交替闪烁 */#includeCH58x_common.hintmain(void){GPIOA_ModeCfg(GPIO_Pin_11,GPIO_ModeOut_PP_5mA);// PA11---RLED_R;GPIOB_ModeCfg(GPIO_Pin_15,GPIO_ModeOut_PP_5mA);// PB15---RLED_L;GPIOA_ModeCfg(GPIO_Pin_14,GPIO_ModeOut_PP_5mA);// PA14---GLED_LGPIOB_ModeCfg(GPIO_Pin_4,GPIO_ModeOut_PP_5mA);// PB4----GLED_R;GPIOB_SetBits(GPIO_Pin_4|GPIO_Pin_15);GPIOA_SetBits(GPIO_Pin_11|GPIO_Pin_14);while(1){GPIOB_ResetBits(GPIO_Pin_15);DelayMs(30);GPIOB_SetBits(GPIO_Pin_15);GPIOA_ResetBits(GPIO_Pin_11);DelayMs(30);GPIOA_SetBits(GPIO_Pin_11);}}实验三四灯依次点亮编写程序让4个LED按照LED1→LED2→LED3→LED4的顺序依次点亮每次只有一个LED亮间隔300ms形成流水灯效果的雏形。#includeCH58x_common.hintmain(void){GPIOA_ModeCfg(GPIO_Pin_11,GPIO_ModeOut_PP_5mA);// PA11---RLED_R;GPIOB_ModeCfg(GPIO_Pin_15,GPIO_ModeOut_PP_5mA);// PB15---RLED_L;GPIOA_ModeCfg(GPIO_Pin_14,GPIO_ModeOut_PP_5mA);// PA14---GLED_LGPIOB_ModeCfg(GPIO_Pin_4,GPIO_ModeOut_PP_5mA);// PB4----GLED_R;GPIOB_SetBits(GPIO_Pin_4|GPIO_Pin_15);GPIOA_SetBits(GPIO_Pin_11|GPIO_Pin_14);GPIOB_SetBits(GPIO_Pin_4|GPIO_Pin_15);GPIOA_SetBits(GPIO_Pin_11|GPIO_Pin_14);while(1){GPIOB_ResetBits(GPIO_Pin_15);DelayMs(30);GPIOB_SetBits(GPIO_Pin_15);GPIOA_ResetBits(GPIO_Pin_11);DelayMs(30);GPIOA_SetBits(GPIO_Pin_11);GPIOA_ResetBits(GPIO_Pin_14);DelayMs(30);GPIOA_SetBits(GPIO_Pin_14);GPIOB_ResetBits(GPIO_Pin_4);DelayMs(30);GPIOB_SetBits(GPIO_Pin_4);}}实验四闪烁次数计数编写程序让LED闪烁10次后停止闪烁并保持常亮状态。使用一个计数变量记录闪烁次数。/* 实验四参考框架 */#includeCH58x_common.h#includeLED.huint8_tTxBuff[]This is a tx exam\r\n;uint8_tRxBuff[100];uint8_ttrigB;/********************************************************************* * fn main * * brief 主函数 * * return none */intmain(){uint8_ti;// 计数变量记录闪烁次数LED_Init();// 闪烁10次for(i0;i10;i){RGB_LED_ON();DelayMs(30);// 亮30msRGB_LED_Off();DelayMs(30);// 灭30ms}// 闪烁完毕保持常亮RGB_LED_ON();while(1){// 空循环保持常亮状态}}**** 实验拓展挑战能否实现LED的SOS闪烁模式即短闪3次亮200ms灭200ms、长闪3次亮600ms灭200ms、再短闪3次然后暂停2秒后重复。这是嵌入式编程中经典的练习题目。学习资源B站系列视频教程手把手教你从零组装无人机百度网盘资料包SDK、教材PDF、完整源码点击下载 提取码: JZS8本系列持续更新欢迎收藏关注。如有问题欢迎在评论区交流。