#申请原创# @21小跑堂
按键检测
实现按键检测通常有2种方法:
轮询:通过不断的查询按键电平状态来判断按键是否有按下
中断:按键按下时IO电平变化触发中断,结合电平判断按键状态
接下来用2种方式分别实现按键检测,按键KEY1和KEY2分别控制LED1和LED2,查看原理图可以知道按键未按下时为高电平,按下后为低电平
轮询方式,通常机械按键按下时不可避免地会有抖动情况发生,一般可以采用延时进行去抖
void led_init()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.IT = GPIO_IT_NONE;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pins = GPIO_PIN_8 | GPIO_PIN_9;
GPIO_Init(CW_GPIOB, &GPIO_InitStruct);
GPIO_WritePin(CW_GPIOB,GPIO_PIN_8 | GPIO_PIN_9,GPIO_Pin_RESET);
}
void key_init()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.IT = GPIO_IT_NONE;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pins = GPIO_PIN_1 | GPIO_PIN_2;
GPIO_Init(CW_GPIOA, &GPIO_InitStruct);
}
int32_t main(void)
{
RCC_HSI_48M_init();
RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
led_init();
key_init();
while (1)
{
if(GPIO_ReadPin(CW_GPIOA,GPIO_PIN_1) == GPIO_Pin_RESET)
{
yuyy_delay_ms(10);
if(GPIO_ReadPin(CW_GPIOA,GPIO_PIN_1) == GPIO_Pin_RESET)
{
while(GPIO_ReadPin(CW_GPIOA,GPIO_PIN_1) == GPIO_Pin_RESET);
GPIO_TogglePin(CW_GPIOB, GPIO_PIN_8);
}
}
if(GPIO_ReadPin(CW_GPIOA,GPIO_PIN_2) == GPIO_Pin_RESET)
{
yuyy_delay_ms(10);
if(GPIO_ReadPin(CW_GPIOA,GPIO_PIN_2) == GPIO_Pin_RESET)
{
while(GPIO_ReadPin(CW_GPIOA,GPIO_PIN_2) == GPIO_Pin_RESET);
GPIO_TogglePin(CW_GPIOB, GPIO_PIN_9);
}
}
}
}
运行效果
中断方式,CW32L031的GPIO中断可以配置为上升沿或下降沿触发(虽然cw32l031_gpio.h有高低电平的中断参数定义但并无效果,手册中也没写支持电平中断),按键按下时从高电平变为低电平时会触发下降沿中断,CW32L031的中断可以配置滤波功能,通过滤波实现去抖
void key_init()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.IT = GPIO_IT_FALLING;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pins = GPIO_PIN_1 | GPIO_PIN_2;
GPIO_Init(CW_GPIOA, &GPIO_InitStruct);
GPIO_ConfigFilter(CW_GPIOA,GPIO_PIN_1 | GPIO_PIN_2,GPIO_FLTCLK_RC150K);
GPIOA_INTFLAG_CLR(bv1| bv2);
NVIC_EnableIRQ(GPIOA_IRQn);
}
void GPIOA_IRQHandler(void)
{
if (CW_GPIOA->ISR_f.PIN1)
{
GPIOA_INTFLAG_CLR(bv1);
if(GPIO_ReadPin(CW_GPIOA,GPIO_PIN_1) == GPIO_Pin_RESET)
GPIO_TogglePin(CW_GPIOB, GPIO_PIN_8);
}
if (CW_GPIOA->ISR_f.PIN2)
{
GPIOA_INTFLAG_CLR(bv2);
if(GPIO_ReadPin(CW_GPIOA,GPIO_PIN_2) == GPIO_Pin_RESET)
GPIO_TogglePin(CW_GPIOB, GPIO_PIN_9);
}
}
int32_t main(void)
{
RCC_HSI_48M_init();
RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
led_init();
key_init();
while (1)
{
}
}
运行效果
定时器的使用
CW32L031拥有三个基本定时器(BTIM)两个通用定时器(GTIM)和一个高级定时器(ATIM),先用BTIM做一个控制LED以1Hz闪烁的定时器
void btim1_init()
{
BTIM_TimeBaseInitTypeDef BTIM_InitStruct = {0};
__RCC_BTIM_CLK_ENABLE();
BTIM_InitStruct.BTIM_Mode = BTIM_Mode_TIMER;
BTIM_InitStruct.BTIM_Period = 50000 - 1;
BTIM_InitStruct.BTIM_Prescaler = 480 - 1;
BTIM_TimeBaseInit(CW_BTIM1, &BTIM_InitStruct);
BTIM_ITConfig(CW_BTIM1, BTIM_IT_OV, ENABLE);
BTIM_Cmd(CW_BTIM1, ENABLE);
NVIC_EnableIRQ(BTIM1_IRQn);
}
void BTIM1_IRQHandler(void)
{
if (BTIM_GetITStatus(CW_BTIM1, BTIM_IT_OV))
{
BTIM_ClearITPendingBit(CW_BTIM1, BTIM_IT_OV);
GPIO_TogglePin(CW_GPIOB, GPIO_PIN_8);
GPIO_TogglePin(CW_GPIOB, GPIO_PIN_9);
}
}
int32_t main(void)
{
RCC_HSI_48M_init();
RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
led_init();
btim1_init();
while (1)
{
}
}
运行效果
通用定时器和高级定时器都有PWM输出功能,可以通过调节PWM占空比来调节LED亮度,评估板上的2个LED分别对应GTIM1的CH3和CH4,接下来写个程序使用按键调节LED亮度
void led_init()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__RCC_GPIOB_CLK_ENABLE();
PB08_AFx_GTIM1CH3();
PB09_AFx_GTIM1CH4();
GPIO_InitStruct.IT = GPIO_IT_NONE;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pins = GPIO_PIN_8 | GPIO_PIN_9;
GPIO_Init(CW_GPIOB, &GPIO_InitStruct);
}
void gtim1_pwm_init()
{
GTIM_InitTypeDef GTIM_InitStruct = {0};
__RCC_GTIM1_CLK_ENABLE();
GTIM_InitStruct.Mode = GTIM_MODE_TIME;
GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE;
GTIM_InitStruct.Prescaler = 48 - 1;
GTIM_InitStruct.ReloadValue = 1000 - 1;
GTIM_InitStruct.ToggleOutState = DISABLE;
GTIM_TimeBaseInit(CW_GTIM1, >IM_InitStruct);
GTIM_OCInit(CW_GTIM1, GTIM_CHANNEL3, GTIM_OC_OUTPUT_PWM_LOW);
GTIM_OCInit(CW_GTIM1, GTIM_CHANNEL4, GTIM_OC_OUTPUT_PWM_LOW);
GTIM_SetCompare3(CW_GTIM1, 0);
GTIM_SetCompare4(CW_GTIM1, 0);
GTIM_Cmd(CW_GTIM1, ENABLE);
}
uint16_t pwm = 0;
void GPIOA_IRQHandler(void)
{
if (CW_GPIOA->ISR_f.PIN1)
{
GPIOA_INTFLAG_CLR(bv1);
if(GPIO_ReadPin(CW_GPIOA,GPIO_PIN_1) == GPIO_Pin_RESET)
{
if(pwm<1000-100)
pwm += 100;
else
pwm = 1000;
GTIM_SetCompare3(CW_GTIM1, pwm);
GTIM_SetCompare4(CW_GTIM1, pwm);
}
}
if (CW_GPIOA->ISR_f.PIN2)
{
GPIOA_INTFLAG_CLR(bv2);
if(GPIO_ReadPin(CW_GPIOA,GPIO_PIN_2) == GPIO_Pin_RESET)
{
if(pwm > 100)
pwm -= 100;
else
pwm = 0;
GTIM_SetCompare3(CW_GTIM1, pwm);
GTIM_SetCompare4(CW_GTIM1, pwm);
}
}
}
编译又有2处优先级警告,找到相关代码处加上括号就好了
运行效果
定时器还可以级联使用来实现更长时间幅度的定时,下面尝试用BTIM和GTIM级联实现1秒的定时器,用BTIM的溢出信号作为GTIM的时钟源
void btim1_init()
{
BTIM_TimeBaseInitTypeDef BTIM_InitStruct = {0};
__RCC_BTIM_CLK_ENABLE();
BTIM_InitStruct.BTIM_Mode = BTIM_Mode_TIMER;
BTIM_InitStruct.BTIM_Period = 1000 - 1;
BTIM_InitStruct.BTIM_Prescaler = 48 - 1;
BTIM_TimeBaseInit(CW_BTIM1, &BTIM_InitStruct);
BTIM_Cmd(CW_BTIM1, ENABLE);
}
void gtim1_counter_init()
{
GTIM_InitTypeDef GTIM_InitStruct = {0};
__RCC_GTIM1_CLK_ENABLE();
GTIM_InitStruct.Mode = GTIM_MODE_COUNTER;
GTIM_InitStruct.OneShotMode = GTIM_COUNT_CONTINUE;
GTIM_InitStruct.Prescaler = 1;
GTIM_InitStruct.ReloadValue = 1000 - 1;
GTIM_InitStruct.ToggleOutState = DISABLE;
GTIM_TimeBaseInit(CW_GTIM1, >IM_InitStruct);
GTIM1_ITRConfig(ITR_SOURCE_BTIM1);
GTIM_ITConfig(CW_GTIM1, GTIM_IT_OV, ENABLE);
GTIM_Cmd(CW_GTIM1, ENABLE);
NVIC_EnableIRQ(GTIM1_IRQn);
}
void GTIM1_IRQHandler(void)
{
if (GTIM_GetITStatus(CW_GTIM1, GTIM_IT_OV))
{
GTIM_ClearITPendingBit(CW_GTIM1, GTIM_IT_OV);
GPIO_TogglePin(CW_GPIOB, GPIO_PIN_8);
GPIO_TogglePin(CW_GPIOB, GPIO_PIN_9);
}
}
运行效果
|