一、PWM
1.定义
英文全称:PULSE WIDTH MODULATION,脉冲宽度调制。
脉冲:频率,方波
宽度:占空比(duty),高电平的宽度
2.用途
(1)控制输出的电压和电流
(2)灯光的亮度
(3)电机
二、编程细节
PWM输出是没有中断触发的,PWM由硬件输出波形,用了中断反而会影响系统定时的效率。
所以,记住以后使用定时器输出PWM都不需要使用到中断
1.如配置STM32F407的TIM14的通道1,10ms即100Hz.
1ms = 0.01s=100HZ
84000000 /8400 = 10000
10000/x = 100
x=100
得到周期8400-1,分频系数10-1
基本配置如下
2.然后还要再配置定时器的输出功能,可以参考固件库手册的例子TIM_PWMOutPut,
这里涉及到了一个寄存器
TIMx_CCMR1:capture/compare mode register 1 --捕获/比较模式寄存器1
从上图可以看出,我们设置占空比是可以动态调整的,关键就在于设置中间这个比较值的大小。
我们会使用到下面这个函数设置TIMx通道1比较值函数,如果使用到通道2,改1为2即可。
假如100hz内,比较值设置为80hz,那么0-79为高电平,80-100为低电平。
void TIM_SetCompare1(TIM_TypeDef* TIMx,uint16_t Comarex);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//pwm模式1,解释如上图所示
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//允许输出
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//有效的时候,输出高电平
TIM_OC1Init(TIM14, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);//因为要周期性输出,所以要自动重装载初值,不断输出PWM脉冲
TIM_ARRPreloadConfig(TIM14,ENABLE);//自动重载使能
3.下面讲一下设置gpio的注意事项
(1)将引脚设置为复用功能
(2)将引脚与定时器进行绑定,告知是复用定时器功能
GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM14);
(3)最好是按照固件库手册的例程来写,有些定时器使能需要配置下面这个函数
TIM_CtrlPWMOutputs(TIM1,ENABLE);
4.主函数部分
uint32_t pwm_cmp = 0;//新建一个比较值
添加两个延时函数
while(1)
{
for(pwm_cmp =1;pwm_cmp<100;pwm_cmp++)
{
//设置比较值,查看所接的LED渐灭,因为0点亮
//如果想要渐亮,设置pwm_cmp为从100--1即可
TIM_SetCompare1(TIM14,pwm_cmp);
delay_ms(10);
}
for(pwm_cmp=99;pwm_cmp>0;pwm_cmp--)
{
TIM_SetCompare1(TIM14,pwm_cmp);
delay_ms(10);
}
}
下面是使用野火开发板STM32F429写的PWM输出
#include "stm32f4xx.h"
//R 红色灯
#define LED1_PIN GPIO_Pin_10
#define LED1_GPIO_PORT GPIOH
#define LED1_GPIO_CLK RCC_AHB1Periph_GPIOH
static __IO u32 TimingDelay;
/**
* @brief 启动系统滴答定时器 SysTick
* @param 无
* @retval 无
*/
void SysTick_Init(void)
{
/* SystemFrequency / 1000 1ms中断一次
* SystemFrequency / 100000 10us中断一次
* SystemFrequency / 1000000 1us中断一次
*/
if (SysTick_Config(SystemCoreClock / 100000))
{
/* Capture error */
while (1);
}
}
/**
* @brief us延时程序,10us为一个单位
* @param
* @arg nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
* @retval 无
*/
void Delay_us(__IO u32 nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
/**
* @brief 获取节拍程序
* @param 无
* @retval 无
* @attention 在 SysTick 中断函数 SysTick_Handler()调用
*/
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
/*
1-初始化LED灯所在的GPIO引脚
PH10 定时器5的CH1
2-查看说明手册,判断定时器是否有输出功能
16 位(TIM3 和 TIM4)或 32 位(TIM2 和 TIM5) 递增、递减和递增/递减自动重载计
数器。
说明可用
3-编写GPIO初始化
4-编写定时器初始化
5-主函数调用
*/
void tim14_init(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/*开启LED相关的GPIO外设时钟*/
RCC_AHB1PeriphClockCmd ( LED1_GPIO_CLK, ENABLE);
RCC_APB1PeriphClockCmd ( RCC_APB1Periph_TIM5, ENABLE);
GPIO_PinAFConfig(GPIOH,GPIO_PinSource10,GPIO_AF_TIM5);
GPIO_InitStructure.GPIO_Pin = LED1_PIN; /*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; /*设置引脚模式为输出模式*/
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /*设置引脚的输出类型为推挽输出*/
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; /*设置引脚为上拉模式*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; /*设置引脚速率为2MHz */
GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure); /*调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO*/
//90Mhz 设置到100HZ输出,90000000/9000/100 = 100hz
TIM_TimeBaseStructure.TIM_Period = 100-1;
TIM_TimeBaseStructure.TIM_Prescaler = 9000-1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM5,&TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM5,TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM5,ENABLE);
// 使能定时器
TIM_Cmd(TIM5, ENABLE);
}
int main(void)
{
uint32_t pwm_cmp = 0;//新建一个比较值
SysTick_Init();
tim14_init();
while(1)
{
for(pwm_cmp =1;pwm_cmp<100;pwm_cmp++)
{
//设置比较值,查看所接的LED渐灭,因为0点亮
//如果想要渐亮,设置pwm_cmp为从100--1即可
TIM_SetCompare1(TIM5,pwm_cmp);
Delay_us(5000); // 1000 * 10us = 100ms
}
for(pwm_cmp=99;pwm_cmp>0;pwm_cmp--)
{
TIM_SetCompare1(TIM5,pwm_cmp);
Delay_us(5000); // 100 * 10us = 1000us = 1ms *100 = 100ms
}
}
}
/*********************************************END OF FILE**********************/
在stm32f4xx_it.c
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
上一篇:STM32独立看门狗(宠物狗)
下一篇:STM32系统嘀嗒定时器实现1ms中断事件
推荐阅读
推荐帖子
- multisim 12的问题 急急急急急急急
- 下载12安装后进入显示无法连接datebase数据库,problem:Accessingthedatebase有大牛能解决吗?????? 而且卸载后重新安装也不好使点击确定后元件库里面什么都没有0.0multisim12的问题急急急急急急急
-
334550282
单片机
- 【雅特力开发板 AT32F421 测评】3、对外设位操作的疑问,难道不好用
- 本帖最后由ddllxxrr于2021-4-1116:38编辑 我觉得位操作十分简单,然而就是这个简单的操作,害了我一整天。我不得不宣布,对外设的位操作失败。我看了下例程提供的位操作是对RAM的,我觉得没有什么实用价值,谁会没有事跑到RAM去操作一个BIT。我要有价值的那就是象51单片机那样的位操作。我本来十分有把握的建了H文件内容如下: #ifndef__BITBAND__ #define__BITBAND__//#defineBITBAND(addr,
-
ddllxxrr
国产芯片交流
- 解决Simplicity Studio V3 windows版make运行出错的问题
- 在使用SimplicityStudioV3windows版时,在编译时遇到一个提示,make不能运行。错误提示如下: 搜索了一下,一般说需要用vs中的rebase重新设置。但是我没有安装庞大的vs,所以又继续查找。 后来在http://www.madwizard.org/electronics/articles/winavrvista发现有提示说问题在msys-1.0.dll上,替换这个文件就正常了。试了一下,果然如此。 为了防止以后外网可能会访问不了,所
-
dcexpert
单片机
- EEworld Datasheet库 改版啦,欢迎纠错!
- >>Datasheet 经过了将近一月的规划,设计,代码实现,内测等等繁复的流程,终于在今早与大家见面了, 希望你喜欢~ 多多纠错~~~ EEworldDatasheet库改版啦,欢迎纠错!
-
soso
下载中心专版
- stm32f103的外部flash
- 请教一个问题,如果使用stm32f103ze的外部flash来存储程序,怎么用仿真器把程序下载到外部flash中?我用的ST-LINK-II,开发环境是IAR4.42,这个开发环境的flashloader中,只有对应于内部flash的,如果要下载到外部flash是不是要自己编写flashloader啊?stm32f103的外部flash
-
abcdtemp
stm32/stm8
- ATSAMD51 EVK 移植 Aduino 笔记
- 【ATSAMD51EVK在Aduino迎宾机器人移植时笔记-哔哩哔哩】https://www.bilibili.com/video/BV1aD4y1V73J/?buvid=XYB5BEEBCDEAF0E2655F6834F01BDC2673CFA&is_story_h5=false&mid=a6uhrPCQfVj6M3teRn1ZjQ%3D%3D&share_from=ugc&share_medium=android&share_plat=android
-
程英茂
Microchip MCU