文章目录
- 前言
- 一、cubemx配置
- 1.RCC配置
- 2.时钟树配置PLL输入=HSE/1=8MHZ
- 3.Timer配置
- 在这里插入图片描述 刹车中断以及定时器溢出中断配置 ![在这里插入图片描述](https://img-blog.csdnimg.cn/3976686986e241ffb8a8e5149ed84143.png) 引脚输出频率选为HIGH,刹车引脚选为推挽输出,所有使用到的引脚如图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/5815ebabd17245a7bdc48ee03f6ad0ff.png)
- 在这里插入图片描述 ![在这里插入图片描述](https://img-blog.csdnimg.cn/58da5f98ffc846ed8d3254892928ca2b.png)![在这里插入图片描述](https://img-blog.csdnimg.cn/ddb05e46ada94e19b78253c4826247e4.png)
- 二、keil5定时器配置及输出
- 三、利用keil5自带逻辑分析仪进行仿真
- 总结
前言
第一次写文章,如果有错误请见谅;
本文主要内容:利用cubemx生成带死区补偿刹车的三相互补PWM,并利用keil进行仿真测试.
提示:以下是本篇文章正文内容,下面案例可供参考
一、cubemx配置
1.RCC配置
1.在用cube配置时钟时,有下面三个选项
Disable(禁用)
BYPASS Clock Source(旁路时钟源)
Crystal/Ceramic Resonator(晶体/陶瓷晶振)
HSE(高速外部时钟源):一般情况下配置为Crystal/Ceramic Resonator(晶体/陶瓷晶振)
LSE(低速外部时钟源):DISABLE
2.时钟树配置PLL输入=HSE/1=8MHZ
1.PLL输入选择HSE,分频因子1,得到PLL输入=8/1=8MHZ
2.PLL倍频因子选为9,PLL输出=system clock=8*9=72MHZ
3.AHB总线分频因子为1,可得AHB频率=72MHZ
4.APB1为低速总线,挂载外设频率最高为36MHZ,定时器时钟72MHZ.当APB1分频因子为一时,挂载在该总线上的定时器倍频因子不起作用,不为1时,定时器频率为APB1频率的2倍。
5.APB2为高速总线,挂载的外设时钟最高可达到系统最大频率。
3.Timer配置
1在选择输出PWM时,Slave Mode ,Trigger Source不会涉及。
2.配置时钟源为内部时钟源,Channel1,2,3配置为PWM互补输出(PWM Generation CHx CHxN),仅有高级定时器Timer1,Timer8具有互补输出。
3.使能刹车 (Active-Break-Input)
1.基本配置
1.Prescaler:
定时器预分频器设置,时钟源经该预分频器才是定时器时钟,它设定TIMx_PSC寄存器的值。可设置范围为0 至65535,实现1 至65536 分频。
2.Period:
定时器周期,实际就是设定自动重载寄存器的值,在事件生成时更新到影子寄存器。可设置范围为0 至65535。
1.自动重载寄存器ARR
自动重载寄存器ARR 用来存放与计数器CNT 比较的值,如果两个值相等就递减重复计数器。可以通过TIMx_CR1 寄存器的ARPE 位控制自动重载影子寄存器功能,如果ARPE 位置1,自动重载影子寄存器有效,只有在事件更新时才把TIMx_ARR 值赋给影子寄存器。如果ARPE 位为0,则修改TIMx_ARR 值马上有效。
3.ClockDivision:
时钟分频,设置定时器时钟CK_INT 频率与数字滤波器采样时钟频率分频比,基本定时器没有此功能。
4.RepetitionCounter:
重复计数器,属于高级控制寄存器专用寄存器位,利用它可以非常容易控制输出PWM 的个数。
在基本/通用定时器发生上/下溢事件时直接就生成更新事件,但对于高级控制定时器却不是这样,高级控制定时器在硬件结构上多出了重复计数器,在定时器发生上溢或下溢事件是递减重复计数器的值,只有当重复计数器为0 时才会生成更新事件。在发生N+1 个上溢或下溢事件(N 为RCR 的值) 时产生更新事件。
定时器溢出时间的计算:
T=((period+1)*(psc+1))/(TIM_CLK_Mhz / TIM_ClockDivision) us
上式中,period为周期寄存器TIMx->Arr的值,
举个定时1秒的例子:上图中APB2_CLK=72M,进入定时器后先把“预分频”系数psc设为71,这时定时器的频率为1M。然后设置“再分频”系数为1,定时器的频率还是1M。设置周期值period=1000000-1,根据频率可知,1秒钟能计1M个数,那么计100000个数就耗时1秒。
5.计数模式
高级控制定时器的计数器有三种计数模式,分别为递增计数模式、递减计数模式和递增/递减(中心对齐) 计数模式。
(1) 递增计数模式
计数器从0 开始计数,每来一个CK_CNT 脉冲计数器就增加1,直到计数器的值与自动重载寄存器ARR 值相等,然后计数器又从0 开始计数并生成计数器上溢事件,计数器总是如此循环计数。如果禁用重复计数器,在计数器生成上溢事件就马上生成更新事件(UEV);如果使能重复计数器,每生成一次上溢事件重复计数器内容就减1,直到重复计数器内容为0 时才会生成更新事件。
(2) 递减计数模式
计数器从自动重载寄存器ARR 值开始计数,每来一个CK_CNT 脉冲计数器就减1,直到计数器值为0,然后计数器又从自动重载寄存器ARR 值开始递减计数并生成计数器下溢事件,计数器总是如此循环计数。如果禁用重复计数器,在计数器生成下溢事件就马上生成更新事件;如果使能重复计数器,每生成一次下溢事件重复计数器内容就减1,直到重复计数器内容为0 时才会生成更新事件。
(3) 中心对齐模式
计数器从0 开始递增计数,直到计数值等于(ARR-1) 值生成计数器上溢事件,然后从ARR 值开始递减计数直到1 生成计数器下溢事件。然后又从0 开始计数,如此循环。每次发生计数器上溢和下溢事件都会生成更新事件。
2.PWM配置
1.PWM 输出模式
PWM 输出模式就是对外输出脉宽(即占空比)可调的方波信号,信号频率由自动重装寄存器ARR 的值决定,占空比由比较寄存器CCR 的值决定。
PWM 模式分为两种,PWM1 和PWM2,总得来说是差不多,就看你怎么用而已,具体的区别下表PWM1 与PWM2 模式的区别。
PWM1 与PWM2 模式的区别:
以PWM1 模式来讲解,以计数器CNT 计数的方向不同还分为边沿对齐模式和中心对齐模式。PWM 信号主要都是用来控制电机,一般的电机控制用的都是边沿对齐模式,FOC 电机一般用中心对齐模式。这里只分析这两种模式在信号感官上(即信号波形)的区别。
1.PWM 边沿对齐模式
在递增计数模式下,计数器从0 计数到自动重载值(TIMx_ARR 寄存器的内容),然后重新从0开始计数并生成计数器上溢事件。
在边沿对齐模式下,计数器CNT 只工作在一种模式,递增或者递减模式。这里我们以CNT 工作在递增模式为例,在中,ARR=8,CCR=4,CNT 从0 开始计数,当CNT<CCR 的值时,OCxREF为有效的高电平,于此同时,比较中断寄存器CCxIF 置位。当CCR=<CNT<=ARR 时,OCxREF为无效的低电平。然后CNT 又从0 开始计数并生成计数器上溢事件,以此循环往复。
2.PWM 中心对齐模式
在中心对齐模式下,计数器CNT 是工作做递增/递减模式下。开始的时候,计数器CNT 从0 开始计数到自动重载值减1(ARR-1),生成计数器上溢事件;然后从自动重载值开始向下计数到1 并生成计数器下溢事件。之后从0 开始重新计数。
2.相关及寄存器
(1) OCMode
比较输出模式选择,总共有八种,常用的为PWM1/PWM2。它设定CCMRx 寄存器OCxM[2:0] 位的值。
(2) Pulse
比较输出脉冲宽度,实际设定比较寄存器CCR 的值,决定脉冲宽度。可设置范围为0 至65535。
(3) OCPolarity
比较输出极性,可选OCx 为高电平有效或低电平有效。它决定着定时器通道
有效电平。它设定CCER 寄存器的CCxP 位的值。
(4) OCNPolarity
比较互补输出极性,可选OCxN 为高电平有效或低电平有效。它设定
TIMx_CCER 寄存器的CCxNP 位的值。
(5) OCFastMode
比较输出模式快速使能。它设定TIMx_CCMR 寄存器的,OCxFE 位的值可以
快速使能或者禁能输出。
(6) OCIdleState
空闲状态时通道输出电平设置,可选输出1 或输出0,即在空闲状态
(BDTR_MOE 位为0) 时,经过死区时间后定时器通道输出高电平或低电平。它设定CR2寄存器的OISx 位的值。
(7) OCNIdleState
空闲状态时互补通道输出电平设置,可选输出1 或输出0,即在空闲状态(BDTR_MOE 位为0) 时,经过死区时间后定时器互补通道输出高电平或低电平,设定值必须与OCIdleState 相反。它设定是CR2 寄存器的OISxN 位的值。
3.死区刹车
断路功能就是电机控制的刹车功能,使能断路功能时,根据相关控制位状态修改输出信号电平。
发送断路时,将产生以下效果:
• TIMx_BDTR 寄存器中主输出模式使能(MOE) 位被清零,输出处于无效、空闲或复位状态;
• 根据相关控制位状态控制输出通道引脚电平;当使能通道互补输出时,会根据情况自动控制输出通道电平;
• TIMx_BDTR 寄存器中主输出模式使能(MOE) 位被清零,输出处于无效、空闲或复位状态;
• 根据相关控制位状态控制输出通道引脚电平;当使能通道互补输出时,会根据情况自动控制输出通道电平;
1.寄存器
(1) OffStateRunMode
运行模式下的关闭状态选择,它设定BDTR 寄存器OSSR 位的值。
(2) OffStateIDLEMode
空闲模式下的关闭状态选择,它设定BDTR 寄存器OSSI 位的值。
(3) LockLevel
锁定级别配置。
(4) DeadTime
配置死区发生器,定义死区持续时间,可选设置范围为0x0 至0xFF。它设定
BDTR 寄存器DTG[7:0] 位的值。
(5) BreakState
断路输入功能选择,可选使能或禁止。
(6) BreakPolarity
断路输入通道BRK 极性选择,可选高电平有效或低电平有效。它设定BDTR
寄存器BKP 位的值。
(7) BreakFilter
断路输入滤波器,定义BRK 输入的采样频率和适用于BRK 的数字滤波器带宽。它设定BDTR 寄存器BKF[3:0] 位的值。
(8) Break2State
断路2 输入功能选择,可选使能或禁止。它设定BDTR 寄存器BK2E 位的值。
(9) Break2Polarity
断路2 输入通道BRK2 极性选择,可选高电平有效或低电平有效。它设定
BDTR 寄存器BK2P 位的值。
(10) Break2Filter
断路2 输入滤波器,定义BRK2 输入的采样频率和适用于BRK2 的数字滤波
器带宽。它设定BDTR 寄存器BK2F[3:0] 位的值。
(11) AutomaticOutput
自动输出使能,可选使能或禁止,它设定BDTR 寄存器AOE 位的值。
4.NVIC及 GPIO
![在这里插入图片描述](https://img-blog.csdnimg.cn/b0a22bb7b2d8459b89011ccf2e968508.png)
刹车中断以及定时器溢出中断配置
![在这里插入图片描述](https://img-blog.csdnimg.cn/3976686986e241ffb8a8e5149ed84143.png)
引脚输出频率选为HIGH,刹车引脚选为推挽输出,所有使用到的引脚如图
![在这里插入图片描述](https://img-blog.csdnimg.cn/5815ebabd17245a7bdc48ee03f6ad0ff.png)
5.工程文件及代码生成配置
二、keil5定时器配置及输出
1.打开keil工程添加启动文件
cubemx生成的项目文件可能没有包含启动文件的路径需要自行添加
![在这里插入图片描述](https://img-blog.csdnimg.cn/098d9dc51eff4e4c96dd5d805b743940.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/29b6969d286c48f8bd39fc2107501057.png)
2定时器配置
1.tim.c文件
包含四个函数
void MX_TIM1_Init(void)//定时器初始化
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* tim_pwmHandle)//中断及刹车初始化
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)//定时器输出引脚初始化
void HAL_TIM_PWM_MspDeInit(TIM_HandleTypeDef* tim_pwmHandle)//失能定时器
初始化函数
void MX_TIM1_Init(void)
{
/* USER CODE BEGIN TIM1_Init 0 */
/* USER CODE END TIM1_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/* USER CODE BEGIN TIM1_Init 1 */
/* USER CODE END TIM1_Init 1 */
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0; //分频器
htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;//计数模式
htim1.Init.Period = 3599;//预装载寄存器
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;//内部时钟分频
htim1.Init.RepetitionCounter = 0;//重复计数
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;//预装载寄存器
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;//主从模式
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1; //输出比较模式
sConfigOC.Pulse = 1200; //PWM脉冲数
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;//输出极性
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;//互补输出极性
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;//快速模式
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;//空闲模式下电平
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_SET;//空闲模式下互补信号电平
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
sConfigOC.Pulse = 2400;
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;//运行状态下刹车使能
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;//空闲状态下使能
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1; //
sBreakDeadTimeConfig.DeadTime = 100; //死区时间
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;//刹车使能
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_LOW;//当引脚为低电平时刹车
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM1_Init 2 */
/* USER CODE END TIM1_Init 2 */
HAL_TIM_MspPostInit(&htim1);
}
2.PWM输出
当我们初始化定时器后PWM并不会使出,需要我们找到专门的启动函数来开启PWM输出功能
1.打开stm32f1xx.hal_tim.c
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)//使能输出
__HAL_TIM_SetCompare(&htim,TIM_CHANNEL,pulse); //改变占空比
若要更改PWM频率则需要修改预装载寄存器的值。并产生一次溢出事件具体函数如下
__HAL_TIM_SET_AUTORELOAD(&htim1,1799);
HAL_TIM_GenerateEvent(&htim1,TIM_IT_UPDATE);
2.将函数添加到主函数内
3.中断函数编写
回调函数为虚函数,因此若要使用中断回调函数只需要在主函数中重新编写中断回调函数即可实现。
中断回调函数:
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM1) {
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_11);
}
中断使能:
HAL_TIM_Base_Start_IT(&htim1);
1.引入库
代码如下(示例):
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
三、利用keil5自带逻辑分析仪进行仿真
1.点击魔法棒,选择xtal为8MHZ
2.debug配置
3.保存设置
4.编译项目
5.检查是否有报错
6.打开debug
7.打开逻辑分析仪
8.打开setup设置
9.新建信号源
10.输入对应的端口及引脚
例如想要观察PA10引脚信号,则需要设置:
portA.10
11.点击运行
通过鼠标滚轮调节窗口显示范围
12.点击AOTU或者右键该区域选择bit
13.测量PWM频率周期,占空比及死区
放大图中区域并点击stop。
单击一侧后,鼠标指向另一方向,则可以查看两者之间的时间差值。
总结
介绍了cubemx+stm32f103c8t6+keil三相带死区互补输出PWM配置及仿真。文中还有点小问题,配置后如果不使用复用引脚,生成的互补通道的PWM波形会出现问题,目前没有搞清楚原因。