历史上的今天
今天是:2024年12月20日(星期五)
2021年12月20日 | STM32定时器输出PWM
2021-12-20 来源:eefocus
一、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独立看门狗(宠物狗)
史海拾趣
|
本帖最后由 paulhyde 于 2014-9-15 03:38 编辑 比赛中常用的模块有: 运算放大器模块 滤波器模块 AGC模块 DDS信号源模块 电机驱动模块 A/D模块 D/A模块 欢迎大家把资料共享,查找资料! … 查看全部问答> |
|
各位大虾,本人使用的s3c2410的芯片,在裸机下编程时出现了一个问题,我写了一段程序用于触发CPU的异常中断,但是CPU中断时没有进入中断服务函数中,不知道各位大虾有没有碰到过这种情况,如何才能够让CPU异常中断进入我的中断服务函数中?… 查看全部问答> |
|
我要用MFC编写PC端蓝牙软件,有搜索、连接、加密和传输文件的功能,希望大虾们能给我点MFC关于蓝牙编程的资料,如果有源代码参考的话就更好了。我能给的分不多,还请大虾们能无私的帮小弟个忙。感激,感激! … 查看全部问答> |
|
以下出错信息: Error[e72]: Segment FIQ_STACK must be defined in a segment definition option (-Z, -b or -P) 我是这样定义的 MODULE ?CSTARTUP RSEG&nbs ...… 查看全部问答> |
|
scancodetovirtualkey,我看了源码是调用*puiVk = MapVirtualKey(*puiSc, MAP_SC_TO_VK); 但这个函数我没找到。有谁知道的,帮忙解答下```… 查看全部问答> |
|
根据udp的协议,编写了服务器端和客户机端的程序,想验证一下收发数据是否正确,可以将收发的程序都下载到目标机下,通过自发自收来实现?vxworks下本机的ip还是:127.0.0.1吗??不知道这种方法是否可以实现??… 查看全部问答> |




