? ? ? ? 之前有些網友試著用有刷的平均電流法采集三相,還搞了個閉環控制。求!結果直接把驅動板給干沒了......
? ? ? ? 做過仿真的朋友們都知道,無刷電機的相電流波形是介于方波和正弦波的。如果拿平均電流去測量,很不靠譜。
? ? ? ? 這節內容為大家分享采集三相模擬量的通用配置思路。
? ? ? ? 一、CubeMX的ADC初始化
? ? ? ? 使能三個ADC通道,分別傳輸UVW線電流(Y型下等于相電流)
????????????????
????????四分頻表示APB2總線/4,也就是說ADC頻率為72Mhz/4 = 18Mhz 這是我們F1下ADC的基礎頻率。若用F407系列請自行計算。
????????12倍原始采樣率、右對齊、掃描轉換模式開、EOC選擇順序轉換、連續轉換模式開、DMA連續請求開、常規采樣開、
????????cycle轉換通道量為2.5/3(因型號不同),我這里設置的是2.5cycles,表示2.5個ADC基礎周期采集一次rank1,由此我們可推算出各個通道的采樣頻率。
????????接著設置所有rank對應的通道(1,2,3)、采樣周期為3個循環? ? ?
????????(ARM架構上絕大部分三相采集都如此配置,可以記住,原因比較難解釋)
? ? ? ? ? ?接著配置DMA, 雖然最終數據寄存器float是32位,但是我們用的是12位采樣,DMA寄存器是uint16_t的,一次讀兩個字節剛合適,不要把概念搞混淆了。
? ? ? ? ? ?
? ? ? ? ? 二、ADC的DMA中斷處理邏輯
uint16_t g_adc_firstave_result[3];
//一次均值結果寄存//一次均值函數
int32_t ADC_GetSampleAvgN(int16_t *Data)
{uint32_t temp[ADC_CH_NUM] = {0,0,0}; //初始化結果寄存器int i,j; //ij計數變量for(i=0;i<ADC_COLL;i++) //COLL為每個ADC通道的DMA容量{ //在順序DMA采集中 DMA寄存器的內容結構為 RANK1數據 RANK2數據 RANK3數據......以此類推 for(j=0;j<ADC_CH_NUM;j++) { //NUM為參與順序DMA的總通道數temp[j] += ADC_ConvValueHex[j+i*ADC_CH_NUM];//temp也按rank排序,把DMA寄存器中,每個獨立通道的數據累加}}for(j=0;j<ADC_CH_NUM;j++){//對每個獨立通道的累加值求均值temp[j] /= ADC_COLL;//把中間變量值傳給最終結果Data[j] = temp[j]; }
}void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{int32_t ADConv = 0 ; //停止DMA,保證數據時序完整性HAL_ADC_Stop_DMA(hadc);//進行一次濾波,并獲取數據 ADC_GetSampleAvgN((int16_t*)g_adc_firstave_result);//重新讓DMA工作HAL_ADC_Start_DMA(hadc,(uint32_t*)ADC_ConvValueHex, ADC_CH_NUM * ADC_COLL);
}
?????????三、定時器中斷處理邏輯
if(timeTickCurrent != 0)timeTickCurrent--;else {if(Motor_State==MOTOR_ENABLE){
//當電機運行時,讀取實際的電流(相電流+偏置電流)for(uint8_t i=0; i<3; i++){adc_val_m1[i] = g_adc_firstave_result[i]; adc_amp[i] = adc_val_m1[i] - adc_amp_offset[i][ADC_AMP_OFFSET_TIMES];if(adc_amp[i] >= 0) adc_amp_un[i] = adc_amp[i]; }
//U相電流
current[0] = ((float)(adc_amp_un[0] * VOLT_RESOLUTION)- 1650.0f)/4020.0f/SM_REST;
//V相電流
current[1] = ((float)(adc_amp_un[1] * VOLT_RESOLUTION)- 1650.0f)/4020.0f/SM_REST;
//Z相電流
current[2] = ((float)(adc_amp_un[2] * VOLT_RESOLUTION)- 1650.0f)/4020.0f/SM_REST;/*W*/Vofa_data(current[0],VOFA_CHANNEL1);
Vofa_data(current[1],VOFA_CHANNEL2);
Vofa_data(current[2],VOFA_CHANNEL3);//上傳到上位機//一節低通濾波暫時不用// current[0] = ((float)(1-FILTER_Q_CURRENT) * LS_Speed_hz) + (FILTER_Q_CURRENT * Speed_hz) ;
// current[1]= ((float)(1-FILTER_Q_CURRENT) * LS_Speed_hz) + (FILTER_Q_CURRENT * Speed_hz) ;
// current[2]= ((float)(1-FILTER_Q_CURRENT) * LS_Speed_hz) + (FILTER_Q_CURRENT * Speed_hz) ;}
if(Motor_State==MOTOR_DISABLE){//當電機停止的時候uint8_t i;//三個均值變量,用于寄存UVW三相的偏置電壓uint32_t avg[3] = {0,0,0};//這里直接用了二維數組存放偏置量//結構為 通道1p1 通道1p2 通道1p3 ... 通道1pn//通道2p1 通道2p2 通道2p3 ... 通道2pn//以此類推adc_amp_offset[0][adc_amp_offset_p] = g_adc_firstave_result[0]; adc_amp_offset[1][adc_amp_offset_p] = g_adc_firstave_result[1];adc_amp_offset[2][adc_amp_offset_p] = g_adc_firstave_result[2];adc_amp_offset_p++;//若數據采集滿,進行二次均值濾波if(adc_amp_offset_p >= ADC_AMP_OFFSET_TIMES){adc_amp_offset_p = 0;}//進行均值累加 for(i = 0; i < ADC_AMP_OFFSET_TIMES; i++) {avg[0] += adc_amp_offset[0][i];avg[1] += adc_amp_offset[1][i];avg[2] += adc_amp_offset[2][i];}//進行平均并把數據重新傳回offset最后一列,作為標準偏置for(i = 0; i < 3; i++) {avg[i] /= ADC_AMP_OFFSET_TIMES;adc_amp_offset[i][ADC_AMP_OFFSET_TIMES] = avg[i]; }}//我這里的偏置采集量設置的是50次,而采集一次相電流所需時間大概在1.5ms左右,所以在電機啟動前需要一個至少大于75ms的delaytimeTickCurrent = TIMECNT_CURRENT;}
????????四、相電流開環圖像
? ? ? ? 此時測量的是平均相電流圖像,與仿真時的實時圖像有所區別,一般不會有周期性的0出現,如果出現了,就得考慮以下采樣頻率是不是取的過大。
? ? ? ? 在實際工程中,最常用的是平均電流做控制。在高精度場景下,也有用實時電流做控制的,但其相應的控制器響應要求更高,經典控制算法無法達到這種需求。
? ? ? ? 其次,查看你的三相電流是不是滿足波峰交替的,如果重合成了一條線,那你的DMA配置及處理過程必然有錯誤。
????????