按键控制输出占空比可调的PWM波

本文介绍了如何使用STM32通过按键控制PWM波的占空比调节,详细展示了从按键扫描到PWM配置的代码实现,包括关键函数如`Key_Scan`、`Advance_Time_Config`和`LED`控制。通过实验结果展示,读者可以理解并应用到自己的项目中。
摘要由CSDN通过智能技术生成

按键的误区

	按键有很多种,按下到放开,一直按。。。。。。一般大家都喜欢用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.

图片:
脉宽为5
依次类推
脉宽为1PA8输出波形

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';
首先,您需要确定使用哪个Cortex微控制器,因为不同的微控制器具有不同的GPIO数量和功能。一般来说,您需要将PWM输出连接到一个可调电阻,以便您可以通过更改电阻值来改变PWM占空比。 以下是一个基本的C程序示例,该程序使用Cortex-M3微控制器的GPIO口控制PWM输出: ```c #include "stm32f10x.h" void PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; /* Enable GPIO clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* Enable TIM clock */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* Configure GPIO pin */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure Timer */ TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period = 1000; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); /* Configure PWM */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 500; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM2, &TIM_OCInitStructure); /* Enable Timer */ TIM_Cmd(TIM2, ENABLE); } int main(void) { PWM_Init(); while(1) { /* Change PWM duty cycle */ TIM_SetCompare1(TIM2, 250); delay(1000); TIM_SetCompare1(TIM2, 750); delay(1000); } } ``` 您可以根据需要更改此示例,例如更改GPIO引脚或PWM占空比。此外,您还需要编写一个`delay()`函数,以便在更改PWM占空比时等待一段时间。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值