这里写自定义目录标题
按键的误区
按键有很多种,按下到放开,一直按。。。。。。一般大家都喜欢用delay()这个延时程序,但有时会碰到很多问题,delay()是不精准延时,按键按下的时候存在抖动,不可能说每次都能很准确地消抖。所以说有时候写的代码达不到预期的效果。
举个例子
在做按键控制输出占空比可调的PWM波时,因为存在delay(),输出波形要等delay()之后才输出。delay()一次的时间可能你设置了20ms,但是你不知道按键按下到弹起之间上升沿和下降沿切换了多少次,不知道有没有完全消抖。所以在按键切换波形的时候会发生误按:按一下可能刚好是一下,也可能是2下,3下,是一个随机数了。为了解决这个问题,我们只需要将按键的高/低电平一直持续到我们放开按键的时刻就可以解决了。
代码如下
main.c
#include “stm32f10x.h”
#include “bsp_advancetime.h”
#include “bsp_key.h”
#include “bsp_led.h”
uint16_t Value;
int main(void)
{
Value=5; //设置初始脉宽为5
LED_GPIO_Config(); //LED初始化
Key_GPIO_Config(); //按键初始化
Advance_Time_Config(); //输出初始化波形,脉宽为5
while(1)
{
if(Key_Scan(GPIOA,GPIO_Pin_0)==KEY_ON) //如果按键按下
{
Value=Value-1;
if(Value==0) //如果脉宽=0的时候切换回5
{
Value=5;
}
Advance_Time_Config(); //输出波形
LED1_TOGGLE; //LED1状态翻转
}
}
}
bsp_advancetime.c
#include “bsp_advancetime.h”
#include “bsp_key.h”
extern uint16_t Value;
void Advance_Time_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/*输出比较通道初始化*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; /*复用推挽输出*/
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
/*输出比较通道互补通道初始化*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
/*输出比较通道刹车通道初始化*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
/*BKIN引脚默认输出低电平 为1时表示刹车*/
GPIO_ResetBits(GPIOB,GPIO_Pin_12);
}
void Advance_Time_Mode_Config(void)
{
/开启TIM1时钟/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
/时基结构体初始化配置/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
/ARR的值 时钟周期/
TIM_TimeBaseInitStruct.TIM_Period=7;
/72M时钟的预分频数 提供给计数器计数/
TIM_TimeBaseInitStruct.TIM_Prescaler=8;
/不启动重复计数/
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
/配置死区时间用/
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
/计数器为向上计数模式/
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
/时基结构体初始化/
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);
/*输出比较结构体初始化*/
TIM_OCInitTypeDef TIM_OCInitStruct;
/*输出模式配置为PWM1*/
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
/*输出使能*/
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
/*互补输出使能*/
TIM_OCInitStruct.TIM_OutputNState=TIM_OutputNState_Enable;
/*Pulse/Period+1*/
TIM_OCInitStruct.TIM_Pulse=Value; /*Pulse实际改变的是CCR的值 当CNT计数到CCR时,电平发生一次翻转*/
/*输出通道为高电平有效*/
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
/*空闲状态时,经过死区时间后为低电平*/
TIM_OCInitStruct.TIM_OCIdleState=TIM_OCIdleState_Reset;
/*输出比较结构体初始化*/
TIM_OC1Init(TIM1, &TIM_OCInitStruct);
/*使能预装载CCR1*/
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
/*使能计数器*/
TIM_Cmd(TIM1,ENABLE);
// 主输出使能,当使用的是通用定时器时,这句不需要
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
void Advance_Time_Config(void)
{
Advance_Time_GPIO_Config();
Advance_Time_Mode_Config();
}
bsp_advancetime.h
#ifndef _BSP_ADVANCETIME_H
#define _BSP_ADVANCETIME_H
#include “stm32f10x.h”
void Advance_Time_GPIO_Config(void);
void Advance_Time_Mode_Config(void);
void Advance_Time_Config(void);
#endif /_BSP_ADVANCETIME_H/
bsp_key.c
#include “bsp_key.h”
void Key_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStruct);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC,&GPIO_InitStruct);
}
uint8_t Key_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
/*检测是否有按键按下 */
if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON )
{
/*等待按键释放 */
while(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == KEY_ON);
return KEY_ON;
}
else
return KEY_OFF;
}
bsp_key.h
#ifndef _BSP_KEY_H
#define _BSP_KEY_H
#include “stm32f10x.h”
#define KEY_ON 1
#define KEY_OFF 0
void Key_GPIO_Config(void);
uint8_t Key_Scan(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
#endif /_BSP_KEY_H/
bsp_led.c
#include “bsp_led.h”
void LED_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_2;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_SetBits(GPIOC,GPIO_Pin_2);
GPIO_Init(GPIOC,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_3;
GPIO_SetBits(GPIOC,GPIO_Pin_3);
GPIO_Init(GPIOC,&GPIO_InitStruct);
}
bsp_led.h
#ifndef _BSP_LED_H
#define _BSP_LED_H
#include “stm32f10x.h”
/* 定义控制IO的宏 */
#define LED1_TOGGLE digitalToggle(GPIOC,GPIO_Pin_2)
#define LED1_OFF digitalHi(GPIOC,GPIO_Pin_2)
#define LED1_ON digitalLo(GPIOC,GPIO_Pin_2)
#define LED2_TOGGLE digitalToggle(GPIOC,GPIO_Pin_3)
#define LED2_OFF digitalHi(GPIOC,GPIO_Pin_3)
#define LED2_ON digitalLo(GPIOC,GPIO_Pin_3)
/* 直接操作寄存器的方法控制IO */
#define digitalHi(p,i) {p->BSRR=i;} //输出为高电平
#define digitalLo(p,i) {p->BRR=i;} //输出低电平
#define digitalToggle(p,i) {p->ODR ^=i;} //输出反转状态
void LED_GPIO_Config(void);
#endif /_BSP_LED_H/
实验结果
链接: link.
图片:
依次类推
如何插入一段漂亮的代码片
去博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片
.
// An highlighted block
var foo = 'bar';