STM32使用HAL库输出连续可调的PWM信号

2023-11-09

项目中要控制一个步进电机控制器,因为涉及到加减速过程,需要频率任意可变。

总体思路是先初始化PWM定时器输出,之后直接修改ARR和PSC寄存器。

初始化代码如下:

/*
*********************************************************************************************************
*	函 数 名: bsp_SetTIMOutPWM
*	功能说明: 设置引脚输出的PWM信号的频率和占空比.  当频率为0,并且占空为0时,关闭定时器,GPIO输出0;
*			  当频率为0,占空比为100%时,GPIO输出1.
*	形    参: GPIOx : GPIOA - GPIOK
*			  GPIO_Pin : GPIO_PIN_0 - GPIO__PIN_15
*			  TIMx : TIM1 - TIM17
*             _ucChannel:使用的定时器通道,范围1 - 4
*			  _ulFreq : PWM信号频率,单位Hz (实际测试,可以输出100MHz),0 表示禁止输出
*			  _ulDutyCycle : PWM信号占空比,单位: 万分之一。如5000,表示50.00%的占空比
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_SetTIMOutPWM(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, TIM_TypeDef* TIMx, uint8_t _ucChannel,
	 uint32_t _ulFreq, uint32_t _ulDutyCycle)
{
	TIM_HandleTypeDef  TimHandle = {0};
	TIM_OC_InitTypeDef sConfig = {0};	
	uint16_t usPeriod;
	uint16_t usPrescaler;
	uint32_t pulse;
	uint32_t uiTIMxCLK;
	const uint16_t TimChannel[6+1] = {0, TIM_CHANNEL_1, TIM_CHANNEL_2, TIM_CHANNEL_3, TIM_CHANNEL_4};

	if (_ucChannel > 6)
	{
//		Error_Handler(__FILE__, __LINE__);
	}
	
	if (_ulDutyCycle == 0)
	{		
		//bsp_RCC_TIM_Disable(TIMx);		/* 关闭TIM时钟, 可能影响其他通道 */		
		bsp_ConfigGpioOut(GPIOx, GPIO_Pin);	/* 配置GPIO为推挽输出 */				
		HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_RESET);	/* PWM = 0 */		
		return;
	}
	else if (_ulDutyCycle == 10000)
	{
		//bsp_RCC_TIM_Disable(TIMx);		/* 关闭TIM时钟, 可能影响其他通道 */
		bsp_ConfigGpioOut(GPIOx, GPIO_Pin);	/* 配置GPIO为推挽输出 */		
		HAL_GPIO_WritePin(GPIOx, GPIO_Pin, GPIO_PIN_SET);	/* PWM = 1 */			
		return;
	}
	
	/* 下面是PWM输出 */
	
	bsp_ConfigTimGpio(GPIOx, GPIO_Pin, TIMx);	/* 使能GPIO和TIM时钟,并连接TIM通道到GPIO */
	
	/*-----------------------------------------------------------------------
		system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:

		HCLK = SYSCLK / 1     (AHB1Periph)
		PCLK2 = HCLK / 2      (APB2Periph)
		PCLK1 = HCLK / 4      (APB1Periph)

		因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
		因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;

		APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14
		APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11

	----------------------------------------------------------------------- */
	if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM9) || (TIMx == TIM10) || (TIMx == TIM11))
	{
		/* APB2 定时器时钟 = 168M */
		uiTIMxCLK = SystemCoreClock;
	}
	else	
	{
		/* APB1 定时器 = 84M */
		uiTIMxCLK = SystemCoreClock / 2;
	}

	if (_ulFreq < 100)
	{
		usPrescaler = 10000 - 1;					/* 分频比 = 10000 */
		usPeriod =  (uiTIMxCLK / 10000) / _ulFreq  - 1;		/* 自动重装的值 */
	}
	else if (_ulFreq < 3000)
	{
		usPrescaler = 100 - 1;					/* 分频比 = 100 */
		usPeriod =  (uiTIMxCLK / 100) / _ulFreq  - 1;		/* 自动重装的值 */
	}
	else	/* 大于4K的频率,无需分频 */
	{
		usPrescaler = 0;					/* 分频比 = 1 */
		usPeriod = uiTIMxCLK / _ulFreq - 1;	/* 自动重装的值 */
	}
	pulse = (_ulDutyCycle * usPeriod) / 10000;

	
	HAL_TIM_PWM_DeInit(&TimHandle);
    
	/*  PWM频率 = TIMxCLK / usPrescaler + 1)/usPeriod + 1)*/
	TimHandle.Instance = TIMx;
	TimHandle.Init.Prescaler         = usPrescaler;
	TimHandle.Init.Period            = usPeriod;
	TimHandle.Init.ClockDivision     = 0;
	TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
	TimHandle.Init.RepetitionCounter = 0;
	TimHandle.Init.AutoReloadPreload = 0;
	if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
	{
//		Error_Handler(__FILE__, __LINE__);
	}

	/* 配置定时器PWM输出通道 */
	sConfig.OCMode       = TIM_OCMODE_PWM1;
	sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
	sConfig.OCFastMode   = TIM_OCFAST_DISABLE;
	sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
	sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
	sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;

	/* 占空比 */
	sConfig.Pulse = pulse;
	if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TimChannel[_ucChannel]) != HAL_OK)
	{
//		Error_Handler(__FILE__, __LINE__);
	}
	
	/* 启动PWM输出 */
	if (HAL_TIM_PWM_Start(&TimHandle, TimChannel[_ucChannel]) != HAL_OK)
	{
//		Error_Handler(__FILE__, __LINE__);
	}
}

更新频率的函数如下:

void bsp_ModifyTIMFreqOut(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, TIM_TypeDef* TIMx, uint8_t _ucChannel,
	 uint32_t _ulFreq)
{
	uint16_t usPeriod;
	uint16_t usPrescaler;
	uint32_t pulse;
	uint32_t uiTIMxCLK;
	const uint16_t TimChannel[6+1] = {0, TIM_CHANNEL_1, TIM_CHANNEL_2, TIM_CHANNEL_3, TIM_CHANNEL_4};

	if (_ucChannel > 6)
	{
//		Error_Handler(__FILE__, __LINE__);
	}

	if ((TIMx == TIM1) || (TIMx == TIM8) || (TIMx == TIM9) || (TIMx == TIM10) || (TIMx == TIM11))
	{
		/* APB2 定时器时钟 = 168M */
		uiTIMxCLK = SystemCoreClock;
	}
	else	
	{
		/* APB1 定时器 = 84M */
		uiTIMxCLK = SystemCoreClock / 2;
	}

	_ulFreq = _ulFreq * 4;
	
	if (_ulFreq < 100)
	{
		usPrescaler = 10000 - 1;					/* 分频比 = 10000 */
		usPeriod =  (uiTIMxCLK / 10000) / _ulFreq  - 1;		/* 自动重装的值 */
	}
	else if (_ulFreq < 3000)
	{
		usPrescaler = 100 - 1;					/* 分频比 = 100 */
		usPeriod =  (uiTIMxCLK / 100) / _ulFreq  - 1;		/* 自动重装的值 */
	}
	else	/* 大于4K的频率,无需分频 */
	{
		usPrescaler = 0;					/* 分频比 = 1 */
		usPeriod = uiTIMxCLK / _ulFreq - 1;	/* 自动重装的值 */
	}
    
    TIM8->PSC = usPrescaler;
    TIM8->ARR = usPeriod; 
    TIM8->EGR = TIM_EGR_UG;         //修改之后要更新寄存器
    
}

这里注意几点:

1、预分频寄存器是否修改都可以,只影响一定的定时精度

2、修改之后一定要更新EGR寄存器,修改才会生效

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32使用HAL库输出连续可调的PWM信号 的相关文章

  • 代码静态分析与安全检测工具COBOT

    COBOT是北大软件开发的软件代码静态分析与安全检测工具 COBOT支持10类1000余种编码规则检查 支持CWE 14类110余种语义缺陷 支持8类90余种常见的安全漏洞分析 COBOT通过度量分析能够检测包括圈复杂度 函数扇入扇出 注释
  • EMI滤波电路是由哪些元件组成的,一文看懂

    通常对于追求效率的电源来说 NTC热敏电阻几瓦的损耗始终会降低电源的转换效率 而且对于关机后在短时间内再次开机的情况 如果没有继电器 处于高温下的NTC热敏电阻将无法发挥正常作用 因此继电器与NTC在高端电源中往往是配套使用 以达到 鱼与熊
  • Macbook Pro M1芯片Python开发环境配置

    文章主要介绍M1 Mac新机器如何进行开发环境配置 由于在进行开发环境配置的时候 需要经常使用终端 而且新机器是没有配置homebrew的 后面一些操作不是很方便 所以本文将会对日常终端使用方面进行一些配置 丰富我们的终端样式和使用 文章大
  • Linux进阶_DNS服务和BIND之详解篇

    成功不易 加倍努力 1 名字解析介绍和DNS 1 1 DNS服务工作原理 1 2 DNS查询类型 1 3 名称服务器 1 4 解析类型 1 5 完整的查询请求经过的流程 2 DNS 服务相关概念和技术 2 1 DNS服务器的类型 2 2 区
  • Kafka学习资料全集,保证你从入门到精通

    1 Kafka架构和工作原理 https www jianshu com p aa4c6994687e 2 Prometheus Grafana kafka exporter监控kafka https blog csdn net an109
  • 【picodet 训练流程】

    picodet训练流程 一 Train 1 环境搭建 2 准备数据 2 1 数据位置 2 2 数据读取和标签读取 2 2 1yml 文件位置 2 2 2数据集路径文件生成 3 修改模型相应参数 3 1 参数文件位置 4 训练 二 Eval

随机推荐

  • window7系统中64位安装matalbR2009b后出现乱码的解决方案

    转自 http blog csdn net shaoguangleo archive 2010 11 29 6042194 aspx MATLAB 中默认的字体是 Monospaced 即等宽字体 这是一种非常适合用于显示程序源代码的字体
  • 使用Flex图表组件

    使用Flex图表组件 以图表或是图的方式显示数据的能力可以使得Flex程序用户的数据交互更为容易 与仅显示简单的数字数据表不同 我们可以显示条状图 饼图 线图或是其他类型的图表 并且可以使用颜色 标题以及二维图形来表示我们的数据 在这一部分
  • 求矢量夹角

    由点乘计算角度 由叉乘计算正负 点乘公式 a b a b cos
  • VQ-VAE

    Generating Diverse High Fidelity Images with VQ VAE 2 摘要 本文主要研究VQ VAE在大尺度图像生成器上的应用 我们改进了自回归的先验来生成比以前更加优秀的图片 本文使用的是简单的编码和
  • springbboot的默认缓存方案:@Cacheable@CachePut@CacheEvict

    Spring Boot 默认使用的缓存方案是基于 Spring Framework 的缓存抽象 在 Spring Boot 中 你可以使用 Cacheable CachePut 和 CacheEvict 注解来实现缓存功能 Cacheabl
  • Bugkuctf--逆向第三题游戏过关题解

    题目链接 https ctf bugku com challenges 先让我们来打开文件 既然题目都说是游戏过关了 那就玩玩这个游戏呗 雾 游戏还是很简单的 但显然这道题应该用逆向的思维来做 废话 正式部分 逆向的题拿到手一般能考虑的工具
  • 行走在前端路上

    从今天起开始写一写实际项目中遇到的各种前端问题 希望对自己和和小伙伴们都能起到一定的帮助作用
  • 架构师必须了解的 5 种最佳软件架构模式

    世界变得越来越依赖软件 软件系统已经渗透到了人类生活的方方面面 并带来了很多便利 从移动应用 用于和人联系 到医疗应用和深度学习模型 到金融技术系统 再到智能建筑 利用技术来自动化许多功能 为了提供所需的解决方案并获得最佳效果 必须使用恰当
  • Qt 疑云解答

    一 qt的mianwindow处不能布局 我们在mainwindow中添加2个控件 pushButton和pushButton 2 QWidget centerWindow new QWidget this this is point to
  • Hashmap扩容方法机制原理

    Hashmap扩容方法 机制原理 1 7版本 数组额定容量为16 元素数量超过负载因子 一般为0 75 后会扩容至原有数组大小 2 遍历老数组每个位置上的链表每个元素 取每个元素的key根据链表长度计算出在新数组中的下表 将元素添加到新数组
  • SylixOS下Redis编程实践

    1 Redis简介 Redis是一个完全开源的key value型数据库 其显著特点是基于内存操作 但是可以持久化到磁盘 相比较其他的数据库 Redis有着明显的优势 响应速度快和特性丰富是其明显的特点 其他的特点这里不一一赘述 Redis
  • pytorch 的 dataset 中使用 onnxruntime

    如果在 dataset 中预处理图像时 用到了 onnxruntime 的 cudaep 出现这样的错误 1 2022 12 13 13 53 01 554864883 E onnxruntime Default cuda call cc
  • Vuepress 导航栏与侧边栏配置详解

    目录 一 目录结构 二 导航栏配置 三 侧边栏配置 四 效果图 图 1 图 2 图 3 图 4 一 目录结构 这是我创建的 vuepress 站点 可参考 https blog csdn net sinat 31213021 article
  • windows下如何安装git以及IDEA如何配置git

    一 安装git git官方下载地址Git Downloads 目前最新的版本是2 15 0 1 1 首先 双击安装包 打开安装界面 然后点击Next下一步 1 2 配置git的安装组件 默认就行 继续点击Next下一步 默认勾选的内容有 创
  • http实现文件分片下载

    文章目录 检测是否支持 HTTP Range 语法 Range请求cURL示例 单一范围 多重范围 条件式分片请求 Range分片请求的响应 文件整体下载 文件分片下载 文本下载 图片下载 封装下载方法 HTTP分片异步下载是一种下载文件的
  • GBDT&GBRT与XGBoost

    在看清华学霸版 Python大战机器学习 的过程中 集成学习章节中出现了两个新的名词 GBDT GBRT 也许是西瓜书定位于全面 而没有拘泥于细节 后来科普发现 这两个东西和陈天奇大神的XGBoost紧密相连 于是估摸着花时间弄懂这两个东西
  • 【算法日志】动态规划刷题:股票买卖附加问题(day42)

    代码随想录刷题60Day 目录 前言 含冷冻期的股票买卖最佳时期 含手续费的股票买卖最佳时期 前言 今天的股票买卖问题会附加一些条件 但总体难度不大 含冷冻期的股票买卖最佳时期 该问题难点在于对几个状态进行解构并写出相应的状态转移方程 in
  • 安卓各文件存储路径汇总(Android file path)

    写下来 省得以后不记得到处翻 Environment getDataDirectory data Environment getDownloadCacheDirectory cache Environment getExternalStor
  • 2017 ICM/MCM Problem E: Sustainable Cities Needed!

    题目理解可持续发展的城市 任务 References 题目理解 可持续发展的城市 许多社区正在实施智能增长计划 以考虑长期 可持续的规划目标 聪明的成长是关于帮助每个城镇和城市变成更加经济繁荣 社会公平和环境可持续的生活地方的意思 2 智能
  • STM32使用HAL库输出连续可调的PWM信号

    项目中要控制一个步进电机控制器 因为涉及到加减速过程 需要频率任意可变 总体思路是先初始化PWM定时器输出 之后直接修改ARR和PSC寄存器 初始化代码如下 函 数 名 bsp SetTIMOutPWM 功能说明 设置引脚输出的PWM信号的