使用大疆M3508、M2006的CAN匯流排知識與配置方法

前言:
兩個月前的一篇文章:PID與三環控制釋出以後,有不少朋友在微信上交流大疆M3508、M2006的使用問題,其中有一個方面值得單獨拿出來聊一聊:CAN通訊
對於很多朋友,包括我自己,使用大疆的M3508、M2006無刷直流電機和C610、C620電調是第一次接觸到CAN通訊。大疆的這幾款產品原本設計的非常容易上手,應該幾天就能熟練使用。但是由於C610、C620電調選用了CAN匯流排通訊,給不少人帶來了困擾。然而使用這幾個電機並不需要把CAN通訊瞭解的有多麼深。
困擾往往來自:
- CAN匯流排之前用的比較少
- 現有CAN通訊資料少而且複雜
這篇文章旨在快速掃盲,給出使用M3508、M2006電機的必備CAN通訊知識,希望能降低使用門檻,給各位朋友節約時間。內容均使用M3508與M2006實測過,演示視訊在文章末尾。
本文僅涉及必備知識,甚至儘量避開復雜的通訊原理,力求淺顯易懂。
0x00 需要額外的CAN收發器!!!
這件事要放到前面去說,因為已經有幾位朋友的經歷指出了其必要性。
如果我們有一塊STM32開發板,也有電調電機和電源。那麼我們的STM32引腳與電調的CAN_H和CAN_L之間是不能直接相連的。
需要購買如下圖所示的CAN收發器,作為兩者連線的橋樑。一般我用的是TJA1050晶片的模組。
CAN收發器是使用電機的必備硬體條件,一定要先確定自己有這個東西。至於原因,咱們接下來說明。
0x01 硬體層面分析
為什麼需要CAN收發器
通過分析硬體層面我們能知道為什麼需要額外的CAN收發器。請看下圖:
從圖中我們能看出,STM32擁有的外設叫做:CAN控制器,它負責CAN通訊的篩選、優先順序、仲裁等問題。相當於咱們的郵局,幫忙蓋個郵戳,分分類。通過複用GPIO以後,它延伸出兩個引腳:CAN_RX
和CAN_TX
,類比串列埠我們知道一個負責收一個負責發。
實際上,這兩個引腳上傳輸的資料已經是CAN報文了,該有的格式它都有,STM32的CAN迴環模式就相當於直接把CAN_RX
和CAN_TX
相連,就可以收到自己發的訊息。
問題是,CAN在設計的時候為了消除共模干擾,特地選用了差分訊號(也叫差模訊號)傳輸。咱們的C610、C620電調,接收發送的就是差分訊號。這才是CAN收發器的作用:
把來自STM32的訊號轉換成差分訊號讓電調聽得懂,把來自電調的差分訊號轉換成STM32聽得懂的訊號。
請注意:
連線CAN_RX
和CAN_TX
引腳與CAN收發器的引腳時,並不需要像串列埠一樣交叉。直接將RX連線到標有RX的引腳,TX類似。
120Ω的終端電阻呢?
不知道朋友們有沒有注意到C610、C620電調上都有一個開關,C620的在側面,旁邊寫著CAN RESISTOR
,這也是CAN匯流排的設計要求。
根據咱們學的《電路理論》這門課,當訊號波長小於電路尺寸的時候,我們就不能把電路當成集中電路來分析。對於can匯流排是一樣的,由於電調採用1MHz的通訊頻率,為了防止一些不必要的干擾,我們需要在CAN匯流排的兩端分別用120Ω電阻跨接起來。比如之前圖中的兩端可以認為是咱們的CAN收發器是一端,下面的電調是另一端。
對於只有一個電調的情況下,可以開啟電調上的電阻,然後直接和CAN收發器連線,這樣雖然少了一端的終端電阻,但實際上可以執行。如果同時控制兩個及以上的電調,那就可以開啟其中兩個的終端電阻,構成匯流排的兩端。當然也可以手動組成如下圖的匯流排結構並且關閉電調上的終端電阻,圖中還加入了電容進行濾波。
0x02 軟體配置簡析
其實,看完硬體部分就已經可以正常使用電調電機了,因為大疆官方例程中已經把CAN通訊配置好了,直接可以使用。
但是如果涉及非常多的裝置同時控制,比如超過四個電機的情況下,或者還有其他的外設要通過CAN匯流排相連,簡單瞭解軟體配置也是很有好處。
而且,我發現很多朋友是在做RoboMaster比賽,全面的瞭解軟硬體還是十分必要的,如果出現問題也有利於排查,不至於浪費大量時間。
接下來我們還是使用咱們的老朋友:大疆官方M2006例程、M3508例程來作為樣本。主要探究以下問題:
- 通訊頻率如何設定為1MHz
- CAN過濾器的配置
- 報文的接收與傳送
兩個檔案:bsp_can.c
和can.c
如何把通訊頻率設定為1MHz?
以下是檔案can.c
中擷取的程式碼(有刪改):
CAN_HandleTypeDef hcan1;
/* CAN1 init function */
void MX_CAN1_Init(void)
{
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 3;//分頻係數設定為3
hcan1.Init.Mode = CAN_MODE_NORMAL;
hcan1.Init.SJW = CAN_SJW_1TQ;
// =================請看這裡
hcan1.Init.BS1 = CAN_BS1_9TQ;
hcan1.Init.BS2 = CAN_BS2_4TQ;
// =====================這裡
//省略一些。。。。。
HAL_CAN_Init(&hcan1);
}
注意,大疆的例程是為大疆的開發板所編寫,其主控晶片是STM32F429,在這裡F4與F1的時鐘頻率差別會影響到配置的具體引數。
咱們重點來看分頻係數的確定以及標出的兩行。
STM32F4一般來說主頻率會配置到168MHz,經過4分頻之後得到了42MHz的APB1時鐘,CAN控制器正是從APB1上獲取時鐘。程式碼中hcan1.Init.Prescaler = 3;
正是將42MHz的時鐘進行3分頻,得到了14MHz的時鐘。這就是真正被使用的頻率。接著我們看傳輸一個bit需要哪幾部分:
所以,傳輸一位的時間可以看作T=(1+BS1+BS2)*tq,tq(time quantum)。所以在例程裡就是1+9+4=14個tq。而tq剛好是CAN時鐘頻率14MHz的倒數,tq=(1/14MHz),T=14*tq,得T=(1/1MHz),同樣f=1/T=1MHz。由此獲得了我們需要的頻率。
同理,如果是F1,APB1時鐘一般是36MHz,那麼我們設定分頻係數為4,BS1=5,BS2=3,也能得到1MHz。
CAN過濾器配置
其實一般來說並不需要注意CAN過濾器得配置,因為官方例程也沒怎麼配置,大可直接套用。
過濾器是針對接收資訊進行篩選得部件,因為CAN總線上得訊息往往比較複雜,通過過濾器可以選出想要接受的訊息。大致過程是過濾器會對所有收到的報文按照咱們設定的規則進行篩選,如果符合要求就會放入FIFO緩衝區儲存下來。而這個規則就是報文的id資訊。為了實現複雜的id篩選,引入了id暫存器和id掩碼暫存器,其配合過程非常的。。精彩。有興趣可以瞭解一下。
下面得程式碼摘自檔案bsp_can.c
(有刪改):
void my_can_filter_init_recv_all(CAN_HandleTypeDef* _hcan)
{
CAN_FilterConfTypeDef CAN_FilterConfigStructure;
static CanTxMsgTypeDef Tx1Message;
static CanRxMsgTypeDef Rx1Message;
CAN_FilterConfigStructure.FilterNumber = 0;
CAN_FilterConfigStructure.FilterMode = CAN_FILTERMODE_IDMASK;
CAN_FilterConfigStructure.FilterScale = CAN_FILTERSCALE_32BIT;
CAN_FilterConfigStructure.FilterIdHigh = 0x0000;
CAN_FilterConfigStructure.FilterIdLow = 0x0000;
CAN_FilterConfigStructure.FilterMaskIdHigh = 0x0000;
CAN_FilterConfigStructure.FilterMaskIdLow = 0x0000;
CAN_FilterConfigStructure.FilterFIFOAssignment = CAN_FilterFIFO0;
CAN_FilterConfigStructure.BankNumber = 14;
CAN_FilterConfigStructure.FilterActivation = ENABLE;
HAL_CAN_ConfigFilter(_hcan, &CAN_FilterConfigStructure) ;
}
這裡我們發現不論是id還是掩碼都是0,也就是接收總線上的所有報文。那麼在多電機的情況下如何區分訊息的發出者呢?
訊息的接收與傳送
我們先看看接收,以下選自bsp_can.c
(有刪改):
void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* _hcan)
{
switch(_hcan->pRxMsg->StdId){
case CAN_2006Moto1_ID://0x201
case CAN_2006Moto2_ID://0x202
case CAN_2006Moto3_ID://0x203
case CAN_2006Moto4_ID://0x204
{
static u8 i;
i = _hcan->pRxMsg->StdId - CAN_2006Moto1_ID;
get_moto_measure(&moto_chassis[i], _hcan);
}
break;
}
這是CAN的接收中斷回撥函式,在來到這個函式之前,獲得的報文已經被儲存在pRxMsg
指向的結構體當中。switch語句通過判別StdId
來確定是不是電機發來的報文,並且判斷是哪個電機。而這個StdId
咱們並不陌生,它是前面所說的FilterId
的一部分。
官方手冊中提到在同一個CAN總線上,最多可以接入8個電調,通過電調的自動分配他們分別是地址0x201~0x208。
再看傳送:
void set_moto_current(CAN_HandleTypeDef* hcan, s16 iq1, s16 iq2, s16 iq3, s16 iq4){
hcan->pTxMsg->StdId = 0x200;
hcan->pTxMsg->IDE = CAN_ID_STD;
hcan->pTxMsg->RTR = CAN_RTR_DATA;
hcan->pTxMsg->DLC = 0x08;
hcan->pTxMsg->Data[0] = (iq1 >> 8);
hcan->pTxMsg->Data[1] = iq1;
hcan->pTxMsg->Data[2] = (iq2 >> 8);
hcan->pTxMsg->Data[3] = iq2;
hcan->pTxMsg->Data[4] = iq3 >> 8;
hcan->pTxMsg->Data[5] = iq3;
hcan->pTxMsg->Data[6] = iq4 >> 8;
hcan->pTxMsg->Data[7] = iq4;
HAL_CAN_Transmit(hcan, 100);
}
按照手冊,我們能看出,如果要給編號為0x2010x204的電調發資訊,要把傳送中的`StdId`設定為0x200,若是要給0x2050x208的四個電調發資訊,則要設定為0x1FF。
後面依照手冊填充資料然後傳送,過程比較簡單。
0x03 總結
又是一篇有關大疆電機的文章,也是結合我自己的經歷和上一篇文章的反饋才有了這篇。現在還記得我剛開始接觸CAN通訊時候的疑惑感,感覺資料都太複雜看不下去。水平確實有限,也就只能力求個淺顯易懂,希望能幫助朋友們節約一些時間吧。相關例程可以在公眾號上向我索要。
這裡放上前一篇文章連結:PID和三環控制-以大疆M3508、M2006為例 https://blog.csdn.net/qq_28039135/article/details/116379392
更多嵌入式,電機控制相關文章請移步公眾號,來找我聊聊天吧:
技術新人,水平有限,還請各位朋友多多指教。如果對文章有任何的疑問或者發現錯誤請一定指出!
演示視訊:
同時控制M3505、M2006雙電機的演示視訊在公眾號原文底部:
歡迎轉載,請註明作者與原文地址:
作者:胡小安
原文連結:https://www.cnblogs.com/huxiaoan/p/15046967.html