【STM32】定时器 —— 输出比较PWM

使用的单片机机型为STM32F103C8T6

在这里插入图片描述

文章目录

  • PWM
  • 输出比较
  • 编程实例
    • 输出比较呼吸灯
    • 舵机转向
    • PWM控制直流电机

PWM

对于5V电路来说,输出只有高电平5V和低电平0V,控制LED灯就是点亮和熄灭,但如果想要控制其亮度呢?这就需要PWM

PWM

PWM (Pulse Width Modulation) 脉冲宽度调制

具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常用于电机控速等领域

拿LED灯举例
当输出高电平时,LED灯点亮;当输出低电平时,LED灯熄灭。但如果在一定周期内,比如1ms内,前100us高电平,后900us低电平,那么在人眼看来,LED灯就是很低的亮度。随着高电平所占时间增多,LED亮度就会增大

换成电机,由于惯性,从高电平转为低电平,电机并不会立刻停止,同样在较短时间内分配高低电平的比率就可以实现不同档位的电机


PWM参数
在这里插入图片描述

  • Ts:周期,如1ms
  • Ton:高电平时间,如400us
  • Toff:低电平时间,如600us

频率 = 1 / Ts = 1KHz
占空比:高电平时间占周期的比率。Ton / Ts = 40%
分辨率:1 / (计数器最大值 + 1)


输出比较

定时器输出比较模块如下
在这里插入图片描述

OC (Output Compare) 输出比较

通过比较 CNT 和 CCR 寄存器值的关系,对输出电平置1、置0 或翻转的操作,用于输出一定频率和占空比的 PWM 波形

通用定时器和高级定时器都拥有4个输出比较通道,如上图的 TIMx_CH1 ~ TIMx_CH4
高级定时器的前3个通道额外拥有死去生成和互补输出的功能

输出部分电路如下:

在这里插入图片描述

通过 CNT 和 CCR比较控制输出使能电路
例如:当CNT < CRR 时,输出高电平,CNT >= CRR 时输出低电平。
配合时基单元(参看【STM32】定时中断),即可输出PWM。

如定时器频率为1MHz,即每1微秒CNT计数加一,设置重装值ARR = 100,总周期为100us,比较器CRR = 40。
CNT计数前40us都输出高电平,后60us输出低电平。如此就输出了频率为10KHz,占空比为40%,分辨率为1%


输出比较模式

在这里插入图片描述

常用的为 PWM模式1 和 PWM模式2,二者效果相反,根据实际场景选择

编程实例

输出比较呼吸灯

  • 程序目标:通过定时器输出比较实现呼吸灯(亮度周期变化)
  • 程序原理:每20ms修改CRR值,输出不同PWM波形

接线图如下:

在这里插入图片描述

通过引脚定义得知,TIM2 的 CH1输出引脚为 A0
同时,将LED灯的正极接在输出引脚上,方便占空比的计算

在这里插入图片描述

PWM基本结构

在这里插入图片描述
PWM使用步骤:

  1. 开启相关外设时钟
//开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  1. 定时器使用内部时钟源72MHz
//时钟源使用内部时钟源,72MHz
TIM_InternalClockConfig(TIM2);
  1. 配置GPIO,注意引脚使用复用推挽输出
//初始化GPIO
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				//注意使用复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
  1. 配置时基单元,频率为1KHz,分辨率为1%
//时基单元
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_TimeBaseStructInit(&TIM_InitStructure);
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;			//时钟分频
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;		//向上计数
TIM_InitStructure.TIM_Period = 100 - 1;						//重装值
TIM_InitStructure.TIM_Prescaler = 720 - 1;					//预分频
TIM_InitStructure.TIM_RepetitionCounter = 0;				//重复计数,高级定时器才有
TIM_TimeBaseInit(TIM2, &TIM_InitStructure);
  1. 配置输出比较,通过修改CCR值改变占空比
//输入/比较器模块
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);		//因为一些属性是高级定时器的,初始化给个初始值
//配置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//输出比较模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//极性,此处设置为高电平
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//使能
TIM_OCInitStructure.TIM_Pulse = 0;								//比较值,即CCR
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
  1. 启动定时器
//开启时钟
TIM_Cmd(TIM2, ENABLE);

完整代码如下:

/*** @brief		初始化PWM功能* @parm		无* @retval		无*/
void PWM_Init(void)
{//开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//时钟源使用内部时钟源,72MHzTIM_InternalClockConfig(TIM2);//	//引脚重定义
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);		//TIM2引脚重定向
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);	//关闭A15的调试接口,使其变成普通引脚使用//初始化GPIOGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				//注意使用复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//时基单元TIM_TimeBaseInitTypeDef TIM_InitStructure;TIM_TimeBaseStructInit(&TIM_InitStructure);TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;			//时钟分频TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;		//向上计数TIM_InitStructure.TIM_Period = 100 - 1;						//重装值TIM_InitStructure.TIM_Prescaler = 720 - 1;					//预分频TIM_InitStructure.TIM_RepetitionCounter = 0;				//重复计数,高级定时器才有TIM_TimeBaseInit(TIM2, &TIM_InitStructure);//输入/比较器模块TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);		//因为一些属性是高级定时器的,初始化给个初始值//配置TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//输出比较模式TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//极性,此处设置为高电平TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//使能TIM_OCInitStructure.TIM_Pulse = 0;								//比较值,即CCRTIM_OC1Init(TIM2, &TIM_OCInitStructure);//开启时钟TIM_Cmd(TIM2, ENABLE);
}

同时提供修改CRR值的函数

/*** @brief		设置比较值* @parm		Compare:比较值  范围:0 ~ 255* @retval		无*/
void PWM_SetCompare(uint8_t Compare)
{TIM_SetCompare1(TIM2, Compare);
}

主程序每隔20ms修改CRR值,实现LED灯由 熄灭 -> 亮度增大 -> 完全点亮 -> 亮度减小 -> 熄灭 的循环

int main()
{PWM_Init();while(1){for(uint8_t i = 0; i < 100; ++i){PWM_SetCompare(i);Delay_ms(20);//延迟20ms}for(uint8_t i = 0; i < 100; ++i){PWM_SetCompare(100 - i);Delay_ms(20);//延迟20ms}}
}

完整程序链接:【STM32】输出比较PWM

舵机转向

舵机是一种根据输入PWM信号占空比来控制输出角度的装置
在这里插入图片描述

输入PWM信号要求:周期为20ms,高电平宽度为0.5ms ~ 2.5ms

在这里插入图片描述

硬件电路如下:
在这里插入图片描述

接线图如下:舵机需要5V驱动,正极接STLINK
在这里插入图片描述

PWM初始化大抵相同,需要注意 ARR、PSC 的设置

/*** @brief		初始化PWM功能* @parm		无* @retval		无*/
void PWM_Init(void)
{//开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//初始化GPIOGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				//注意使用复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//内部时钟TIM_InternalClockConfig(TIM2);//时基单元TIM_TimeBaseInitTypeDef TIM_InitStructure;TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;			//时钟分频TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;		//向上计数TIM_InitStructure.TIM_Period = 20000 - 1;					//重装值,计数周期TIM_InitStructure.TIM_Prescaler = 72 - 1;					//预分频TIM_InitStructure.TIM_RepetitionCounter = 0;				//重复计数,高级定时器才有TIM_TimeBaseInit(TIM2, &TIM_InitStructure);//输入/比较器模块TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);		//因为一些属性是高级定时器的,初始化给个初始值//配置TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//输出比较模式TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//极性,此处设置为高电平TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//使能TIM_OCInitStructure.TIM_Pulse = 0;								//比较值,即CCRTIM_OC2Init(TIM2, &TIM_OCInitStructure);//开启时钟TIM_Cmd(TIM2, ENABLE);
}

此处设置 PSC = 72,ARR = 20000
频率为50Hz,即周期为20ms

-90° 为0.5ms,对应CRR为500,-45°对应为1000…

/*** @brief		设置舵机角度  -90为0.5ms,对应CRR为500,-45°对应为1000.....	* @parm		角度   范围:0 ~ 180* @retval		无*/
void Servos_SetAngle(float Angle)
{PWM_SetCompare(Angle / 180 * 2000 + 500);
}

完整程序链接:

PWM控制直流电机

直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时,电机正转,当电极反接时,电机反转
直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作
TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向

在这里插入图片描述

硬件电路

在这里插入图片描述

PWMA 和 PWMB 接收PWM波形
AIN1、AIN2 和 BIN1、BIN2控制电机正反转
定义AIN1高电平,AIN2低电平为正转,则AIN1低电平,AIN2高电平为反转

接线图如下

在这里插入图片描述

PWM配置

/*** @brief		初始化PWM功能* @parm		无* @retval		无*/
void PWM_Init(void)
{//开启时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//初始化GPIOGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				//注意使用复用推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//内部时钟TIM_InternalClockConfig(TIM2);//时基单元TIM_TimeBaseInitTypeDef TIM_InitStructure;TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;			//时钟分频TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;		//向上计数TIM_InitStructure.TIM_Period = 100 - 1;						//重装值,计数周期TIM_InitStructure.TIM_Prescaler = 36 - 1;					//预分频TIM_InitStructure.TIM_RepetitionCounter = 0;				//重复计数,高级定时器才有TIM_TimeBaseInit(TIM2, &TIM_InitStructure);//输入/比较器模块TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);		//因为一些属性是高级定时器的,初始化给个初始值//配置TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//输出比较模式TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//极性,此处设置为高电平TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//使能TIM_OCInitStructure.TIM_Pulse = 0;								//比较值,即CCRTIM_OC3Init(TIM2, &TIM_OCInitStructure);//开启时钟TIM_Cmd(TIM2, ENABLE);
}

还需要配置 A4 和 A5引脚控制电机正反转

/*** @brief		舵机初始化* @parm		无* @retval		无*/
void Motor_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//初始化输出高低电平的引脚GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);PWM_Init();
}/*** @brief		设置舵机角度  0为500,45为1000,90为1500....	* @parm		角度   范围:0 ~ 180* @retval		无*/
void Motor_SetSpeed(int16_t Speed)
{if(Speed >= 0)//正转{//设置GPIO引脚高低电平GPIO_SetBits(GPIOA, GPIO_Pin_4);GPIO_ResetBits(GPIOA, GPIO_Pin_5);//设置占空比,输出PWM波形PWM_SetCompare(Speed);}else//反转{GPIO_ResetBits(GPIOA, GPIO_Pin_4);GPIO_SetBits(GPIOA, GPIO_Pin_5);PWM_SetCompare(-Speed);}
}

完整程序链接:


以上就是本篇博客的所有内容,感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

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

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

相关文章

Anaconda 下安装OpenCV 4.10.0

大家也可以使用pip安装。 pip install opencv-python4.10.0 这里使用conda安装 conda install opencv4.10.0 import cv2 print(cv2.__version__)

深入探索 C++ 类型转换的奥秘

目录 1. C语言中的类型转换 2.C的类型转换 &#xff08;1&#xff09;static_cast &#xff08;2&#xff09; dynamic_cast &#x1f60a;&#x1f60a;static_cast和dynamic_cast在面对继承和多态的父子类强转的区别&#xff1a; 1.static_cast 和 继承关系中的强转 …

量产小妙招---KdTreeFLANN的使用

1 概念 KDTreeFLANN是一种结合了k-d树&#xff08;k-dimensional tree&#xff09;数据结构和FLANN&#xff08;Fast Library for Approximate Nearest Neighbors&#xff09;算法库的技术&#xff0c;主要用于高效地进行最近邻搜索等操作。 KdTreeFLANN是Point Cloud Library …

62 基于单片机的智能饮水机

所有仿真详情导航&#xff1a; PROTEUS专栏说明-CSDN博客 目录 一、主要功能 二、硬件资源 三、主程序编程 四、资源下载 一、主要功能 基于51单片机&#xff0c;采用DS1302时钟模块读取时间&#xff0c;DS18B20温度传感器检测时间&#xff0c;超声波检测&#xff0c;如果…

制造业数据集成案例分享:3小时内实现MySQL到MySQL数据对接

ZZ刷新生产用料清单四化库存-制造一处-3小时&#xff1a;MySQL到MySQL数据集成案例分享 在现代制造业中&#xff0c;实时、准确的数据流动是确保生产效率和资源优化的关键。本文将分享一个实际运行的系统对接集成案例——“ZZ刷新生产用料清单四化库存-制造一处-3小时”&#…

大数据新视界 -- 大数据大厂之 Hive 临时表与视图:灵活数据处理的技巧(上)(29 / 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

QT入门看这一篇就够了——超详细讲解(40000多字详细讲解,涵盖qt大量知识)

目录 一、Qt概述 1.1 什么是Qt 1.2 Qt的发展史 1.3 Qt的优势 1.4 Qt版本 1.5 成功案例 二、创建Qt项目 2.1 使用向导创建 2.2 一个最简单的Qt应用程序 2.2.1 main函数中 2.2.2 类头文件 2.3 .pro文件 2.4 命名规范 2.5 QtCreator常用快捷键 三、Qt按钮小程序 …

【k8s】创建基于sa的token的kubeconfig

需求 创建一个基于sa的token的kubeconfig文件&#xff0c;并用这个文件来访问集群。 具体创建sa 和sa的token请参考文章: 【k8s】给ServiceAccount 创建关联的 Secrets-CSDN博客 创建sa apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata:namespace: jtkjdevnam…

STM32F103单片机使用STM32CubeMX新建IAR工程步骤

打开STM32CubeMX软件&#xff0c;选择File 选择新建工程 在打开的窗口输入单片机型号 在右下角选择单片机型号&#xff0c;然后点右上角 start project&#xff0c;开始新建工程。 接下来设置调试接口&#xff0c;在左边System Core中选择 SYS&#xff0c;然后在右右边debu…

MATLAB 最小二乘平面拟合(90)

MATLAB 最小二乘平面拟合(90) 一、算法介绍二、算法实现1.代码2.结果:一、算法介绍 平面方程: ax+by+cz+d = 0 执行任务:读取一组点云(这里用自定义生成的平面模拟点云代替,在其中添加了噪声来模拟真实的数据),使用最小二乘拟合平面,来输出平面参数,并可视化显示拟…

Redis面试专题-持久化

目录 前言 持久化相关知识 1.三种持久化机制 2.RDB持久化 3.深入剖析一下RDB持久化过程 4.AOF持久化 5.RDB和AOF对比​编辑 面试题 1.redis持久化机制有哪些&#xff1f; 2.那仔细讲讲你对他们的理解 3.你刚刚说AOF的文件很大&#xff0c;那AOF文件会越来越大&#xf…

Java --- JVM编译运行过程

目录 一.Java编译与执行流程&#xff1a; 二.编译过程&#xff1a; 1.编译器&#xff08;javac&#xff09;&#xff1a; 2.字节码文件&#xff08;.class&#xff09;&#xff1a; 三.执行过程&#xff1a; 1.启动JVM&#xff08;Java虚拟机&#xff09;&#xff1a; 2…

sheng的学习笔记-AI-序列模型(Sequence Models),RNN,GRU,LSTM

Ai目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 基础知识 定义&#xff1a; 序列模型是输入输出均为序列数据的模型&#xff0c;它能够将输入序列数据转换为目标序列数据。常见的序列模型类型包括一对一、一对多、多对一、部分多对多和完全多对多。 重要的是需要有顺序…

Excel技巧:如何批量调整excel表格中的图片?

插入到excel表格中的图片大小不一&#xff0c;如何做到每张图片都完美的与单元格大小相同&#xff1f;并且能够根据单元格来改变大小&#xff1f;今天分享&#xff0c;excel表格里的图片如何批量调整大小。 方法如下&#xff1a; 点击表格中的一个图片&#xff0c;然后按住Ct…

16-02、JVM系列之:内存与垃圾回收篇(二)

JVM系列之&#xff1a;内存与垃圾回收篇(二) ##本篇内容概述&#xff1a; 1、堆Heap Area 2、方法区Method Area 3、运行时数据区总结 4、对象的实例化内存布局和访问定位一、堆 Heap Area 1、堆的核心概念 一个JVM实例只存在一个堆内存&#xff0c;堆也是Java内存管理的核心…

android studio 读写文件操作(应用场景二)

android studio版本&#xff1a;2023.3.1 patch2 例程&#xff1a;readtextviewIDsaveandread 本例程是个过渡例程&#xff0c;如果单是实现下图的目的有更简单的方法&#xff0c;但这个方法是下一步工作的基础&#xff0c;所以一定要做。 例程功能&#xff1a;将两个textvi…

【算法】——前缀和(矩阵区域和详解,文末附)

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;前缀和模版 二&#xff1a;前缀和模版2 三&#xff1a;寻找数组的中心下标 四&#x…

数字图像处理(11):RGB转YUV

&#xff08;1&#xff09;RGB颜色空间 RGB颜色空间&#xff0c;是一种基于红色、绿色、蓝色三种基本颜色进行混合的颜色空间&#xff0c;通过这三种颜色的叠加&#xff0c;可以产生丰富而广泛的颜色。RGB颜色空间在计算机图像处理、显示器显示、摄影和影视制作等领域具有广泛应…

nodejs33: react中的IndexedDB 原有API+操作库idb+数据库事务

在 React 中使用 IndexedDB 作为本地数据库存储可以有效地管理大量的数据&#xff0c;比如缓存、离线功能或状态持久化。可以通过索引进行快速查询&#xff0c;支持事务处理&#xff0c;并且异步操作。 特点&#xff1a; 存储键值对。 支持事务。 数据可以分层组织为数据库、…

创造未来:The Sandbox 创作者训练营如何赋能全球创造者

创作者训练营让创造者有能力打造下一代数字体验。通过促进合作和提供尖端工具&#xff0c;The Sandbox 计划确保今天的元宇宙是由一个个创造者共同打造。 2024 年 5 月&#xff0c;The Sandbox 推出了「创作者训练营」系列&#xff0c;旨在重新定义数字创作。「创作者训练营」系…