打印
[开发板]

【CW32L031CxTx StartKit评估板测评】4.按键与定时器的使用

[复制链接]
634|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
#申请原创# @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);
    }
}
运行效果


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

144

主题

692

帖子

6

粉丝