1. 程式人生 > >使用Stm32Cubemx配置定時器正交編碼模式詳解(附上程式思想介紹)

使用Stm32Cubemx配置定時器正交編碼模式詳解(附上程式思想介紹)

        這篇文章也是本人做完一個專案後抱著想記錄點東西鞏固下知識同時又想給後來的技術同伴一點參考的想法寫下來的,和本人之前有關中穎晶片的博文意圖是一致的。看完本篇文章可以瞭解stm32晶片如何配置定時器正交編碼模式的同時對cubemx也會有一定的瞭解。這款工具很好用,很方便,希望所有用st晶片的夥伴們都能掌握它的用法,使用一種工具很快能上手,主要是大家要了解標準庫和HAL庫之間的一些微小機制區別就很容易了,這篇文章不打算講這些,要不跑題了,有空的話專門寫一篇文章,不過大家也可以在網上找到很多資料,廢話不多說了下一段進入主題。

        這裡假設大家都下了cubemx軟體,對軟體具有一定的熟悉度。用stm32f030系列來為例吧。對於什麼叫正交編碼就不多說了,想必要看我這篇文章的應該都是直接工程或專案中用到了,具有一定基礎,實在不知道的就網上找資料了。這裡還是插入兩幅時序圖,一個代表增,一個代表減。


開啟cubemx,新建工程,下面直接上圖比較直觀;



這裡選擇定時器1,輸入通道是通道1和通道2,注意這裡的外部中斷並不是用來接編碼器的第三跟線(可以用作清零計數器作用),後面會向大家解釋。


主要配置清單:

1.不分頻;

2.向上計數;

3.選擇 Encoder Mode TI1 and TI2;

4.兩路通道配置成上升沿檢測;

這裡我是要用4倍模式的即上升沿和下降沿都要檢測到並且計數器加一或減一,但為什麼cubemx卻配製成上升沿檢測,之前我也試過配製成雙邊模式,但效果不對,當然您知道為什麼也煩請一定評論告訴我。

到現在也沒講cubemx怎麼用,我相信寫程式的對這種工具都很容易上手,稍微點一下就通,也就不花多少筆墨在這上面,不過還是要提醒下,使用cubemx生成的程式碼一定要寫在/*BEGIN*/和/*END*/之間,否則下次重新更改配置生成後自己寫的程式碼會被覆蓋,配置好之後儲存自動生成工程程式碼。

接下來講講一些程式設計思想,用到正交編碼的地方大部分是用作帶方向的計數,至於大家各自專案裡計數的含義(或者說得到的脈衝數所代表的含義)各不相同,在我的專案中脈衝數代表距離,大家很快便明白。

上圖配置中我配置的是0 - 20000計數。使用函式__HAL_TIM_GET_COUNTER(&htim1)可以實時獲取計數值。編碼器帶方向,在我使用的過程中正轉計數器從0計數到20000,反轉計數器從20000計數到0.這樣的話假設從0開始經過一段時間假設計數值是10000那這10000是經過正轉n個20000之後的10000還是反轉n個20000的10000,可能你會說設一個更新中斷計數。我們設定的是向上計數,怎麼判斷他是正轉的20000還是反轉的20000更新中斷,正轉當轉到20000時更新中斷產生,翻轉當轉到0跳到20000也有一個更新中斷。這時,大家會想到實時設定兩個獲取計數器的值,更新中斷裡判斷兩個值得情況便知道正反轉,理論是可以的,但是當轉速過快,或者我乾脆就在0和20000附近來回轉,那麼情況便很糟糕,隨時計數可能亂套。這時大家還會想到配製成中央對齊模式是否可以,本人配置過,效果不對,可能編碼器只能從0計數到預裝載值,或者從預裝載值計數到0;那這個時候怎麼辦,__HAL_TIM_SET_COUNTER()這個功能派上用場了,初始值用它將計數器配置為10000(這裡以20000為例),每次進更新中斷在中斷裡都設定成這個值,這樣就達到了從中點要麼向上,要麼向下計數的結果。避免稍微移動轉盤出現0和20000來回產生中斷的情況。至於怎麼處理資料,我直接上程式碼,文字已經寫得夠多了,大家也看不情願了,最後的結果是可以很方便的得到不管如何轉(一直正轉,一直反轉,時而正轉時而反轉)相對於最初真實的距離點(是n個正或反20000倍數加m(零頭)個脈衝)。

這是中斷裡面的處理過程(下面的註釋和專案是不一致的,主要為了說明問題):

 if(htim == &htim1)
{
if(puse_n.puse_count < 10000)  //向下計數     和更新中斷產生前的計數值比較便知道是正轉產生的更新中斷還是反轉產生的
{
puse_n.loop_num--;       //10000的倍數
}
if(puse_n.puse_count > 10000) //向上計數
{
puse_n.loop_num++;
}
__HAL_TIM_SET_COUNTER(&htim1,10000);
}

這是獲取最後結果的函式:

void get_true_distance(Puse_number* my_puse)
{
my_puse->puse_count = __HAL_TIM_GET_COUNTER(&htim1);
if(my_puse->loop_num == 0 && my_puse->puse_count > 10000)   //剛開始是正轉
{
my_puse->true_puse = my_puse->puse_count - 10000;
}
else if(my_puse->loop_num == 0 && my_puse->puse_count < 10000)  //剛開始是反轉
{
my_puse->true_puse = 10000 - my_puse->puse_count;
}
else if(my_puse->loop_num > 0 )
{
my_puse->true_puse = my_puse->loop_num*10000 + my_puse->puse_count - 10000;  //正轉my_puse->loop_num倍的10000後
}
else if(my_puse->loop_num < 0)
{
my_puse->true_puse = (-1)*my_puse->loop_num*10000 + 10000 - my_puse->puse_count;  //反轉my_puse->loop_num倍的10000後
}
else if(my_puse->loop_num == 0 && my_puse->puse_count == 10000)   //起點
{
my_puse->true_puse = 0;
}
}

my_puse->true_puse是最後結果,這裡程式碼裡面有一點需要提出,當採用中間值時,實際更新中斷是每10000個脈衝計數產生一次,變數命名給閱讀者帶來的麻煩請諒解。

希望對使用編碼器的技術同伴有所啟發,不對之處煩請指正!