知识点
1. GPIO控制
2. LED灯驱动原理
3. 按键检查原理
硬件部分
如上图,LED灯负极接地,正极通过470欧电阻后,接到了MCU的引脚上。可以看出,当MCU的GPIO口输出
高电平时LED亮,
低电平时LED灭。
如上图,
当按键弹起时,GPIO接在3.3V上,为高电平
当按键按下时,GPIO接到地上,为低电平
注意:
- 原理图中的K1,K2,K3分别对应板子上的K2,K3,K4,本文都是按原理图描述
- 0.1uF电容作用去抖动
功能设计
设计一个小功能,KEY3按下 4个LED灯亮,弹起时4个LED灭。子功能设计包括,
1. 功能状态设计
如上图,该功能一共要经历上面几个状态,从而也就明白我们需要提供哪些功能函数,细节读下面的代码。
static VOID LED_Init(VOID)
{
DRV_LED_Init();
DRV_KEY_Init();
}
static VOID LED_SetLedStatus(IN U8 status)
{
if (DRV_KEY_DOWN == status)
{
DRV_LED_On(DRV_LED1);
DRV_LED_On(DRV_LED2);
DRV_LED_On(DRV_LED3);
DRV_LED_On(DRV_LED4);
}
else if (DRV_KEY_UP == status)
{
DRV_LED_Off(DRV_LED1);
DRV_LED_Off(DRV_LED2);
DRV_LED_Off(DRV_LED3);
DRV_LED_Off(DRV_LED4);
}
else
{
;
}
}
static VOID LED_CheckKeyStatus(VOID)
{
U8 keyStatus = 0;
keyStatus = DRV_KEY_GetStatus(DRV_KEY3);
if (DRV_KEY_DOWN == keyStatus)
{
APP_Delay(50); /* 50ms去抖动 */
keyStatus = DRV_KEY_GetStatus(DRV_KEY3);
if (DRV_KEY_DOWN == keyStatus)
{
LED_SetLedStatus(DRV_KEY_DOWN);
}
}
else
{
LED_SetLedStatus(DRV_KEY_UP);
}
}
VOID APP_LED_Test(VOID)
{
LED_Init();
LED_SetLedStatus(DRV_KEY_UP);
while (1)
{
LED_CheckKeyStatus();
}
}
2. 定时器设计
1. 采用systick作为功能定时器,初始配置成1ms一次中断
2. 提供delay延时函数
static U32 gDrvSystickDelayCount = 0;
S32 DRV_SYSTICK_Init(VOID)
{
/* 1000Hz,1ms中断一次 */
if (SysTick_Config(SystemCoreClock / 1000))
{
return OS_ERROR;
}
NVIC_SetPriority(SysTick_IRQn, 0x00);
return OS_OK;
}
/* 1ms中断一次 */
VOID SysTick_Handler(VOID)
{
if (gDrvSystickDelayCount > 0)
{
gDrvSystickDelayCount--;
}
}
VOID DRV_SYSTICK_Delay(IN U32 ms)
{
gDrvSystickDelayCount = ms;
while (1)
{
if (gDrvSystickDelayCount <= 0)
{
break;
}
}
return;
}
3. LED驱动
- 提供初始化函数接口
- 提供LED on/off接口
#define DRV_LED1 GPIOC,GPIO_PIN_0
#define DRV_LED2 GPIOC,GPIO_PIN_2
#define DRV_LED3 GPIOE,GPIO_PIN_0
#define DRV_LED4 GPIOE,GPIO_PIN_1
#define DRV_LED_On(led) GPIO_SetBits(led);
#define DRV_LED_Off(led) GPIO_ResetBits(led);
extern void DRV_LED_Init(void);
4. 按键驱动
- 提供初始化接口
- 提供获取按键状态接口
#define DRV_KEY3 GPIOB, GPIO_PIN_14
#define DRV_KEY_GetStatus(key) GPIO_ReadInputBit(key)
#define DRV_KEY_DOWN 0
#define DRV_KEY_UP 1
extern VOID DRV_KEY_Init(VOID);
总结
IO配置总结(配置时钟(必配)–>选择复用(选配)–>选择模式(必配)–>配置速率(必配)):
-
判断是GPIO(通用IO)和AFIO(复用IO),可以从datasheet的PIN definition章节查到,如图default是作为普通GPIO口配置,remap(复用)可以作为TM1_BKIN
-
IO作为普通GPIO口使用,配置流程如下:
-
配置GPIO时钟,由下图可以看出,GPIO挂在APB2上,所以,配置代码如下
RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_GPIOC |RCC_APB2PERIPH_GPIOE,ENABLE);
-
配置GPIO方向、模式和速率如上图几种方式,配置代码如下,注意,输入时速率硬件已经配置好了,软件不需要配置
GPIO_InitPara GPIO_InitStructure; /* 上拉输出,50MHz */ GPIO_InitStructure.GPIO_Pin = GPIO_PIN_0 | GPIO_PIN_2; GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP; GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ; GPIO_Init(GPIOC,&GPIO_InitStructure); /* 浮空输入 */ GPIO_InitStructure.GPIO_Pin = GPIO_PIN_14; GPIO_InitStructure.GPIO_Mode = GPIO_MODE_IN_FLOATING; GPIO_Init(GPIOB,&GPIO_InitStructure);
-
配置GPIO口中断,参考中断章节
-
-
AFIO remap流程,先使能AF时钟,再调用pinRemap函数重新映射即可
RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_AF, ENABLE); GPIO_PinRemapConfig(GPIO_REMAP_SWJ_DISABLE, ENABLE);
参考资料
《GD32F10xCH_V1.1.pdf》
《GD32103C-EVAL-V1.1.pdf》
《GD32F103xxDatasheetRev2.2.pdf》
代码路径
https://github.com/YaFood/GD32F103/tree/master/TestLED
https://gitee.com/YaFOOD/GD32F103/tree/master/TestLED