STM32的HAL库开发---高级定时器---互补输出带死区实验

一、互补输出简介

 互补输出:OCx输出高电平,则互补通道OCxN输出低电平。OCx输出低电平,则互补通道OCxN输出高电平。

带死区控制的互补输出:OCx输出高电平时,则互补通道OCxN过一会再输出输出低电平。这个时间里输出的电平为无效电平。

二、带死区控制的互补输出应用H桥

在H桥中间的是电动机, 电流从左边流向右边为正转,从右边流向左边为反转。正转的时候,Q1和Q4导通,反转的时候,Q2和Q3导通。4个三极管都是NPN型三极管,都需要高电平才能导通。

Q1和Q3连接的OC1,Q2和Q3连接的是互补通道OC1N。当OC1输出高电平时,Q1和Q4导通,电机正转,OC1N输出低电平,Q2和Q3都截止。当OC1N输出高电平时,Q2和Q3导通,电机反转,此时OC1输出低电平,Q1和Q4截止。

如果输出通道OC1和互补输出通道OC1N都为有效电平,在这个图里边有效电平为高电平,都为有效电平则短路。

由于元器件是有延迟特性,所以需要加上死区时间控制。这个电路图的无效电平为低电平。

三、捕获/比较通道的输出部分(通道1至3)

1、OC1RE为输出参考信号,高电平有效。

2、TIMx_CCMR1的OC1M设置输出比较模式,在F1系列有8种比较模式。

3、 ETRF信号,设置了OC1CE为,则ETRF信号来的时候,OC1REF会被强制清0。

4、配置TIMx_CCER寄存器的CC1E和CC1NE位,来设置输出通道使能和输出互补通道使能。当使能输出通道,关闭互补输出通道,则直接走死区发生器上面那个线,经过输出极性选择器,从OC1输出。当关闭输出通道,使能互补输出通道,则经过互补输出极性选择器,从OC1N输出。

死区输出:同时使能输出通道和互补输出通带,OC1REF信号经过死区发生器,然后分别经过各自的极性选择器,来到OC1和OC1N。

MOE位:高级定时器的主输出控制,想输出。必须置1,否则两个通道都无法输出。

补充:

高级定时的刹车功能寄存器BDTR里边有一个OSSR位,对用在运行状态(MOE = 1)时,可以控制输出和互补输出通道电平。

手册种给出如下表格

重点看红色部分,当OSSR位设置为1时,如果只使能了输出通道或者互补输出通道中的任意一个,那个另一个通道会输出无效电平。当OSSR位设置为0的时候,另一个通道都是输出0。这个对于学习电机控制的时候有用,如果程序不设置这位,对于想使用一个定时器的互补输出通道控制电机,是不行的,因为另一个通道一直输出0。

 sBreakDeadTimeConfig.OffStateRunMode=TIM_OSSR_ENABLE;

如果设置了这位,另一个通道会根据你设置的有效电平,来输出无效电平。

    sConfig.OCNPolarity = TIM_OCNPOLARITY_LOW;
    sConfig.OCPolarity = TIM_OCPOLARITY_LOW;

下面这俩是控制在刹车输入时,MOE位会被自动清零,然后输出通道和互补输出通道根据空闲状态输出电平,但是要注意,如果你两个通道都设置的是低电平有效,那下面这个设置就是无效的,因为硬件不允许两个通道同时输出有效电平,他会同时输出高电平。但是你设置的是高电平有效,下面这个设置会使两个通道都输出低电平,也就是同时输出无效电平。

    sConfig.OCIdleState = TIM_OCIDLESTATE_RESET;
    sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;

四、死区时间计算

1、确定tDTS的值:

 其中CKD位在TIMx_CR1寄存器里边设置,Ft为定时器时钟频率,F1系列就是72Mhz。

2、判断DTG[7:5],选择计算公式,在TIMx_BDTR寄存器设置。

3、带入选择的公式计算。

 五、刹车(断路)功能

1、使能刹车功能:将TIMx_BDTRBKE位置1,刹车输入信号极性由BKP位设置

将TIMx_BKIN引脚复用为刹车功能,刹车信号经过极性选择后,来到或门。BI为刹车中断。

使能刹车功能后:由TIMx_BDTRMOEOSSIOSSR位,TIMx_CR2的OISxOISxN位,TIMx_CCERCCxECCxNE位控制OCxOCxN输出状态

无论何时,OCxOCxN输出都不能同时处在有效电平,由硬件强制设置。

2、发生刹车后,会怎么样?

  • MOE位被清零,OCx和OCxN为无效、空闲或复位状态(OSSI位选择),MOE为0,被称为空闲模式,为1被称为运行模式。
  • OCx和OCxN的状态:由相关控制位状态决定,当使用互补输出时:根据情况自动控制输出电平,参考参考手册使用刹车(断路)功能小节
  • BIF位置1,如果使能了BIE位,还会产生刹车中断;如果使能了TDE位,会产生DMA请求
  • 如果AOE位置 1,在下一个 更新事件UEV时,MOE位被自动置 1

从图中可以看出,当刹车信号来时,MOE位会被置0,同时输出通道电平由OIS1位决定,OIS1为1,则输出高电平,OIS1为0,则输出低电平。

 1、设置输出通道极性为高电平有效,当OCxREF下降沿来的时候,没有延迟,当上升沿来的时候,需要加死区延迟。当刹车信号来的时候,OISx为0,输出低电平,低电平不是有效输出电平,所以没有延迟。

设置互补输出通道为高电平有效,在OCxREF下降沿来的时候,OCxN需要加死区延迟,在OCxREF上升沿来的时候,OCxN变为低电平,不需要加死区延迟。刹车信号来的时候,设置的OCSxN为1,为有效电平,需要加死区延迟。

2、设置输出通道极性为高电平有效,当OCxREF下降沿来的时候,不需要死区延迟,当上升沿来的时候,需要加死区延迟。当刹车信号来的时候,OISx为1,输出高电平,高电平是有效输出电平,需要加死区延迟。

设置互补输出通道为低电平有效,在OCxREF下降沿来的时候,OCxN需要加死区延迟,在OCxREF上升沿来的时候,OCxN变为高电平,不需要加死区延迟。刹车信号来的时候,设置的OCSxN为1,为无效电平,不需要加死区延迟。

3、互补输出没有开启,设置输出通道为高电平有效,输出与OCxREF一样,刹车信号来的时候,OCSx为0,为无效电平,不需要死区延迟。

互补输出通道没有开启,设置的设置互补输出通道为高电平有效,同时OCSxN为1,高电平是有效输出电平,需要加死区延迟。

4、互补输出没有开启,设置输出通道为高电平有效,输出与OCxREF一样,刹车信号来的时候,OCSx为1,为有效电平,需要死区延迟。

互补输出通道没有开启,设置的设置互补输出通道为高电平有效,同时OCSxN为0,低电平不是有效输出电平,不需要加死区延迟。

4、互补输出没有开启,设置输出通道为高电平有效,输出与OCxREF一样,刹车信号来的时候,OCSx为1,为有效电平,需要死区延迟。

互补输出通道没有开启,设置的设置互补输出通道为高电平有效,同时OCSxN为0,低电平不是有效输出电平,不需要加死区延迟。

 六、高级定时器互补输出带死区控制实验配置步骤

1、HAL_TIM_PWM_Init()函数,配置定时器基础工作参数。这个函数与HAL_TIM_Base_init()函数功能是一样的。

2、HAL_TIM_PWM_MspInit(),配置NVIC、CLOCK、GPIO等。

3、HAL_TIM_PWM _Configchannel()函数,配置PWM模式/比较值。

4、HAL_TIMEx_ConfigBreakDeadTime()函数,配置刹车功能、死区时间等。

5、HAL_TIM_PWM _Start()函数,使能输出、主输出、计数器。

6、HAL_TIM_PWMN _Start()函数,使能互补输出、主输出、计数器。

 七、高级定时器互补输出带死区控制实验

1、寄存器版本

#include "./BSP/TIMER/atim.h"

//配置定时器1的通道1 和 通道1互补输出  PE8 PE9
void Advanced_TIM_Init(void)
{
	//开启定时器1时钟
	RCC->APB2ENR |= (1 << 11);
	
	//设置CKD分频系数为4
	TIM1->CR1 |= (1 << 9);
	TIM1->CR1 &= ~(1 << 8);
	
	//设置ARR寄存器缓冲功能
	TIM1->CR1 |= (1 << 7);
	
	//注意硬件不允许同时输出有效电平 有效电平在CCxP和CCxNP设置
	//设置OIS1 输出空闲状态
	//TIM1->CR2 |= (1 << 8);
	TIM1->CR2 &= ~(1 << 8);
	
	//设置OIS1N 互补输出空闲状态
	TIM1->CR2 |= (1 << 9);
	
	//设置CC1S模式为输出 00 
	TIM1->CCMR1 &= ~(0X03 << 0);
	
	//OC1M 设置为PWM1模式 110 
	TIM1->CCMR1 |= (0X03 << 5);
	TIM1->CCMR1 &= ~(1 << 4);
	
	
	//CC1NP 互补输出高电平有效
	TIM1->CCER &= ~(1 << 3);
	
	//CC1NE 开启互补输出比较使能
	TIM1->CCER |= (1 << 2);
	
	//CC1P 输出高电平有效
	TIM1->CCER &= ~(1 << 1);
	
	//CC1E开启输出比较使能
	TIM1->CCER |= (1 << 0);
		
	//设置预分频系数为71
	TIM1->PSC = 71;
	
	//设置预装载值为999 
	TIM1->ARR = 999;
	
	//设置CCR1输出比较值 控制占空比
	TIM1->CCR1 = 0.3 * (TIM1->ARR + 1) - 1;
	
	//MOE 开启主输出
	TIM1->BDTR |= (1 << 15);
	
	//AOE 开启刹车失效之后MOE自动恢复
	TIM1->BDTR |= (1 << 14);
	
	//刹车极性高电平有效
	TIM1->BDTR |= (1 << 13);
	
	//开启刹车使能
	TIM1->BDTR |= (1 << 12);
	
	//CKD分频系数设置为4 72M/4 取倒数为Tdts时间 
	//然后用100 成这个时间为死区延迟时间 5.56us
	//设置DTG死区延时为100 
	TIM1->BDTR |= 100;
	
	TIM1->EGR |= (1 << 0);
	
	//开启GPIOE1时钟
	RCC->APB2ENR |= (1 << 6);
	
	//设置PE8为复用推挽输出
	GPIOE->CRH |= (0X03 << 0);
	GPIOE->CRH |= (1 << 3);
	GPIOE->CRH &= ~(1 << 2);
	
	//设置PE9为复用推挽输出
	GPIOE->CRH |= (0X03 << 4);
	GPIOE->CRH |= (1 << 7);
	GPIOE->CRH &= ~(1 << 6);
	
	//设置PE15为复用推挽输出
	GPIOE->CRH |= (0X03 << 28);
	GPIOE->CRH |= (1 << 31);
	GPIOE->CRH &= ~(1 << 30);
	
	//使能AFIO时钟
	RCC->APB2ENR |= (1 << 0);
	
	//设置TIM1完全重映射 将CH1映射到PE9 CH1N映射到PE8 BKIN映射到PE15上
	AFIO->MAPR |= (0x03 << 6);
	
	//使能计数器
	TIM1->CR1 |= (1 << 0);
}

注意:配置过程中发现刹车输入使能位和刹车极性位设置无效,但是debug的时候通过断点设置便可以,全速运行就不可以  问题还没有找到,有思路的小伙伴可以私信我。

2、库函数版本

atim.h头文件 

#ifndef __ATIM_H
#define __ATIM_H

#include "stm32f1xx.h"
void Advanced_TIM_Init(void);
#endif

 atim.c源文件

#include "./BSP/TIMER/atim.h"


TIM_HandleTypeDef htim;

void Advanced_TIM_Init(void)
{
	htim.Instance = TIM1;
	htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
	htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV4;
	htim.Init.CounterMode = TIM_COUNTERMODE_UP;
	htim.Init.Period = 999;
	htim.Init.Prescaler = 71;
	
	//配置PWM输出
	HAL_TIM_PWM_Init(&htim);
	
	TIM_OC_InitTypeDef sConfig = {0};
	
	sConfig.OCIdleState = TIM_OCIDLESTATE_SET;
	sConfig.OCMode = TIM_OCMODE_PWM1;
	sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
	sConfig.OCNPolarity = TIM_OCNPOLARITY_HIGH;
	sConfig.OCPolarity = TIM_OCPOLARITY_HIGH;
	sConfig.Pulse = 499;
	HAL_TIM_PWM_ConfigChannel(&htim,&sConfig,TIM_CHANNEL_1);
	
	TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
	
	sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
	sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
	sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
	sBreakDeadTimeConfig.DeadTime = 100;
	sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
	sBreakDeadTimeConfig.OffStateRunMode=TIM_OSSR_DISABLE;
	
	//刹车输入及死区时间配置
	HAL_TIMEx_ConfigBreakDeadTime(&htim,&sBreakDeadTimeConfig);
	
	HAL_TIM_PWM_Start(&htim,TIM_CHANNEL_1);
	
	HAL_TIMEx_PWMN_Start(&htim,TIM_CHANNEL_1);
}


void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
	//开启定时器1时钟
	__HAL_RCC_TIM1_CLK_ENABLE();
	
	//开启GPIOE时钟
	__HAL_RCC_GPIOE_CLK_ENABLE();
	
	GPIO_InitTypeDef GPIO_Init = {0};
	GPIO_Init.Mode = GPIO_MODE_AF_PP;
	GPIO_Init.Pin  = GPIO_PIN_8;
	GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH;
	
	//初始化PE8为复用推挽输出
	HAL_GPIO_Init(GPIOE, &GPIO_Init);
	
	//初始化PE9为复用推挽输出
	GPIO_Init.Pin  = GPIO_PIN_9;
	HAL_GPIO_Init(GPIOE, &GPIO_Init);
	
	GPIO_Init.Mode = GPIO_MODE_INPUT;
	GPIO_Init.Pull = GPIO_PULLDOWN;
	GPIO_Init.Pin  = GPIO_PIN_15;
	HAL_GPIO_Init(GPIOE, &GPIO_Init);
	
	//开启AFIO时钟
	__HAL_RCC_AFIO_CLK_ENABLE();
	
	//开启TIM1完全重映射
	__HAL_AFIO_REMAP_TIM1_ENABLE();
}

 main.c源文件 

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/TIMER/atim.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
	sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
    led_Init();                         /* LED初始化 */
	Advanced_TIM_Init();
    while(1)
    { 
		LED0(1);
		LED1(0);
		delay_ms(500);
		
		LED0(0);
		LED1(1);
		delay_ms(500);
    }
}

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

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

相关文章

git提交到GitHub问题汇总

1.main->master git默认主分支是maser&#xff0c;如果是按照这个分支名push&#xff0c;GitHub会出现两个branch&#xff0c;与预期不符 解决方案&#xff1a;更改原始主分支名为main git config --global init.defaultBranch main2.git&#xff1a;OpenSSL SSL_read: SS…

【图片合并转换PDF】如何将每个文件夹下的图片转化成PDF并合并成一个文件?下面基于C++的方式教你实现

医院在为患者进行诊断和治疗过程中&#xff0c;会产生大量的医学影像图片&#xff0c;如 X 光片、CT 扫描图、MRI 图像等。这些图片通常会按照检查时间或者检查项目存放在不同的文件夹中。为了方便医生查阅和患者病历的长期保存&#xff0c;需要将每个患者文件夹下的图片合并成…

vite + axios 代理不起作用 404 无效

vite axios 代理不起作用 先看官方示例 export default defineConfig({server: {proxy: {// 字符串简写写法/foo: http://localhost:4567,// 选项写法/api: {target: http://jsonplaceholder.typicode.com,changeOrigin: true,rewrite: (path) > path.replace(/^\/api/, )…

Spring Boot接入Deep Seek的API

1&#xff0c;首先进入deepseek的官网&#xff1a;DeepSeek | 深度求索&#xff0c;单击右上角的API开放平台。 2&#xff0c;单击API keys&#xff0c;创建一个API&#xff0c;创建完成务必复制&#xff01;&#xff01;不然关掉之后会看不看api key&#xff01;&#xff01;&…

Windows 系统下使用 Ollama 离线部署 DeepSeek - R1 模型指南

引言 随着人工智能技术的飞速发展&#xff0c;各类大语言模型层出不穷。DeepSeek - R1 凭借其出色的语言理解和生成能力&#xff0c;受到了广泛关注。而 Ollama 作为一款便捷的模型管理和部署工具&#xff0c;能够帮助我们轻松地在本地环境中部署和使用模型。本文将详细介绍如…

Python+Flask搭建属于自己的B站,管理自己电脑里面的视频文件。支持对文件分类、重命名、删除等操作。

适用场景 个人用户:管理本地图片和视频文件,快速查找和分类。 团队协作:共享文件分类标签,提升团队文件管理效率。 教育机构:用于教学资源管理,方便教师和学生查找资料。 企业应用:作为内部文件管理系统,支持批量操作和分类管理。 功能介绍 文件浏览与播放:用户可以浏…

深入Linux系列之进程地址空间

深入Linux系列之进程地址空间 1.引入 那么在之前的学习中&#xff0c;我们知道我们创建一个子进程的话&#xff0c;我们可以在代码层面调用fork函数来创建我们的子进程&#xff0c;那么fork函数的返回值根据我们当前所处进程的上下文是返回不同的值&#xff0c;它在父进程中返…

前端 CSS 动态设置样式::class、:style 等技巧详解

一、:class 动态绑定类名 v-bind:class&#xff08;缩写为 :class&#xff09;可以动态地绑定一个或多个 CSS 类名。 1. 对象语法 通过对象语法&#xff0c;可以根据条件动态切换类名。 <template><div :class"{ greenText: isActive, red-text: hasError }&…

ArgoCD实战指南:GitOps驱动下的Kubernetes自动化部署与Helm/Kustomize集成

摘要 ArgoCD 是一种 GitOps 持续交付工具,专为 Kubernetes 设计。它能够自动同步 Git 仓库中的声明性配置,并将其应用到 Kubernetes 集群中。本文将介绍 ArgoCD 的架构、安装步骤,以及如何结合 Helm 和 Kustomize 进行 Kubernetes 自动化部署。 引言 为什么选择 ArgoCD?…

go语言文件和目录

打开和关闭文件 os.Open()函数能够打开一个文件&#xff0c;返回一个*File 和一个 err。操作完成文件对象以后一定要记得关闭文件。 package mainimport ("fmt""os" )func main() {// 只读方式打开当前目录下的 main.go 文件file, err : os.Open(".…

LLM应用实践(1)- 物流状态判断

原文&#xff1a;LLM应用实践&#xff08;1&#xff09;- 物流状态判断 稳定输出 JSON 字符串 为了能够更好的贴合实际的业务场景的应用&#xff0c;我们通常期望大模型返回的数据是 JSON 格式的&#xff0c;这样能够降低对大模型返回内容处理的复杂度&#xff0c;如果返回了…

redis高级数据结构Stream

文章目录 背景stream概述消息 ID消息内容常见操作独立消费创建消费组消费 Stream弊端Stream 消息太多怎么办?消息如果忘记 ACK 会怎样?PEL 如何避免消息丢失?分区 Partition Stream 的高可用总结 背景 为了解决list作为消息队列是无法支持消息多播问题&#xff0c;Redis5.0…

SpringMVC SpringMVC拦截器 拦截器基础知识

1.什么是拦截器 SpringMVC提供了Intercepter拦截器机制&#xff0c;类似于Servlet当中的Filter过滤器&#xff0c;用于拦截用户的请求并作出相应的处理&#xff0c;比如通过拦截器来进行用户权限验证或者用来判断用户是否登录。SpringMVC拦截器是可插拔式的设计&#xff0c;需…

TAPEX:通过神经SQL执行器学习的表格预训练

摘要 近年来&#xff0c;语言模型预训练的进展通过利用大规模非结构化文本数据取得了巨大成功。然而&#xff0c;由于缺乏大规模高质量的表格数据&#xff0c;在结构化表格数据上应用预训练仍然是一个挑战。本文提出了TAPEX&#xff0c;通过在一个合成语料库上学习神经SQL执行…

Matlab机械手碰撞检测应用

本文包含三个部分&#xff1a; Matlab碰撞检测的实现URDF文件的制作机械手STL文件添加夹爪 一.Matlab碰撞检测的实现 首先上代码 %% 检测在结构环境中机器人是否与物体之间发生碰撞情况&#xff0c;如何避免&#xff1f; % https://www.mathworks.com/help/robotics/ug/che…

激活函数篇 04 —— softmax函数

将模型的输出转换为概率分布&#xff0c;使得模型能够输出每个类别的概率值。 Softmax ( a i ) e a i ∑ j 1 n e a j \text{Softmax}(a_i)\frac{e^{a_i}}{\sum_{j1}^n e^{a_j}} Softmax(ai​)∑j1n​eaj​eai​​ 其中&#xff0c; a i a_i ai​ 是输入向量中的第 i i i 个…

软件工程的熵减:AI如何降低系统复杂度

软件开发的世界&#xff0c;如同一个不断膨胀的宇宙。随着功能的增加和时间的推移&#xff0c;代码库越来越庞大&#xff0c;系统复杂度也随之水涨船高。代码膨胀、维护困难、开发效率低下等问题困扰着无数开发者。这不禁让人联想到物理学中的“熵增”原理——一个孤立系统的熵…

springboot008房屋租赁系统

版权声明 所有作品均为本人原创&#xff0c;提供参考学习使用&#xff0c;如需要源码数据库配套文档请移步 www.taobysj.com 搜索获取 技术实现 开发语言&#xff1a;Javavue。 框架&#xff1a;后端spingboot前端vue。 模式&#xff1a;B/S。 数据库&#xff1a;mysql。 开…

DeepSeek训练成本与技术揭秘

引言&#xff1a;在当今人工智能蓬勃发展的时代&#xff0c;DeepSeek 宛如一颗耀眼的新星&#xff0c;突然闯入大众视野&#xff0c;引发了全球范围内的热烈讨论。从其惊人的低成本训练模式&#xff0c;到高性能的模型表现&#xff0c;无一不让业界为之侧目。它打破了传统认知&…

计算机视觉语义分割——Attention U-Net(Learning Where to Look for the Pancreas)

计算机视觉语义分割——Attention U-Net(Learning Where to Look for the Pancreas) 文章目录 计算机视觉语义分割——Attention U-Net(Learning Where to Look for the Pancreas)摘要Abstract一、Attention U-Net1. 基本思想2. Attention Gate模块3. 软注意力与硬注意力4. 实验…