按键有很多种,按下到放开,一直按。。。。。。一般大家都喜欢用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';
一个简单的表格是这么创建的:
项目 | Value |
---|---|
电脑 | $1600 |
手机 | $12 |
导管 | $1 |
使用:---------:
居中
使用:----------
居左
使用----------:
居右
第一列 | 第二列 | 第三列 |
---|---|---|
第一列文本居中 | 第二列文本居右 | 第三列文本居左 |
SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:
TYPE | ASCII | HTML |
---|---|---|
Single backticks | 'Isn't this fun?' |
‘Isn’t this fun?’ |
Quotes | "Isn't this fun?" |
“Isn’t this fun?” |
Dashes | -- is en-dash, --- is em-dash |
– is en-dash, — is em-dash |
一个具有注脚的文本。1
Markdown将文本转换为 HTML。
您可以使用渲染LaTeX数学表达式 KaTeX:
Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n−1)!∀n∈N 是通过欧拉积分
Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=∫0∞tz−1e−tdt.
你可以找到更多关于的信息 LaTeX 数学表达式here.
可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::
这将产生一个流程图。:
我们依旧会支持flowchart的流程图:
如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。
如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。
注脚的解释 ↩︎