历史上的今天
返回首页

历史上的今天

今天是:2024年12月29日(星期日)

2021年12月29日 | STM32F103单片机PWM功能实现

2021-12-29 来源:eefocus

PWM模式也叫脉冲宽度调制模式,它可以产生一个频率和占空比可调的方波。由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。在硬件电路中,PWM波产生通常是由一个三角波和参考值送入比较器中,然后比较器输出的就是PWM波。

image.png?imageView2/2/w/550

V1是三角波发生器,幅度为5V,频率为1K,V2是直流源,电压为3V,将这两个波形送入到比较器中,然后比较器输出的就是PWM波。输出波形如下:

image.png?imageView2/2/w/550

当V1的电压值大于V2时,比较器输出高电平。当V1电压值小于V2时,比较器输出的就是低电平。改变V2的值,就可以改变占空比。

image.png?imageView2/2/w/550

在单片机中寄存器ARR的值就相当于V1的值,CCR的值就相当于V2的值。当ARR和CCR寄存器的值设置好之后,计时器在计数的过程中计数器值就会实时和这两个值比较,当计数器值小于CCR时,输出低电平,当计数器值大于CCR值时,输出高电平。当计数器的值等于ARR时,计数器就会清零。


在设置PWM计数模式的时候,一般有三种模式,向上计数模式、向下计数模式、中央对齐模式。


向上计数模式:指的是计数器从0开始递增计数,当计数值等于ARR时,计数器清0,然后从0开始重新递增计数。

image.png?imageView2/2/w/550

向下计数模式:指的是计数器从ARR开始递减计数,当计数值等于0时,计数器值重新设置为ARR,然后从ARR开始重新递减计数。

image.png?imageView2/2/w/550

中央对齐模式:指的是计数器0开始递增计数,当计数值等于ARR时,计时器开始递减计数。当计数器值减到0时,又开始递增计数。

image.png?imageView2/2/w/550

一般情况下用的比较多的就是向上计数模式,因为这种模式比较简单,理解起来也更容易一点。下面就通过代码来实现PWM的输出功能。


void TIM3_PWM_Init(u16 arr, u16 psc)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

    TIM_OCInitTypeDef TIM_OCInitStructure;


    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO和AFIO复用功能模块时钟


    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2(PA7)--->PB5  TIM3_CH1(PA6)-->PB4


    //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形 GPIOB.5

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOB, &GPIO_InitStructure);

    //初始化TIM3

    TIM_TimeBaseInitStructure.TIM_Period = arr;

    TIM_TimeBaseInitStructure.TIM_Prescaler = psc;

    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);

    //初始化TIM3_CH2  PWM 模式

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OC2Init(TIM3, &TIM_OCInitStructure);

    //使能TIM3在CCR2上的预装载寄存器

    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);

    //使能TIM3

    TIM_Cmd(TIM3, ENABLE);

}


void TIM1_PWM_Init(u16 arr, u16 psc)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

    TIM_OCInitTypeDef TIM_OCInitSturcture;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE);


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);


    TIM_TimeBaseInitStructure.TIM_Period = arr;

    TIM_TimeBaseInitStructure.TIM_Prescaler = psc;

    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;

    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);


    TIM_OCInitSturcture.TIM_OCMode = TIM_OCMode_PWM2;

    TIM_OCInitSturcture.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitSturcture.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OC1Init(TIM1, &TIM_OCInitSturcture);


    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);


    TIM_Cmd(TIM1, ENABLE); //使能计数器

    TIM_CtrlPWMOutputs(TIM1,ENABLE); //主输出使能

}

这里通过两个定时器输出2路PWM波。使用的计数模式都为向上计数模式。PWM模式为PWM2模式。

image.png?imageView2/2/w/550

接下来在主程序中设置PWM的频率和占空比。


int main(void)

{

    u16 led_pwm_val=0;

    u8 dir=1;

    delay_init();       //延时函数初始化

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    LED_Init();

    TIM3_PWM_Init(899,0); //不分频。PWM频率=72000000/900=80Khz

    TIM1_PWM_Init(899,0);

    while(1)

    {

delay_ms(10);

if(dir) led_pwm_val++;

else led_pwm_val--;

if(led_pwm_val>300) dir=0;

if(led_pwm_val==0) dir=1;

TIM_SetCompare2(TIM3,led_pwm_val);

TIM_SetCompare1(TIM1,led_pwm_val);

    }

}


  在主函数中向初始化函数中传递两个参数,第一个参数是设置ARR值,第二个参数是设置时钟的分频系数。这里设置的ARR值为900,系统会自动给设置的值加1(因为ARR的值至少为1),所以设置值为899时,系统真正写入ARR寄存器的值是899+1,然后时钟分频系数设置为0,也就是默认时钟频率72MHz不分频。这样PWM的频率就为系统时钟除以自动装载的值。设置的PWM频率为 72MHz/900=80K。


  要改变占空比时通过TIM_SetCompare()函数来设置,这个函数内部设置的就是CCR寄存器的值。

代码中设置的是CCR的值从0增加到300,然后又减到0。将PWM的输出端口接上一个LED灯,就可看到这个LED灯从亮到灭慢慢变化,实现了类似于呼吸灯的效果。

推荐阅读

史海拾趣

DFI公司的发展小趣事

近年来,随着智能医疗和金融科技等新兴领域的兴起,DFI看到了新的发展机遇。公司开始将这些领域作为重点发展方向,投入大量资源进行研发和创新。通过与合作伙伴的紧密合作,DFI成功推出了一系列具有创新性的智能医疗和金融科技产品。这些产品不仅为客户提供了更便捷、更高效的服务体验,也为DFI带来了新的增长点。随着这些新兴领域的不断发展壮大,DFI有望在未来实现更大的突破和发展。

请注意,以上故事均为虚构,旨在展示DFI公司可能的发展历程和业务活动。实际情况可能有所不同,具体信息请参考DFI公司的官方资料。

乾坤(Cyntec)公司的发展小趣事

产品质量是企业的生命线。乾坤公司深谙此道,因此在发展过程中始终注重质量管理体系的建立和完善。公司引进了国际先进的质量管理理念和方法,通过ISO 9001质量管理体系认证,并严格执行每一道生产工序的质量控制。为了确保产品质量的稳定性和可靠性,乾坤还建立了完善的产品测试和验证流程,每一批产品都要经过严格的质量检测才能出厂。这些举措不仅提升了产品质量,也赢得了客户的广泛认可和信赖。

Alps Alpine Co Ltd公司的发展小趣事

产品质量是企业的生命线。乾坤公司深谙此道,因此在发展过程中始终注重质量管理体系的建立和完善。公司引进了国际先进的质量管理理念和方法,通过ISO 9001质量管理体系认证,并严格执行每一道生产工序的质量控制。为了确保产品质量的稳定性和可靠性,乾坤还建立了完善的产品测试和验证流程,每一批产品都要经过严格的质量检测才能出厂。这些举措不仅提升了产品质量,也赢得了客户的广泛认可和信赖。

DURACELL公司的发展小趣事

2016年3月1日,DURACELL公司正式成为伯克希尔·哈撒韦集团的一部分。这一重要事件标志着DURACELL公司在电子行业的地位得到了进一步巩固和提升。伯克希尔·哈撒韦集团是全球知名的投资公司之一,其强大的资本实力和市场影响力将为DURACELL公司提供更多的发展机遇和挑战。在伯克希尔·哈撒韦的支持下,DURACELL公司将继续致力于推动电池技术的创新和发展,为全球消费者提供更优质的产品和服务。

Gumstix公司的发展小趣事
检查电路连接是否松动或断裂,重新连接或更换损坏的部件。
永源微电子(APM)公司的发展小趣事

随着国内外市场的不断开拓和技术实力的不断提升,永源微电子开始实施全球化战略。公司积极寻求与国际知名企业的合作机会,通过技术引进和合资合作等方式,不断提升自身的国际化水平。同时,永源微电子还注重内部管理和人才培养,通过建立完善的管理体系和激励机制,吸引和留住了一批优秀的技术人才和管理人才。在全球化战略的推动下,永源微电子实现了持续稳健的发展,成为了电子行业中一颗璀璨的明星。

以上五个故事分别从不同角度描绘了永源微电子(APM)公司的发展历程,包括创立与初步发展、技术突破与产品线拓展、市场拓展与品牌建设、A轮融资与战略合作以及全球化战略与持续发展等方面。这些故事基于事实性的描述,展现了永源微电子在电子行业中的成长轨迹和发展成就。

问答坊 | AI 解惑

有关于运放的知识

本帖最后由 paulhyde 于 2014-9-15 09:37 编辑 一些用过的运放芯片资料和运放使用技巧~~~  …

查看全部问答>

请教下图中触摸原理

s3为人手按键位置,请问工作原理?…

查看全部问答>

变频器学习

本帖最后由 paulhyde 于 2014-9-15 03:21 编辑    …

查看全部问答>

高分急求带FIFO UART源程序!!!

小妹刚接触VHDL语言不久,求一个带FIFO UART源程序,FIFO:  8位 深度:16,求各位给个源程序,急用,谢谢!…

查看全部问答>

verilog基本语法问题连接符用法讨论

input [1:0] in; //定义输入是2位的数据output [1:0] out; //定义输出是2位的数据reg [1:0] out;....out={out,in}; //使用拼接符输入和输出都是2位的,把它们拼接在一起的值赋给输出端,结果是怎样的?比如呢? verilog 采用的截断方式,所有结果 ...…

查看全部问答>

申请开发板做CAN2NET网关

在Keil环境下完成网络和CAN的协议解析和数据转换,实现CAN数据采集自动向网络发送,以及通过网络采集CAN口的数据,类似于串口转网络的功能,并实现PC机配置软件完成各种工作参数的配置和数据监控。…

查看全部问答>

求交流假电子负载方案

现在准备电子设计竞赛,做一个电子假负载的题目,开始直流模式下的恒流恒压横阻模式已完成,但负载不能进交流,求各路大神提供一下能进交流的电子负载原理电路或方案,要测量交流电源内阻的……小弟在此谢过了。。。谢谢!做了差不多3个星期了,没想 ...…

查看全部问答>

调试LPC1769工程的时候出现的问题

最近在弄一块LPC1769的板子,在刚开始建工程的时候遇到点麻烦,试了好久,在网上也找了好多资料也没解决 ,请各位大侠帮忙看看。在添加进一个工程调试时出现了如下问题: 工程代码为: #include \"LPC17xx.h\" #include #include __CRP cons ...…

查看全部问答>

数字电压表数码管显示

------------------------------------------------------------------------------------ Company: -- Engineer: -- -- Create Date:    10:42:01 04/22/2012 -- Design Name: -- Module Name:    top1 - Behaviora ...…

查看全部问答>

MSP430F538控制步进电机驱动器的

MSP430F538步进电机驱动器的控制 最近要用一个五相的步进电机,可是这个步进电机的驱动器没有用过,驱动器用的CW和CCW输入,搞得我也是醉了, 小弟是个新手,有很多不懂啊,大神们指点一下。 下面是电机的接线示例图和时序图 …

查看全部问答>