0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32单片机--PWM输出

电子工程师 2018-04-03 08:54 次阅读

采用定时器2的通道2,使PA1输出频率1K,占空比40的PWM波形,用PA8随意延时取反led灯,指示程序运行

上午花了半天时间熟悉了stm32的PWM模块。中午利用午饭时间把PWM功能调试成功。当然,很简单的东西,也许很多前辈估计都不屑一顾的东西。

今天最大的感叹就是网络资源实在是个巨大的宝库,真的很庆幸,在这个复杂的社会环境里,在一个到处充斥着私心、私利的时代,各个网站,各个论坛上的众多网友都时刻保持着开源的氛围。学习一定要和他人交流,而网络提供了这么一个极好的平台。

废话少说,言归正传。

实现功能:采用定时器2的通道2,使PA1输出频率1K,占空比40的PWM波形,用PA8随意延时取反led灯,指示程序运行。

首先熟悉一下定时器的PWM相关部分。看图最明白

其实PWM就是定时器的一个比较功能而已。

CNT里的值不断++,一旦加到与CCRX寄存器值相等,那么就产生相应的动作。这点和AVR单片机很类似。既然这样,我们要产生需要的PWM信号,就需要设定PWM的频率和PWM的占空比。

首先说频率的确定。由于通用定时器的时钟来源是PCLK1,而我又喜欢用固件库的默认设置,那么定时器的时钟频率就这样来确定了,如下:

AHB(72MHz)→APB1分频器(默认2)→APB1时钟信号(36MHz)→倍频器(*2倍)→通用定时器时钟信号(72MHz)。

这里为什么是这样,在RCC模块学习记录里有详细记载,不多说。

因此图中的CK_PSC就是72MHz了。

下面的资料也是网上一搜一大把,我就罗列了:

STM32的PWM输出有两种模式,模式1(PWM1)和模式2(PWM2),由TIMx_CCMRx寄存器中的OCxM位确定的(“110”为模式1,“111”为模式2)。模式1和模式2的区别如下:

110:PWM模式1-在向上计数时,一旦TIMx_CNT=TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。

111:PWM模式2-在向上计数时,一旦TIMx_CNT=TIMx_CCR1时通道1为有效电平,否则为无效电平。

由此看来,模式1和模式2正好互补,互为相反,所以在运用起来差别也并不太大。我用的是模式一,因此后面的设定都是按照模式一来设定的。

PWM的周期是就是由定时器的自动重装值和CNT计数频率决定的。而CNT的计数时钟是CK_PSC经分频器PSC得到,因此CNT的时钟就是CK_PSC/分频系数。这个分频系数在TIM_TimeBaseStructure.TIM_Prescaler确定。成都网站设计我设置的值是72,因此CNT的计数频率也就是CK_CNT的频率为1MHz。

下一步就是确定定时器自动重装值。因为CNT每自加到ARR寄存器的值时就会自动清零,当然前提是设定为为向上计数模式,而就是根据这个溢出事件来改变PWM的周期。所以PWM信号的频率由ARR的值来确定。我设置的值是1000-1,即TIM_TimeBaseStructure.TIM_Period = 1000-1;因此PWM的周期是1MHz/1000=1KHz。

接下来就要确定PWM的占空比了。因为CNT在自加到ARR值的过程中会不断和CRRX的值相比较,一旦二者相等就产生匹配事件,但要注意CNT不会理会这件事,它会继续++直到等于ARR。而CRRX的值我设定为400-1,那么占空比就随之确定为40%。

好了,下面就是库函数的配置了。

TIMER输出PWM实现步骤

1.设置RCC时钟;

2.设置GPIO;

3.设置TIMx定时器的相关寄存器;

4.设置TIMx定时器的PWM相关寄存器。

首先是main函数和全局变量申明,很简单,不作说明


GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_OCInitTypeDef TimOCInitStructure;

int main(void)
{

rcc_cfg();
gpio_cfg();
tim2_cfg();
pwm_cfg();
//
while (1)
{

GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);

delay();


GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_RESET);

delay();
}
}

下面是IO口的配置:

void gpio_cfg()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}

此处要注意的是PWM输出口要配置为复用推挽输出,原因我也不知道,反正照搬就是了。

下面是TIM配置函数,注释很清楚了,不作说明:

void tim2_cfg()
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);

TIM_DeInit(TIM2);
TIM_InternalClockConfig(TIM2);
//预分频系数为72,这样计数器时钟为72MHz/72 = 1MHz
TIM_TimeBaseStructure.TIM_Prescaler = 72;
//设置时钟分割
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
//设置计数器模式为向上计数模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
//设置计数溢出大小,每计1000个数就产生一个更新事件
TIM_TimeBaseStructure.TIM_Period = 1000-1;
//将配置应用到TIM2中
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);

//禁止ARR预装载缓冲器
TIM_ARRPreloadConfig(TIM2, DISABLE);

TIM_Cmd(TIM2, ENABLE);//使能TIMx外设
}

接下来是关键的PWM的配置函数:

void pwm_cfg()

{

//设置缺省值

TIM_OCStructInit(&TimOCInitStructure);

//PWM模式1输出

TimOCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

//设置占空比,占空比=(CCRx/ARR)*100%或(TIM_Pulse/TIM_Period)*100%

TimOCInitStructure.TIM_Pulse = 400-1;

//TIM输出比较极性高

TimOCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

//使能输出状态

TimOCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

//TIM2的CH2输出

TIM_OC2Init(TIM2, &TimOCInitStructure);

//设置TIM2的PWM输出为使能

TIM_CtrlPWMOutputs(TIM2,ENABLE);

}

stm32固件库的输出比较单元结构体与定时器的时基单元是分开定义的,而PWM模式只是输出比较结构体成员TimOCInitStructure.TIM_OCMode的一个取值,当把此结构体填充完后,还要映射到某个定时器,用TIM_OCXInit函数实现,我用了一个X,说明不止一个这样的函数,事实上,stm32的通用定时器都有四个通道,每个通道对应一个初始化函数,这里真够纠结的!最后还要使能该定时器的PWM输出功能,TIM_CtrlPWMOutputs(TIM2,ENABLE)函数要注意,是outputs而不是output,说明TIM2不止一个通道嘛!够复杂,够繁琐的!

下面是输出比较单元的结构体原型:

typedef struct
{
uint16_t TIM_OCMode;

uint16_t TIM_OutputState;

uint16_t TIM_OutputNState;

uint16_t TIM_Pulse;

uint16_t TIM_OCPolarity;

uint16_t TIM_OCNPolarity;

uint16_t TIM_OCIdleState;

uint16_t TIM_OCNIdleState;
} TIM_OCInitTypeDef;

其中没有加色的成员是高级定时器才有的,通用定时器就不用管了。

这里还有个TimOCInitStructure.TIM_OCPolarity成员需要注意,它有什么作用呢?在网上查的资料,如下图:

前面说到pwm有pwm1和pwm2两种模式,这两种模式只能控制到OCXREF为止,TIM_OCPolarity 能控制OC1是直接等于OCXREF,还是取反极性!OC1才是最终的PWM信号。

这里有个小插曲,我用示波器去测量PWM信号,发现信号居然是双极性的,然后改变TIM_OCPolarity ,再测,还是双极性,只是倒了个跟头。还真以为stm32单片机能输出两极性的PWM,后面把示波器改为直流档(之前用的是交流档),波形才从零电位一下纵向移上去。以后要注意!

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • STM32
    +关注

    关注

    2239

    文章

    10665

    浏览量

    348518
收藏 人收藏

    评论

    相关推荐

    单片机应用技术:任务拓展pwm信号输出#单片机

    单片机输出PWM信号
    学习硬声知识
    发布于 :2022年11月09日 20:50:23

    利用单片机PWM自动控制输出电压

    想通过单片机STM32F030C8T6的PWM控制电源电压的输出,交流电源输出电压0-300V;例如当P
    发表于 06-21 11:03

    单片机PWM自动控制输出电压的大小

    想通过单片机STM32F030C8T6的PWM控制电源电压的输出,交流电源输出电压0-300V;例如当P
    发表于 06-21 11:24

    STM32单片机输出PWM进行长距离传输问题?

    问题是这样的: 使用STM32F103系列单片机输出3路频率随时间缓慢周期性变化的PWM波,需要传给1m以外的另外一个单片机进行采集并计算出
    发表于 04-26 14:14

    请问STM32单片机输出PWM怎么进行长距离传输?

    问题是这样的: 使用STM32F103系列单片机输出3路频率随时间缓慢周期性变化的PWM波,需要传给1m以外的另外一个单片机进行采集并计算
    发表于 05-05 02:46

    如何编写STM32单片机PWM脉冲输出程序?

    伺服电机控制器的基础参数怎么设置?如何编写STM32单片机PWM脉冲输出程序?
    发表于 10-08 08:58

    stm32以及51单片机PWM输出详解

    stm32以及51单片机PWM输出详解第一部分:stm321、问题:什么叫PWM?回答:(1)脉
    发表于 12-01 06:26

    使用STM32单片机输出PWM波形

      在使用STM32单片机输出PWM波形的时候,通常可以直接使用定时器提供的PWM模式。可以通过自动重装载寄存器(TIMx_ARR)来设置定
    发表于 12-06 07:56

    单片机控制pwm输出,每次烧录后pwm输出不正常

    有无朋友回答一下stm32单片机烧录之后的状态;我用stm32输出pwm波控制舵机,我设置的正常初始化
    发表于 04-05 23:07

    使用STM32F1单片机实现PWM输出的源代码和工程文件免费下载

    本文档的主要内容详细介绍的是使用STM32F1单片机实现PWM输出的源代码和工程文件免费下载。
    发表于 11-21 17:20 32次下载
    使用<b class='flag-5'>STM32</b>F1<b class='flag-5'>单片机</b>实现<b class='flag-5'>PWM</b><b class='flag-5'>输出</b>的源代码和工程文件免费下载

    基于STM32单片机的小车PWM调速系统

    基于STM32单片机的小车PWM调速系统
    发表于 06-03 09:22 40次下载

    STM32单片机PWM输出学习

    STM32单片机PWM输出学习PWM原理:PWM表示脉冲宽度调制,它是一系列脉冲,这些脉冲将以方
    发表于 11-11 11:51 26次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>单片机</b><b class='flag-5'>PWM</b><b class='flag-5'>输出</b>学习

    STM32单片机PWM输出(F103VET6)

    最近在使用单片机进行直流电机的控制,驱动器使用的L298N,在使用的时候控制一台直流电机,驱动器上用三个输入端子来控制,IN1,IN2是控制方向,使能端子就可以使用PWM来进行速度控制
    发表于 11-23 18:21 0次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>单片机</b>的<b class='flag-5'>PWM</b><b class='flag-5'>输出</b>(F103VET6)

    stm32F051系列 单片机引脚定时器输出pwm波形控制风扇转速

    输出功能的io。此文章来详述使用stm32F051R8T6型号单片机,带有定时器输出功能的引脚来输出pw
    发表于 11-29 14:06 14次下载
    <b class='flag-5'>stm32</b>F051系列 <b class='flag-5'>单片机</b>引脚定时器<b class='flag-5'>输出</b><b class='flag-5'>pwm</b>波形控制风扇转速

    基于STM32单片机PWM输出使用库文件设计源代码

    基于STM32单片机PWM输出使用库文件设计源代码
    发表于 04-26 14:56 5次下载