大疆M3508、M2006必備CAN匯流排知識與配置方法

  • 2021 年 7 月 23 日
  • 筆記

使用大疆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收发器

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收發器連接,這樣雖然少了一端的終端電阻,但實際上可以運行。如果同時控制兩個及以上的電調,那就可以打開其中兩個的終端電阻,構成匯流排的兩端。當然也可以手動組成如下圖的匯流排結構並且關閉電調上的終端電阻,圖中還加入了電容進行濾波。

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為例 //blog.csdn.net/qq_28039135/article/details/116379392

更多嵌入式,電機控制相關文章請移步公眾號,來找我聊聊天吧:

公众号

技術新人,水平有限,還請各位朋友多多指教。如果對文章有任何的疑問或者發現錯誤請一定指出!

演示影片:

同時控制M3505、M2006雙電機的演示影片在公眾號原文底部:

文章二维码


歡迎轉載,請註明作者與原文地址:

作者:胡小安

原文鏈接://www.cnblogs.com/huxiaoan/p/15046967.html

Tags: