stm32 定时器输出比较(OC)与PWM的理解和应用

不积跬步,无以至千里;不积小流,无以成江海。
大家好,我是闲鹤,公众号 xxh_zone,十多年开发、架构经验,先后在华为、迅雷服役过,也在高校从事教学3年;目前已创业了7年多,主要从事物联网/车联网相关领域和业务。
喜欢交友、骑行、写毛笔字、弹吉他、折腾硬件和写代码。

相关阅读:

  • STM32 外部中断的理解
  • STM32 定时器中断

1. 定时器TIM简介

  • TIM 是 stm32 微控制器中的定时器模块。stm32 包含多个定时器模块,每个定时器模块有不同的功能和配置,适用于各种应用场景。
  • 定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
  • 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从模式等多种功能

定时器分类
图1
基本定时器结构(时基单元):
图2

2. TIM 定时器相关概念

  • 计数模式
    • 向上计数模式(Up-counter mode)
    • 向下计数模式(Down-counter mode)
    • 中心对齐模式(Center-aligned mode)
  • 预分频器(Prescaler)
    主要作用是控制(降低)计数器时钟频率。
计数器时钟频率 = 定时器输入时钟频率(CK_PSC) / (预分频值 + 1) = CK_PSC / (PSC + 1)


通常 CK_PSC 为内部时钟CK_INT,即为72MHz

  • 自动重装寄存器(ARR)
    设置计数器的周期值。当计数器达到该值时,会产生一个更新时间(中断或 DMA 请求),计数器重新从 0 开始计数。
  • 输出比较(Output Compare, OC)
    定时器的输出比较功能可以用来产生精准的输出信号。通过设置比较寄存器(CCR),可以控制输出引脚的状态。
  • 输入捕获(Input Capture)
    定时器的输入捕获功能可以测量外部信号的周期和脉宽。
  • PWM 模式(Pulse Width Modulation)
    定时器 PWM 模式可以产生占空比可调的 PWM 信号,常用于电机控制、LED调光等。

3. 输出比较(Output Compare, OC)

框图如下:
图3

  • 输出比较可以通过比较 CNT 与 CCR 寄存器值的关系,来对输出电平进行置1、置0或翻转等操作,用于输出一定频率和占空比的 PWM 波形;
  • 每个高级定时器和通用定时器都拥有4个输出比较通道
  • 高级定时器的前3个通道额外拥有死区生成和互补输出的功能

输出比较产生的信号模式:
图4

4. PWM

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

  • 频率:PWM 信号的周期倒数。
f = 1 / Ts = CK_PSC / (PSC + 1) / (ARR + 1)
  • 占空比:高电平时间(Ton)与周期时间(Ts)的比值,通常用百分比表示。
占空比 = Ton / Ts = Ton / (ARR + 1) = CCR / (ARR + 1)

占空比决定了输出信号在一个周期内为高电平的时间比例

  • 分辨率:分辨率是占空比的最小变化步距。分辨率通常由定时器的计数位数(如8位、16位等)决定,影响 PWM 信号的精细度。
分辨率 = 1 / (计数器最大值 + 1) = 1 / (ARR + 1)


见图:
图5
PWM 基本结构图,也是作为后续编程的参考图:
图6

5. 应用举例

5.1 使用 PWM 驱动 LED 呼吸灯

这个例子主要通过 PWM 实现 LED 呼吸灯的效果。
基本思想:通过 TIM2 定时器,输出 PWM 脉宽给到 LED ,LED 呈现呼吸闪烁的过程。
实现思维逻辑:
根据 PWM 基本结构图,基本步骤为:

  1. 初始化时基单元
  2. 配置 OC
  3. 由于需要控制一个 LED 灯,所以需要配置一个 GPIO 用于输出 PWM 的信号
  4. 运行控制逻辑

硬件电路:
由于使用的是 TIM2 定时器的通道1即 TIM2_CH1_ETR 输出信号,而 TIM2_CH1_ETR 输出复用的是 PA0 口,如图:
图7PA0 口插上 LED 的正极,负极接在 GND 上。
代码:
PWM.c

void PWM_Init(void)
{
	// 初始化时基单元
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // TIM2 在 APB1 总线
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; // 时基单元结构体
	TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分频
	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up; // 计数器模式
	TIM_TimeBaseStruct.TIM_Period = 100 - 1; // 计数周期 ARR
	TIM_TimeBaseStruct.TIM_Prescaler = 7200 - 1 ; // 预分频器 PSC
	TIM_TimeBaseStruct.TIM_RepetitionCounter = 0; // 重复计数器,高级定时器才会用到
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStruct);
	
	// OC 配置 定时器通道配置
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; // OC 输出模式 见图7
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; // 输出极性 见图7 REF 置有效电平
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; // 输出使能状态
	TIM_OCInitStruct.TIM_Pulse = 0; // CCR 比较寄存器 0 ~ 100
	TIM_OC1Init(TIM2, &TIM_OCInitStruct);
	
	// GPIO 配置
	// 这里需要复用 PA0 口,所以 AFIO 一并启用
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
	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 
	TIM_Cmd(TIM2, ENABLE);
}

void SetCompare1(uint16_t Compare1)
{
	TIM_SetCompare1(TIM2, Compare1);
}

main.c:

int main() 
{
	PWM_Init();

	int8_t i = 0;
	while(1) {
		for(i = 0; i <= 100; i++) {
			SetCompare1(i);
			Delay_ms(10);
		}
		for(i = 100; i >= 0; i--) {
			SetCompare1(i);
			Delay_ms(10);
		}
	}
}

5.1 使用 PWM 驱动 舵机

PWM 驱动舵机与 PWM 驱动 LED 呼吸灯整个流程基本一致,不同的是要根据舵机的特性来控制 PWM 输出的脉宽信号。
舵机的特性:

舵机预分频器计算:

  1. 预分频器:72,TIM_CLK = 72MHz / 72 = 1MHz
  2. 定时周期: TIM_Period = PWM周期 * TIM_CLCK频率 - 1
    其中 PWM 周期为 20ms, 定时器时钟频率为 1MHz,因此 TIM_Period = 20ms * 1MHZ - 1 = 20000 - 1

角度到脉宽的线性变换公式:

代码:
大部分的代码都与 LED 呼吸灯类似,就是几个参数有所改变:

void PWM_Init(void)
{
	//
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
	TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseStruct.TIM_Period = 20000 - 1;
	TIM_TimeBaseStruct.TIM_Prescaler = 72 - 1;
	TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStruct);
	
	// OC
	TIM_OCInitTypeDef TIM_OCInitStruct;
	TIM_OCStructInit(&TIM_OCInitStruct);
	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_Pulse = 0;
	TIM_OC1Init(TIM2, &TIM_OCInitStruct);
	
	//
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
	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);
	
	TIM_Cmd(TIM2, ENABLE);
}

void Servo_Angle(float angle)
{
	TIM_SetCompare1(TIM2, angle / 180.0 * 2000 + 500);
}

main.c

int main() 
{
	OLED_Init();
	PWM_Init();
	Key_Init();

	float angle = 0;
	Servo_Angle(0);
	char str[100] = {0};
	int8_t is_rt = 0;
	while(1) {
		if(Key_Read() ==1) {
			if(is_rt == 1) angle -= 20;
			else angle += 20;
		}
		Servo_Angle(angle);
		sprintf(str, "angle: %d    ", (int)angle);
		OLED_ShowString(1, 1, str);
		if(angle == 180) is_rt = 1;
		if(angle == 0) is_rt = 0;
		
	}
}

相关阅读:

  • STM32 外部中断的理解
  • STM32 定时器中断

近期文章:
百万级物联网框架设计
从华为无线网络框架说Dispatch服务
【自动化运维】不要相信人,把所有的东西都交给机器去处理

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

盛夏之约,即将启程,2024中国北京消防展将于6月26举行

盛夏之约&#xff0c;即将启程&#xff0c;2024中国北京消防展将于6月26举行 盛夏之约&#xff0c;即将启程&#xff01;备受瞩目的2024中国&#xff08;北京&#xff09;消防技术与设备展览会将于6月26-28 日在北京.首钢会展中心盛大召开。作为消防安全和应急救援的年度盛会&…

DDMA信号处理以及数据处理的流程---DDMA原理介绍

Hello&#xff0c;大家好&#xff0c;我是Xiaojie&#xff0c;好久不见&#xff0c;欢迎大家能够和Xiaojie一起学习毫米波雷达知识&#xff0c;Xiaojie准备连载一个系列的文章—DDMA信号处理以及数据处理的流程&#xff0c;本系列文章将从目标生成、信号仿真、测距、测速、cfar…

LeetCode790多米诺和托米诺平铺

题目描述 有两种形状的瓷砖&#xff1a;一种是 2 x 1 的多米诺形&#xff0c;另一种是形如 “L” 的托米诺形。两种形状都可以旋转。给定整数 n &#xff0c;返回可以平铺 2 x n 的面板的方法的数量。返回对 109 7 取模 的值。平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺…

【教程】从0开始搭建大语言模型:文本预处理

从0开始搭建大语言模型&#xff1a;文本预处理 参考仓库&#xff1a;LLMs-from-scratch 理解Word embedding 深度神经网络模型&#xff0c;包括LLM&#xff0c;不能直接处理原始文本&#xff0c;因此需要一种方法将它转换为连续值的向量&#xff0c;也就是embedding。如下图…

【YOLOV8】1.开发环境搭建

Yolo8出来一段时间了,包含了目标检测、实例分割、人体姿态预测、旋转目标检测、图像分类等功能,所以想花点时间总结记录一下这几个功能的使用方法和自定义数据集需要注意的一些问题,本篇是第一篇,开发环境的配置。 YOLO(You Only Look Once)是一种流行的物体检测和图像分割…

UE4_Ben_图形52_水下效果处理

学习笔记&#xff0c;不喜勿喷&#xff0c;欢迎指正&#xff0c;侵权立删&#xff01;祝愿生活越来越好&#xff01; 在这个后期处理的效果中&#xff0c;我们可以看到有很多不同的&#xff0c;这里有浓雾&#xff0c;波纹扭曲&#xff0c;镜头扭曲和边缘模糊&#xff0c;在第4…

Linux中安装Docker,并使用Docker安装MySQL和Redis

1、安装docker 1卸载系统之前的docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine2、安装Docker-CE #安装必须的依赖 sudo yum install -y yum-utils \device-map…

抽象,自定义函数,递归

6.1懒惰是一种美德 如果你 在一个地方编写了一些代码&#xff0c;但需要在另一个地方再次使用&#xff0c;该如何办呢&#xff1f; 假设你编写了一段代码&#xff0c;它计算一些斐波那契数&#xff08;一种数列&#xff0c;其中每个数都是前两个数的和&#xff09;。 现在的…

Freeswitch-soundtouch-变声开发

文章目录 一、介绍二、安装soundtouch2.1 源码安装方式&#xff08;推荐&#xff09;2.1.1下载源码2.1.2解压2.1.3 编译2.1.4 迁移&#xff08;可选&#xff09; 2.2 apt-get 安装 三、使用3.1 终端使用3.2 Freeswitch使用3.2.1编译Freeswitch的mod_soundtouch3.2.2启用 mod_so…

Qt图像处理技术九:得到QImage图像的灰度直方图

效果 原理 得到灰度化值&#xff0c;将灰度化的值带入0-255内&#xff0c;增加&#xff0c;得到可视化图形 源码 // 绘制直方图 QImage drawHistogram(const QImage &image) {QVector<int> histogram(256, 0);// 计算图像的灰度直方图for (int y 0; y < image…

static的用法

static一般用于修饰局部变量&#xff0c;全局变量&#xff0c;函数 1 static修饰局部变量 是因为改为static int a1;后&#xff0c;出了作用域&#xff0c;不会销毁a的值&#xff0c;想要理解其本质&#xff0c;首先先看一下这个图&#xff1a; static修饰局部变量时&#xf…

【代码随想录】【算法训练营】【第30天】 [322]重新安排行程 [51]N皇后 [37]解数独

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 30&#xff0c;周四&#xff0c;好难&#xff0c;会不了一点~ 题目详情 [322] 重新安排行程 题目描述 322 重新安排行程 解题思路 前提&#xff1a;…… 思路&#xff1a;回溯。 重点&…

yolo水果品质:新鲜腐烂橙子检测/分类数据集(3k+图像全标注)

yolo水果品质检测之新鲜腐烂橙子数据集&#xff0c;整个数据集共包含3852张图像&#xff0c;yolo标注完整&#xff08;txt格式&#xff09;,标注类别分为新鲜橙子&#xff08;0&#xff09;和腐烂橙子&#xff08;1&#xff09;两类 图像统一格式&#xff1a;jpg 图像统一分辨…

windows10子系统wsl ubuntu22.04下GN/ninja环境搭建

打开windows10子系统 ubuntu22.04 ubuntu22.04: 首先需要 安装ninja $sudo apt install ninja-build $ ninja --version 1.10.0 安装clang $sudo apt install clang $clang --version Ubuntu clang version 14.0.0-1ubuntu1.1安装gn Github: https://github.com/timniederh…

ar地产沙盘互动体验提供更加丰富多彩的楼盘信息

AR增强现实技术作为其重要分支&#xff0c;正逐步在全球市场中崭露头角。国内的AR增强现实技术公司正致力于链接物理世界和虚拟世界&#xff0c;为用户带来沉浸式的AR体验。它们打造线上线下联动的一站式文旅景区数字化运营平台&#xff0c;让您在享受旅游的同时&#xff0c;也…

什么是Vector Database(向量数据库)?

什么是Vector Database(向量数据库)&#xff1f; 向量数据库是向量嵌入的有组织的集合&#xff0c;可以随时创建、读取、更新和删除。向量嵌入将文本或图像等数据块表示为数值。 文章目录 什么是Vector Database(向量数据库)&#xff1f;什么是嵌入模型(Embedding Model)&…

用蒙特卡罗积分法近似求解定积分的值及举例

一、背景知识 1、连续随机变量的概率密度函数 对于连续型随机变量的概率密度函数&#xff08;PDF&#xff09;&#xff0c;其在整个定义域上的积分必须等于1。这是概率密度函数的一个基本属性&#xff0c;它确保了随机变量取任何值的概率之和等于1&#xff0c;符合概率论的公…

家用洗地机哪个牌子好?专家推荐榜单助你挑选最合适的洗地机

随着科技不断发展&#xff0c;智能家居产品逐渐融入我们日常生活中&#xff0c;洗地机作为家庭清洁必备工具&#xff0c;越来越受到消费者青睐&#xff0c;但是面对市面上种类繁多的洗地机&#xff0c;我们如何挑选到适合自己的产品呢&#xff1f;专家推荐榜单助你挑选最合适的…

在vue项目中使用markdown-it回显markdown文本

前言 其实有很多插件都是可以用来回显markdown文本的,这个插件也是其中之一。 文档地址:markdown-it | markdown-it 中文文档 这个文档在vue2和vue3里面都可以使用,所以还是比较推荐的 使用 安装 npm install markdown-it --save 应用 <template><div><…

正邦科技(第10天)

这里写目录标题 任务一任务二任务三 任务一 下位机报上来的十进制数据进行解析&#xff1a; 360170 固定报文&#xff0c;一个F对应一个字节&#xff0c;温度值&#xff0c;湿度值&#xff0c;烟雾浓度值是十进制转16进制&#xff0c;告警状态需要高低位移位&#xff0c;然后再…