历史上的今天
返回首页

历史上的今天

今天是:2024年08月24日(星期六)

2019年08月24日 | STM32F103ZET6 — PWM(TIM1)

2019-08-24 来源:eefocus

简介

首先聊聊 PWM 输出。脉宽调制(PWM,Pulse Width Modulation)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。尤其是电机控制。


PWM 的主要参数包括频率和占空比。


死区的概念是在 PWM 控制电机引入的。由于 H 桥的存在,每个桥的上半桥和下半桥是绝对不能同时导通的,但高速的PWM驱动信号在达到功率元件的控制端时,往往会由于各种各样的原因产生延迟的效果,造成某个半桥元件在应该关断时没有关断,造成功率元件烧毁。


死区就是在互补的输出中,人为的插入 Delay,以致 H 桥不至于出现同时导通的情况。类似于 DTPHx 和 DTPHx_ 信号 :

STM32 的定时器功能十分强大,不仅仅实现了定时器的基本功能,对于高级定时器 TIM1/TIM8,更是能够输出 PWM,波形,同时还带插入死区的互补输出。天生就是拿来做电机控制的一把好手。


TIM1 对应的 Pin

TIM1 能够输出 4 路 PWM 信号,所有逻辑全部做在了硬件里面,也就是说, TIM1/TIM8 的硬件逻辑中,绑定了几个引脚,不单纯的只是 Timer:

如图所示,TIM1 的四个 Channel 1 ~ Channel 4 分别对应着 PA8 ~ PA11,互补输出的信号 Channel 1 N ~ Channel 3 N 分别对应到了 PB13 ~ PB15 管脚。


对应到单板上:

     

好了,然后连接逻辑分析仪上去:


环境准备 Ready!!!



TIM1 功能

TIM1 的功能能强大,不仅仅支持计数器,同时可以支持 4 个独立通道的:


输入捕获

输出比较

PWM 生成

单脉冲输出

死区时间可编程的互补输出

刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态

支持针对定位的增量(正交)编码器和霍尔传感器电路

触发输入作为外部时钟或者按周期的电流管理

这里关注 PWM 相关的逻辑。


TIM1 时钟

TIM1 的时钟来源于 APB2 的时钟输入:


需要开启 TIM 的时钟输入。这里配置的 APB2 时钟为 72MHz。


TIMxCLK 输入到 TIM1 模块后,会有一个预分频器(TIMx_PSC),对其进行分频,分出来的频率就供给 TIM1 的频率 (上限 65536)。同时存在一个自动装载寄存器 (TIMx_ARR) ,这个寄存器的作用是当计数器以预分频后的时钟进行计数后,达到这个装载寄存器的值,就完成一次 Timer 事件。


TIM1 还包含一个重复计数器,灵活的配置这个寄存器,能够使得多次达到 TIMx_ARR 的值后,才产生对应的事件。


TIM1 有一个预装载的功能,如果打开这个功能,代表更新 TIMx_ARR 寄存器的值,将在下一次完成事件后,才对 TIMx_ARR 进行更新,否则,立即更新 TIMx_ARR。


计数器的方式有三种:向上计数,向下计数,以及中央对齐模式(向上/向下计数) ,非常灵活。具体的详见 DataSheet。



TIM1 的 PWM 功能

TIM1 的支持的配置相当繁多,这里仅仅以向上计数的方式介绍。


在 PWM 模式中,主要是控制波形的周期和占空比:


周期的控制方式由,TIMx_ARR寄存器确定


由TIMx_CCRx寄存器确定占空比的信号。


这里引入了一个 TIMx_CCRx 寄存器,他是一个比较输出的寄存器:


下面是一个PWM模式1的例子。当 TIMx_CNT < TIMx_CCRx 时,PWM 输出的参考信号 OCxREF 为高,否则为低。以此来达到控制占空比的要求。


针对这个, STM32 有一个有效电平的概念,即先定义有效电平是 1 还是 0,然后根据和比较寄存器的比较情况,来输出有效电平。(够繁琐)。


TIM1 的配置过程

1. 当然,还是需要首先开启管脚的时钟和配置管脚的 mode


2. 配置 NVIC (如果有中断需要)


3. 开启 TIM1/TIM8 的时钟


4. 配置 TIMx_ARR 寄存器,来确定周期


5. 配置分频寄存器,确定分频参数


6. 配置计数方式(向上,向下,中央)


7. 配置 PWM1 模式


8. 开启输出和互补输出


9. 配置 TIMx_CCRx ,比较寄存器的值(后面可以更改)


10. 配置输出信号的极性


11. 开启每个输出通道的预装入功能


12. 配置死区时间


13. 开启 TIM1 的整个模块的预装入功能


14. 打开 PWM 输出


15. 开启 TIM1 的使能位


#include "stm32f10x.h"

#include "stm32f10x_rcc.h"

#include "stm32f10x_gpio.h"

#include "stm32f10x_dma.h"

#include "stm32f10x_tim.h"

#include "stm32f10x_pwr.h"

 

#include "sk_pwm.h"

 

#define TIMx_DEFAULT_PERIOD     (1000)

#define CCRx_DEFAULT_VALUE      (TIMx_DEFAULT_PERIOD / 2)

#define TIMx_DEFAULT_PRE        (72)

 

static void SK_PWM_PortInit(void)

{

    GPIO_InitTypeDef  stGpioInit;

 

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);

 

    stGpioInit.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;

    stGpioInit.GPIO_Mode = GPIO_Mode_AF_PP;

    stGpioInit.GPIO_Speed = GPIO_Speed_50MHz;

 

    GPIO_Init(GPIOA, &stGpioInit);

 

    stGpioInit.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;

    GPIO_Init(GPIOB, &stGpioInit);

}

 

static void SK_PWM_NvicInit(void)

{

    NVIC_InitTypeDef NVIC_InitStructure;

 

    NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

}

 

static void SK_PWM_ClockInit(void)

{

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_TIM8, ENABLE);

}

 

static void SK_PWM_ModeInit(void)

{

    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    TIM_OCInitTypeDef  TIM_OCInitStructure;

    TIM_BDTRInitTypeDef      TIM1_BDTRInitStruct;

 

    // Configure the period and prescaler

    TIM_TimeBaseStructure.TIM_Period = (TIMx_DEFAULT_PERIOD - 1);

    TIM_TimeBaseStructure.TIM_Prescaler = (TIMx_DEFAULT_PRE - 1);

    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

 

    // Configure the Output mode

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;

    TIM_OCInitStructure.TIM_Pulse = CCRx_DEFAULT_VALUE;

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OCInitStructure.TIM_OCNPolarity= TIM_OCPolarity_High;

    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;

    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

    TIM_OC1Init(TIM1, &TIM_OCInitStructure);

    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);

 

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_Pulse = CCRx_DEFAULT_VALUE / 2;

    TIM_OC2Init(TIM1, &TIM_OCInitStructure);

    TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);

 

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_Pulse = CCRx_DEFAULT_VALUE / 4;

    TIM_OC3Init(TIM1, &TIM_OCInitStructure);

    TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);

 

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_Pulse = CCRx_DEFAULT_VALUE / 10;

    TIM_OC4Init(TIM1, &TIM_OCInitStructure);

    TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);

 

    TIM1_BDTRInitStruct.TIM_OSSRState = TIM_OSSRState_Disable;

    TIM1_BDTRInitStruct.TIM_OSSIState = TIM_OSSIState_Disable;

    TIM1_BDTRInitStruct.TIM_LOCKLevel = TIM_LOCKLevel_OFF;

    TIM1_BDTRInitStruct.TIM_DeadTime = 205;

    TIM_BDTRConfig(TIM1, &TIM1_BDTRInitStruct);

 

    TIM_ARRPreloadConfig(TIM1, ENABLE);

    TIM_CtrlPWMOutputs(TIM1, ENABLE);

 

    TIM_ClearFlag(TIM1, TIM_FLAG_Update);

    TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);

}

 

static void SK_PWM_Enable(void)

{

    TIM_Cmd(TIM1, ENABLE);

}

 

void SK_PWM_Init(void)

{

    SK_PWM_PortInit();

    SK_PWM_ClockInit();

    SK_PWM_NvicInit();

    SK_PWM_ModeInit();

    SK_PWM_Enable();

}

 

void TIM1_UP_IRQHandler(void)

{

    static uint32_t cnt = 0;

    if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)

    {

        TIM_ClearITPendingBit(TIM1, TIM_IT_Update);

    }

}

 


测试结果

使用逻辑分析仪抓到的结果如下:


1. 不带死区控制的互补输出

互补输出时间 delta 测量为 0,即几乎是同时输出翻转:

2. 带死区控制的互补输出

互补输出时间 delta 测量为 5us,实现死区控制:


推荐阅读

史海拾趣

Edcon Components Netherlands Cv公司的发展小趣事

为了进一步扩大市场份额,Edcon Components Netherlands Cv开始积极拓展国际市场。公司通过对不同国家和地区的市场进行深入分析,制定了精准的市场拓展策略。通过与当地经销商建立合作关系,Edcon的产品逐渐进入国际市场,并在多个国家和地区取得了成功。国际市场的拓展不仅为公司带来了更多的商机,也提升了公司的品牌影响力。

HI Microwave Technology Limited公司的发展小趣事

人才是企业最宝贵的资源。HI Microwave高度重视人才培养和团队建设,通过引进和培养高素质的技术人才和管理人才,不断提升企业的核心竞争力。公司建立了完善的人才激励机制和培训体系,鼓励员工不断学习和创新。同时,公司还注重营造和谐、开放的企业文化氛围,激发员工的积极性和创造力。这些措施为公司的持续发展提供了有力的人才保障和智力支持。

AMRI Enterprise Co Ltd公司的发展小趣事

品质是AMRI Enterprise Co Ltd的生命线。公司始终坚持品质至上的原则,通过严格的质量管理体系和持续改进的工艺流程,确保产品的稳定性和可靠性。同时,AMRI还注重品牌建设,通过提升品牌形象和塑造企业文化,增强客户对公司的信任度和忠诚度。这些努力使得AMRI的产品在市场上赢得了良好的口碑和广泛的认可。

富芯森美(FUXINSEMI)公司的发展小趣事

为了确保产品质量,富芯森美在成立初期便启动了严格的质量管理体系建设。公司通过了ISO、IATF 16949等国际质量管理体系认证,并严格按照标准执行。同时,公司产品还通过了UL、ROHS、REACH、HF等多项国际测试,确保了产品的安全性和可靠性。这一系列的举措不仅提升了富芯森美的市场竞争力,也赢得了客户的广泛信赖。

CHENMKO公司的发展小趣事

随着新能源汽车产业的快速发展,富芯森美敏锐地捕捉到了这一市场机遇。公司投入大量资源研发车规级功率半导体器件,产品设计遵循APQP标准,制造管理符合IATF 16949要求,质量检验则严格遵循AEC-Q101标准。这些举措使得富芯森美的车规级产品能够满足汽车行业的严苛要求,成功打入新能源汽车供应链体系,为公司带来了新的增长点。

General Transistor Corp公司的发展小趣事

为了进一步巩固市场地位和提升竞争力,GTC开始实施并购整合战略。公司通过收购具有技术优势和市场潜力的企业,实现了技术、产品和市场的快速扩张。同时,GTC还积极寻求战略转型,从单一的电子元器件分销商和生产商向综合性电子解决方案提供商转变。这一战略转型为公司带来了新的增长点和发展机遇。

问答坊 | AI 解惑

基于单片机控制的并联型有源电力滤波器

这是我的毕业设计 希望大家帮帮我 我现在已经焦头烂额了 网上都是基于DSP控制的滤波器 就是没有基于单片机控制的 真的郁闷 我的邮箱是westlife009@tom.com 我的QQ是232125740 欢迎大家一起交流 [ 本帖最后由 westlifeljb 于 2008-5-15 17:15 编 ...…

查看全部问答>

新手学堂:嵌入式开发都需要学习什么

这是一个初学者常问的问题,也是初学者问嵌入式该如何入门的根源。我感觉有两个方面,偏硬和偏软.我不认为嵌入式开发软件占绝对比重,相反,软硬件都懂,才是嵌入式高手所应该追求的,也是高手的必由之路。   硬件道路:   第一步: pcb设 ...…

查看全部问答>

AD和DA部分芯片合集(资料和程序)

AD和DA部分芯片合集(资料和程序),分享下…

查看全部问答>

请问是否有办法让程序在窗口最小化的方式下启动

这里要求程序在窗口最小化的方式下启动,这里在OnInitDlg()中用ShowWindow(SW_MINIMIZE);窗口会闪一下,至少上面的标题栏会改变,是否有什么办法可以解决,我看了一下CDialog::OnInitDialog()的原文件,里面是用::SetForegroundWindow(m_hWnd);来显示窗 ...…

查看全部问答>

分享湿度计的读写时序和编程

湿度计的读写时序包括读时序和写时序,写时序如下:向 SH T21写8 个数据位 ,然后在第9 个时钟周期 ,读取 SHT21 的应答位 ,应位为 0 ,表示SHT21正确接收到了一个字节 ,也就是 8 个写时序加 1 个读时序。SH T21 读写数据的规则是:DA TA在 SCK时钟的下 ...…

查看全部问答>

LED照明智能控制解决方案

能量效率更高、功能更强的新型LED固态发光(SSL)产品的发展很快,被认为是照明市场上的主要革命性进步。在许多垂直应用中,如信号灯、汽车、LCD TV背光,LED已经毫无争议地成为传统光源的替代产品。但对于范围更广的通用照明,LED还没有被广泛接受 ...…

查看全部问答>

LM3S811的UART口如何引出

我准备使用TI研讨会发的LM3S811套件,我看原理图811的UART口,也就是PA0,PA1和板上另一个芯片的PA0.PA1通过0欧姆电阻相连,如果我要使用811的UART,把PA0,PA1引出到232芯片上进行串口通信时,会不会对另一个芯片产生影响,或者是应该如何把811的 ...…

查看全部问答>

物联网目前的发展如何?电子工程师在其中做哪些方面的工作?

看到这个题目,忽然感到自己想说些话,关于技术,也关于一些感触。     在无锡呆了多年,作为一个电子技术不算特别发达的城市,真正能称得上电子产业的除了前几年轰轰烈烈的电动车产业链外,恐怕就只能算上现在的物联网示范城市了。 &n ...…

查看全部问答>

微软笔试面试题集锦

一.最基本题型(说明:此类题型比较简单)     QUOTE: 1. 1 到 100 有多少个 9 2. 连续整数之和为 1000 的共有几组 3. U2 合唱团在 17 分钟内得赶到演唱会场,途中必需跨过一座桥,四个人从桥的同一端出发,你得帮助他 们到达另一端, ...…

查看全部问答>