STM32主从定时器输出个数、频率可调的脉冲

STM32中发出脉冲一般有两种方式:

1)利用定时中断输出脉冲,但是间隔的延时会影响其他主程序的进程,当控制多个电机的时候就非常不可取;

2)利用PWM脉宽调制,并通过主从定时器进行设定,好处是不占用主程序时钟,且能精准控制;

 下面以定时器1为主,定时器2为从进行配置:

PWM.c文件

#include "stm32f10x.h"   // Device header/***定时器1主模式,定时器2从模式***/
void TIM1_config(u16 Cycle)
{GPIO_InitTypeDef GPIO_InitStructure; //GPIO设置,创建结构体TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//定时器设置结构体TIM_OCInitTypeDef  TIM_OCInitStructure; //pwm波对应设置结构体RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_TIM1 , ENABLE); //开启时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//GPIO_Init(GPIOA, &GPIO_InitStructure);TIM_TimeBaseStructure.TIM_Period = Cycle-1;                                                   TIM_TimeBaseStructure.TIM_Prescaler =71;                    //设置用来作为TIMx时钟频率除数的预分频值                                                     TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //设置时钟分割:TDTS= Tck_tim            TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;            //重复计数,一定要=0!!!TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);               //装载                        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;          //选择定时器模式:TIM脉冲宽度调制模式1       TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能TIM_OCInitStructure.TIM_Pulse = Cycle/2-1;                    //设置待装入捕获寄存器的脉冲值                                   TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;      //输出极性       TIM_OC1Init(TIM1, &TIM_OCInitStructure);     //装载通道1,PA8 TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);//设置或者重置 TIMx 主/从模式//TIMx: x 可以是 2, 3 或者 4,来选择 TIM 外设//TIM_MasterSlaveMode:定时器主/从模式,TIM 主/从模式使能TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);//选择 TIMx 触发输出模式//TIMx: x 可以是 2, 3 或者 4,来选择 TIM 外设//TIM_TRGOSource:触发输出模式//TIM_TRGOSource_Update:使用更新事件作为触发输出(TRGO)//    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  //使能或者失能 TIMx 在 CCR3 上的预装载寄存器TIM_ARRPreloadConfig(TIM1, ENABLE);  // 使能或者失能 TIMx 在 ARR 上的预装载寄存器 //允许或禁止在定时器工作时向ARR的缓冲器中写入新值,以便在更新事件发生时载入覆盖以前的值
}/***定时器2从模式***/
void TIM2_config(u16 PulseNum)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; //对应结构体声明NVIC_InitTypeDef NVIC_InitStructure;  //NVIC 对应结构体声明RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_TimeBaseStructure.TIM_Period = PulseNum-1;   TIM_TimeBaseStructure.TIM_Prescaler =0;    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);  TIM_SelectInputTrigger(TIM2, TIM_TS_ITR0);//选择 TIMx 输入触发源,TIM 内部触发 0      TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_External1 );// 等同 TIM2->SMCR|=0x07 //设置从模式寄存器 //   TIM2->SMCR|=0x07;                                  //设置从模式寄存器       TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE); //NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
}//入口设定函数
void Pulse_output(u16 Cycle,u16 PulseNum)
{TIM1_config(Cycle); //装载   TIM_Cmd(TIM1, ENABLE);//使能TIM_CtrlPWMOutputs(TIM1, ENABLE);   //高级定时器一定要加上,主输出使能TIM2_config(PulseNum);//装载TIM_Cmd(TIM2, ENABLE);//使能TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除TIMx 的中断待处理位TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能或者失能指定的 TIMx 中断
}//中断处理函数
void TIM2_IRQHandler(void) 
{ if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)     // TIM_IT_CC1{ TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除中断标志位 TIM_CtrlPWMOutputs(TIM1, DISABLE);  //主输出使能TIM_Cmd(TIM1, DISABLE); // 关闭定时器 TIM_Cmd(TIM2, DISABLE); // 关闭定时器 TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);         } 
} 

PWM.h文件

#ifndef __PWM_H
#define __PWM_Hvoid Pulse_output(u16 Cycle,u16 PulseNum);//入口函数void TIM1_config(u16 Cycle);//1为主模式
void TIM2_config(u16 PulseNum);//2为从模式#endif 

主函数调用:

Pulse_output(1000,8000);//1KHZ,8000个脉冲

其中/TIM_SelectInputTrigger(TIM1, TIM_TS_ITR2);中的参数需要注意,参考手册查对应的可用连接,如下:

 问题:

ARR的值最高只能是65535,所以这种方法最多只能输出65535个脉冲。有待改进。

解决方法:(2024.10.26)

将需要发送的脉冲数拆分为高16位和低16位,没进入中断前将低16位装载到从定时器的ARR,第一次进入中断再将高16位装载到从定时器ARR,第二次进入中断关闭脉冲输出和定时器。

 完整代码:

#include "stm32f10x.h"   // 包含STM32F10x系列的设备头文件// 定义全局变量
volatile u16 PulseNum_High = 0;  // 高16位脉冲计数
volatile u16 PulseNum_Low = 0;   // 低16位脉冲计数
volatile int pulseStage = 0;     // 脉冲阶段标志/*** @brief 配置TIM1定时器*/
void TIM1_config(void)
{GPIO_InitTypeDef GPIO_InitStructure;  // 定义GPIO初始化结构体TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;  // 定义TIM1时间基础初始化结构体TIM_OCInitTypeDef  TIM_OCInitStructure;  // 定义TIM1输出比较初始化结构体RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);  // 使能TIM1时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  // 使能GPIOA时钟// 配置GPIOA的Pin8为复用推挽输出模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);// 配置TIM1时间基础TIM_TimeBaseStructure.TIM_Period = 100-1;  // 定时周期为99,即100个计数周期TIM_TimeBaseStructure.TIM_Prescaler = 720-1;  // 预分频器为719,即720分频TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;  // 时钟分频为1TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  // 向上计数模式TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;  // 重复计数器为0TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);  // 初始化TIM1时间基础// 配置TIM1输出比较模式TIM_OCStructInit(&TIM_OCInitStructure);  // 初始化输出比较结构体TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;  // PWM模式1TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  // 输出使能TIM_OCInitStructure.TIM_Pulse = 50;  // 比较值为50TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;  // 输出极性为高TIM_OC1Init(TIM1, &TIM_OCInitStructure);  // 初始化TIM1通道1的输出比较模式TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable);  // 使能主从模式TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);  // 选择触发输出源为更新事件TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);  // 使能通道1的CCR预装载TIM_ARRPreloadConfig(TIM1, ENABLE);  // 使能自动重装载寄存器预装载TIM_CtrlPWMOutputs(TIM1, DISABLE);  // 关闭TIM1的PWM输出TIM_Cmd(TIM1, DISABLE);  // 关闭TIM1
}/*** @brief 配置TIM2定时器*/
void TIM2_config(void)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;  // 定义TIM2时间基础初始化结构体NVIC_InitTypeDef NVIC_InitStructure;  // 定义NVIC初始化结构体RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  // 使能TIM2时钟// 配置TIM2时间基础TIM_TimeBaseStructure.TIM_Period = 65535;  // 定时周期为65535TIM_TimeBaseStructure.TIM_Prescaler = 0;  // 预分频器为0TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;  // 时钟分频为1TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  // 向上计数模式TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);  // 初始化TIM2时间基础TIM_SelectInputTrigger(TIM2, TIM_TS_ITR0);  // 选择输入触发源为内部触发器0TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_External1);  // 选择从模式为外部触发模式1TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);  // 禁用TIM2更新中断TIM_ARRPreloadConfig(TIM2, ENABLE);  // 使能自动重装载寄存器预装载// 配置NVICNVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  // 配置优先级分组为2NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  // 中断通道为TIM2NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  // 抢占优先级为0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  // 子优先级为0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  // 使能中断通道NVIC_Init(&NVIC_InitStructure);  // 初始化NVICTIM_Cmd(TIM2, DISABLE);  // 关闭TIM2
}/*** @brief 输出指定周期和数量的脉冲* @param Cycle 周期值,对应TIM1的ARR* @param PulseNum 脉冲数量,最大为65535*/
void Pulse_output(u16 Cycle, u32 PulseNum)
{// 如果脉冲数量大于65535,则需要使用高位和低位计数if(PulseNum >= 65536){PulseNum_High = (PulseNum >> 16) * 65536 - 1;  // 计算高16位计数值PulseNum_Low = (PulseNum & 0xFFFF) - 1;  // 计算低16位计数值pulseStage = 0;  // 设置脉冲阶段为高16位}else{PulseNum_High = 0;  // 高16位计数值为0PulseNum_Low = (PulseNum & 0xFFFF) - 1;  // 计算低16位计数值pulseStage = 1;  // 设置脉冲阶段为低16位}TIM1_config();  // 配置TIM1TIM2_config();  // 配置TIM2TIM_Cmd(TIM2, DISABLE);  // 关闭TIM2TIM_SetAutoreload(TIM2, PulseNum_Low);  // 设置TIM2的自动重装载寄存器为低16位计数值TIM_GenerateEvent(TIM2, TIM_EventSource_Update);  // 触发TIM2更新事件以更新ARRTIM_Cmd(TIM2, ENABLE);  // 开启TIM2TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  // 清除TIM2更新中断标志TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);  // 使能TIM2更新中断TIM_SetAutoreload(TIM1, Cycle);  // 设置TIM1的自动重装载寄存器为周期值TIM_GenerateEvent(TIM1, TIM_EventSource_Update);  // 触发TIM1更新事件以更新ARRTIM_SetCompare1(TIM1, Cycle / 2);  // 设置TIM1的比较值为周期值的一半,以生成50%占空比的PWMTIM_GenerateEvent(TIM1, TIM_EventSource_CC1);  // 触发TIM1捕获/比较事件TIM_CtrlPWMOutputs(TIM1, ENABLE);  // 开启TIM1的PWM输出TIM_Cmd(TIM1, ENABLE);  // 开启TIM1
}/*** @brief TIM2中断服务函数*/
void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)  // 检查是否为TIM2更新中断{TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  // 清除TIM2更新中断标志if (pulseStage == 0)  // 如果处于高16位计数阶段{pulseStage = 1;  // 切换到低16位计数阶段TIM_Cmd(TIM2, DISABLE);  // 关闭TIM2TIM_SetAutoreload(TIM2, PulseNum_High);  // 设置TIM2的自动重装载寄存器为高16位计数值TIM_GenerateEvent(TIM2, TIM_EventSource_Update);  // 触发TIM2更新事件以更新ARRTIM_Cmd(TIM2, ENABLE);  // 开启TIM2TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  // 清除TIM2更新中断标志TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);  // 使能TIM2更新中断}else  // 如果处于低16位计数阶段{// 脉冲输出完成,停止定时器TIM_CtrlPWMOutputs(TIM1, DISABLE);  // 关闭TIM1的PWM输出TIM_Cmd(TIM1, DISABLE);  // 关闭TIM1TIM_Cmd(TIM2, DISABLE);  // 关闭TIM2TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);  // 禁用TIM2更新中断}}
}

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

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

相关文章

微知-Lecroy力科的PCIe协议分析仪型号命名规则(PCIe代,金手指lanes数量)

文章目录 要点主要型号命名规则各代主要产品图片Summit M616 协议分析仪/训练器Summit T516 分析仪Summit T416 分析仪Summit T3-16分析仪Summit T28 分析仪 综述 要点 LeCroy(力科)成立于1964年,是一家专业生产示波器厂家。在美国纽约。一直把重点放在研制改善生产…

安卓14上蓝牙调用SystemProperties.set(),解决找不到SystemProperties.set()的问题

近期遇到一个需求,要在安卓14的蓝牙模块中调用SystemProperties.set()。 安卓14中的蓝牙,和安卓12的版本有较大的不同。它在packages/modules目录下,而安卓12是分散在packages/apps和frameworks/base等目录下;安卓14的蓝牙打包产…

Hash表算法

哈希表 理论知识(本文来自于代码随想录摘抄)什么是哈希常见的三种哈希结数组:set:map:其他常用方法或者技巧(自己总结的) 练习题和讲解有效的字母移位词349. 两个数组的交集1. 两数之和454. 四数相加 II15. 三数之和 总…

4款专业音频在线剪辑工具帮你开启创意之路。

音频在线剪辑工具能够为我们提供很大的便利,对于不管是专业的音乐制作人还是音频创作爱好者来说,都能借助一些音频编辑工具来充分发挥自己的创意。所以这一次,我要给大家介绍几个专业方便的音频剪辑工具。 1、福昕音频在线 直达链接&#x…

基于yolov8的布匹缺陷检测系统,支持图像、视频和摄像实时检测【pytorch框架、python源码】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示: 基于yolov8的布匹缺陷检测系统,支持图像、视频和摄像实时检测【pytorch框架、python源码】_哔哩哔哩_bilibili (一)简介 基于yolov8的布匹缺陷检测系统是在 PyTo…

基于SSM的心理咨询管理管理系统(含源码+sql+视频导入教程+文档+PPT)

👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的心理咨询管理管理系统拥有三个角色:学生用户、咨询师、管理员 管理员:学生管理、咨询师管理、文档信息管理、预约信息管理、测试题目管理、测试信息管理…

Cesium基础-(Entity)-(Corridor 走廊)

里边包含Vue、React框架代码详细步骤、以及代码详细解释 4、Corridor 走廊 以下是 CorridorGeometry 类的属性、方法和静态方法,以表格形式展示: 属性 属性名类型默认值描述positionsArray.定义走廊中心的坐标点数组。widthnumber走廊

预览 PDF 文档

引言 在现代Web应用中,文件预览功能是非常常见的需求之一。特别是在企业级应用中,用户经常需要查看各种类型的文件,如 PDF、Word、Excel 等。本文将详细介绍如何在Vue项目中实现 PDF 文档的预览功能。 实现原理 后端API 后端需要提供一个…

GIT使用list

清空当前commit区 方法 1:软重置到初始状态 如果希望保留文件内容,但清空所有 commit 历史,可以使用以下命令: git reset --soft $(git rev-list --max-parents0 HEAD)解释: --soft 表示重置 commit 历史&#xff…

uniapp的IOS证书申请(测试和正式环境)及UDID配置流程

1.说明 本教程只提供uniapp在ios端的证书文件申请(包含正式环境和开发环境)、UDID配置说明,请勿用文档中的账号和其他隐私数据进行测试,请勿侵权! 2.申请前准备 证书生成网站:苹果应用上传、解析&#x…

【AscendC算子开发】笔记3 矩阵计算及高级开发技巧

pytorch调用算子 矩阵计算 为什么上图提供了两种矩阵结果访问方式? 如果只需要结果,那么拿注释的一行代码就可以得到结果,如果之后还有其他的操作,可以计算一小块就用起来,那么需要使用上述操作,可以形成流…

Unity Newtonsoft.Json 大对象序列化失败

Unity Newtonsoft.Json 大对象序列化失败 💣崩溃了没?😀替代方案 💣崩溃了没? Newtonsoft.Json.JsonTextWriter:WriteValueInternal(string,Newtonsoft.Json.JsonToken) InvalidCastException: Specified cast is not…

Kafka认证时Successfully logged in真的认证成功了?

背景 某个应用需要配置 Kafka 集群信息,且需要在验证集群是否可达。基本实现思路是创建一个生产者对象,然后发送一条测试数据,调用 Producer 的 send 方法发送消息后,再调用 get() 方法,即同步发送消息,测…

SpringBoot后端开发常用工具详细介绍——flyway数据库版本控制工具

文章目录 什么是flyway简介为什么要使用flyway 流程介绍整合springboot添加pom文件配置flyway向resource/db/migration添加sql文件 注意事项1. 迁移报错2. 迁移顺序 参考 什么是flyway 简介 为什么要使用flyway 我们在开发时往往会有这样一种情况: 进行软件开发…

【Linux系统编程】线程深入运用

目录 一,C线程与系统线程 二,分离线程 三,线程结构 四,__thread关键字 五,Linux线程互斥 1,线程互斥相关的背景概念 2,互斥锁 3,死锁 4,互斥锁的弊端 六&#…

2024年10月25日练习(双指针算法)

一.283. 移动零 - 力扣(LeetCode) 1.题目描述: 这里题目要求了说必须在不复制数组的情况下对数组进行原地操作,所以说不能来用暴力的解法来 实现。 2.算法原理: 这个题目就是经典的数组划分,数组分块问题…

react-signature-canvas 实现画笔与橡皮擦功能

react-signature-canvas git 地址 代码示例 import React, { Component } from react import { createRoot } from react-dom/clientimport SignaturePad from ../../src/index.tsximport * as styles from ./styles.module.cssclass App extends Component {state { trimmed…

NLTK无法下载?

以下内容仅为当前认识,可能有不足之处,欢迎讨论! 文章目录 nltk无法下载怎么办?什么是NLTK?为什么要用NLTK?如何下载? nltk无法下载怎么办? 什么是NLTK? NLTK是学习自然…

【Qt】窗口——Qt窗口的概念、常用的窗口函数、菜单栏、工具栏、状态栏、浮动窗口、对话框

文章目录 Qt窗口Qt窗口的概念菜单栏工具栏状态栏浮动窗口对话框 Qt 窗口 Qt窗口的概念 QMainWindow 类概述: QMainWindow 是一个为用户提供主窗口程序的类,它继承自 QWidget 类,并且提供了一个预定义的布局。 菜单栏 菜单栏常用属性&#xf…

紫光同创——盘古 50KN 网口板

本原创文章由深圳市小眼睛科技有限公司创作,版权归本公司所有,如需转载,需授权并注明出处(www.meyesemi.com) 一、开发系统介绍 盘古 50KN 网口板开发板(MES50H-Ethernet)采用了核心板扩展板的结 构&#…