STM32 PWM驱动设计

单片机学习!

目录

文章目录

前言

一、PWM驱动配置步骤

二、代码示例及注意事项

2.1 RCC开启时钟

2.2 配置时基单元

2.3 配置输出比较单元

2.4 配置GPIO

2.5 运行控制

三、PWM周期和占空比计算

总结


前言

        PWM本质是利用面积等效原理来改变波形的有效值。


一、PWM驱动配置步骤

第一步、RCC开启时钟,将需要的TIM外设和GPIO外设的时钟打开。

第二步、配置时基单元,包括时钟源选择的配置。

第三步、配置输出比较单元,包括CCR的值、输出比较模式、极性选择、输出使能这些参数。(在库函数中也是用结构体统一来配置)。

第四步、配置GPIO,把PWM对应的GPIO口初始化为复用推挽输出的配置。

第五步、运行控制,启动计数器就可以输出PWM了。

二、代码示例及注意事项

2.1 RCC开启时钟

        将需要的TIM外设GPIO外设的时钟打开。打开时钟后定时器的基准时钟和整个外设的工作时钟就会同时打开。

代码示例:

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//使用APB1的开启时钟函数,因为TIM2是APB1总线的外设。RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

2.2 配置时基单元

        配置时基单元,包括时钟源选择的配置。

  1. 时基单元的选择时钟源。对于定时中断可选择内部时钟源。
  2. 配置时基单元,包括预分频器、自动重装器、计数模式等,这些参数可用结构体配置。

代码示例:

	TIM_InternalClockConfig(TIM2);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision= TIM_CKD_DIV1;//指定时钟分频TIM_TimeBaseInitStructure.TIM_CounterMode= TIM_CounterMode_Up;//计数器模式TIM_TimeBaseInitStructure.TIM_Period= 100-1;//ARR自动重装器的值TIM_TimeBaseInitStructure.TIM_Prescaler= 720-1;//PSC预分频器的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter= 0;//重复计数器的值TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);

结构体成员:

  • TIM_ClockDivision:指定时钟分频,用于信号经过滤波器时的滤波采样频率。
  • TIM_CounterMode:计数器模式,这里选择向上计数模式TIM_CounterMode_Up。
  • TIM_Period :ARR自动重装器的值。
  • TIM_Prescaler:PSC预分频器的值。
  • TIM_RepetitionCounter:重复计数器的值,只有高级定时器才有,本文初始化通用寄存器,所以值给0。

        时基单元中关键寄存器参数ARR、PSC都有设置,但是这里没有CNT计数器的参数,CNT参数的配置可根据需要在函数 TIM_SetCounter 和函数 TIM_GetCounter 中操作。

        决定定时时间的参数是 TIM_Period 和 TIM_Prescaler 。定时时间可用计数器溢出频率公式计算,定时频率=72M/(PSC+1)/(ARR+1)。

2.3 配置输出比较单元

        配置输出比较单元,包括CCR的值、输出比较模式、极性选择、输出使能这些参数。(在库函数中也是用结构体统一来配置)。

void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

        这里4个初始化函数对应4个输出比较通道(单元),不同的通道对应的GPIO口也不一样,函数的选择需要根据GPIO口的配置选择。代码示例中使用PA0口,对应第一个输出比较通道,选择TIM_OC1Init函数。

代码示例:

	TIM_OCInitTypeDef TIM_OCInitStructture;TIM_OCStructInit(&TIM_OCInitStructture);TIM_OCInitStructture.TIM_OCMode=TIM_OCMode_PWM1; //设置输出比较的模式。TIM_OCInitStructture.TIM_OCPolarity=TIM_OCPolarity_High; //设置输出比较的极性TIM_OCInitStructture.TIM_OutputState=TIM_OutputState_Enable; //设置输出使能TIM_OCInitStructture.TIM_Pulse=50; //设置CCRTIM_OC1Init(TIM2,&TIM_OCInitStructture);   

        代码示例中的程序并没有给结构体的所有成员赋值,而是用TIM_OCStructInit函数先给结构体成员赋一个初始值,再修改部分的结构体成员。这个结构体变量是局部变量,若不给成员赋初始值,它成员的值就是不确定的,这会导致一些问题。比如当你想把高级定时器当作通用定时器输出PWM时,只配置了通用定时器需要的结构体成员,剩下这些没赋值成员就会导致高级定时器输出PWM出现一些奇怪的问题。

        TIM_OCStructInit函数需要把结构体变量的地址传进去,才能给结构体赋初始值。

1. TIM_OCMode设置输出比较的模式。

        TIM_OCMode输出比较模式参数对应含义:

  • TIM_OCMode_Timing 冻结模式                
  • TIM_OCMode_Active 相等时置有效电平                 
  • TIM_OCMode_Inactive 相等时置无效电平               
  • TIM_OCMode_Toggle 相等时电平翻转                 
  • TIM_OCMode_PWM1 PWM模式1                   
  • TIM_OCMode_PWM2 PWM模式2                   
  • TIM_ForcedAction_Active 强制输出有效电平
  • TIM_ForcedAction_InActive 强制输出无效电平

        注:强制输出两种模式的参数不可以在初始化时使用

2. TIM_OCPolarity设置输出比较的极性。

  • TIM_OCPolarity_High 高级性,是极性不翻转,REF波形直接输出。意思是有效电平是高电平,REF有效时,输出高电平。
  • TIM_OCPolarity_Low  低级性,REF电平取反,意思是有效电平为低电平。

3. TIM_OutputState设置输出使能。

4.TIM_Pulse置CCR。 ARR,PSC,CCR共同决定PWM的周期和占空比
 

        以上配置已经把输出比较通道初始化好了,在TIM2的OC1通道上就可以输出PWM波形了,最终这个波形需要通过GPIO口才可以输出。那TIM2的OC1通道是借用哪个GPIO口呢?下文来选择并配置GPIO。


注:TIM_OC1Init是通道1的初始化函数,若通道1、2、3、4都需要的话可以直接在后面加TIM_OC2Init、TIM_OC3Init、TIM_OC4Init,这样就可以同时使用4个通道来输出4个PWM了。

代码示例:

	TIM_OCInitTypeDef TIM_OCInitStructture;TIM_OCStructInit(&TIM_OCInitStructture);TIM_OCInitStructture.TIM_OCMode=TIM_OCMode_PWM1; //设置输出比较的模式。TIM_OCInitStructture.TIM_OCPolarity=TIM_OCPolarity_High; //设置输出比较的极性TIM_OCInitStructture.TIM_OutputState=TIM_OutputState_Enable; //设置输出使能TIM_OCInitStructture.TIM_Pulse=50; //设置CCRTIM_OC1Init(TIM2,&TIM_OCInitStructture);TIM_OC2Init(TIM2,&TIM_OCInitStructture);TIM_OC3Init(TIM2,&TIM_OCInitStructture);TIM_OC4Init(TIM2,&TIM_OCInitStructture);   

        同一个定时器的不同通道输出的PWM,因为不同通道是共用一个计数器的,所以它们的频率必须是一样的;它们的占空比由各自的CCR决定,所以占空比可以各自设定;他们的相位由于计数器更新,所有PWM同时跳变,所以它们的相位是同步的。

        这就是同一个定时器不同通道输出PWM的特点。如果使用多个设备如电机或者舵机,那使用同一个定时器不同通道的PWM就完全可以。


2.4 配置GPIO

        输出比较通道借用GPIO口可以在引脚定义表中查看:

        默认复用功能这一列就是片上外设的端口和GPIO的连接关系。可以找到 TIM2_CH1_ETR 在 PA0 这一行,这说明 TIM2 的 ETR 引脚和通道1的引脚都是借用了 PA0 这个引脚位置,就是TIM2的引脚复用在了PA0引脚上。所以使用TIM2的OC1通道也就是CH1通道输出PWM,就只能在PA0引脚上输出,而不能任意选择引脚输出。

同理:

  • 使用TIM2_CH2只能在PA1端口输出
  • 使用TIM2_CH3只能在PA2端口输出
  • 使用TIM2_CH4只能在PA3端口输出

表中其他外设也是同理:如使用SPI1_MISO只能在PA6端口输出。虽然引脚与外设都是规定好的,但是还可以根据情况做一次改动。在引脚定义表重定义(重映射)这一列,还可以对应更改。如既要使用 USART2_TX 引脚又要使用 TIM2_CH3 通道,但是它俩都在PA2端口输出,这就冲突了没法同时使用。这时可以在重定义列表里找一下,有 TIM2_CH3 ,那么 TIM2_CH3 就可以从PA2端口输出换为从PB10端口输出。这样就避免了两个外设引脚的冲突。但是如果重映射的列表里找不到,那外设复用的GPIO就不能挪位置。配置重映射需要用AFIO来完成。

        配置GPIO,把PWM对应的GPIO口初始化为复用推挽输出的配置。

代码示例:

	GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode= GPIO_Mode_AF_PP;//这里选择复用推挽输出。GPIO_InitStruct.GPIO_Pin= GPIO_Pin_0;GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStruct);

        这里选择复用推挽输出。
        原因:对于普通的开漏/推挽输出,引脚的控制权是来自于输出数据寄存器的,定时器控制引脚需要使用复用开漏/推挽输出的模式,复用开漏/推挽输出模式中输出数据寄存器将被断开,输出控制权将转移给片上外设,通过引脚定义表可知,这里片上外设引脚连接的就是TIM2的CH1通道。所以只有把GPIO设置为复用推挽输出,引脚的控制权才能交给片上外设,PWM波形才能通过引脚输出。
  

2.5 运行控制

        运行控制:整个模块配置完成后,还需要使能一下计数器,PWM波形就能通过PA0输出了。

代码示例:

    TIM_Cmd(TIM2,ENABLE);

三、PWM周期和占空比计算

计算公式:

  • PWM频率:    Freq = CK_PSC / (PSC + 1) / (ARR + 1)      PWM频率等于计数器更新频率。
  • PWM占空比:    Duty = CCR / (ARR + 1)
  • PWM分辨率:    Reso = 1 / (ARR + 1)

        ARR、PSC、CCR共同决定PWM的周期和占空比

代码示例中产生的是一个频率为1KHHz,占空比为50%,分辨率为1%的PWM波形。

代入公式:

  • 72M/(PSC+1)/(ARR+1)=1000
  • CCR/(ARR+1)=50%
  • 1/(ARR+1)=1%

得出:

  • (ARR+1)=100
  • CCR=50
  • (PSC+1)=720

对应代码中:

  • ARR 给 100-1;
  • PSC 给 720-1;
  • CCR 给 50。

        代码运行时,PWM占空比也可更改,可选择使用TIM_SetCompare1、TIM_SetCompare2、TIM_SetCompare3、TIM_SetCompare4 函数改变CCR寄存器的值来调节PWM占空比。但是PWM的占空比是由ARR、PSC、CCR共同决定。


总结

        以上就是今天要讲的内容,本文仅仅简单介绍了PWM驱动配置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/434865.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探索IOC和DI:解密Spring框架中的依赖注入魔法

IOC与DI的详细解析 IOC详解1 bean的声明2 组件扫描 DI详解 IOC详解 1 bean的声明 IOC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象。IOC容器创建的对象称为bean对象。 要把某个对象交给IOC容器管理,需要在类上…

春运挑战:网络购票平台需引入分账系统提高交易效率

随着春运的来临,网络购票平台面临了巨大的挑战。旅游平台的车票、机票、酒店等订单激增,给平台的交易承载力带来了巨大压力。为了应对这一挑战,网络购票平台需要提前引入分账系统,以提高整体的交易效率。 春运背景与挑战 春运是中…

手把手教你搓一个最小系统板【画PCB-->布线 -->制版-->焊接】

文章目录 一、基础电路1. 晶振电路2. 稳压电路3. 复位/按键电路4. BOOT电路5. SWD接口6. 滤波电容7. LED电路8. 拓展引脚设计总览 二、布局布线三、制版四、焊接 在大学嵌入式相关专业,有许多同学是更偏向软件上的设计,并不懂硬件上的实现,而…

ANSYS 2023 下载安装教程,附安装包和工具,轻松安装,无套路

前言 ANSYS是一款融结构、流体、电场、磁场、声场分析于一体的大型通用有限元分析(FEA)软件,能与多数计算机辅助设计软件接口,实现数据的共享和交换,如Creo,NASTRAN、Algor、IDEAS、AutoCAD等. 准备工作 1、Win10及以上系统 2、提前准备好…

java自动化将用例和截图一起执行测试放入world中直接生成测试报告【搬代码】

1.首先我们得用例写好之后放入文档中,把不用的案例类型、前置条件去掉之后,如图: 放到桌面后,先看执行结果: 首先,我们先创建一个时间,这个时间主要是给图片创建名称,并且要在插入…

Linux服务器配置与管理(第二次实验)

实验目的及具体要求 目的 1.掌握基于命令行的文件操作 2.掌握基于命令行的目录操作 3.掌握用户账户的命令行操作 4.掌握组账户的命令行操作 5.熟悉磁盘分区操作 6.掌握调整优先级的方法 具体要求 1.掌握基于命令行的文件和目录操作 ①创建测试目录 ②创建文件 ③复…

肌无力的判断方法有什么?

肌无力可能发病在身体的多个部位,最为显著的就是眼睑肌无力,那么除了这种明眼就可以看见的,那些不明显的又该怎么判断呢?看了你就知道了。 因为肌无力是一种比较常见的疾病,所以我们要了解全身肌肉无力的症状,下面为大家介绍肌无…

攻防演练 |解决Nmap无法扫描B段资产问题

前段时间老大发来任务,让帮忙用nmap扫一些ip段,我拿过来就准备开扫… 但是发现nmap无法直接扫描同一B段不同C段下的IP段,例如111.111.111.0-111.111.222.255 原本我是准备写个工具联动nmap来扫描大批量IP段资产的 但是由于环境有些问题&am…

2024 高级前端面试题之 JS 「精选篇」

该内容主要整理关于 JS 的相关面试题,其他内容面试题请移步至 「最新最全的前端面试题集锦」 查看。 JS模块精选篇 1. 数据类型基础1.1 JS内置类型1.2 null和undefined区别1.3 null是对象吗?为什么?1.4 1.toString()为什么可以调用&#xff1…

04. OSPF

文章目录 一. 初识OSPF1.1. OSPF概述1.2. OSPF特性1.3. OSPF的专业术语1.4. OSPF维护的3张表1.5. OSPF报文类型1.6. OSPF的邻居状态 二. 实验题2.1. 实验1:点到点链路上的OSPF2.1.1. 实验目的2.1.2. 实验拓扑图2.1.3. 实验步骤(1)IP地址配置&…

配置ARP安全综合功能示例

组网图形 ARP安全简介 ARP(Address Resolution Protocol)安全是针对ARP攻击的一种安全特性,它通过一系列对ARP表项学习和ARP报文处理的限制、检查等措施来保证网络设备的安全性。ARP安全特性不仅能够防范针对ARP协议的攻击,还可以…

力扣算法-Day20

541. 反转字符串II 给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。 如果剩余字符少于 k 个,则将剩余字符全部反转。如果剩余字符小于 2k 但大于或等于 k 个&#xff0c…