历史上的今天
返回首页

历史上的今天

今天是:2024年09月16日(星期一)

2021年09月16日 | 【STM32模块化程序】PWM产生

2021-09-16 来源:eefocus

一、STM32的通用定时器介绍

STM32F103ZE 拥有 TIM2、TIM3、TIM4 和 TIM5 共 4 个通用定时器。


STM32F103C8拥有TIM2/TIM3/TIM4这三个通用定时器


通用定时器除了具备基本定时器的向上计数器功能外,还可以向下、向上/向下计数。


此外还具备独立通道,能够实现输入捕获、输出比较、PWM 输出、单脉冲输出的功能。


二、输出比较产生PWM

1、产生PWM的几种方式

①、硬件实现。比如STM32 自带的 PWM 输出功能。


注意了,硬件实现的时候,外部接线需要接到通用定时器的外部通道上!


②、通用定时器的输出比较实现软件的PWM,这个软件产生的PWM要比定时器模拟产生的PWM精确许多。


③、单纯的定时器计数实现PWM。


2、STM32的输出比较相关介绍

每个通用定时器拥有4路捕获/比较通道。


每路通道都有一个捕获/比较寄存器(TIMx_CCRx)用于装载初值。

同时该寄存器包含两个寄存器,一个是供用户写入比较值的,另一个是和计数器比较的当前捕获/比较寄存器。


捕获/比较模式寄存器 x(TIMx_CCMRx)中有输出比较预装载使能位(OCxPE ),开启后只有当更新时间到来时, TIMx_CCRx寄存器的比较值,才会传入到当前捕获/比较寄存器。否则写入的比较值将立即生效。


当计数器和捕获/比较模式寄存器 x(TIMx_CCMRx)一样时,会发生什么呢?


①、假如此时设置了事件产生寄存器(TIMx_EGR)中的 CCxG 位,会产生一个捕获/比较事件。


②、设置了相应的中断使能位TIMx_DIER 寄存器中的 CCxIE 位,则会产生一个捕获/比较中断。


3、输出比较产生PWM代码实现

timer.c



#include "timer.h"


/* TIM4中断优先级配置函数 */

void NVIC_TIM4Enable(void)

{

    NVIC_InitTypeDef NVIC_initstructure;


    NVIC_initstructure.NVIC_IRQChannel = TIM4_IRQn;           //选择TIM4中断通道

    NVIC_initstructure.NVIC_IRQChannelCmd = ENABLE;           //使能中断通道

    NVIC_initstructure.NVIC_IRQChannelPreemptionPriority = 0; //设定抢占优先级为0

    NVIC_initstructure.NVIC_IRQChannelSubPriority = 0;        //设定响应优先级为0

    NVIC_Init(&NVIC_initstructure);

}


/* TIM4初始化函数*/

void TIM4Init(void)

{

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;


    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);        //使能TIM4时钟

    TIM_TimeBaseStructure.TIM_Period = 255;                     //自动重装载值设为255,方便产生0-255级RGB颜色等级

    TIM_TimeBaseStructure.TIM_Prescaler = 72*39-1;              //计数周期设为39us,以使RGB刷新达到100Hz无闪烁效果

    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                //基本定时器没有时钟分频功能,此项会被忽略

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置向上计数模式

    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);             //初始化TIM4

    TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);           //使能TIM4 CCR1的预装载寄存器

    TIM_SetCompare1(TIM4, 0);                                   //设定TIM4捕获比较1寄存器值为0

    NVIC_TIM4Enable();                                          //初始化TIM4中断优先级

    TIM_ClearITPendingBit(TIM4, TIM_IT_Update|TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3); //清除中断标志位,否则启动中断会先进中断服务函数

    TIM_ITConfig(TIM4, TIM_IT_Update|TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3, ENABLE);  //使能TIM4更新中断和捕获/比较1、2、3的中断源

    TIM_Cmd(TIM4, ENABLE);                                      //使能TIM4定时器

}


stm32f10x_it.c


...


/* TIM4中断 */

void TIM4_IRQHandler (void)

{

    /* 采用直接寄存器操作,可以获得比库函数更高的执行效率,节省中断函数执行时间 */

    if ((TIM4->SR & TIM_FLAG_Update) != 0) //检测是否为定时器溢出中断

    {

        TIM4->SR = ~TIM_FLAG_Update; //清除更新中断标志位

        if (TIM4->CCR1 != 0)         //比较值(即占空比)不为0时,点亮小灯,下同

        {

            LED = 1;

        }

    }    

    else if ((TIM4->SR & TIM_IT_CC1) != 0) //检测比较中断产生时熄灭小灯,下同

    {

        TIM4->SR = ~TIM_IT_CC1; //清除捕获/比较通道1中断标志位

        LED = 0;

    }

}


此处只是简单的验证,所以在主函数通过设定比较值来改变占空比。


TIM_SetCompare1(TIM4, 5); //这里的设置的范围是0~255(定时器设置的时候分了256级!)


//当然也可以直接采用寄存器的方式 TIM4->CCR1 = 5;


还需要注意的是通用定时器的分频值,预计装载值。具体解释可以看<这里>。


三、硬件PWM

硬件实现的时候,外部接线需要接到通用定时器的外部通道上!当然也不可以,不在对应的外部通道上!(前提得能重映射!)


基本定时器不能输出PWM,通用和高级定时器才可以。


而通用和高级的配置又有所不同,一个一个来看…


1、高级定时器的硬件PWM输出

对应TIM1_CH1 - PA8 ; TIM_CH4 - PA11


void TIM1Init()

{

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

TIM_OCInitTypeDef  TIM_OCInitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  //使能GPIO外设时钟使能

//设置该引脚为复用输出功能,输出TIM1 CH1 CH4的PWM脉冲波形

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_11; //TIM_CH1 //TIM_CH4

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

TIM_TimeBaseStructure.TIM_Period = 255; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值

TIM_TimeBaseStructure.TIM_Prescaler = 72*39-1; //设置用来作为TIMx时钟频率除数的预分频值  不分频

TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式

TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

//TIM_OCMode;TIM_OCPolarity-对应输出的占空比CCR。 TIM_OCMode=1;TIM_OCPolarity=High或者TIM_OCMode=2;TIM_OCPolarity=Low为正常

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能

TIM_OCInitStructure.TIM_Pulse = 1;                            //设置待装入捕获比较寄存器的脉冲值;也就是刚上电的占空比

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;     //输出极性:TIM输出比较极性高

TIM_OC1Init(TIM1, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

TIM_OC4Init(TIM1, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

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

TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH1预装载使能  

TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);  //CH4预装载使能  

TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIMx在ARR上的预装载寄存器

TIM_Cmd(TIM1, ENABLE);  //使能TIM1

}


2、通用定时器的硬件PWM输出

对应TIM3_CH2 - PA7


void TIM3Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

TIM_OCInitTypeDef TIM_OCInitStructure;

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

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能 GPIOA时钟

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

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM_CH2

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIO

//初始化 TIM3

TIM_TimeBaseStructure.TIM_Period = 255; //设置在自动重装载周期值

TIM_TimeBaseStructure.TIM_Prescaler = 72*39-1; //设置预分频值

TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数模式

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化 TIMx

//初始化 TIM3 Channel2 PWM 模式

TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择 PWM 模式 1

TIM_OCInitStructure.TIM_Pulse = 255;

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性高

TIM_OC2Init(TIM3, &TIM_OCInitStructure); //初始化外设 TIM3 OC2

TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能预装载寄存器

TIM_Cmd(TIM3, ENABLE); //使能 TIM3

}

推荐阅读

史海拾趣

Brilliance公司的发展小趣事

在国内市场取得一定成功后,Brilliance公司开始将目光投向国际市场。公司制定了详细的国际化战略,积极寻求与国际知名企业的合作机会。通过与国外合作伙伴的共同努力,Brilliance的产品逐渐打入国际市场,并获得了良好的口碑。同时,公司还积极参加国际电子展会和交流活动,提升了品牌知名度和影响力。

Engelking Elektronik GmbH公司的发展小趣事

作为一家有社会责任感的企业,Engelking Elektronik始终关注环保和可持续发展问题。公司积极采用环保材料和清洁能源,减少生产过程中的污染排放和资源浪费。此外,Engelking Elektronik还积极参与公益活动和慈善捐赠,回馈社会。公司坚信只有关注社会责任和可持续发展才能实现企业的长期繁荣和稳定。

HDK(北陆电气)公司的发展小趣事

Engelking Elektronik一直将品质管理作为公司的核心竞争力之一。公司建立了完善的质量管理体系,从原材料采购到产品制造、测试和包装等各个环节都进行严格的质量控制。此外,公司还定期邀请第三方机构进行质量审核和评估,确保产品符合国际标准和客户要求。通过持续改进和优化生产流程,Engelking Elektronik的产品质量得到了客户的高度认可和信赖。

上海双岭电子(Double-peak)公司的发展小趣事

在保持核心技术优势的同时,双岭电子也积极探索跨界合作的可能性。通过与国内外知名企业和研发机构的合作,公司成功将场效应半导体器件应用于传感器、仪器仪表和自动化控制等领域。这种跨界合作不仅拓宽了公司的市场渠道,也提升了产品的附加值。同时,双岭电子还积极参与各类行业展会和交流活动,与业界同行建立了良好的合作关系。

Alpha (Taiwan)公司的发展小趣事

Alpha (Taiwan)公司自创立之初,便致力于电子技术的研发与创新。面对日益激烈的市场竞争,公司不断投入资金,引进先进设备,吸引了一批优秀的研发人才。这些人才凭借深厚的专业知识和敏锐的市场洞察力,成功开发出一系列具有竞争力的电子产品,如高性能的芯片、精密的传感器等。这些产品的推出,不仅提升了公司的市场地位,也为公司的快速发展奠定了坚实基础。

Cables To Go公司的发展小趣事

随着电子设备的普及和互联网的发展,Cables To Go公司看到了巨大的市场潜力。公司积极拓展销售渠道,通过线上电商平台和线下实体店相结合的方式,将产品销往全国各地。此外,公司还积极开拓国际市场,与多个国家和地区的代理商建立了合作关系,进一步扩大了市场份额。这种跨越式的市场拓展策略为公司的快速发展奠定了坚实的基础。

问答坊 | AI 解惑

PROTEUS中文教程

PROTEUS中文教程.doc…

查看全部问答>

从工行漏洞看国内银行金融网站

http://blog.eeworld.net/zhblue/archive/2007/01/02/1472585.aspx 今天我也原创一回,谁给我推荐推荐,算然短点,还是希望我们linux版友支持 …

查看全部问答>

.NET Micro Framework 有人做吗?

哪里有好的教程呀? http://msdn2.microsoft.com/en-us/embedded/bb267253.aspx…

查看全部问答>

异步时钟信号同步

在异步设计中,为了防止亚稳态,信号的同步是必须要进行的 单bit信号的同步通常是用时钟锁存的方法 从异步的时钟频率来看,还可以细分为两小类  第一类 被同步的信号时钟域的频率比本时钟域的频率低 这时候可以直接通过双锁存的方法来 ...…

查看全部问答>

电源设计小贴士 20:注意那些意外谐振响应

简介:注意那些意外谐振响应您曾经将输入电压接通到您的电源却发现它已经失效了吗?短暂的输入电压上升时间和可产生两倍于输入电源电压的高 Q 谐振电路可能会是问题所在。如果您迅速中断感应元件中的电流便会出现类似问题。会出现这类问题的一些情 ...…

查看全部问答>

单片机复位电路设计

单片机复位电路设计 (转自 http://www.hpoo.ne) 一、概述 影响单片机系统运行稳定性的因素可大体分为外因和内因两部分:  1、外因     射频干扰,它是以空间电磁场的形式传递 在机器内部的导体(引线或零件引脚)感生出相应 ...…

查看全部问答>

分区PBR详解:分区引导扇区知识

转帖:感谢作者 分区PBR详解: 分区引导扇区知识 一、FAT32的分区引导扇区 分区引导扇区DBR(DOS BOOT RECORD)是由FORMAT高级格式化命令写到该扇区的内容;DBR是由硬盘的MBR装载的程序段。DBR装入内存后,即开始执行该引导程序段,其主要功能 ...…

查看全部问答>

友晶 altera de2-115 fpga开发板 9.5新 配件齐全

如题 近全新 功能完全正常 1800rmb 或换onyx m92系列电纸书加差价 需要的qq:1033015591 [ 本帖最后由 loadjump 于 2012-9-30 12:39 编辑 ]…

查看全部问答>

Altium Designer中这个问题怎么处理?

如图所示: 一个按键的PCB封装,焊盘2和焊盘2之间在按键内部是物理连接的,所以之间不需要再布线连接,但是在PCB设计时会在这两个焊盘间有连接提示飞线,这样对布线(影响走线)和校验(如果置之不理的话)会有影响。请问这种情况怎么处理?怎 ...…

查看全部问答>

关于ths3001和buf634级联的问题

本帖最后由 paulhyde 于 2014-9-15 03:30 编辑 由于altium designer没法更好的显示原理图,所以用TINA做了这个原理图,请大家帮我看看有什么问题 这是我自制的pcb 测试的时候出现两个三个问题,第一个问题就是ths3001和buf634级联的地方那个Ro ...…

查看全部问答>