日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32定时器编码器模式实现直流有刷电机测速(HAL库)

發布時間:2024/3/24 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32定时器编码器模式实现直流有刷电机测速(HAL库) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

最近在做一個單片機大作業,要用到直流有刷,在這里把學習編碼器的知識記錄一下,學習參考資料:

正點原子DMF407電機控制專題教程_V1.0

編碼器測速原理

我所使用的編碼器是市面上常見的磁電增量式編碼器,其有AB兩相,用于輸出電機轉動時的脈沖數,AB兩相的先后順序決定了電機的轉動方向

這其實就是單片機的外部計數器模式,51中也帶有同樣的功能

信號從通道被采樣后的處理過程如下

編碼器的計數接口是利用脈沖的邊沿來計數的,我們知道AB兩相都有脈沖且相位差為90度,那么一次檢測最多可以得到四個邊沿,此時我們可以通過配置計數的方式來實現不同的邊沿計數

由圖可以看出,總共有三種計數方式供我們選擇,不同的模式對應了不同的計數形式,這里我選用的是第三種,因此會產生四個邊沿,相當于對信號進行了四倍頻,即一個脈沖信號會計數4次,在計算時要注意

寄存器部分

在編碼過程中有幾個重要的寄存器要簡單介紹一下

TIMx_CR1控制寄存器

?我們要關注這里的DIR位,通過判斷DIR來判斷計數器所處的模式是遞增還是遞減,流程大致為:配置好定時器的裝載值為65536,不分頻,那么每一次接收到65536個脈沖后定時器就會溢出進入定時器中斷,此時通過判斷DIR是0還是1來判斷是正轉還是反轉,進而將得到的脈沖數累積到總脈沖數中進行速度計算

同時還要注意 CEN位,該位用于使能計數器的工作,也就是相當于選擇模式,對應硬件就是內部的開關,用于判斷是外部定時器模式還是內部定時器模式,當該位置1為外部定時器模式

TIMx_CCMR1捕獲/比較模式寄存器1

在這里IC1F為濾波器,其實現方法為通過配置寄存器來設定濾波系數,例如在一個采樣周期下,當N=2時代表要兩個相同的事件(比如兩個相同電位的高電平信號)才能視為一個有效邊沿,這個過程基于數字濾波器實現,寄存器配置如下

IC1PSC是輸入捕獲預分頻器,和上述原理類似,這里我和教程一樣,選擇一個邊沿就觸發一次計數

CC1S用于配置定時器通道,這里不做多要求,IC1映射到TI1就可以了

TIMx_SMCR從模式控制器

?SMS代表的三位用于配置編碼器模式123,具體對應關系如下

?至此要用到的所有寄存器就介紹完了,接下來我們來進行CUBEMX工程的創建

硬件信息

主控芯片我選擇的是STM32F103C8T6,電機用的是常見的自帶編碼器的直流有刷減速電機,編碼器線數為11,電機驅動選用L298N,同時用OLED屏幕顯示電機轉速信息

工程創建

首先配置時鐘樹,直接拉滿,再初始化幾個IO口用于驅動電機

?剩下的流程就是選擇對應的IDE生成工程即可

代碼部分

初始化外設

/* USER CODE BEGIN 2 */run_left_motor(50,1); //左輪電機啟動OLED_Init(); //OLED初始化OLED_Clear();HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL); //開啟定時器編碼器通道HAL_TIM_Base_Start_IT(&htim4); //開啟定時中斷通道/* USER CODE END 2 */

?初始化電機以及編碼器

#define ROTO_RATIO 44 //編碼器線數11*分頻系數4 #define REDUTATION_RATIO 30 //電機減速比30//編碼器結構體 typedef struct {int encode_old;int encode_new;float speed; }ENCODE_TypeDef; //電機結構體 typedef struct {float speed; }Motor_TypeDef;extern ENCODE_TypeDef g_encode_left; extern Motor_TypeDef g_motor_left;

?電機轉動

void run_left_motor(uint8_t speed,unsigned char dir) {uint32_t arr;HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);if(dir == 1){HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_SET);}else{HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_1,GPIO_PIN_RESET);}HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);arr = __HAL_TIM_GET_AUTORELOAD(&htim2);__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,(1.0*speed/100)*arr); }

電機速度計算

//encoder_now為定時器編碼器模式下的計數值,ms代表每隔多少ms進入一次計算公式 void left_speed_compute(int32_t encode_now,uint8_t ms) {uint8_t i=0,j=0;float temp = 0.0; //用于后續冒泡排序static uint8_t sp_count=0,k=0; //用于判斷隔多長時間進一次計算,靜態變量,不會隨著函數調用被刷新static float speed_array[10]={0.0}; //上面的k為數組的索引值if(sp_count == ms) //當調用函數次數超過50次即每間隔50ms進入一次計數{g_encode_left.encode_new = encode_now; //編碼器值更新g_encode_left.speed = (g_encode_left.encode_new - g_encode_left.encode_old); //脈沖變化數計算//通過脈沖計算速度,公式:(50ms內記錄的脈沖數/50ms*60)/減速比/編碼器線數/分頻系數 = 每分鐘的脈沖數/已知常量speed_array[k++] = (float)(g_encode_left.speed*((1000/ms)*60.0)/(REDUTATION_RATIO*ROTO_RATIO));g_encode_left.encode_old = g_encode_left.encode_new; //更新編碼器計數值//冒泡排序法if(k==10){for(i=10;i>=1;i--){for(j=0;j<(i-1);j++) {if (speed_array[j] > speed_array[j + 1]) {temp = speed_array[j];speed_array[j] = speed_array[j + 1];speed_array[j + 1] = temp;}}}temp = 0.0; //初始化temp//去除兩邊高低數據for(i=2;i<8;i++){temp += speed_array[i];}temp = (float)(temp/6);/** 一階低通濾波 Y(n)= qX(n) + (1-q)Y(n-1)* 其中 X(n)為本次采樣值;Y(n-1)為上次濾波輸出值;Y(n)為本次濾波輸出值,* q 為濾波系數*/g_motor_left.speed = (float)((g_motor_left.speed)*(float)0.52)+((float)0.48*temp);//顯示當前速度unsigned char Tx_Buf[20];sprintf((char *)Tx_Buf,"Left: %.2f",g_motor_left.speed);OLED_ShowString(1,2,Tx_Buf,5);k = 0;}sp_count = 0;}sp_count++; }

溢出計數統計以及調用計算

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {//判斷編碼器的溢出方向if(htim->Instance == TIM1){if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim1)){g_tim1_encode_count--;}else{g_tim1_encode_count++;}}//每間隔1ms更新一次脈沖數if(htim->Instance == TIM4){int Left_encode_now = gtim_get_encode();left_speed_compute(Left_encode_now,50);} } //更新脈沖數 int gtim_get_encode(void) {return ( int32_t )__HAL_TIM_GET_COUNTER(&htim1) + g_tim1_encode_count * 65536; /* 當前計數值+之前累計編碼器的值=總的編碼器值 */ }

實驗現象驗證

轉動時轉速為20r/min?

不轉動時轉速為0

總結

以上是生活随笔為你收集整理的STM32定时器编码器模式实现直流有刷电机测速(HAL库)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。