zoukankan      html  css  js  c++  java
  • BLDC开发笔记6.利用硬件COM事件换相

    前面我是用霍尔触发中断进行换相,这里将使用定时器的COM事件来换相。吐槽下看懂这个还真不容易。另外有什么不对的请帮忙指出。

    什么是COM事件?

    在中文参考手册中的13.3.14产生六步PWM输出有以下描述:

    COM事件,其实就是为了让换相时相应的通道同时打开/关断,因为如果按前面在霍尔触发中断中写配置函数的话,是顺序进行的,有延时,不能做到同时配置。那么在切换的时候上一步的MOS状态多少会影响下一步(其实我感觉影响很小)。COM事件能让下一步的配置暂时缓存在影子寄存器中,等待COM事件触发生效,触发后就将相应的输出比较通道使能位同步更新,进行换相,然后可以在COM中断中配置下一步的通道状态。

    我理解的使用COM事件另一个好处就是,能更灵活的对定时器进行同步操作。比如在ADC进行瞬时电流采样时候,就可以利用一个通用定时器去和高级定时器(输出PWM)同步,去触发ADC转换。方式更灵活。

    需要注意的是,COM事件产生时,生效的是上一次在中断中的配置(硬件完成),在COM中断中配置的是下一步的状态。所以我们需要提前一相进行配置。

    COM事件可由软件产生,也可以由硬件产生,这里主要解析硬件COM事件。

    硬件COM事件产生的流程


    上面是ST官方的主要流程框图,不过我觉得还是结合下面通用定时器功能框图解析比较清晰。

    总的说就是用一个通用定时器去触发一个高级定时器。下面是官方参考手册中给出的产生COM事件流程。

    1. 三个hall信号经过异或后,任意一相跳变,都会产生脉冲信号IC1PS,先将计数值传给输入捕获寄存器1

    2. 计数器复位,重新从零开始计数。在下一个脉冲IC1PS到来之前,输入捕获寄存器1的值,就表示了两个霍尔之间的时间。

    3. 将输出比较通道2发出的PWM作为TRGO输入源,注意配置为PWM2模式(当CNT<CCR时输出无效电平),设置一个较小的占空比,将主定时器的TRGO作为另一个高级定时器(从定时器)的TRGI触发源,每一次主定时器的TRGO有上升沿时,就会在从定时器触发一次硬件COM事件,进行换相。

    下面是中文参考手册实例:

    这里也注明了,在COM事件到来时,要写入的是下一个步骤的通道配置。

    用OC2REF作为TRGO好处就是能够自定义触发COM时间。

    我用的是TIM3去触发TIM1产生COM事件。

    TIM3初始化

    TIM3的初始化和前面文章中用霍尔触发中断的初始化中,时基和输入捕获通道初始化是一样的,只不过加入输出比较通道2的初始化和COM事件的配置。

    因为计数器一直在计数,而且计数器的ARR是有限的,所以这里就需要理清楚整个思路(ps:只是个人理解,可能我还没遇到这个情况,如果不对麻烦指出来)

    1. 刚开始,电机停止时候,初始设置PWM占空比为0,因为没有霍尔状态改变,计数器一直在计数,那么就一直产生溢出事件,不断触发COM事件,但是无所谓,因为没有霍尔状态改变,并不会捕获CNT的值,并且因为设置占空比为0,所以电机还是停转状态
    2. 电机启动,按照给定PWM占空比转动,TIM3利用TIM_TS_TI1F_ED正常触发COM事件,因为开始计数器一直计数,第一次产生捕获事件时候,并不知道会停在哪里,可能并不是我们想要的CNT值,但是我们可以将其过滤掉。我们通过设置反馈调整时间(50ms在滴答定时器进行转速计算和PI算法),其实就已经把这个值过滤掉了。之后正常捕获。关于电机转速慢到超出计数器ARR,则需要根据实际最低转速调整时基配置,保证长于霍尔传感器上的两次变化的时间间隔。触发延时变长其实是相对而言的,最大65535个周期我觉得是足以应对大部分情况的。
    3. 电机停止,同1,设置占空比为0等操作进行停转。
    4. 考虑堵转保护,我的思路是使能TIM3输入捕获中断,每次在里面将堵转标志清零,在COM中断中加一,如果超过一定数值就关闭PWM输出(这个数值不能太大,比如为5),这样做是因为两个中断理论上时间线上是不同的,会先触发输入捕获中断,再触发COM中断,不过需要控制输入捕获中断的执行时间,不要在里面进行太多事务处理,做到互不妨碍,这里我的配置应该有10us间隔时间,应该是足够的,这里待我完善。
            //使能Timx霍尔传感器接口,CH1CH2CH3异或输入
    	TIM_SelectHallSensor(HALL_TIMx,ENABLE);  
    	
    	//输入触发源选择TIM_TS_TI1F_ED
    	TIM_SelectInputTrigger(HALL_TIMx, TIM_TS_TI1F_ED);
    	
    	//从模式选择:复位模式
    	TIM_SelectSlaveMode(HALL_TIMx, TIM_SlaveMode_Reset);
    	
    	//主从模式选择使能
    	TIM_SelectMasterSlaveMode(HALL_TIMx, TIM_MasterSlaveMode_Enable); 
    	
    	//输出比较通道2配置
    	TIM_OCInitTypeDef TIM_OCInitStruct;
    	TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM2;  //选择PWM模式2
            TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;  
    	TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
            TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;  //高电平有效  
    	TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High;
            TIM_OCInitStruct.TIM_OutputState = TIM_OutputNState_Disable;  //关闭,不用输出   
    	TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Disable;   
    	TIM_OCInitStruct.TIM_Pulse= 10;  //设置占空比
    	TIM_OC2Init(HALL_TIMx, &TIM_OCInitStruct);
    	
    	//选择TRGO触发源为OC2Ref
    	TIM_SelectOutputTrigger(HALL_TIMx,TIM_TRGOSource_OC2Ref);
    

    COM中断服务函数

    void TIM1_TRG_COM_IRQHandler(void)
    {
      if(TIM_GetITStatus(BLDC_TIMx, TIM_IT_COM) !=RESET)
      {      
          //检测霍尔状态,换相
          HALL_Position_commutate();  
          
          //清楚标志位
          TIM_ClearITPendingBit(BLDC_TIMx, TIM_IT_COM);
      }
    }
    

    TIM1初始化

    TIM1的初始化和前面文章中用输出六步PWM的初始化中,时基和输出比较通道初始化是一样的,加入COM事件配置,注意换相函数需要提前一相配置。

    	//输入触发源选择,选择定时器3,这里可以试下,如果选择错误,TIM1是不会由PWM输出的,进而验证
            TIM_SelectInputTrigger(BLDC_TIMx,TIM_TS_ITR2);  
    
    	//从模式,选择复位模式
    	TIM_SelectSlaveMode(BLDC_TIMx, TIM_SlaveMode_Reset); 
    	
            //COM事件配置
            /*配置ccxe,ccxne,ocxm是预装载的,只有com事件产生才更新,这个预装载和CCRX值的预装载不同,CCRX预装载由
            TIM_OC1PreloadConfig 配置,配置的寄存器不同*/
    	TIM_CCPreloadControl(BLDC_TIMx, ENABLE); 
    
    	//使能com事件
            TIM_SelectCOM(BLDC_TIMx, ENABLE);  
    	
    	//中断优先级配置
    	NVIC_InitStruct.NVIC_IRQChannel = TIM1_TRG_COM_IRQn;
    	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
    	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
    	NVIC_Init(&NVIC_InitStruct);
    	TIM_ITConfig(BLDC_TIMx, TIM_IT_COM ,ENABLE);
    	TIM_ClearITPendingBit( BLDC_TIMx, TIM_IT_COM);
    

    然后在COM中断中检测霍尔相位,进行换相。

    启动函数

    启动的时候由于没有霍尔状态改变来触发,需要软件触发COM事件。

    void BLDC_Start(void)
    {
            TIM_SetCompare1(BLDC_TIMx,0);
    	TIM_SetCompare2(BLDC_TIMx,0);
    	TIM_SetCompare3(BLDC_TIMx,0);
    	TIM_CCxCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCx_Enable);
    	TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_1,TIM_CCxN_Enable);
    	TIM_CCxCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCx_Enable);
    	TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_2,TIM_CCxN_Enable);
    	TIM_CCxCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCx_Enable);
    	TIM_CCxNCmd(BLDC_TIMx,TIM_Channel_3,TIM_CCxN_Enable);
    	TIM_GenerateEvent(BLDC_TIMx, TIM_EventSource_COM);  //软件触发COM事件生效配置
    	TIM_ClearFlag(BLDC_TIMx, TIM_FLAG_COM);
    	
    	Delay_nms(5);  //等待boost电容充电完成,大于大概4-5个电容充电时间常数即可
    	
            HALL_Position_commutate();  //检测霍尔状态,换相
            TIM_GenerateEvent(BLDC_TIMx, TIM_EventSource_COM);  
    	TIM_ClearFlag(BLDC_TIMx, TIM_FLAG_COM);
    }
    
  • 相关阅读:
    python相关遗漏知识点补充
    关于viewpager的滑动问题
    C++学习一二
    Neo4j 爬坑笔记for3.2.6
    ZTree简单粗暴快速使用
    阅读HashMap——jdk7时遇到的问题记录
    【安装】Hadoop2.8.0搭建过程整理版
    html、jsp页面标签的遍历
    tomcat配置多个数据源
    java线程
  • 原文地址:https://www.cnblogs.com/ckk-blog/p/14015327.html
Copyright © 2011-2022 走看看