STM32——PWM原理及应用(附代码)

1.什么是PWM?

​ 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制可以理解为控制脉冲的宽度,利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,它通过控制信号的脉冲宽度,实现对电压或电流的精确控制。在嵌入式的应用中,如数字信号控制的LED只有完全亮与灭两种状态,怎么能实现控制亮度大小呢?这就用到了PWM等效输出模拟量。

PWM的基本工作原理

在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制来等效地获得所需要的模拟参量,常应用于电机控速等领域。

那么什么是惯性系统呢?如LED在熄灭的时候,由于余晖和人眼视觉暂留的现象,LED不会立马熄灭,而是有一定的惯性,过了一小段时间才熄灭的。具有惯性的系统才能使用PWM。

PWM目的:

使用PWM波形,等效地实现一个模拟信号的输出

2.PWM的相关参数

PWM主要有三个参数:频率、占空比、分辨率

  1. 频率(Frequency):是指1秒钟内信号从高电平到低电平再回到高电平的次数(一个周期),也就是说一秒钟PWM有多少个周期。

  2. 占空比(Duty Cycle):是一个脉冲周期内,高电平的时间与整个周期时间的比例,占空比决定了PWM等效出来的模拟电压的大小,占空比越大,模拟电压越趋近于高电平。

  3. 分辨率(Resolution):就是占空比变化的快慢占空比变化的细腻程度。占空比跳的快如按照1%跳变与按照0.1%跳变,那么0.1%的跳变就越细腻,越柔和。

参数介绍

频率 = 1 / TS

占空比 = TON / TS

分辨率 = 占空比变化步距

注:TS:一个高低电平变换周期的时间。Ton:高电平占用的时间。

频率越快,等效地模拟信号就越平稳,不过性能开销越大。一般PWM的频率在几k到几十khz,这写频率就足够快了。

PWM的核心思想

比如利用PWM调节LED亮度,就是让LED不断地点亮、熄灭、点亮、熄灭...,当这个点亮熄灭的频率足够大时,LED就不会闪烁了,而是呈现出一个中等的亮度。调控点亮、熄灭的比例时,就能让LED呈现出不同的亮度级别。这也是PWM的基本思想。

3.定时器是怎么输出波形的?

定时器波形步骤

第一步:CNT(计数器)与CCR(捕获比较寄存器)进行比较,如果CNT大于or等于CCR,就会给输出模式控制器传一个信号;

第二步:输出模式控制器就会改变它输出OC1REF的高低电平,REF信号实际上就是信号的高低电平(REF:reference,参考信号);

第三步:CC1P:极性选择寄存器,给0,信号就会走对应的0那一路,信号不变;给1,信号会经过一个非门,极性翻转;

第四步:信号从OC1输出。

输出模式控制器

输出模式控制器:stm32有8种模式,可以通过寄存器配置,需要哪个模式,就配置哪个

4.PWM实现流程

注:黄色线:计算器溢出频率(ARR),也是PWM更新频率;红色线:捕获比较寄存器(CCR)的值;蓝色线:计数器(CNT)的值。

5.PWM的基本结构

时基单元在上一篇定时器有详细介绍,这里主要介绍输出比较单元。定时器不断更新计数值,并且不断与捕获比较寄存器的值进行比较,当计数器的值大于等于捕获比较寄存器的值时,电平就会从高电平跳到低电平,当计数器的值小于捕获比较寄存器时,电平就会从低电平跳到高电平。

注:捕获比较寄存器的是我们根据自己的需求设置的。

6.PWM参数计算公式

PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)

PWM占空比: Duty = CCR / (ARR + 1)

PWM分辨率: Reso = 1 / (ARR + 1)

Reso定义的分辨率是占空比最小的变化步距

注:

        ARR:Automatic Reload Register,自动重装寄存器。计数到该值时,会重新计数,也就是重装的意思。

        CCR:Catch Compare Register,捕获比较寄存器,CC捕获/比较意思,R是Register,寄存器的意思。两个共用,输入捕获寄存器。输出比较寄存器,比较CNT与CCR的值,CNT计数自增,CCR自己给定。当CNT大于CCR(小于或者等于)时,置1置0,然后输出应该电平不断跳变的PWM波形。

7.PWM驱动呼吸灯代码

一般人眼睛对于80Hz以上刷新频率则完全没有闪烁感,那么我们平时见到的LED灯,当它的频率大于50Hz的时候,人眼就会产生视觉暂留效果,基本就看不到闪烁了,而是误以为是一个常亮的LED灯。由于频率很高时看不到闪烁,占空比越大LED越亮,占空比越小LED越暗。所以,在频率一定时,可以用不同占空比改变LED灯的亮度,使其达到一个呼吸灯的效果。

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	//本代码初始化的是TIM2的定时器
	//1.开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	//引脚重映射
	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);
	//关闭调试功能
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
	//初始化GPIO
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//GPIO_Pin_15
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	//2.选择时基单元的时钟源(是内部时钟还是外部时钟)
	TIM_InternalClockConfig(TIM2);
	//3.配置时基单元
	//声明一个时基时钟的实参
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	//配置分频,滤波时选择的频率
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	//计数器模式
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	//ARR自动重装器的值,10KHz计10k个数,就是1s。
	TIM_TimeBaseInitStructure.TIM_Period = 100-1;//ARR
	//PSC预分频器的值.72MHz/7200 = 10KHz
	TIM_TimeBaseInitStructure.TIM_Prescaler = 720-1;//PSC
	//重复计数器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	//初始化比较单元
	TIM_OCInitTypeDef TIM_OCInitStructure;
	//给结构体赋初始值
	TIM_OCStructInit(&TIM_OCInitStructure);
	//设置输出比较的模式
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	//设置输出比较的极性
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	//设置输出使能
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	//设置CCR的
	TIM_OCInitStructure.TIM_Pulse = 0;//CRR
	
	
	TIM_OC1Init(TIM2,&TIM_OCInitStructure);
	
	
	//启动定时器
	TIM_Cmd(TIM2,ENABLE);

}

//设置捕获比较寄存器的值
void PWM_SetCompare1(uint16_t Compare)
{
	TIM_SetCompare1(TIM2,Compare);
}

8.PWM驱动舵机

舵机的控制就是通过一个固定的频率,给其不同的占空比来控制舵机不同的转角。

舵机的频率一般为频率为50HZ,也就是一个20ms左右的时基脉冲,而脉冲的高电平部分一般为0.5ms-2.5ms范围,来控制舵机不同的转角。

500-2500us的PWM高电平部分对应控制180度舵机的0-180度。

以180度角为例,那么对应的控制如下:

0.5ms-------------0度;

1.0ms------------45度;

1.5ms------------90度;

2.0ms-----------135度;

2.5ms-----------180度;

下图演示占空比从1ms变化到2ms时,转角的变化。

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	//本代码初始化的是TIM2的定时器
	//1.开启时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	//引脚重映射
	//GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);
	//关闭调试功能
	//GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
	//初始化GPIO
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//GPIO_Pin_15
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	//2.选择时基单元的时钟源(是内部时钟还是外部时钟)
	TIM_InternalClockConfig(TIM2);
	//3.配置时基单元
	//声明一个时基时钟的实参
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	//配置分频,滤波时选择的频率
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	//计数器模式
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	//ARR自动重装器的值,10KHz计10k个数,就是1s。
	TIM_TimeBaseInitStructure.TIM_Period = 20000-1;//ARR
	//PSC预分频器的值.72MHz/7200 = 10KHz
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1;//PSC
	//重复计数器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	//初始化比较单元
	TIM_OCInitTypeDef TIM_OCInitStructure;
	//给结构体赋初始值
	TIM_OCStructInit(&TIM_OCInitStructure);
	//设置输出比较的模式
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	//设置输出比较的极性
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	//设置输出使能
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	//设置CCR的
	TIM_OCInitStructure.TIM_Pulse = 0;//CRR
	
	
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	
	
	//启动定时器
	TIM_Cmd(TIM2,ENABLE);

}

void PWM_SetCompare2(uint16_t Compare)
{
	TIM_SetCompare2(TIM2,Compare);
}

### 回答1: 在接口测试中,依赖登录状态的接口需要先进行登录操作,获取登录后的token或session等信息,然后将这些信息作为请求参数传递给需要测试的接口。测试时需要验证登录状态是否正确,以及接口返回的数据是否符合预期。同时,还需要测试登录状态失效后的接口返回情况,以保证系统的安全性和稳定性。 ### 回答2: 在接口测试中,当涉及到需要登录状态的接口时,需要特别注意测试。因为这些接口需要保证在正确的登录状态下才能正确地进行操作和返回结果。下面是一些应该考虑到的测试步骤: 1.确定登录状态对接口的影响 在测试依赖登录状态的接口之前,需要明确登录状态对接口的影响。为此,我们应该在测试计划中提供详细的用例。测试人员应该体面地覆盖所有目标结果,并特别注意测试通过不同用户角色的接口,以确保在不同用户角色的登录状态下接口行为的正确性。 2.独立测试登录接口 在测试依赖登录状态的接口之前,需要先独立测试登录接口。如果登录接口出现问题,那么依赖登录状态的接口肯定无法工作。在这种情况下,测试团队必须确保登录接口能够正常的执行和返回预期结果。 3.操纵缓存和Cookies 测试通过操纵缓存和Cookies模拟操作会话失效情况,从而测试依赖登录状态的接口。例如,通过删除或修改Cookies或缓存数据以模拟过期会话,以确保接口的行为和状态正确响应。同时,测试也可以操作在同一时间内的多个会话,以确保会话和管理的正确性。 4.模拟登录和注销场景 测试人员可以通过不同的方式模拟登录和注销场景。例如,测试可以通过模拟重复登录或同时存在多个登录会话的情况来测试接口的准确性,并且在随后的注销场景中,测试可以验证是否安全注销了会话,并且没有留下敏感信息在会话中。 5.模拟会话超时 在实际使用过程中,会话超时是常见的场景之一。测试人员需要模拟会话超时的场景,并且确认接口的响应是否正确。 总之,测试依赖于登录状态的接口是非常重要的。确保正确地测试会话管理,行为和状态会有助于提高整个应用程序的质量,达到用户的期望。 ### 回答3: 在进行接口测试中,遇到依赖登录状态的接口,需要采取一些特殊的测试方法,以确保测试结果的准确性和全面性。以下是一些测试建议: 1. 准备测试数据 登录状态的接口测试需要有一定的测试数据,包括登录用户名和密码。测试数据可以通过手动创建,或者通过自动化测试工具创建。 2. 保持登录状态 在进行接口测试时,需要保持登录状态才能执行后续操作。可以使用手动方式登录,或者通过代码自动化登录,并将登录状态保存下来。 3. 测试正常登录和非法登录的情况 接口测试时需要测试正常登录和非法登录的情况,以确保系统能够正确处理这些情况。正常登录需要输入正确的用户名和密码,而非法登录则需要输入不存在的用户名或错误的密码。 4. 测试登录状态失效的情况 在接口测试中,需要模拟登录状态失效的情况,以确保系统能够正确处理这种情况。可以通过手动方式注销登录,或者在代码中设置登录状态失效。 5. 测试重复登录的情况 有些系统可能不允许用户重复登录,需要测试这种情况。可以通过手动方式和代码自动化方式测试。 6. 针对特定用户测试 如果是针对特定用户进行接口测试,需要使用特定用户的账号进行测试,确保测试结果具有代表性。 综上所述,接口测试中依赖登录状态的接口测试,需要考虑多种情况,依据不同情况采取不同的测试方法,这样才能保证测试结果的准确性和完整性。同时,可以通过自动化测试工具执行测试,提高测试效率和一致性。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值