历史上的今天
返回首页

历史上的今天

今天是:2024年09月27日(星期五)

正在发生

2021年09月27日 | stm32之定时器运用———呼吸灯

2021-09-27 来源:eefocus

呼吸灯原理

1.在模拟电路中,呼吸灯的实现可以通过一个呈现正弦的电压控制,这个电压是连续变化的,所以肉眼看上去就是逐渐变暗,逐渐变亮。


2.而在数字电路中如何实现这种效果呢?就需要通过pwm,也就是脉冲宽度调制,将模拟量转换为数字量。只要能够用连续电压控制的东西都是可以通过pwm方式来驱动,效果是一样的。


3.

这里写图片描述

上面一块区域的面积等于对应下来的矩形的面积,当然,取得块的间隔越小(即pwm的周期越小),效果越好。这时,如果周期定了,就可以通过改变占空比来实现面积的改变,从而模拟出上面那张图的电压的连续变化。


注意:pwm波的高度是一定的,所以只能通过改变宽度(占空比)来实现面积的改变


4.说明:观察这张图,会发现下面的pwm波是中心与上面的对齐(即pwm中心为高电平),然后左右扩展,每个波的周期还是一样。当然这时可以的。但更多的是运用左对齐(起始为高电平),然后向右扩展直到面积到达要求。


5.stm32实现pwm输出的原理:设点一个值为a,然后在设置一个重装值b,b>a.开始计数,当计数值小于a时,输出高电平,当计数值大于a时,输出低电平,直到计数到b,到b后又重复来一遍。所以改变这个a就可以改变占空比、


6.PWM 的输出其实就是对外输出脉宽可调(即占空比调节)的方波信号,信号频率是由自动重装寄存器 ARR 的值决定,占空比由比较寄存器 CCR 的值决定。其示意图如图 19.1.2 所示:

这里写图片描述

从图 19.1.2 中可以看到,PWM 输出频率是不变的,改变的是 CCR 寄存器内的值,此值的改变将导致 PWM 输出信号占空比的改变。占空比其实就是一个周期内高电平时间与周期的比值。PWM 输出比较模式总共有 8 种,具体由寄存器 CCMRx 的位 OCxM[2:0]配置。我们这里只讲解最常用的两种 PWM 输出模式:PWM1 和 PWM2,PWM1 和 PWM2 这两种模式用法差不多,区别之处就是输出电平的极性不同。如图 19.1.3 所示:

这里写图片描述

pwm输出配置步骤

其实 PWM 输出和上一章一样也是通用定时器的一个功能,因此还是要用到定时器的相关配置函数


1.因为pwm是由定时器输出的,既然用到定时器,就先要使能定时器的时钟:


RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);//我们用的为tim14定时器


2.因为用到io作为输出,所以要打开io口的时钟:


RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);//注意:io口的外设均是挂在AHB1总线上的


3.通过看手册,TIM14 的 CH1 通道对应的管脚是 PF9,而pf9有很多复用功能,所以要选择pf9的输出模式:通过函数:


void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource,

uint8_t GPIO_AF);//前两个参数不说了。第三个参数为复用为哪种功能,这里我们使用的是 TIM14 功能,所以参数为 GPIO_AF_TIM14


所以函数为:GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);//AF就是复用的意思


4.配置io口,同之前led时一样,只不过参数有些变化:


      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;//PF9 管脚模式配置为复用输出

      GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;

      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//速度不变

      GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推完输出不变

      GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上啦输出不变

      GPIO_Init(GPIOF,&GPIO_InitStructure);


5.初始化定时器参数,包含自动重装值,分频系数,计数方式等.同前面使用定时器中断


      TIM_TimeBaseInitStructure.TIM_Period = pre;//预装值,这里依然通过参数传递进来

      TIM_TimeBaseInitStructure.TIM_Prescaler = psc;//预分频系数

      TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//固定不变

      TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数

      TIM_TimeBaseInit(TIM14,&TIM_TimeBaseInitStructure);


6.定时器基本的参数配置完了,但是还没设置它为pwm输出模式:

用到的函数为:


void TIM_OCxInit(TIM_TypeDef* TIMx,TIM_OCInitTypeDef* TIM_OCInitStruct);//


注意:我们知道每个通用定时器有多达 4 路 PWM 输出通道(对于 TIM9-TIM14 最多有 2 路),所以TIM_OCxInit 函数名中的 x 值可以为 1/2/3/4。函数的第一个参数相信大家一看就清楚,是用来选择定时器的。第二个参数是一个结构体指针变量:


typedef struct

{

uint16_t TIM_OCMode; //比较输出模式

uint16_t TIM_OutputState; //比较输出使能

uint16_t TIM_OutputNState; //比较互补输出使能

uint32_t TIM_Pulse; //脉冲宽度

uint16_t TIM_OCPolarity; //输出极性

uint16_t TIM_OCNPolarity; //互补比较输出极性

uint16_t TIM_OCIdleState; //空闲状态下比较输出状态

uint16_t TIM_OCNIdleState; //空闲状态下比较输出状态

}


这里我们比较常用的 PWM 模式所需的成员变量:

TIM_OCMode:比较输出模式选择,总共有 8 种,最常用的是 PWM1 和 PWM2。

TIM_OutputState:比较输出使能,用来使能 PWM 输出到 IO 口。

TIM_OCPolarity:输出极性,用来设定输出通道电平的极性,是高电平还是低电平。

结 构 体 内 其 他 的 成 员 变 量 TIM_OutputNState , TIM_OCNPolarity ,

TIM_OCIdleState 和 TIM_OCNIdleState 是高级定时器才用到的。


所以配置完为:


TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;     

TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;

TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;

TIM_OC1Init(TIM14,&TIM_OCInitStructure);


7.开启定时器


TIM_Cmd(TIM14,ENABLE);


8.修改 TIMx_CCRx 的值控制占空比(这一步写在主函数中,因为要实时去改变占空比).


其实经过前面几个步骤的配置,PWM 已经开始输出了,只是占空比和频率是固定的,例如本章要实现呼吸灯效果,那么就需要调节 TIM14 通道 1 的占空比,通过修改 TIM14_CCR1 值控制。调节占空比函数是:


void TIM_SetCompare1(TIM_TypeDef* TIMx, uint32_t Compare1);//对 于 其 他 通 道 , 分 别 有 对 应 的 函 数 名 , 函 数 格 式 是 TIM_SetComparex(x=1/2/3/4)。

1

分析:第一个参数不说了,第二个参数是计数值。。注意:这个计数值一定要小于前面设定定时器时总的预装载值(TIM_TimeBaseInitStructure.TIM_Period = pre);


代码:


pwm.c


#include "pwm.h"


void TIM14_PWM_Init(u16 pre,u16 psc)

{

      GPIO_InitTypeDef GPIO_InitStructure;

      TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

      TIM_OCInitTypeDef TIM_OCInitStructure;



      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);//´ٍ؟ھ¶¨ت±ئ÷µؤت±ضس

          RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);//زٍخھسأµ½¶ث؟ع£¬ثùزشزھت¹ؤـ¶ث؟عت¼ت±ضس£¬ءيحâioµؤحâةè¶¼تا¹ز½سشعAHB1×ـدكةدµؤ


          GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);


      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;

          GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;

      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;//ثظ¶ب

      GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//حئحئحىتن³ِ

      GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//ةدہ­

      GPIO_Init(GPIOF,&GPIO_InitStructure);//شع³ُت¼»¯ز»دآ


          TIM_TimeBaseInitStructure.TIM_Period = pre;//ةèضأ¶¨ت±ئ÷µؤضـئع£¬ز²¾حت£×¢زâ£؛صâہïخھ´«µؤ²خت‎

      TIM_TimeBaseInitStructure.TIM_Prescaler = psc;//¶¨ت±ئ÷ش¤·ضئµدµت‎

          TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//ح¨³£²»ذق¸ؤثû£¬¹ج¶¨µؤ£¬ز»°مآج²¨µؤت±؛ٍسأ

      TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//دٍةد¼ئت‎£¬´سءم؟ھت¼¼ئت‎£¬¼ئت‎µ½ضط×°ضµ

      TIM_TimeBaseInit(TIM14,&TIM_TimeBaseInitStructure);//³ُت¼»¯ز»دآ


          TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;

        TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;

          TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;

        TIM_OC1Init(TIM14,&TIM_OCInitStructure);


        TIM_Cmd(TIM14,ENABLE);


}


mian.c


int main()

{

    u8 fx = 0;

    u32 i = 0;//ำรภดภผำ

    RCC_HSE_Config(8,336,2,7);

    Beep_Init();

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    SysTick_Init(168);

    key_init();

    LED_Init();

    TIM14_PWM_Init(500-1,84-1);//2000hz,ึฦฺถจมห,0.5MS


    //while(1)

    //{

        //  if(fx==0)

            //{

                //  i++;

                //  if(i==300)

                //  {

                    //      fx=1;

                //  }

            //}


            //else

            //{

            //      i--;

                //if(i==0)

            //  {

                //      fx=0;

                //}

            //}

         // TIM_SetCompare1(TIM14,i);

            //delay_ms(10);

    //}



    /********the second code*****/

        while(1)

        {

           while(i<=300)

           {

              TIM_SetCompare1(TIM14,i);

              delay_ms(10);

              i++;

           }


           while(i!=0)

           {

              TIM_SetCompare1(TIM14,i);

              delay_ms(10);

              i--;

           }

      }

}


补充:

1.主函数中注释代码是官方的代码,下面是我自己原创的代码。官方代码是引用了一个变量来判断方向。


2.观察主函数的代码,我们设定的定时器为0.5ms,意思就是pwm波的周期为0.5ms,而每次执行完TIM_SetCompare1(TIM14,i);波形(占空比)就会改变,而后面写的delay_ms(10);是为了维持这一个波形一段时间,反映在模拟信号上就是电压变化的很平缓,很慢,自然亮度的变化也就很缓慢自然。自然,这个延迟时间知道要大于你定时时间好几倍吧-.-


扩展

试试用pwm输出来控制板子上的蜂鸣器来实现控制他的声音大小


提示:看电路图发现beep连在pf9上,而pf9本来就是tim13的复用口。所以只需在这个代码基础上修改定时器的标号为tim13即可

推荐阅读

史海拾趣

Cofan Usa Inc公司的发展小趣事

在快速发展的过程中,Cofan Usa Inc公司意识到供应链管理的重要性。为了确保产品质量和交货期的稳定性,公司开始优化供应链管理流程,与优质供应商建立长期合作关系,并引入先进的供应链管理系统。这些举措有效提升了公司的运营效率和市场竞争力。

迪一电子公司的发展小趣事

迪一电子公司成立于2006年,最初只是一家规模较小的半导体电子元器件制造企业。在创业初期,公司面临着资金紧张、技术落后和市场竞争激烈等多重困难。然而,创始人李政坚信半导体行业的发展潜力,带领团队不断研发新产品,提高产品质量,逐渐在市场上赢得了一席之地。

DRS Technologies公司的发展小趣事

在全球电子行业快速发展的背景下,DRS面临着来自各方面的挑战。为了应对这些挑战,DRS不断加强研发投入,提高产品质量和服务水平。同时,公司也积极拓展国际市场,寻求更多的合作机会。通过这些努力,DRS在全球电子行业中保持了领先地位,并为未来的发展奠定了坚实的基础。

请注意,由于篇幅限制,以上故事均为概述性质,具体细节和背景信息可能有所省略。

Fong Ya Enterprise Co Ltd公司的发展小趣事

DRS Technologies公司成立于1968年,由Leonard Newman和David Gross两位工程师共同创立。当时,他们正在Loral Corporation研究反潜战的信号处理技术。然而,当Loral决定转向其他技术方向时,Newman和Gross决定继续他们的研究,并创立了DRS。他们的努力最终导致了AN/SQR-17无源潜艇探测系统的开发,这一系统至今仍在广泛使用。

德国ACAM公司的发展小趣事

2023年,ACAM公司与上海科技大学智造系统工程中心(CASE)签署了增材制造联合研发、应用研究和教育培训协议。这次合作标志着ACAM公司在增材制造领域的布局进一步深化,双方将共同推动增材制造技术的创新和应用,为行业的发展贡献更多的力量。

这五个故事展示了德国ACAM公司在电子行业中的发展历程和取得的成就。从创立之初的技术突破,到被收购后的技术实力大增,再到超声波计量领域的革命性突破,以及与高校合作推动增材制造发展,ACAM公司始终保持着创新的精神和不断进取的态度,为电子行业的发展做出了重要贡献。

Altus Technology Inc公司的发展小趣事

Altus Technology Inc自成立以来,始终将技术创新作为公司发展的核心驱动力。在早期,公司研发团队通过不懈努力,成功开发出了一款具有革命性的芯片,这款芯片在性能和功耗上均优于当时的同类产品。凭借这一技术突破,Altus在市场上迅速获得了一席之地,并吸引了大量合作伙伴和投资人的关注。随着技术的不断迭代和升级,Altus逐渐在电子行业中树立了技术领先的形象,并持续推出了一系列创新产品,巩固了市场地位。

问答坊 | AI 解惑

加快电源启动的分流稳压器

在特定应用中,设计要求可能  需要系统的开关模式电源比普通电源能更迅速地提供输出。图 1 显示了这种电源的自举(或称启动)电路。在开关模式电源的 PFC(功率因数校正)预稳压器中,电路的 PWM(脉宽调制器),即 IC1,从辅助绕组 L1 ...…

查看全部问答>

m16中文手册

m16中文手册第一部分…

查看全部问答>

下面的汇编语言程序怎么分析

STACK  SEGMENT STACK        DB 1024 DUP(0) STACK  ENDS DATA   SEGMENT TABF   DW   262,350,352,350,441,393,350,393,441        DW  & ...…

查看全部问答>

在WINCE5中打开串口错误?

我写了一个串口程序,在模拟器PPC2003上调试是可以的,能正常的打开串口并收发数据,但部署到真机(WINCE5)串口都打不开,代码如下:                 try          &n ...…

查看全部问答>

//---------TCPMP如何指定从哪帧开始播放,播放到哪帧停止--------

TCPMP如何指定从哪帧开始播放,播放到哪帧停止. 在我的项目中,使用的视频文件是AVI格式的,打算用TCPMP实现,要准确的定位播放起始帧与结束帧,并播放从起始帧到结束帧之间的视频段。 跪求高人指点。…

查看全部问答>

用pl2303做了一个USB转串口,电脑检测不到。

用pl2303做了一个USB转串口,可是电脑怎么都检测不到。只有当我将万用表接到17脚和地时,电脑才能检测到。查了好几天了,请各位老师帮我看看。D:\\网址\\44.jpg…

查看全部问答>

关于短信猫的开发包问题

想买个短信猫做个简单的应用。但问了下如果提供2次开发包要贵几倍了。    网上下了个金仓短信猫的2次开发包[免费的],里面提供了很多语言的接口和演示,还不错,但不知道短信猫的开发包能否通用.....…

查看全部问答>

做逻辑的难点在于系统结构设计和仿真验证

刚去公司的时候BOSS就和我讲,做逻辑的难点不在于RTL级代码的设计,而在于系统结构设计和仿真验证方面。目前国内对可综合的设计强调的比较多,而对系统结构设计和仿真验证方面似乎还没有什么资料,这或许也从一个侧面反映了国内目前的设计水平还比 ...…

查看全部问答>

新手提问,多多帮忙啊!!

我刚接触到TI公司的2000系列DSP,我装好CCS2000后,启动SetUpCCS2000后,在configurition里我选择的是F2812Device Sumilator,保存后启动CCS,可在打开和新建工程的时候都有问题,具体的时在新建工程的对话框里Target一栏里没有可选项,所以就不能建 ...…

查看全部问答>

zstack的时钟

使用cc2530,timer2是mac timer。某些资料上面说周期是320us。但是不明白函数osalTimeUpdate()里边的操作 tmp = (ticks320us * 8) + remUsTicks; 以及osalTimeUpdate()调用的函数 CONVERT_320US_TO_MS_ELAPSED_REMINDER( tmp, elapsedMSec, r ...…

查看全部问答>