历史上的今天
返回首页

历史上的今天

今天是:2025年02月15日(星期六)

2020年02月15日 | STM32单片机--PWM输出

2020-02-15 来源:eefocus

采用定时器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,后面把示波器改为直流档(之前用的是交流档),波形才从零电位一下纵向移上去。以后要注意!

推荐阅读

史海拾趣

安森德(Ascend)公司的发展小趣事

随着国内市场的日益饱和,安森德公司开始将目光投向海外市场。公司制定了国际化战略,积极布局全球市场。通过在海外设立分公司或办事处,安森德成功将产品和服务推向国际市场。同时,公司还积极参与国际技术交流和合作,不断吸收国际先进技术和经验,提升自身的国际竞争力。这些举措为安森德公司的全球化发展奠定了坚实的基础,也为公司的未来发展打开了更广阔的空间。

请注意,以上故事仅为虚构内容,旨在满足您的需求。实际上,安森德公司的发展历程可能涉及更多具体的细节和事实,您可以查阅相关公开资料或咨询公司工作人员以获取更准确的信息。

Electro-Mech Components Inc公司的发展小趣事

在1966年,Electro-Mech Components, Inc. (EMC)做出了一个重要的战略决策——在墨西哥北下加利福尼亚州的蒂华纳开设一家制造工厂。这个决定标志着EMC正式进军国际市场,并开始了其在全球范围内的业务布局。蒂华纳工厂的建立为EMC带来了更低的制造成本和更广阔的市场前景。随着工厂规模的逐渐扩大,EMC的产品线也日益丰富,从最初的发光按钮开关逐渐扩展到指示灯和多开关互锁组件等多个领域。

Digital Core Design公司的发展小趣事

随着《古墓丽影》系列游戏的成功,Core Design的团队迅速扩张。当PS2主机即将推出时,索尼和Core Design都对这款新主机充满期待。为了抓住这一机遇,Core Design将“古墓丽影”的制作团队从最初的12人增加到60人,随后又增加到了100人。这一举措展示了Core Design对市场和技术的敏锐洞察力和决心。

Anderson Power公司的发展小趣事

然而,随着《古墓丽影》系列的不断发展,Core Design也面临了一些挑战。其中最为严重的是版权问题。由于Core Design在后续的一些作品中可能违背了“古墓”的本源,享有Lara Croft和《古墓丽影》版权的游戏发行商Eidos作出了剥夺Core Design《古墓丽影》系列开发权的决定。这一决定对Core Design来说无疑是一个巨大的打击,但也促使其开始寻找新的发展机遇。

EMC [ELAN Microelectronics Corp]公司的发展小趣事

作为一家有社会责任感的企业,义隆电子一直积极履行社会责任,致力于可持续发展。公司注重环境保护和资源节约,采用环保材料和节能技术生产产品。同时,公司还积极参与公益事业和社会活动,回馈社会。这种注重社会责任和可持续发展的企业文化使得义隆电子在行业内树立了良好的形象。

以上五个故事简要概述了义隆电子股份有限公司(Elan Microelectronics Corp.)在不同发展阶段的关键事件和成就。这些故事展示了义隆电子在技术创新、市场拓展、人才培养和社会责任等方面的努力和成就。

博通集成(BEKEN)公司的发展小趣事

随着公司规模的扩大和市场需求的增长,博通集成开始实施国际化战略,积极拓展海外市场。公司在全球范围内设立了多个子公司和技术分部,以便更好地服务全球客户。通过国际化战略和全球布局,博通集成不仅提升了企业的国际竞争力,还为全球用户提供了更加优质的产品和服务。

这些故事展示了博通集成在电子行业中的发展历程和成就。通过不断的技术创新、市场拓展、战略合作和国际化战略的实施,博通集成逐渐发展成为无线连接芯片设计领域的领军企业。未来,随着无线通讯技术的不断发展和应用领域的不断拓展,博通集成将继续保持创新精神和市场敏锐度,推动企业的持续发展。

问答坊 | AI 解惑

噪声系数测量的三种方法

摘要:本文介绍了测量噪声系数的三种方法:增益法、Y系数法和噪声系数测试仪法。这三种方法的比较以表格的形式给出。 前言在无线通信系统中,噪声系数(NF)或者相对应的噪声因数(F)定义了噪声性能和对接收机灵敏度的贡献。本篇应用笔记详细阐述这 ...…

查看全部问答>

找手机开发,地点北京

现有手机开发项目,要求有经验的手机开发团队参与。有意可以发:project911@163.com…

查看全部问答>

谁有EVC4.0+PocketPc2003开发PDA反面的电子书?

我刚刚接触EVC4.0+PocketPc2003开发PDA程序,在网上总找不到 相关的电子教程,哪位前辈能提供些教程啊!急 啊!…

查看全部问答>

《程序员面试宝典》 一本很好的面试书籍

《程序员面试宝典》一本很好的面试书籍…

查看全部问答>

制作高频加热设备过程中的一些新感触

开年后,心思都在高频加热设备上,到今天,实验结果比较满意,频率920KHz,已经达到4500W的功率,目前看还有一定的扩展余量,基本满足产品需求,下一步将继续完善,实现产品化。 总的来说,做电源之前有两次经历,一次是03年的电动自行车项目,用a ...…

查看全部问答>

高频无线类要用模块

本帖最后由 paulhyde 于 2014-9-15 09:44 编辑 各位高手,根据刚出的2011清单 高频无线类的应该会有 请问需要准备什么模块啊?能提供一些资料吗?谢谢!  …

查看全部问答>

求摄像头大神指点

本帖最后由 jameswangsynnex 于 2015-3-3 19:58 编辑 拆了手头nokiaE66的摄像头...想用STM32 cortex m3驱动它...... 没怎么接触过手机的摄像头...貌似摄像头后有块STv0986... 找到原理图...想知道摄像头引脚:PDATA2P...PDATA2N...PCLK2P...PCLK2 ...…

查看全部问答>

EEWORLD大学堂----MSP430进阶培训—MSP430F5529的使用与开发

MSP430进阶培训—MSP430F5529的使用与开发:https://training.eeworld.com.cn/course/236 ????? MSP430F5529是德州仪器新一代F5xxx系列MCU的典型代表,不但拥有更低的功耗,而且在模拟外设、?数字外设和系统软件开发方面有了很大的改进。本培训课 ...…

查看全部问答>

51单片机产生spwm波

求教为什么TH0=0x216,这样的话对应的二进制不就不止8位了嘛 搜索 复制 …

查看全部问答>