普通定时器输出互补PWM带死区

2023-05-16

普通定时器输出互补PWM带死区

一般来说三相半桥电路需要互补PWM驱动,而且互补PWM需要带死区,死区的大小跟管子的性能参数有关。公司为了省成本,在云台上把电机驱动芯片替换成三相半桥。用6个MOS驱动无刷电机。这下就需要用到互补PWM了。
然后选型的单片机只有一路高级定时器tim1,另外一个电机的PWM驱动分别是tim3,tim4.不同的定时器怎么实现互补PWM而且带死区呢。
1、定时器主从功能
2、定时器中心对齐模式
3、tim3使用PWM1模式,tim4使用PWM2模式
4、输出PWM时占空比预留死区

在我的项目中互补PWM都已经实现,死区也已经实现,但是发现板子驱动电流还是很大,达不到要求,在经历了几天各种怀疑硬件问题的过程当中也寻找了很多解决办法。PWM配置问题等。。。
后来发现,波形的高电平有重叠。再次记住高电平不能有重叠的现象,要不就会出现短路导致电流过大。
具体配置代码如下:

tim1为主定时器
void bsp_InitTMR1_PWM1(uint16_t arr,uint16_t psc)
{
    GPIO_InitType GPIO_InitStructure;
    TMR_TimerBaseInitType TMR_TMReBaseStructure;
    TMR_OCInitType TMR_OCInitStructure;
		NVIC_InitType NVIC_InitStructure;
		TMR_BRKDTInitType TIM_BDTRInitStruct;

    /* 使能GPIO时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_GPIOA, ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_GPIOB, ENABLE);
    /* 使能TMR1时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_TMR1, ENABLE);

    /* 配置GPIO */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pins = GPIO_Pins_8 | GPIO_Pins_9 | GPIO_Pins_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; /* 复用模式 */
    GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
	
		GPIO_InitStructure.GPIO_Pins = GPIO_Pins_13 | GPIO_Pins_14 | GPIO_Pins_15; //TIM1_CH1N,TIM1_CH2N
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
		GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
		GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* 配置TMR1 */
    TMR_TimeBaseStructInit(&TMR_TMReBaseStructure);
    TMR_TMReBaseStructure.TMR_Period = arr;              /* PWM周期 */
    TMR_TMReBaseStructure.TMR_DIV = psc;                   /* 120分频,即1MHz */
    TMR_TMReBaseStructure.TMR_ClockDivision = 0;               /* 时钟除频 */
    TMR_TMReBaseStructure.TMR_CounterMode = TMR_CounterDIR_Up; /* 向上计数 */
    TMR_TimeBaseInit(TMR1, &TMR_TMReBaseStructure);
		
		/* Set the default configuration */
		TIM_BDTRInitStruct.TMR_OSIMRState = TMR_OSIMRState_Enable;//运行模式下关闭状态选择
		TIM_BDTRInitStruct.TMR_OSIMIState = TMR_OSIMIState_Enable;//空闲模式下关闭状态选择
		TIM_BDTRInitStruct.TMR_LOCKgrade = TMR_LOCKgrade_OFF;//软件错误锁定配置:锁定关闭无保护
		TIM_BDTRInitStruct.TMR_DeadTime = 0x40;//DTG[7:0]死区发生器配置:(死区时间DT)  ,注意死区时间要设成100ns左右,否则过大会导致MOS栅极PWM波形异常,太小导致上下臂短路
		//TDTS = 125nS(8MHz)
		//DTG[7: 5] = 0xx => DT = DTG[7: 0] * Tdtg, Tdtg = TDTS;
		//DTG[7: 5] = 10x => DT =(64+DTG[5: 0]) * Tdtg, Tdtg = 2 * TDTS;
		//DTG[7: 5] = 110 => DT =(32+DTG[4: 0]) * Tdtg, Tdtg = 8 * TDTS; 
		//DTG[7: 5] = 111=> DT =(32 + DTG[4: 0]) *  Tdtg, Tdtg = 16 * TDTS;
		TIM_BDTRInitStruct.TMR_Break = TMR_Break_Disable;  //刹车配置:使能刹车
		TIM_BDTRInitStruct.TMR_BreakPolarity = TMR_BreakPolarity_High;//刹车输入极性选择:高电平有效
		TIM_BDTRInitStruct.TMR_AutomaticOutput = TMR_AutomaticOutput_Enable;//自动输出使能配置:MOE只能软件置1
		TMR_BRKDTConfig(TMR1, &TIM_BDTRInitStruct); //配置互补输出死区时间

    /* 配置PWM从TMR1_CH1输出 */
    TMR_OCStructInit(&TMR_OCInitStructure);
    TMR_OCInitStructure.TMR_OCMode = TMR_OCMode_PWM1;                           /* PWM模式 */
    TMR_OCInitStructure.TMR_OutputState = TMR_OutputState_Enable;		/* 使能输出 */
		TMR_OCInitStructure.TMR_OutputNState = TMR_OutputNState_Enable;
    TMR_OCInitStructure.TMR_Pulse = 1000; /* PWM占空比 */
    TMR_OCInitStructure.TMR_OCPolarity = TMR_OCPolarity_High;                   /* 高电平有效 */
		TMR_OCInitStructure.TMR_OCNPolarity = TMR_OCNPolarity_High;
		TMR_OCInitStructure.TMR_OCIdleState = TMR_OCIdleState_Reset;
		TMR_OCInitStructure.TMR_OCNIdleState = TMR_OCNIdleState_Reset;
    TMR_OC1Init(TMR1, &TMR_OCInitStructure);
		TMR_OC2Init(TMR1, &TMR_OCInitStructure);
		TMR_OC3Init(TMR1, &TMR_OCInitStructure);

    /* 使能定时器TIM1在CCM上的周期值 */
		TMR_OC1PreloadConfig(TMR1, TMR_OCPreload_Enable);
		TMR_OC2PreloadConfig(TMR1, TMR_OCPreload_Enable);
    TMR_OC3PreloadConfig(TMR1, TMR_OCPreload_Enable);
    /* 使能TIM3在AR上的预装载寄存器 */
    TMR_ARPreloadConfig(TMR1, ENABLE);

    /* 使能TMR1 */
    TMR_Cmd(TMR1, ENABLE);
		
		TMR_CtrlPWMOutputs(TMR1, ENABLE);
		
		TMR_INTConfig(TMR1,TMR_INT_CC1,ENABLE);
    NVIC_InitStructure.NVIC_IRQChannel = TMR1_CC_IRQn;        
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;     
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStructure);
		
		TMR_SelectOutputTrigger(TMR1, TMR_TRGOSource_OC1);
		TMR_SelectMasterSlaveMode(TMR1, TMR_MasterSlaveMode_Enable);  //主从模式
}
volatile uint32_t TMR1_Count = 0;
void TMR1_CC_IRQHandler(void)  //24k  42us
{
	if (TMR_GetINTStatus(TMR1, TMR_INT_CC1) != RESET)     // TIM_IT_CC1
	{
		TMR_ClearITPendingBit(TMR1, TMR_INT_CC1); // 清除中断标志位 
		TMR1_Count ++;
		
//		all_foc_update();
	}
}
tim3为从定时器
void bsp_InitTMR3_PWM(void)
{
    GPIO_InitType GPIO_InitStructure;
    TMR_TimerBaseInitType TMR_TMReBaseStructure;
    TMR_OCInitType TMR_OCInitStructure;
		NVIC_InitType NVIC_InitStructure;

    /* 使能GPIO时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_GPIOA, ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_GPIOB, ENABLE);
    /* 使能TMR1时钟 */
    RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_TMR3, ENABLE);

    /* 配置GPIO */
    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pins = GPIO_Pins_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; /* 复用模式 */
    GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
	
		GPIO_InitStructure.GPIO_Pins = GPIO_Pins_0 | GPIO_Pins_1; //TIM1_CH1N,TIM1_CH2N
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
		GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
		GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* 配置TMR1 */
    TMR_TimeBaseStructInit(&TMR_TMReBaseStructure);
    TMR_TMReBaseStructure.TMR_Period = CYCLE - 1;              /* PWM周期 */
    TMR_TMReBaseStructure.TMR_DIV = 1;                   /* 120分频,即1MHz */
    TMR_TMReBaseStructure.TMR_ClockDivision = 0;               /* 时钟除频 */
    TMR_TMReBaseStructure.TMR_CounterMode = TMR_CounterDIR_CenterAligned1; /* 向上计数 */
		TMR_TMReBaseStructure.TMR_RepetitionCounter = 0x0000;
    TMR_TimeBaseInit(TMR3, &TMR_TMReBaseStructure);
		

    /* 配置PWM从TMR1_CH1输出 */
    TMR_OCStructInit(&TMR_OCInitStructure);
    TMR_OCInitStructure.TMR_OCMode = TMR_OCMode_PWM1;                           /* PWM模式 */
    TMR_OCInitStructure.TMR_OutputState = TMR_OutputState_Enable;		/* 使能输出 */
		TMR_OCInitStructure.TMR_OutputNState = TMR_OutputNState_Disable;
    TMR_OCInitStructure.TMR_Pulse = 1000; /* PWM占空比 */
    TMR_OCInitStructure.TMR_OCPolarity = TMR_OCPolarity_High;                   /* 高电平有效 */
//		TMR_OCInitStructure.TMR_OCNPolarity = TMR_OCNPolarity_High;
		TMR_OCInitStructure.TMR_OCIdleState = TMR_OCIdleState_Reset;
    TMR_OC1Init(TMR3, &TMR_OCInitStructure);
		TMR_OC3Init(TMR3, &TMR_OCInitStructure);
		TMR_OC4Init(TMR3, &TMR_OCInitStructure);
		
		TMR_SelectMasterSlaveMode(TMR3, TMR_MasterSlaveMode_Enable);
		TMR_SelectInputTrigger(TMR3, TMR_TRGSEL_ITR0);
		TMR_SelectSlaveMode(TMR3, TMR_SlaveMode_Trigger);

    /* 使能定时器TIM1在CCM上的周期值 */
		TMR_OC1PreloadConfig(TMR3, TMR_OCPreload_Enable);
		TMR_OC3PreloadConfig(TMR3, TMR_OCPreload_Enable);
    TMR_OC4PreloadConfig(TMR3, TMR_OCPreload_Enable);
    /* 使能TIM3在AR上的预装载寄存器 */
    TMR_ARPreloadConfig(TMR3, ENABLE);

    /* 使能TMR1 */
    TMR_Cmd(TMR1, ENABLE);
		
		TMR_CtrlPWMOutputs(TMR1, ENABLE);
}
tim4为从定时器
void bsp_InitTMR4_PWM(void)
{
		GPIO_InitType GPIO_InitStructure;
    TMR_TimerBaseInitType TMR_TMReBaseStructure;
		NVIC_InitType NVIC_InitStructure;
    TMR_OCInitType TMR_OCInitStructure;

    /* 使能GPIO时钟 */
		RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_GPIOB, ENABLE);
    /* 使能TMR1时钟 */
    RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_TMR4, ENABLE);

    /* 配置GPIO */
		GPIO_InitStructure.GPIO_Pins = GPIO_Pins_6 | GPIO_Pins_7 | GPIO_Pins_8;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
		GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
		GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* 配置TMR4 */
    TMR_TimeBaseStructInit(&TMR_TMReBaseStructure);
    TMR_TMReBaseStructure.TMR_Period = CYCLE - 1;              /* PWM周期 */
    TMR_TMReBaseStructure.TMR_DIV = 1;                   /* 120分频,即1MHz */
    TMR_TMReBaseStructure.TMR_ClockDivision = 0;               /* 时钟除频 */
    TMR_TMReBaseStructure.TMR_CounterMode = TMR_CounterDIR_CenterAligned1; /* 向上计数 */
		TMR_TMReBaseStructure.TMR_RepetitionCounter = 0x0000;
    TMR_TimeBaseInit(TMR4, &TMR_TMReBaseStructure);
		
		TMR_SelectMasterSlaveMode(TMR4, TMR_MasterSlaveMode_Enable);
		TMR_SelectInputTrigger(TMR4, TMR_TRGSEL_ITR0);
		TMR_SelectSlaveMode(TMR4, TMR_SlaveMode_Trigger);

    /* 配置PWM从TMR1_CH1输出 */
    TMR_OCStructInit(&TMR_OCInitStructure);
		
    TMR_OCInitStructure.TMR_OCMode = TMR_OCMode_PWM1;                           /* PWM模式 */
    TMR_OCInitStructure.TMR_OutputState = TMR_OutputState_Enable;		/* 使能输出 */
		TMR_OCInitStructure.TMR_OutputNState = TMR_OutputNState_Disable;
    TMR_OCInitStructure.TMR_Pulse = 1050; /* PWM占空比 */
    TMR_OCInitStructure.TMR_OCPolarity = TMR_OCPolarity_Low;                   /* 高电平有效 */
//		TMR_OCInitStructure.TMR_OCNPolarity = TMR_OCNPolarity_High;
		TMR_OCInitStructure.TMR_OCIdleState = TMR_OCIdleState_Reset;
    TMR_OC1Init(TMR4, &TMR_OCInitStructure);
		TMR_OC2Init(TMR4, &TMR_OCInitStructure);
		TMR_OC3Init(TMR4, &TMR_OCInitStructure);
		
    /* 使能定时器TIM1在CCM上的周期值 */
		TMR_OC1PreloadConfig(TMR4, TMR_OCPreload_Enable);
		TMR_OC2PreloadConfig(TMR4, TMR_OCPreload_Enable);
    TMR_OC3PreloadConfig(TMR4, TMR_OCPreload_Enable);
    /* 使能TIM3在AR上的预装载寄存器 */
    TMR_ARPreloadConfig(TMR4, ENABLE);

    /* 使能TMR1 */
    TMR_Cmd(TMR1, ENABLE);
		
		TMR_CtrlPWMOutputs(TMR1, ENABLE);
}

设置占空比是预留tim3 tim4占空比不一样,即可实现死区

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

普通定时器输出互补PWM带死区 的相关文章

随机推荐

  • HeidiSQL工具导出导入MySQL数据

    有时候 为了数据方便导出导入SQL 我们可以借助一定的工具 方便我们队数据库的移植 可以达到事半功倍的效果 在这里 就给大家简单的介绍一款能方便导出或者导入MySQL的数据 首先 选择你要导出的数据库 点击鼠标右键 如下图所示 这里是进行对
  • Navicat相关注册码

    Navicat相关注册码 用户名和组织随便起 注册码如下 Navicat for SQL Server V10 0 10 NAVD 3CG2 6KRN IEPM NAVL NIGY 6MYY XWQE NAVI C3UU AAGI 57FW
  • 我心目中的好的技术教程

    作者 xff1a 朱金灿 来源 xff1a http blog csdn net clever101 当人类进入互联网时代 xff0c 便宣告一个新的学习模式 网上学习的诞生 现在各种网上教程之多可以用恒河沙数来形容 xff08 这里暂时除
  • TCP的建立

    大家好呀 xff0c 我是请假君 xff0c 今天又来和大家一起学习数通了 xff0c 今天要分享的知识是TCP的建立 TCP是一个面向连接的可靠的传输控制协议 xff0c 在每次数据传输之前首先需要建立连接 xff0c 连接建立成功后才开
  • Java根据数字金额生成大写金额

    要求 根据用户输入金额数字转换成相对应大写金额例如 xff1a 430 65 xff0c 转换成肆佰叁拾元陆角伍分代码如下 xff1a public class MoneyFormatUtils private static final S
  • POI 设置Excel单元格背景色(参考颜色代码)

    创建一个 workbook 对象 Workbook workbook 61 new XSSFWorkbook 创建一个 sheet Sheet sheet 61 workbook createSheet 创建一行 Row row 61 sh
  • RedisTemplate之opsForValue使用说明

    转载链接出自 xff1a https blog csdn net qq 25135655 article details 80357137 Redis中opsForValue 方法的使用介绍 xff1a 1 set K key V valu
  • Python爬虫(二)——爬取电影天堂,保存下载地址

    首先我们开始要分析一下 xff0c 下载种子我们需要哪几步 xff1a 获取所有电影页的访问地址获取电影页源码提取出下载地址将下载地址保存 首先第一步 xff0c 我们来分析一下电影天堂网站的结构 xff0c 发现他跟我们的古诗文网还是非常
  • pixhawk飞控中添加uORB主题

    本说明针对 Firmware v1 2 0 参考 xff1a https pixhawk org start id 61 zh dev shared object communication 1 添加流程说明 在Firmware msg下新
  • px4 多旋翼SITL仿真

    好久不写csdn了 xff0c 自己的笔记都记在了onenote里面了 xff0c 没有时间写东西分享 xff0c 今天找了个记得比价规整的分享一下 备注 xff1a SITL需要程序源码和QGC xff0c 以及配置环境时安装的一些东西
  • keil空间不足,.\Objects\template.axf: Error: L6406E: No space in execution regions with .ANY selector mat

    关于keil空间报错 xff0c 我总结了一下集中解决方案 xff1a 1 有可能是所选主控芯片RAM xff0c ROM真的被用完了 xff0c 这是需要更换主控芯片 2 keil里面的优化还可以继续优化省出一点空间 下面红色标的选择跟你
  • 无人机之姿态控制篇

    姿态控制篇 拿四旋翼无人机为例 xff0c 四个桨叶旋转是的无人机产生了升力 xff0c 但是这个升力要怎么匹配才能使得无人机能够平稳的飞行呢 xff0c 这个就是无人机姿态控制的关键 如图四个电机1 2 3 4 xff0c 水平位置X x
  • 无人机小四轴定高篇

    无人机定高篇 定高 xff0c 也是无人机的标配功能 xff0c 可以说必须要有的 一般来说定高怎么做 xff0c 常规的思维就是计算出无人机的高度和Z轴速度 xff0c 然后对高度和速度进行PID运算 实际上大思想就是这么的简单 xff0
  • 无人机光流定点讲解

    无人机光流定点 光流是测速算法 xff0c 并不是直接定位的 简单理解 xff0c 光流就是通过检测图像中光点和暗点的移动 xff0c 来判断图像中像素点相对于飞行器的移动速度 如果地面是静止的 xff0c 自然就可以得到飞行器相对于地面的
  • TinyXml快速入门(一)

    作者 xff1a 朱金灿 来源 xff1a http blog csdn net clever101 对于xml文件 xff0c 目前我的工作只是集中在配置文件和作为简单的信息文件来用 xff0c 因此我不太喜欢使用msxml这种重量级的x
  • 华大单片机HC32L130/HC32L136从机IIC通信

    从机IIC理论知识 主机IIC的做法比较多 xff0c 从机IIC的就相对比较难一点 先补充一下从机IIC的思路 xff1a 先看IIC时序图 xff0c 然后根据时序图理清IIC从机需要做哪些判断 xff1a 从机发送 xff1a 判断I
  • cannot access memory

    cannot access memory 先说一个经历 xff1a 在一次我测试单片机FLASH时候 xff0c 程序就是一直运行的擦除FALSH xff0c 写入FLASH 然后再想通过SWD重新烧录程序就无法烧录进去了 具体现象如下 x
  • 无刷电机反方向高速旋转

    无刷电机反方向高速旋转 最近遇到一个问题 xff0c 就是无刷电机在给正转的力的时候如果用手往反方向快速的掰 xff0c 突然的电机会往反方向高速运动 xff0c 除非电机有阻力让转速慢下来 xff0c 要不就会一直反方向运动 经过一个晚上
  • 串口仿真数据正常,不接仿真数据异常

    今天遇到一个奇怪的问题 xff0c 折腾了大半天 具体问题如下 xff1a 串口我用的DMA空闲中断接收 xff0c 接仿真器仿真时接收数据完全正确 xff0c 没有异常 但是仿真器不接的时候 xff0c 正常外部供电串口接收数据就异常了
  • 普通定时器输出互补PWM带死区

    普通定时器输出互补PWM带死区 一般来说三相半桥电路需要互补PWM驱动 xff0c 而且互补PWM需要带死区 xff0c 死区的大小跟管子的性能参数有关 公司为了省成本 xff0c 在云台上把电机驱动芯片替换成三相半桥 用6个MOS驱动无刷