基于STM32F4实现FOC(磁场定向控制)一:电流采样和波形产生

2023-05-16

一.ADC的配置问题

1.GPIO初始化配置
开始ADC对应的GPIO口,本驱动程序使用到五个GPIO,分别对应U V W三相电流及母线电压和温度采样,统一配置为模拟输入。
GPIO的配置代码如下:

	
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA |RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB| RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOE, ENABLE);	  /* Enable GPIOA, GPIOC, GPIOE,GPIOD, AFIO clocks */ 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);		//84Mhz																							/* Enable ADC1 clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); 		//84																			/* Enable ADC2 clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);		//高级定时器 168MHz																						/* Enable TIM1 clock */

	//GPIO初始化
	//.ADC的GPIO
	GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC1_GPIO_PIN1 | RHEOSTAT_ADC1_GPIO_PIN2| RHEOSTAT_ADC1_GPIO_PIN3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(RHEOSTAT_ADC1_UVWGPIO_PORT, &GPIO_InitStructure);
	
	GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC1_GPIO_PIN4 |RHEOSTAT_ADC1_GPIO_PIN5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(RHEOSTAT_ADC_TEMPVOLTGPIO_PORT, &GPIO_InitStructure);
	

2.ADC初始化配置

  1. ADC1和ADC2配置:配置为同步注入模式,设置分频值,关闭DMA。

  2. 为了在电机开始运行前采集到的当前的零飘电流,需要先进行可以采集零飘电流的ADC配置,配置如下: ADC1和ADC2采用相同的配置。 关闭扫描模式 关闭边沿触发 关闭连续转换 数据左对齐 数据设置为12位

  3. 在进行完配置之后如果立即开始采集零漂电流,会出现采样值为0的情况,解决方法时设置微小延时,等待内部校准。

  4. 开始零漂电流的采集:使用ADC1来采集三相电流,先关闭注入通道转换结束中断,防止在采集到零漂电流后进入ADC中断,开始FOC计算。关闭中断后关闭ADC的边沿触发,防止在采集过程中收到别的触发信号。设置ADC1的注入通道的采样对象和周期,开始采集。

    零漂电流:零点漂移(零漂)是直接耦合放大电路中存在的一个特殊问题。所谓零点漂移的是指放大电路在没有输入信号时,用灵敏的直流表测量输出端,也会有变化缓慢的输出电压产生,称为零点漂移现象。零点漂移的信号会在各级放大的电路间传递,经过多级放大后,在输出端成为较大的信号,如果有用信号较弱,存在零点漂移现象的直接耦合放大电路中,漂移电压和有效信号电压会混杂在一起被逐级放大,当漂移电压大小可以和有效信号电压相比时,是很难在输出端分辨出有效信号的电压;在漂移现象严重的情况下,往往会使有效信号“淹没”,使放大电路不能正常工作。

  5. 电机运行状态的电流采集:将ADC1和2配置为运行状态所需要的模式,即ADC1和ADC2的注入通道1分别采集A相电流和B相电流,并在运行中动态调整;通道2分别采集母线电压和温度。同时将触发条件设置为定时器的更新触发,等待电机启动。电机启动后,将触发条件设置为定时器的输出捕获触发,使用定时器1(产生pwm波的定时器)的闲置通道配置为pwm模式,同步定时器产生的pwm波,在合适的点触发ADC。

ADC的配置代码如下:

 ADC_DeInit();
 
	
  /* ADC1 configuration ------------------------------------------------------*/
	ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_InjecSimult;
	ADC_CommonInitStructure.ADC_Prescaler =  ADC_Prescaler_Div6 ;
	ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled ;
	ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; //不起作用
	ADC_CommonInit(&ADC_CommonInitStructure);
  ADC_StructInit(&ADC_InitStructure);
	
	
	
																		//注入同步模式    主ADC
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
	ADC_InitStructure.ADC_ExternalTrigConvEdge= ADC_ExternalTrigConvEdge_None;               //关闭外部边沿触发
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;																			//连续转换关闭
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T8_CC1;										//不起作用
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;																		//数据左对齐
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
	ADC_InitStructure.ADC_NbrOfConversion = 1	;																						
  ADC_Init(RHEOSTAT_ADC1, &ADC_InitStructure);
	
  /* ADC2 Configuration ------------------------------------------------------*/
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;
	ADC_InitStructure.ADC_ExternalTrigConvEdge= ADC_ExternalTrigConvEdge_None;               //关闭外部边沿触发
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;																			//连续转换关闭
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T8_CC1;										//不起作用
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;																		//数据左对齐
	ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
	ADC_InitStructure.ADC_NbrOfConversion = 1	;																																														
  ADC_Init(RHEOSTAT_ADC2, &ADC_InitStructure);
	
  ADC_Cmd(RHEOSTAT_ADC1, ENABLE);
  ADC_Cmd(RHEOSTAT_ADC2, ENABLE);
	
   while(WaitForAD != 0  )		//计时结束
   {
			WaitForAD--;
   } 


	//读取零电流偏移值    由于没有产生PWM波              在此情况下读取零电流值
 SVPWM_3ShuntCurrentReadingCalibration();
	
  /* ADC2 Injected conversions configuration */  																					
  ADC_InjectedSequencerLengthConfig(RHEOSTAT_ADC2,2);																								//ADC2的注入通道序列长度配置为2
	
  ADC_InjectedChannelConfig(RHEOSTAT_ADC2, PHASE_A_ADC_CHANNEL, 1, SAMPLING_TIME_CK);								//A相        ADC通道6    
  ADC_InjectedChannelConfig(RHEOSTAT_ADC2, TEMP_FDBK_CHANNEL,   2, SAMPLING_TIME_CK);								//温度反馈   ADC通道9     
	
	//中断优先级配置
	//AD转换中断配置
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);																						//配置优先级小组  4个抢占优先级 4个子优先级
  NVIC_InitStructure.NVIC_IRQChannel = Rheostat_ADC_IRQ;//ADC1和ADC2 注入中断							//1和2的中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ADC_PRE_EMPTION_PRIORITY;					//1			
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = ADC_SUB_PRIORITY;													//0  
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
  
  //定时器1更新中断

  NVIC_InitStructure.NVIC_IRQChannel =  Rheostat_TIM_IRQ ;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = TIM1_UP_PRE_EMPTION_PRIORITY;			//1
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = TIM1_UP_SUB_PRIORITY;											//0
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;																			
  NVIC_Init(&NVIC_InitStructure);
}

//读取零电流偏移值

void SVPWM_3ShuntCurrentReadingCalibration(void)
{
	static u16 bIndex;
	
  hPhaseAOffset=0;				//三相的偏执电流
  hPhaseBOffset=0;
  hPhaseCOffset=0;
static u8 FourAvg = 0;
	ATemp = 0;
	BTemp = 0;
	CTemp = 0;
   while(WaitForAD != 0  )		//计时结束
   {
			WaitForAD--;
   } 
	
  /* ADC1 Injected group of conversions end interrupt disabling */
  ADC_ITConfig(RHEOSTAT_ADC1, ADC_IT_JEOC, DISABLE);															//禁止ADC1的注入通道转换结束中断 
	

	ADC_ExternalTrigInjectedConvEdgeConfig(ADC1, ADC_ExternalTrigInjecConvEdge_None);
//  ADC1->CR2 = ADC1->CR2 |= 0x300000;
//	ADC_ExternalTrigInjectedConvEdgeConfig(RHEOSTAT_ADC1,ADC_ExternalTrigInjecConvEdge_RisingFalling); //上升沿触发	
	
  ADC_InjectedSequencerLengthConfig(RHEOSTAT_ADC1,3);                             //ADC1的注入序列长度配置为3
  ADC_InjectedChannelConfig(ADC1, PHASE_A_ADC_CHANNEL,1,SAMPLING_TIME_CK);				//配置ADC1的注入通道的采样对象及优先级和周期
  ADC_InjectedChannelConfig(ADC1, PHASE_B_ADC_CHANNEL,2,SAMPLING_TIME_CK);
  ADC_InjectedChannelConfig(ADC1, PHASE_C_ADC_CHANNEL,3,SAMPLING_TIME_CK); 
	
	
	
  ADC_ClearFlag(RHEOSTAT_ADC1, ADC_FLAG_JEOC);  																	//清除ADC1的注入通道转换结束位

 
		 
	ADC_SoftwareStartInjectedConv(RHEOSTAT_ADC1);	
for(FourAvg = 0;FourAvg < AvgCurNum;FourAvg ++)
	{


  for(bIndex=0; bIndex <NB_CONVERSIONS; bIndex++)													//得到地电压    转换16次求和
  {													
  while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_JEOC)) {}											//等待转换结束

	ATemp += (ADC_GetInjectedConversionValue(RHEOSTAT_ADC1,ADC_InjectedChannel_1)>>3);												//获取ADC1的注入通道1 2 3的值  对应上面的 PHASE_A_ADC_CHANNEL.....
  BTemp	+= (ADC_GetInjectedConversionValue(RHEOSTAT_ADC1,ADC_InjectedChannel_2)>>3);												//注入组数据采用左对齐,需要右移三位才是真实数据
  CTemp += (ADC_GetInjectedConversionValue(RHEOSTAT_ADC1,ADC_InjectedChannel_3)>>3); 	
		
	ADC_ClearFlag(RHEOSTAT_ADC1, ADC_FLAG_JEOC);  											
  ADC_SoftwareStartInjectedConv(RHEOSTAT_ADC1);		
  }	

}
	

	hPhaseAOffset = (u16)(ATemp/AvgCurNum);
	hPhaseBOffset = (u16)(BTemp/AvgCurNum);
	hPhaseCOffset =	(u16)(CTemp/AvgCurNum);
  SVPWM_InjectedConvConfig();  																						//配置ADC1采样
	

}


//此功能在对使用的三个ADC通道进行校准后,将ADC1配置为电流读取和温度电压反馈
void SVPWM_InjectedConvConfig(void)
{

  /* ADC1 Injected conversions configuration */ 
  ADC_InjectedSequencerLengthConfig(RHEOSTAT_ADC1,2);
	ADC_InjectedSequencerLengthConfig(RHEOSTAT_ADC2,2);
	
  ADC_InjectedChannelConfig(RHEOSTAT_ADC1, PHASE_B_ADC_CHANNEL, 1,  SAMPLING_TIME_CK);      //配置ADC1采样B相电流的通道 优先级及周期		IB  PA4
  ADC_InjectedChannelConfig(RHEOSTAT_ADC1, BUS_VOLT_FDBK_CHANNEL, 2, SAMPLING_TIME_CK);		 	//配置母线电压的采样优先级及周期						BUS VOLT PB0
	

  /* ADC1 Injected conversions trigger is TIM1 TRGO */ 

  ADC_ExternalTrigInjectedConvConfig(RHEOSTAT_ADC1,ADC_ExternalTrigInjecConv_T1_TRGO); //trgo 触发 Trgo 是什么      //定时器1的触发信号作为启动注入通道组转换的外部事件   定时器1的updatae
	ADC_ExternalTrigInjectedConvEdgeConfig(RHEOSTAT_ADC1,ADC_ExternalTrigInjecConvEdge_Falling); //上升沿触发																																																			//与上面对应

	
  ADC_ITConfig(RHEOSTAT_ADC1, ADC_IT_JEOC | ADC_IT_AWD, ENABLE);	
	//使能ADC1的模拟看门狗中断,并开启扫描模式
	//使能ADC1的注入通道转换结束中断 并开启规则通道组转换结束后自动的注入通道转换
}		

3.运行状态下的ADC
在运行状态下,ADC1和ADC2注入通道1的采集对象在不同的扇区会有不同的配置。这是由于三相采样电阻在驱动电路的下桥臂导通时才有电流,为保证能采集的电流,只找导通时间最长的两相,剩余的一相根据基尔霍夫电流定律计算。根据PWM波图像,在第四和第五扇区,采集A相和B相电流;在第一和第六扇区,采集C相和B相电流;在第二和第三扇区,采集A相和C相电流。
电流获取代码如下:

//更新电流
Curr_Components SVPWM_3ShuntGetPhaseCurrentValues(void)
{
	
  Curr_Components Local_Stator_Currents;
	Curr_Components new_value;
	Curr_Components result;
  s32 wAux;
	u8 count;
	s32 sum1 = 0;
	s32 sum2 = 0;
	int i,j,temp;
	

//	printf("bSector = %d\r\n",bSector);
  switch (bSector)
   {
		 //只有在下桥臂导通的时候才能检测电流,选择下桥臂导通时间长的相去检测电流   4 5扇区时 A B相的下桥臂导通时间长  C相导通时间短  不检测C相 
   case 4: 														
   case 5: //Current on Phase C not accessible     												//C相电流不可获得
            wAux = (s32)(hPhaseAOffset)- ((ADC1->JDR1)<<1); 							//JDR1左移一位表示真实的Q15格式的AD转换值, A相   数据左对齐2^15,为了变成Q15格式,再乘2^15,即左移一位
//	 printf("hPhaseAOffset = %d\r\n",hPhaseAOffset);
           //Saturation of Ia 					
            if (wAux < S16_MIN)	
            {					
              Local_Stator_Currents.qI_Component1= S16_MIN;								//AD转换的下限
            }  					
            else  if (wAux > S16_MAX)
                  { 
                    Local_Stator_Currents.qI_Component1= S16_MAX;  				//AD转换的上限
                  }
                  else
                  {
                    Local_Stator_Currents.qI_Component1= wAux;						//转换值即不大于上限 也不小于下限  则直接赋值
									}
                     
        
            wAux = (s32)(hPhaseBOffset)-((ADC2->JDR1)<<1);								//偏执电流-采样值                B相
           // Saturation of Ib
            if (wAux < S16_MIN)
            {
              Local_Stator_Currents.qI_Component2= S16_MIN;
            }  
            else  if (wAux > S16_MAX)                                    /S16_MAX 被修改了 
                  { 
                    Local_Stator_Currents.qI_Component2= S16_MAX;
                  }
                  else
                  {
                    Local_Stator_Currents.qI_Component2= wAux;
                  }
           break;
           
   case 6:																																		
   case 1:  
//printf("hPhaseAOffset = %d\r\n",hPhaseAOffset);
            wAux = (s32)(hPhaseBOffset)-((ADC1->JDR1)<<1);                  //B相
            //Saturation of Ib 
            if (wAux < S16_MIN)
            {
              Local_Stator_Currents.qI_Component2= S16_MIN;
            }  
            else  if (wAux > S16_MAX)
                  { 
                    Local_Stator_Currents.qI_Component2= S16_MAX;
                  }
                  else
                  {
                    Local_Stator_Currents.qI_Component2= wAux;
                  }
            // Ia = -Ic -Ib 
            wAux = ((ADC2->JDR1)<<1)-hPhaseCOffset-Local_Stator_Currents.qI_Component2;
            //Saturation of Ia
            if (wAux> S16_MAX)
            {
               Local_Stator_Currents.qI_Component1 = S16_MAX;
            }
            else  if (wAux <S16_MIN)
                  {
                   Local_Stator_Currents.qI_Component1 = S16_MIN;
                  }
                  else
                  {  
                    Local_Stator_Currents.qI_Component1 = wAux;
                  }
           break;
           
   case 2:
   case 3:  // Current on Phase B not accessible
//printf("hPhaseAOffset = %d\r\n",hPhaseAOffset);
            wAux = (s32)(hPhaseAOffset)-((ADC1->JDR1)<<1);
            //Saturation of Ia 
            if (wAux < S16_MIN)
            {
              Local_Stator_Currents.qI_Component1= S16_MIN;
            }  
            else  if (wAux > S16_MAX)
                  { 
                    Local_Stator_Currents.qI_Component1= S16_MAX;
                  }
                  else
                  {
                    Local_Stator_Currents.qI_Component1= wAux;
                  }
     
            // Ib = -Ic-Ia;
            wAux = ((ADC2->JDR1)<<1) - hPhaseCOffset -   Local_Stator_Currents.qI_Component1;
            // Saturation of Ib
            if (wAux> S16_MAX)
            {
              Local_Stator_Currents.qI_Component2=S16_MAX;
            }
            else  if (wAux <S16_MIN)
                  {  
                    Local_Stator_Currents.qI_Component2 = S16_MIN;
                  }
                  else  
                  {
                    Local_Stator_Currents.qI_Component2 = wAux;
                  }                     
           break;

   default:
           break;
   } 
    return(Local_Stator_Currents); //返回采样电流
    }

二.定时器的配置问题

配置能够产生6路pwm波的定时器,改变定时器的占空比即可控制电机转速或转矩。
1.GPIO初始化配置
需要一个能够产生6路PWM波的高级定时器,定时器1或定时器8,对应6个GPIO口,同时需要一个刹车GPIO,共计需要7个GPIO。配置为复用推挽模式。
代码如下:

GPIO_StructInit(&GPIO_InitStructure);	
  GPIO_InitStructure.GPIO_Pin = RHEOSTAT_TIM1_GPIO_PIN1 | RHEOSTAT_TIM1_GPIO_PIN2 | RHEOSTAT_TIM1_GPIO_PIN3  ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(RHEOSTAT_TIM1_GPIO_PORT, &GPIO_InitStructure); 


  //TIM1N
  GPIO_InitStructure.GPIO_Pin =  RHEOSTAT_TIM1N_GPIO_PIN1 | RHEOSTAT_TIM1N_GPIO_PIN2 | RHEOSTAT_TIM1N_GPIO_PIN3;
  GPIO_Init(RHEOSTAT_TIM1N_GPIO_PORT, &GPIO_InitStructure); 

2.定时器的初始化配置
定时器的初始化代码如下:

	
	//定时器初始化
  TIM_DeInit(TIM1);
  TIM_TimeBaseStructInit(&TIM1_TimeBaseStructure);
  TIM1_TimeBaseStructure.TIM_Prescaler = PWM_PRSC;						//1																						
  TIM1_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;      
  TIM1_TimeBaseStructure.TIM_Period = PWM_PERIOD;		//PWM_PERIOD					 ARR  顶点值		2500						
  TIM1_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV2;    //和死区时间计算有关
  TIM1_TimeBaseStructure.TIM_RepetitionCounter = REP_RATE;											//溢出2次触发中断
  TIM_TimeBaseInit(TIM1, &TIM1_TimeBaseStructure);

3.输出捕获模式的配置
定时器的四个通道都配置为中央对齐模式
代码如下:

//配置TIM的PWM输出
  TIM_OCStructInit(&TIM1_OCInitStructure);
  TIM1_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; 														//PWM1             向上计数时cnt<crr有效
  TIM1_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
  TIM1_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;                  
  TIM1_OCInitStructure.TIM_Pulse = 0x505; 												//crr	
  TIM1_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; 										//通道低电平有效
  TIM1_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;         					//互补通道低电平有效
  TIM1_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;									//设置输出空闲状态
  TIM1_OCInitStructure.TIM_OCNIdleState = LOW_SIDE_POLARITY;          					//reset
  
  TIM_OC1Init(TIM1, &TIM1_OCInitStructure); 																		//配置通道1
  TIM_OC2Init(TIM1, &TIM1_OCInitStructure);																			//配置通道2
  TIM_OC3Init(TIM1, &TIM1_OCInitStructure);																			//配置通道3
  GPIO_StructInit(&GPIO_InitStructure);
	
  TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
  TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
  TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
	
	//TIM1通道4的PWM配置
  TIM_OCStructInit(&TIM1_OCInitStructure);
  TIM1_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;  
  TIM1_OCInitStructure.TIM_OutputState = 	TIM_OutputState_Enable;             //使能主通道
  TIM1_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;                  
  TIM1_OCInitStructure.TIM_Pulse = PWM_PERIOD-1;  //   												// 在PWM波的正中间采样
  TIM1_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 									//主通道高电平有效	
  TIM1_OCInitStructure.TIM_OCNPolarity =TIM_OCNPolarity_Low;         					//互补通道低电平有效   没有用 互补通道关闭
  TIM1_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;								//主通道输出空闲状态
  TIM1_OCInitStructure.TIM_OCNIdleState = LOW_SIDE_POLARITY;            			//互补通道输出空闲状态
  TIM_OC4Init(TIM1, &TIM1_OCInitStructure);
  
  TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);

4.刹车和死区配置
刹车可以通俗的理解为停止产生PWM波,当改变刹车位的电平时,会启动或停止PWM的产生。
死区是为了保证mos开关电路不在同一时刻导通,烧毁电路。
代码如下:


	//刹车和死区配置
  TIM1_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;							//当定时器不工作时,一旦CCxE=1或CCxNE = 1(即主通道捕获比较或互补捕获比较通道使能),首次开启OC/OCN并输出无效电平,然后置OC/OCN使能输出信号=1
	TIM1_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;							//当定时器不工作时,一旦主通道或互补通道使能,OC/OCN首先输出其空闲电平,然后OC/OCN使能输出信号=1					
  TIM1_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; 									//锁定级别1,不能写入TIMx_BDTR寄存器的DTG、BKE、BKP、AOE、和TIMx_CR2寄存器的OISx/OISxN位	
  TIM1_BDTRInitStructure.TIM_DeadTime = DEADTIME;														//死区   4
  TIM1_BDTRInitStructure.TIM_Break = TIM_Break_Disable;											//刹车功能使能
  TIM1_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low;         //刹车输入低电平有效
  TIM1_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;	//关闭自动输出  只能由软件置1
  TIM_BDTRConfig(TIM1, &TIM1_BDTRInitStructure);

//设置更新事件为TIM1的TRGO 设置ADC触发为TIM1的TRGO时,即使用TIM1的更新作为触发
	TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);                     //选择定时器1的更新事件被选为触发输入(TRGO)  定时器1位主模式	
 
	TIM_ClearITPendingBit(TIM1, TIM_IT_Break);																//清除刹车中断标记位
  TIM_ITConfig(TIM1, TIM_IT_Break,ENABLE);																	//使能刹车中断
  

	TIM_Cmd(TIM1, ENABLE);																										//使能定时器1	
		
  // Resynch to have the Update evend during Undeflow
  TIM_GenerateEvent(TIM1, TIM_EventSource_Update);		//重新初始化计数器,并产生一个更新事件,注意预分频器的计数器也被清0(但是预分频系数不变!若在中心对称模式下
	//或向上计数则计数器被清0,若向下计数则取TIMx_ARR的值。


		//Clear Update Flag
    TIM_ClearFlag(TIM1, TIM_FLAG_Update);																		//清除中断标志位
		TIM_ITConfig(TIM1, TIM_IT_Update, DISABLE);															//关闭更新中断   
	  TIM_ITConfig(TIM1, TIM_IT_CC4,DISABLE);																	//关闭捕获/比较中断

获取源码:公众号【程序员DeRozan】回复1207

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

基于STM32F4实现FOC(磁场定向控制)一:电流采样和波形产生 的相关文章

  • 4g dtu透传模块

    4g dtu透传模块 xff0c 是一款支持双向透明传输的产品 xff0c 用户使用无需关心复杂的协议 xff0c 产品为双向透传 xff0c 只需要简单配置即可 同时产品为4G全网通 xff0c 支持国内全部运营商网络 xff0c 通讯模
  • PCB设计学习笔记(一)原理图界面

    一 画原理图库 多个引脚可以ctrl 43 c一个引脚后 xff0c 编辑 gt 设置粘贴阵列 xff0c 一次性复制出来多个引脚 二 原理图界面 生成原理图库 xff1a 在一个现成的原理图界面可以直接将现有的原理图内的原件生成一个原理图
  • novatel计算odom--GPS坐标与UTM坐标转换

    保证你的novatel的driver是在ros drivers上的驱动 1 简介 1 1 消息 gps common定义了两个通用消息 xff0c 供GPS驱动程序输出 xff1a gps common GPSFix和gps common
  • 搭建自己的slam系统

    手头有的传感器 一个vlp16线激光雷达 一个120 的fisheye相机 一整套novatel GPS 43 IMU 采集了一个闭环的bag 第一步 数据预处理 将camera的数据单独提取出来 因为没有时间戳 因此无法做到传感器的紧耦合
  • KCF_ROS + TLD_ROS 原理以及源码分析

    扩展链接 xff1a 百度搜素vot2016 xff0c 会有相关的资料 KCF缺点是有边界效应 有一个改进的版本是 xff1a SRDCF 大牛的 CSDN博客 说明 xff1a http blog csdn net app 120620
  • 数据结构+算法=程序

    xff08 1 xff09 数据结构 43 算法 61 程序 每个学计算机的人都听过这个公式 这个公式是尼克劳斯沃斯在1976年出版 算法 43 数据结构 xff1a 程序 一书中提出 尼克劳斯沃斯还是Pascal编程语言的发明人 xff0
  • librealsense源码编译-- Failed to identify Internet connection, disabling BUILD_WITH_TM2

    问题概述 xff1a 由于Realsense t265源码编译需要在CMakeList txt中将BUILD WITH TM2设置为ON xff0c 但是由于国内网络原因 xff0c 无法通过网络连接检测 xff0c 因此我通过查找文件 x
  • 内外网映射环境配置

    一 环境搭建 1 环境说明 此环境由内 外网组成 xff0c 主要实现内外网映射功能 2 环境配置图 本手册中 xff0c 内网使用78 网段 xff0c 外网使用 20 网段 外网交换机IP 地址为 192 168 20 1 3 配置路由
  • 浅析extern “C”的作用

    浅析extern C 的作用 关于extern C 的作用和意思 xff0c 网上资料已经有很多了 xff08 我也参考了几篇 xff09 xff0c 不过我还是觉得有必要自己总结一下 xff0c 毕竟 好记性不如烂笔头 嘛 到C标准函数库
  • 使用prometheus+grafana监控k8s集群

    Prometheus官网地址 xff1a https prometheus io GitHub地址 xff1a https github com prometheus prometheus 一 prometheus的安装 Prometheu
  • ARM 学习笔记(四) 快速上下文切换(FCSE)技术

    接上回说 xff0c 我们已经了解存储器管理的方法 xff0c 现在我们来看一下 xff0c ARM 对不同进程的地址管理 快速上下文切换技术 xff08 Fast Context Switch Extension FCSE xff09 F
  • Linux与Windows串口通信

    串口是常用的计算机与外部串行设备之间的数据传输通道 xff0c 由于串行通信方便易行 xff0c 所以应用广泛 现在国际上不断有串口新技术及新规格推出 xff0c 结合社会各方面需要 xff0c 串口通信发展的空间庞大 串口通讯技术因其自身
  • Git代码下载以及子模块更新git submodule update --init

    Git代码下载 加速代码下载 xff1a git clone https ghproxy com https github com 加入https ghproxy com 后下载速度会快很多 xff0c 还是由于科学上网的问题 子模块下载
  • 解决UnicodeEncodeError: 'gbk' codec can't encode character '\xbb' in position

    在抓取网页上面的一些源代码的时候 xff0c 将uft 8的编码写入文档 xff0c 并输出的时候 xff0c 出现这了这个报错 xff0c 说gbk无法编码 xbb 查找相关资料 xff1a 1 str转bytes叫encode xff0
  • FIFO(First-In First-Out)先进先出页面置换算法详解

    FIFO xff08 First In First Out xff09 先进先出页面置换算法 xff1a FIFO淘汰算法总是淘汰最先装入内存的页面 xff0c 即选择在内存中驻留时间最久的页面进行淘汰 该算法实现只需把一个进程已调入内存的
  • 解决方法:git遇到过的错误

    用git也是走了很多弯路 比如 xff1a 这种错误 1 git commit a fatal Unable to create 39 E git index lock 39 File exists Another git process
  • 路径规划学习入门

    运动规划简介 当虚拟人开始一次漫游时 xff0c 首先全局规划器根据已有的长期信息进行全局静态规划 xff0c 确定虚拟人应该经过的最优化路线 然后全局规划器控制执行系统按照该路径运动 在运动过程中 xff0c 感知系统会持续对周围环境进行
  • 测试开发工程师面试题目

    测试开发工程师面试题目 1 什么是兼容性测试 兼容性测试侧重哪些方面 主要检验的是软件的可移植性 xff0c 检查软件在不同的硬件平台软件平台上是否可以正常的运行 细分会有 xff1a 平台的兼容 xff0c 网络兼容 xff0c 数据库兼
  • 【ROS2】四、使用tf坐标变换实现小海龟跟随

    1 创建功能包 创建工作空间并在工作空间下创建功能包 xff1a span class token function mkdir span p turtle tf ws src span class token builtin class
  • 滑模控制简单理解(hm-1)

    变结构控制 xff08 VSC xff09 是一种特殊的非线性控制器 xff0c 表现为控制的不连续性 xff0c 又称滑模控制 xff08 SMC xff09 一般步骤为滑模面的设计 趋近率的设计 控制器的求解 滑模控制的理解 如图所示

随机推荐

  • BP神经网络的数学本质

    原创文章 xff0c 转载请说明来自 老饼讲解 BP神经网络 xff1a bp bbbdata com 目录 一 隐神经元与tansig函数 二 BP本质 三 BP神经网络的曲线拟合要素 一 误差函数 二 拟合基函数 三 待解参数与求解算法
  • GAZEBO_PLUGIN_PATH 设置方法

    http answers gazebosim org question 13391 how to set gazebo plugin path correctly and add the plugin into gazebo ros Hi
  • Linux 0.11 系统调用的实现机制

    Linux 0 11 系统调用的实现机制 一 系统调用概述 系统调用本质上是一种中断 xff0c 中断号为0x80 xff0c 即128号中断 通常我们使用的是库函数 xff0c 而不是直接使用系统调用 xff0c 这主要是因为库函数一般都
  • 滤波算法及优缺点

    传感器比如关节力矩传感器采用滑动平均滤波算法 xff0c 滤波点数选1则为原始数据 xff0c 选点数100则采样100个求平均 点数越大滤波延迟越大 xff0c 越平滑 所以需要根据实际项目测试 在matlab中采用了三种滤波方法 xff
  • putty支持多标签,支持log每行加时间

    在现在的免费telnet 串口连接工具中 Tera Term 支持脚本ttl 且有每行时间记录 有一个不好的是个终端连接不友好 xff0c 也能用 xff0c 就是看起来不方便 xff0c 是一个外挂的补丁 putty 不支持多标签 不支持
  • Jetson xavier nx 入门系列—— jeston系列性能对比

    官方对比网址 xff1a https developer nvidia com embedded develop hardware family 算力对比 参考 xff1a https blog csdn net u013673476 ar
  • 在C语言中,字符串总是以‘\0‘作为结尾

    字符串结束标志 xff08 划重点 xff09 字符串是一系列连续的字符的组合 xff0c 要想在内存中定位一个字符串 xff0c 除了要知道它的开头 xff0c 还要知道它的结尾 找到字符串的开头很容易 xff0c 知道它的名字 xff0
  • cmake 学习笔记(一)

    最大的Qt4程序群 KDE4 采用cmake作为构建系统Qt4的python绑定 pyside 采用了cmake作为构建系统开源的图像处理库 opencv 采用cmake 作为构建系统 看来不学习一下cmake是不行了 xff0c 一点一点
  • 如何用github创建博客

    1 创建一个仓库 xff0c 设置名称为用户名 github io xff0c 不然会报404 2 在设置中找到github pages选项 xff0c 选择theme 3 将仓库使用github客户端克隆到本地 4 将克隆到本地仓库内容清
  • VS创建的aspx文件下没有设计-拆分-源 并且工具箱中的控件为灰色

    首先在视图中打开工具箱 这时是没有控件的 右键点击全部显示 但是仍然是灰色 没法使用 我的 Master文件夹里有设计 拆分 源 但是aspx文件里没有 解决方法
  • 【支线】输电杆塔识别-YOLO v5在Aidlux的部署

    目录 0 前言1 模型训练1 1 任务描述1 2 输电杆塔数据集采集1 3 输电杆塔数据集标注1 4 数据增强1 5 折腾1 6 训练1 7 测试 2 NX部署2 1 软硬件2 2 Tensor RT 优化推理2 3 ROS Topic发送
  • 程序员与厨师

    不管你信不信 反正我是信了 每一个程序员上辈子都是呆在厨房的厨子 好吧 你不信 我来证明给你看 1 下厨前 你得知道做的是早餐还是中晚餐 中晚餐的话 怎么也得走趟超市 如遇到好友聚会 怎么着也得做出一桌对得起朋友的饭菜 还有你得分析 朋友中
  • 用研扬科技的UP Square做软路由是不是杀鸡用牛刀啊?

    折腾了好几遍终于整踏实了 xff01
  • 炎炎夏日,看小Y重燃烈焰战火——Y450外接显卡

    xfeff xfeff 目录 前言 实际效果 预算VS结算 配件开箱 硬件连接 软件环境配置 xff08 重点 xff09 前言 我家小Y已经陪伴我4年多了 xff0c 四年里 xff0c 她带给我的欢乐是超值的 xff08 联保了4年多
  • 深度学习情感分类常用方法(综述)

    论文原文 xff1a Deep Learning for Sentiment Analysis A Survey 原文地址 xff1a https arxiv org ftp arxiv papers 1801 1801 07883 pdf
  • 嵌入式单片机之stm32串口你懂了多少!!

    stm32作为现在嵌入式物联网单片机行业中经常要用多的技术 xff0c 相信大家都有所接触 xff0c 今天这篇就给大家详细的分析下有关于stm32的出口 xff0c 还不是很清楚的朋友要注意看看了哦 xff0c 在最后还会为大家分享有些关
  • uC/OS-II 学习笔记之:消息邮箱

    更多原创 uC OS II学习笔记之 xff1a 系列 基础及嵌入式相关知识详解 xff0c 请访问可乐虎博客 xff1a http blog csdn net dcx1205 相信不会让您失望 xff01 xff01 一 消息邮箱的概念
  • uC/OS-II 学习笔记之:信号量、消息邮箱、消息队列之间的使用区别

    更多原创 uC OS II学习笔记之 xff1a 系列 基础及嵌入式相关知识详解 xff0c 请访问可乐虎博客 xff1a http blog csdn net dcx1205 相信不会让您失望 xff01 xff01 1 用信号量进行行为
  • Python3抓取糗百、不得姐、kanqu.com

    测试电脑配置有点低 xff0c 正常配置速度会比较快 有问题可以加群 xff1a 544471255 交流 使用必看 1 该代码使用Python3 6 43 版本 2 需要安装依赖库如下 可使用类似 pip install requests
  • 基于STM32F4实现FOC(磁场定向控制)一:电流采样和波形产生

    一 xff0e ADC的配置问题 1 GPIO初始化配置 开始ADC对应的GPIO口 xff0c 本驱动程序使用到五个GPIO xff0c 分别对应U V W三相电流及母线电压和温度采样 xff0c 统一配置为模拟输入 GPIO的配置代码如