前幾篇有關於CANBus的文章都是利用環回模式去做測試~這一篇會透過Arduino+MCP2515與STM32完成CANBus通訊~
MEGA2560 | MCP2515 |
---|---|
D52 | SCK |
D53 | CS |
D50 | MISO |
D51 | MOSI |
5V | VCC |
GND | GND |
MCP2515 | STM32 L476RG |
---|---|
CAN H | PA12 |
CAN L | PA11 |
這部分有已經寫好的庫可以使用,我是使用連結 這個庫來完成的
這邊要注意MCP2515的Baud Rate設定,這邊設定是8MHZ選擇125k bit/s
#include <SPI.h>
#include <mcp2515.h>
struct can_frame canMsg;
struct can_frame canMsg1;
MCP2515 mcp2515(53); //CSS
void setup() {
canMsg1.can_id = 0x1876AC23 | CAN_EFF_FLAG;
canMsg1.can_dlc = 8;
canMsg1.data[0] = 0x05;
canMsg1.data[1] = 0x06;
canMsg1.data[2] = 0x07;
canMsg1.data[3] = 0x08;
canMsg1.data[4] = 0x09;
canMsg1.data[5] = 0x0A;
canMsg1.data[6] = 0x0B;
canMsg1.data[7] = 0x0C;
while (!Serial);
Serial.begin(115200);
mcp2515.reset();
mcp2515.setBitrate(CAN_125KBPS,MCP_8MHZ);
//mcp2515.setLoopbackMode();
mcp2515.setNormalMode();
Serial.println("********MCP2515&STM32_CAN_Test*********");
Serial.println("********Send Message*********");
mcp2515.sendMessage(&canMsg1);
Serial.print(canMsg1.can_id, HEX);
Serial.print(" ");
Serial.print(canMsg1.can_dlc, HEX);
Serial.print(" ");
for (int i = 0; i<canMsg1.can_dlc; i++)
{
Serial.print(canMsg1.data[i],HEX);
Serial.print(" ");
}
Serial.println();
delay(100);
}
void loop() {
//mcp2515.sendMessage(&canMsg1);
//delay(100);
if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK)
{
Serial.print(canMsg.can_id, HEX);
Serial.print(" ");
Serial.print(canMsg.can_dlc, HEX);
Serial.print(" ");
for (int i = 0; i<canMsg.can_dlc; i++)
{ // print the data
Serial.print(canMsg.data[i],HEX);
Serial.print(" ");
}
Serial.println();
delay(100);
mcp2515.sendMessage(&canMsg1);
Serial.print(canMsg1.can_id, HEX);
Serial.print(" ");
Serial.print(canMsg1.can_dlc, HEX);
Serial.print(" ");
for (int i = 0; i<canMsg1.can_dlc; i++)
{ // print the data
Serial.print(canMsg1.data[i],HEX);
Serial.print(" ");
}
Serial.println();
delay(100);
}
}
先確認一下系統時鐘是多少 後續再設定TQ與Baud Rate時才不會出錯~
在這邊我系統時鐘是16Mhz
接著來看看CAN的設置
PSC的部分設定為16 TQ會等於1000ns
BS1 選擇4 BS2選擇3 採樣點會落在62.5%
最後Baud Rate會等於125k bit/s (這邊要與另一端設備相同)
全域變數宣告
uint8_t TxBuffer[8] = {0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};
uint8_t RxBuffer[8];
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
uint32_t TxMailBox;
接收中斷回調函數
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, RxBuffer);
}
設置Filter模式 這邊我選擇LIST也就是所有ID必須完全相符才會接收
void ConfigFliter(void)
{
CAN_FilterTypeDef CAN1Filter;
CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
CAN1Filter.FilterMode = CAN_FILTERMODE_IDLIST;
CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
CAN1Filter.FilterBank = 0;
CAN1Filter.FilterIdHigh = ((0x1876AC23<<3)>>16) & 0xffff;
CAN1Filter.FilterIdLow =((0x1876AC23<<3)& 0xffff) | CAN_ID_EXT;
CAN1Filter.SlaveStartFilterBank = 0;
HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter);
}
main
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_CAN1_Init();
/* USER CODE BEGIN 2 */
ConfigFliter();
HAL_CAN_Start(&hcan1);
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
TxHeader.DLC =8;
TxHeader.ExtId = 0x08C53451;
TxHeader.IDE = CAN_ID_EXT;
TxHeader.RTR = CAN_RTR_DATA;
TxHeader.TransmitGlobalTime = DISABLE;
HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxBuffer, &TxMailBox);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
這邊我先將MCP2515做環回測試確定傳送與接收正常後才與STM32對接做測試~
下圖為Arduino & MCP2515 LoopBack 測試畫面
Arduino傳送端
STM32所接收到的資料
由於我只有一塊STM32,所以用MCP2515來當作另一端設備,手邊有兩塊的話可以直接將CANRX與另一端TX相連做測試就可以了~