打印
[活动]

【极海APM32F407IG Tiny Board开发板测评】4.按键+定时器测试

[复制链接]
1038|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 yuyy1989 于 2023-7-13 20:37 编辑

#申请原创# @21小跑堂
4.按键+定时器测试
先整理了一下开发板支持文件,因为工程只针对APM32F407IG Tiny Board,便将其它板子的文件都删掉了,目录结构变成了这样

把目录下的几个bsp文件也都加到了工程中


bsp的头文件有包含main.h,但是我自己创建的这个工程并没有这个文件,就都改成了Board_APM32F407_TINY.h,另外修改的时候发现Board_APM32F407_TINY中的bsp_usart.c中的串口初始化函数中写的还是APM_MINI_COMInit,应该是官方漏改了,不过也在这里给官方提个意见,这些开发板支持函数还是不要加什么MINI TINY的了,不然的话如果要把例程移植到其它板子上还要去替换这些函数名,一不小心就会有像前面提到的那样有漏掉的,如果能保持一致就省事多了

4.1 按键轮询
通过不断的查询按键电平状态来判断按键是否有按下,由于按下键时有可能会抖动所以延时一下再次判断电平,简单实现按键1 2控制LED2 3亮灭的代码

代码示例
#include "Board_APM32F407_TINY.h"
#include "bsp_delay.h"

int main(void)
{
    APM_DelayInit();
    APM_TINY_LEDInit(LED2);
    APM_TINY_LEDInit(LED3);
    APM_TINY_PBInit(BUTTON_KEY1,BUTTON_MODE_GPIO);
    APM_TINY_PBInit(BUTTON_KEY2,BUTTON_MODE_GPIO);
    while (1)
    {
        if(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET)
        {
            APM_DelayMs(30);
            if(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET)
            {
                while(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET);
                APM_TINY_LEDToggle(LED2);
            }
        }
        if(APM_TINY_PBGetState(BUTTON_KEY2) == BIT_RESET)
        {
            APM_DelayMs(30);
            if(APM_TINY_PBGetState(BUTTON_KEY2) == BIT_RESET)
            {
                while(APM_TINY_PBGetState(BUTTON_KEY2) == BIT_RESET);
                APM_TINY_LEDToggle(LED3);
            }
        }
    }
}

void SysTick_Handler(void)
{
    APM_DelayTickDec();
}
编译烧录查看效果

4.2 按键中断
配置按键IO在下降沿时产生中断,由于按下键时有可能会抖动导致多次中断,还是需要延时判断一下按键电平

代码示例
#include "Board_APM32F407_TINY.h"
#include "bsp_delay.h"

uint8_t key1down = 0;
uint8_t key2down = 0;

int main(void)
{
    APM_DelayInit();
    APM_TINY_LEDInit(LED2);
    APM_TINY_LEDInit(LED3);
    APM_TINY_PBInit(BUTTON_KEY1,BUTTON_MODE_EINT);
    APM_TINY_PBInit(BUTTON_KEY2,BUTTON_MODE_EINT);
    while (1)
    {
        if(key1down > 0)
        {
            key1down = 0;
            APM_DelayMs(30);
            if(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET)
                APM_TINY_LEDToggle(LED2);
        }
        if(key2down > 0)
        {
            key2down = 0;
            APM_DelayMs(30);
            if(APM_TINY_PBGetState(BUTTON_KEY2) == BIT_RESET)
                APM_TINY_LEDToggle(LED3);
        }
    }
}

void EINT15_10_IRQHandler(void)
{
    if(EINT_ReadIntFlag(KEY1_BUTTON_EINT_LINE))
    {
        key1down = 1;
        EINT_ClearIntFlag(KEY1_BUTTON_EINT_LINE);
    }
    if(EINT_ReadIntFlag(KEY2_BUTTON_EINT_LINE))
    {
        key2down = 1;
        EINT_ClearIntFlag(KEY2_BUTTON_EINT_LINE);
    }
}

void SysTick_Handler(void)
{
    APM_DelayTickDec();
}
编译烧录查看效果

4.3 定时器
APM32F407有很多定时器定时器可用

用timer3做一个闪灯程序,按键切换闪烁速度
timer3是一个16位的定时器,从这张图中可以看到timer3的最大时钟是42M

之前对定时器时钟理解有误,对于定时器的频率还有额外描述

再来看看系统初始化时APB1和2的分频系数

所以timer3的时钟频率为84MHz,将timer3的时钟设置为1分频,预分频系数设置为42,计数周期设置为,1000就能得到一个每0.5ms触发一次的定时器
代码示例
#include "Board_APM32F407_TINY.h"
#include "bsp_delay.h"
#include "apm32f4xx_tmr.h"

volatile uint16_t tim3count = 0;
volatile uint16_t tim3countmax = 200;

void tim3_init()
{
    TMR_BaseConfig_T TMR_TimeBaseStruct;
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR3);
    TMR_TimeBaseStruct.clockDivision = TMR_CLOCK_DIV_1;
    TMR_TimeBaseStruct.countMode = TMR_COUNTER_MODE_UP;
    TMR_TimeBaseStruct.division = 41;
    TMR_TimeBaseStruct.repetitionCounter = 0;
    TMR_TimeBaseStruct.period = 999;
    TMR_ConfigTimeBase(TMR3, &TMR_TimeBaseStruct);
    TMR_EnableInterrupt(TMR3,TMR_INT_UPDATE);
    NVIC_EnableIRQRequest(TMR3_IRQn, 0, 0);
    TMR_Enable(TMR3);
}

int main(void)
{
    APM_DelayInit();
    APM_TINY_PBInit(BUTTON_KEY1,BUTTON_MODE_GPIO);
    APM_TINY_PBInit(BUTTON_KEY2,BUTTON_MODE_GPIO);
    tim3_init();
    while (1)
    {
        if(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET)
        {
            APM_DelayMs(30);
            if(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET)
            {
                while(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET);
                tim3countmax = 500;
            }
        }
        if(APM_TINY_PBGetState(BUTTON_KEY2) == BIT_RESET)
        {
            APM_DelayMs(30);
            if(APM_TINY_PBGetState(BUTTON_KEY2) == BIT_RESET)
            {
                while(APM_TINY_PBGetState(BUTTON_KEY2) == BIT_RESET);
                tim3countmax = 200;
            }
        }
    }
}

void SysTick_Handler(void)
{
    APM_DelayTickDec();
}

void TMR3_IRQHandler(void)
{
    if(TMR_ReadIntFlag(TMR3, TMR_INT_UPDATE) == SET)
    {
        if(tim3count < tim3countmax)
            tim3count++;
        else
        {
            tim3count = 0;
            APM_TINY_LEDToggle(LED2);
            APM_TINY_LEDToggle(LED3);
        }
        TMR_ClearIntFlag(TMR3, TMR_INT_UPDATE);
    }
}
编译烧录查看效果

4.4 PWM输出
板子上的2个LED接的是PE5 PE6,可以使用timer9来实现pwm输出

写个程序两个按键分别控制LED的不同亮度,注意LED是低电平点亮,所以PWM要设置为低电平有效

代码示例
#include "Board_APM32F407_TINY.h"
#include "bsp_delay.h"
#include "apm32f4xx_tmr.h"

void pwm_init()
{
    TMR_BaseConfig_T TMR_TimeBaseStruct;
    TMR_OCConfig_T OCcongigStruct;
    GPIO_Config_T GPIO_ConfigStruct;
   
    RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOE);
   
    GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_5, GPIO_AF_TMR9);
    GPIO_ConfigPinAF(GPIOE, GPIO_PIN_SOURCE_6, GPIO_AF_TMR9);
   
    GPIO_ConfigStruct.pin = GPIO_PIN_5 | GPIO_PIN_6;
    GPIO_ConfigStruct.mode = GPIO_MODE_AF;
    GPIO_ConfigStruct.otype = GPIO_OTYPE_PP;
    GPIO_ConfigStruct.speed = GPIO_SPEED_100MHz;
    GPIO_Config(GPIOE, &GPIO_ConfigStruct);
   
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR9);
    TMR_TimeBaseStruct.clockDivision = TMR_CLOCK_DIV_1;
    TMR_TimeBaseStruct.countMode = TMR_COUNTER_MODE_UP;
    TMR_TimeBaseStruct.division = 83;
    TMR_TimeBaseStruct.repetitionCounter = 0;
    TMR_TimeBaseStruct.period = 999; //频率1k 占空比调节0-1000
    TMR_ConfigTimeBase(TMR9, &TMR_TimeBaseStruct);
   
    OCcongigStruct.mode = TMR_OC_MODE_PWM1;              //PWM模式1,计数小于比较值时输出有效电平
    OCcongigStruct.outputState = TMR_OC_STATE_ENABLE;    //通道使能
    OCcongigStruct.idleState = TMR_OC_IDLE_STATE_SET;    //空闲高电平
    OCcongigStruct.polarity = TMR_OC_POLARITY_LOW;       //有效电平为低电平
    OCcongigStruct.outputNState = TMR_OC_NSTATE_DISABLE; //互补通道失能
    OCcongigStruct.nIdleState = TMR_OC_NIDLE_STATE_RESET;//互补通道空闲电平
    OCcongigStruct.nPolarity = TMR_OC_NPOLARITY_HIGH;    //互补通道有效电平
    OCcongigStruct.pulse = 500;                          //初始50%
    TMR_ConfigOC1(TMR9, &OCcongigStruct);
    TMR_ConfigOC2(TMR9, &OCcongigStruct);
   
    TMR_ConfigOC1Preload(TMR9, TMR_OC_PRELOAD_ENABLE);
    TMR_EnableAutoReload(TMR9);
    TMR_Enable(TMR9);
    TMR_EnablePWMOutputs(TMR9);
}

int main(void)
{
    APM_DelayInit();
    APM_TINY_LEDInit(LED2);
    APM_TINY_LEDInit(LED3);
    APM_TINY_PBInit(BUTTON_KEY1,BUTTON_MODE_GPIO);
    APM_TINY_PBInit(BUTTON_KEY2,BUTTON_MODE_GPIO);
    pwm_init();
    while (1)
    {
        if(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET)
        {
            APM_DelayMs(30);
            if(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET)
            {
                while(APM_TINY_PBGetState(BUTTON_KEY1) == BIT_RESET);
                TMR_ConfigCompare1(TMR9,900);
                TMR_ConfigCompare2(TMR9,900);
            }
        }
        if(APM_TINY_PBGetState(BUTTON_KEY2) == BIT_RESET)
        {
            APM_DelayMs(30);
            if(APM_TINY_PBGetState(BUTTON_KEY2) == BIT_RESET)
            {
                while(APM_TINY_PBGetState(BUTTON_KEY2) == BIT_RESET);
                TMR_ConfigCompare1(TMR9,100);
                TMR_ConfigCompare2(TMR9,100);
            }
        }
    }
}

void SysTick_Handler(void)
{
    APM_DelayTickDec();
}
编译烧录,查看效果





使用特权

评论回复
沙发
tpgf| | 2023-8-1 13:13 | 只看该作者
这个按键的延时时间是根据经验来的吗

使用特权

评论回复
板凳
yuyy1989|  楼主 | 2023-8-1 13:26 | 只看该作者
tpgf 发表于 2023-8-1 13:13
这个按键的延时时间是根据经验来的吗

习惯了,以前前看某个教程是延时的30ms

使用特权

评论回复
地板
nawu| | 2023-8-1 16:52 | 只看该作者
这个是使用的中断模式进行检测的吗

使用特权

评论回复
5
aoyi| | 2023-8-1 17:33 | 只看该作者
如果是用轮询模式 会不会导致漏掉信号啊

使用特权

评论回复
6
zljiu| | 2023-8-2 08:22 | 只看该作者
while循环中的时间间隔设定的依据是什么

使用特权

评论回复
7
gwsan| | 2023-8-2 09:43 | 只看该作者
按键信号没有检测到的概率大不大呢?

使用特权

评论回复
8
yuyy1989|  楼主 | 2023-8-2 09:55 | 只看该作者
gwsan 发表于 2023-8-2 09:43
按键信号没有检测到的概率大不大呢?

如果按按键的速度超过了每秒30次或者每次按下保持时间短于30毫秒,那漏掉的概率很大,想要精准些的话可以用示波器看一下实际抖动的时间有多长,或者硬件设计加上去抖

使用特权

评论回复
9
tfqi| | 2023-8-3 10:48 | 只看该作者
为什么我们常用的触摸按键会用着用着就不好用了呢

使用特权

评论回复
10
yuyy1989|  楼主 | 2023-8-3 11:26 | 只看该作者
tfqi 发表于 2023-8-3 10:48
为什么我们常用的触摸按键会用着用着就不好用了呢

触摸按键应该没那么容易失灵吧,倒是这种机械按键按压次数多了后,触点部分会氧化发黑再按的时候就会接触不良

使用特权

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

本版积分规则

认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

149

主题

708

帖子

7

粉丝