本帖最后由 LIZARD925 于 2025-6-22 00:24 编辑
#技术资源# #申请原创#
APM32E030系列使用记录--GPIO的使用
我将极海官网APME030的例程,根据B站江科大的例程,新建了一个工程模版,在这里介绍一下模板的结构,并说明如何在这个工程模板上进行GPIO的操作,如点灯、按键等,例程已上传附件,仅供参考。
工程模板的介绍:
1、DebugConfig
2、library
3、Listings
4、Objects
5、start
6、user
模版分为这六个文件夹,其中DebugConfig、Listings和Objects文件夹是 Keil MDK 5 自动生成的,DebugConfig文件夹用于存储一些调试配置文件,Listings和Objects文件夹用来存储 Keil MDK 5 编译过程的一些中间文件;library文件夹下放的是APM32E030用到的驱动标准库文件,不需要改;start文件下放的是外设寄存器文件、内核寄存器描述文件、时钟文件等,也不需要更改;user文件夹下,存放中断函数与主函数,可根据自己喜好进行添加。
GPIO操作之点亮LED灯:
我们先打开工程模版,新建一个system 的文件夹,放我们的延时函数,延时函数使用 系统嘀嗒定时器 进行实现,文件添加完成后,记得在工程中添加文件的路径

将延时函数复制过来即可使用,添加进工程后,如图所示
#include "apm32e030.h" // Device header
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
此时我们写一个简单的IO翻转来测试延时函数的准确性,使用逻辑分析仪进行测量,可看到时间和我们设置的时间相差无几,IO的初始化也可参考例程进行更改
int main (void)
{
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOB); //打开GPIOB的时钟
GPIO_Config_T GPIO_InitStructure;
GPIO_InitStructure.mode = GPIO_MODE_OUT; // 输出模式
GPIO_InitStructure.pin = GPIO_PIN_6;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.outtype = GPIO_OUT_TYPE_PP; //推挽输出
GPIO_Config(GPIOB,&GPIO_InitStructure);
while(1)
{
Delay_ms(500);
GPIO_WriteBitValue(GPIOB,GPIO_PIN_6,0);
Delay_ms(500);
GPIO_WriteBitValue(GPIOB,GPIO_PIN_6,1);
}
}
此时可看到延时函数没问题,我们将点灯程序进行封装,添加hardware文件夹,放入led.c\led.h文件,如图所示,硬件原理图在此链接进行下载:
https://www.geehy.com/uploads/tool/APM32E030R%20Micro-EVB%20V1.0.SchDoc.pdf
添加好后,我们根据原理图初始化对应的GPIO口,初始化PB6和PB7这个两个引脚,调用后测试无误,为流水灯的现象,具体代码如下:



#include "LED.h"
void LED_init(void)
{
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOB); //打开GPIOB的时钟
GPIO_Config_T GPIO_InitStructure;
GPIO_InitStructure.mode = GPIO_MODE_OUT; // 输出模式
GPIO_InitStructure.pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.outtype = GPIO_OUT_TYPE_PP; //推挽输出
GPIO_Config(GPIOB,&GPIO_InitStructure);
GPIO_SetBit(GPIOB, GPIO_PIN_6|GPIO_PIN_7); //初始化LED为灭
}
void LED1_on(void)
{
GPIO_ClearBit(GPIOB,GPIO_PIN_6); //亮
}
void LED1_off(void)
{
GPIO_SetBit(GPIOB,GPIO_PIN_6); //灭
}
void LED2_on(void)
{
GPIO_ClearBit(GPIOB,GPIO_PIN_7); //亮
}
void LED2_off(void)
{
GPIO_SetBit(GPIOB,GPIO_PIN_7); //灭
}
void LED1_turn(void)
{
if(GPIO_ReadOutputBit(GPIOB,GPIO_PIN_6)==0) //电平反转
{
GPIO_SetBit(GPIOB,GPIO_PIN_6);
}
else
{
GPIO_ClearBit(GPIOB,GPIO_PIN_6);
}
}
void LED2_turn(void)
{
if(GPIO_ReadOutputBit(GPIOB,GPIO_PIN_7)==0) //电平反转
{
GPIO_SetBit(GPIOB,GPIO_PIN_7);
}
else
{
GPIO_ClearBit(GPIOB,GPIO_PIN_7);
}
}
#ifndef __LED_H__
#define __LED_H__
#include "apm32e030.h" // Device header
#include "apm32e030_gpio.h"
#include "apm32e030_rcm.h"
void LED_init(void);
void LED1_on(void);
void LED1_off(void);
void LED2_on(void);
void LED2_off(void);
void LED1_turn(void);
void LED2_turn(void);
#endif
#include "apm32e030.h" // Device header
#include "Delay.h"
#include "LED.h"
int main (void)
{
LED_init();
while(1)
{
LED1_turn();
Delay_ms(500);
LED2_turn();
}
}
GPIO操作之按键输入
此例程主要验证APM32E030的GPIO输入功能,对于普通的按键检测,只需初始化GPIO为输入模式,并配置引脚上下拉,在while1中一直读取即可,GPIO初始化:
void key_init(void)
{
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA); //打开GPIOA的时钟
GPIO_Config_T GPIO_InitStructure;
GPIO_InitStructure.mode = GPIO_MODE_IN; // 输入模式
GPIO_InitStructure.pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.pupd = GPIO_PUPD_PU; //上拉输入
GPIO_Config(GPIOA,&GPIO_InitStructure);
}
进行按键的消抖与按键状态的读取,使用的都是通用的函数:
uint8_t key_getnum(void)
{
uint8_t keynum=0;
if(GPIO_ReadInputBit(GPIOA,GPIO_PIN_0)==0)//判断按键是否按下
{
Delay_ms(10);
while(GPIO_ReadInputBit(GPIOA,GPIO_PIN_0)==0);
Delay_ms(10);
keynum=1;
}
if(GPIO_ReadInputBit(GPIOA,GPIO_PIN_1)==0)//判断按键是否按下
{
Delay_ms(10);
while(GPIO_ReadInputBit(GPIOA,GPIO_PIN_1)==0);
Delay_ms(10);
keynum=2;
}
return keynum;
}
此时只需在主函数中调用读取,进行按键的判断
GPIO操作之按键中断输入
对于外部中断输入的验证,我们需要打开引脚的复用,并打开 SYSCFG 时钟,配置中断线与触发边沿,并设置中断优先级为15;
用户手册中也有对SYSCFG 的介绍:主要用于管理地址映射和控制中断,具体是指:控制部分 IO 口上的I2C 的超快模式;TMR16,TMR17,USART1 和 ADC 的 DMA 触发源的重映射;存储器到代码起始区的重映射;管理连接到 GPIO 的外部中断
void key_eint_init(void) //中断按键
{
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA); //打开GPIOA的时钟
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
GPIO_Config_T GPIO_InitStructure;
GPIO_InitStructure.mode = GPIO_MODE_IN; // 输入模式
GPIO_InitStructure.pin = GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.pupd = GPIO_PUPD_PU; //上拉输入
GPIO_Config(GPIOA,&GPIO_InitStructure);
SYSCFG_EINTLine(SYSCFG_PORT_GPIOA, SYSCFG_PIN_0); //跟管脚
SYSCFG_EINTLine(SYSCFG_PORT_GPIOA, SYSCFG_PIN_1);
EINT_Config_T EXTI_InitStructure;
EXTI_InitStructure.line = EINT_LINE0|EINT_LINE1;
EXTI_InitStructure.lineCmd = ENABLE;
EXTI_InitStructure.mode = EINT_MODE_INTERRUPT;
EXTI_InitStructure.trigger = EINT_TRIGGER_FALLING;
EINT_Config(&EXTI_InitStructure);
NVIC_EnableIRQRequest(EINT0_1_IRQn, 0x0f);
}
此时,即可使用中断的方式进行按键的读取,在中断中加入自己的逻辑:
void EINT0_1_IRQHandler(void)
{
if (EINT_ReadStatusFlag(EINT_LINE0) == SET)
{
EINT_ClearStatusFlag(EINT_LINE0);
LED1_turn();
}
if (EINT_ReadStatusFlag(EINT_LINE1) == SET)
{
EINT_ClearStatusFlag(EINT_LINE1);
LED2_turn();
}
}
外部中断的中断函数具体在此处:
具体的中断可看用户手册:
|