目錄
一、CAN總線簡(jiǎn)介
??????? 1.1 CAN概述
??????? 1.2 CAN總線較其他串行通信優(yōu)勢(shì)
??????? 1.3 CAN總線通信
???????? 1.4 報(bào)文種類及格式
???????? 1.5 CAN應(yīng)用
二、CAN工程創(chuàng)建及配置
??????? 2.1 工程設(shè)計(jì)及原理框圖
???????? 2.2 工程創(chuàng)建接配置
三、代碼設(shè)計(jì)
??????? 3.1 修改輸出源文件can.c
??????? 3.2 自定義can應(yīng)用驅(qū)動(dòng)
?3.3 CAN調(diào)用實(shí)現(xiàn)
四、編譯及測(cè)試
??????? 4.1 編譯及測(cè)試
???????? 4.2 測(cè)試
一、CAN總線簡(jiǎn)介
??????? 1.1 CAN概述
????????CAN是Controller Area Network(控制區(qū)域網(wǎng)絡(luò)) 的縮寫,是ISO國(guó)際標(biāo)準(zhǔn)化的串行通信協(xié)議。由德國(guó)電氣商博世公司在1986年率先提出。此后,CAN通過ISO11898及ISO11519進(jìn)行了標(biāo)準(zhǔn)化?,F(xiàn)在在歐洲已是汽車網(wǎng)絡(luò)的標(biāo)準(zhǔn)協(xié)議。
????????CAN協(xié)議經(jīng)過ISO標(biāo)準(zhǔn)化后有兩個(gè)標(biāo)準(zhǔn):ISO11898標(biāo)準(zhǔn)和ISO11519-2標(biāo)準(zhǔn)。其中ISO11898是針對(duì)通信速率為125Kbps~1Mbps的高速通信標(biāo)準(zhǔn),總線最大長(zhǎng)度達(dá)到40m/1Mbps,連接單元數(shù)最大支持到30;而ISO11519-2是針對(duì)通信速率為125Kbps以下的低速通信標(biāo)準(zhǔn),總線最大長(zhǎng)度達(dá)到1km/40kbps,連接單元數(shù)最大支持到20。
????????CAN 控制器根據(jù)兩根線上的電位差來(lái)判斷總線電平??偩€電平分為顯性電平和隱性電平,二者必居其一。發(fā) 送方通過使總線電平發(fā)生變化,將消息發(fā)送給接收方。只有2個(gè)設(shè)備簡(jiǎn)單通信時(shí),當(dāng)成USART串口使用,多個(gè)設(shè)備同時(shí)通信時(shí),遵循CAN協(xié)議,使用郵箱、識(shí)別符、過濾器功能:總線空閑時(shí),所有單元都可發(fā)送消息,而兩個(gè)以上的單元同時(shí)開始發(fā)送消息時(shí),根據(jù)標(biāo)識(shí)符(ID,非地址)決定優(yōu)先級(jí)。兩個(gè)以上的單元同時(shí)開始發(fā)送消息時(shí),對(duì)各消息ID 的每個(gè)位進(jìn)行逐個(gè)仲裁比較。仲裁獲勝(優(yōu)先級(jí)最高)的單元可繼續(xù)發(fā)送消息,仲裁失利的單元?jiǎng)t立刻停止發(fā)送而進(jìn)行接收工作。
??????? 1.2 CAN總線較其他串行通信優(yōu)勢(shì)
????????CAN總線相比起其他串行通信協(xié)議,具有以下優(yōu)勢(shì):
??????? 【1】由于連接總線的單元,沒有類似“地址”的信息,因此,在總線上添加單元時(shí),已連接的其他單元的軟硬件和應(yīng)用層都不需要做改變。??????
??????? 【2】具有錯(cuò)誤檢測(cè)、錯(cuò)誤通知和錯(cuò)誤恢復(fù)功能:所有單元都可以檢測(cè)錯(cuò)誤(錯(cuò)誤檢測(cè)功能),檢測(cè)出錯(cuò)誤的單元會(huì)立即同時(shí)通知其他所有單元(錯(cuò)誤通知功能),正在發(fā)送消息的單元一旦檢測(cè)出錯(cuò)誤,會(huì)強(qiáng)制結(jié)束當(dāng)前的發(fā)送。強(qiáng)制結(jié)束發(fā)送的單元會(huì)不斷反復(fù)地重新發(fā)送此消息直到成功發(fā)送為止(錯(cuò)誤恢復(fù)功能)。
??????? 【3】故障封閉功能:CAN可以判斷出錯(cuò)誤的類型是總線上暫時(shí)的數(shù)據(jù)錯(cuò)誤(如外部噪聲等)還是持續(xù)的數(shù)據(jù)錯(cuò)誤(如單元內(nèi)部故障、驅(qū)動(dòng)器故障、斷線等)。由此功能,當(dāng)總線上發(fā)生持續(xù)數(shù)據(jù)錯(cuò)誤時(shí),可將引起此故障的單元從總線上隔離出去。
??????? 【4】連接節(jié)點(diǎn)多。CAN 總線是可同時(shí)連接多個(gè)單元的總線。可連接的單元總數(shù)理論上是沒有限制的。但實(shí)際上可連接的單元數(shù)受總線上的時(shí)間延遲及電氣負(fù)載的限制。降低通信速度,可連接的單元數(shù)增加;提高通信速度,則可連接的單元數(shù)減少。
??????? 1.3 CAN總線通信
??????? CAN總線是基于相同波特率通信的,所以設(shè)備接入前要知道總線上的波特率是多少。在STM32CubeMX上,其波特率計(jì)算如下圖所示:波特率=(pclk1/((1+8+7)*9)) = 36Mhz/16/9 = 250Kbits。
???????? 在數(shù)據(jù)傳輸方面,一次最多只能發(fā)送8個(gè)字節(jié)的數(shù)據(jù),這是由CAN協(xié)議規(guī)定的。多于8個(gè)的需要第二次再發(fā)送,需要開發(fā)者自己實(shí)現(xiàn)連續(xù)多數(shù)據(jù)發(fā)送的函數(shù)來(lái)實(shí)現(xiàn)大于8字節(jié)數(shù)據(jù)量的應(yīng)用。
????????同一條 CAN 總線的不同主機(jī),不能同時(shí)發(fā)送相同 ID 的報(bào)文:如果使用 2 個(gè)及以上驅(qū)動(dòng)器,連接在同一條 CAN 線上,必須設(shè)置為不同的編號(hào),比如 0 組 1 號(hào)和 0 組 2 號(hào),如果不設(shè)置為不同的編號(hào),一旦讓驅(qū)動(dòng)器回傳報(bào)文,報(bào)文 ID 則會(huì)相同,就會(huì)造成總線致命沖突,此時(shí)驅(qū)動(dòng)器會(huì)進(jìn)入硬件錯(cuò)誤狀態(tài)。
??????? CAN接口兼容規(guī)范2.0A和2.0B(主動(dòng)式),可以接收和發(fā)送11位標(biāo)識(shí)符的標(biāo)準(zhǔn)幀,也可以接收和發(fā)送29位標(biāo)識(shí)符的擴(kuò)展幀。具有3個(gè)發(fā)送郵箱和2個(gè)接收FIFO(郵箱及FIFO可以看做是緩存區(qū)域),3級(jí)14個(gè)可調(diào)節(jié)濾波器。
??????? “發(fā)送郵箱”是用于CAN總線數(shù)據(jù)發(fā)送的,總共有3個(gè),每個(gè)郵箱只裝一個(gè)報(bào)文,并且存在優(yōu)先級(jí)關(guān)系。優(yōu)先級(jí)越高表示其里面的數(shù)據(jù)會(huì)被優(yōu)先發(fā)送。數(shù)據(jù)在發(fā)送前都會(huì)被送到優(yōu)先級(jí)最高且空閑的發(fā)送郵箱,然后依次發(fā)送。如果所有郵箱都滿了,會(huì)溢出標(biāo)記為1,需要等待空郵箱。滿郵箱按先后次序排隊(duì)發(fā)送報(bào)文,發(fā)送完成后變成空郵箱。
??????? FIFO:表面的意思是“先入先出”,是指有層級(jí)深度的接收郵箱。一般CAN有2個(gè)FIFO郵箱(FIFO0和FIFO1),每個(gè)FIFO有3層深度,3層深度是指每個(gè)郵箱可以接收3個(gè)報(bào)文,但讀取時(shí)只能讀到最先收到的報(bào)文報(bào)文處理完成后,再讀取時(shí)則是下一個(gè)報(bào)文。
??????? 過濾器:可由硬件判斷報(bào)文中的標(biāo)識(shí)符,過濾掉標(biāo)識(shí)符不匹配的報(bào)文(過濾掉不想要的ID,接收想要的ID)。CAN總線控制器通常提供了14個(gè)或28個(gè)過濾器組,每組2個(gè)32為寄存器。過濾器是由硬件實(shí)現(xiàn)的,只有與過濾器匹配的報(bào)文才需要軟件處理。在接收?qǐng)?bào)文時(shí),數(shù)據(jù)先進(jìn)入過濾器,與過濾器匹配的報(bào)文會(huì)被放入FIFO郵箱。過濾器根據(jù)下列優(yōu)先級(jí)規(guī)則來(lái)確定:
????????1,位寬為32位的過濾器,優(yōu)先級(jí)高于位寬為16位的過濾器
????????2,對(duì)于位寬相同的過濾器,標(biāo)識(shí)符列表模式的優(yōu)先級(jí)高于屏蔽位模式
????????3,位寬和模式都相同的過濾器,優(yōu)先級(jí)由過濾器號(hào)決定,過濾器號(hào)小的優(yōu)先級(jí)高
??????? 最終CAN總線通信如下圖示意:
???????? 1.4 報(bào)文種類及格式
??????? CAN報(bào)文包含以下幾種,其中數(shù)據(jù)幀及遙控幀是重點(diǎn)常用格式:
??????? 【1】數(shù)據(jù)幀,用于發(fā)送單元向接收單元傳送數(shù)據(jù)的幀。
??????? 【2】遙控幀或遠(yuǎn)程幀,用于接收單元向具有相同ID的發(fā)送單元請(qǐng)求數(shù)據(jù)的幀。 ???
??????? 【3】錯(cuò)誤幀,用于當(dāng)檢測(cè)出錯(cuò)誤時(shí)向其它單元通知錯(cuò)誤的幀。
??????? 【4】過載幀,用于接收單元通知其尚未做好接收準(zhǔn)備的幀。
??????? 【5】幀間隔,用于將數(shù)據(jù)幀及遙控幀與前面的幀分離開來(lái)的幀。
??????? 每種類型的報(bào)文格式都不相同,數(shù)據(jù)幀和遙控幀格式如下:
??????? 數(shù)據(jù)幀和遙控幀有標(biāo)準(zhǔn)格式和擴(kuò)展格式兩種格式,類似于I2C協(xié)議里的7位和10位地址。CAN的數(shù)據(jù)幀和遙控幀的標(biāo)識(shí)符(ID)的標(biāo)準(zhǔn)格式有11個(gè)位標(biāo)識(shí)符,擴(kuò)展格式有29個(gè)位標(biāo)識(shí)符。設(shè)備可以用標(biāo)識(shí)符(ID)判斷數(shù)據(jù)是不是發(fā)給自己的。
??????? CAN總線收發(fā)數(shù)據(jù)報(bào)文,根據(jù)標(biāo)示符(也就是 ID)來(lái)決定優(yōu)先級(jí)的。必須注意的是,在同一CAN網(wǎng)絡(luò)中,所有單元必須設(shè)定成統(tǒng)一的通信速度,CAN設(shè)備可通過發(fā)送“遙控幀” 請(qǐng)求其他單元發(fā)送數(shù)據(jù)。CAN支持Normal 正常模式、Silent 靜默模式、Loopback 環(huán)回模式測(cè)試、Silent_loopback 靜默換回模式測(cè)試共四種模式,在CubeMX對(duì)應(yīng)如下:
???????? 1.5 CAN應(yīng)用
????????CAN具有很高的可靠性,廣泛應(yīng)用于:汽車電子、工業(yè)自動(dòng)化、船舶、醫(yī)療設(shè)備、工業(yè)設(shè)備等方面。
二、CAN工程創(chuàng)建及配置
??????? 2.1 工程設(shè)計(jì)及原理框圖
????????本文采用STM32L496VGTX+獨(dú)立CAN 收發(fā)器(TJA1050)和STM32F103C8Tx開發(fā)板(已經(jīng)集成了CAN 收發(fā)器-TJA1050)進(jìn)行CAN通信。
????????STM32L496VGTX預(yù)留了擴(kuò)展引腳PD0、PD1支持CAN1,然后通過擴(kuò)展引腳接入TJA1050:
???????? TJA1050原理框圖,STM32L496VGTX擴(kuò)展口PD0、PD1接下圖的PA11、PA12。
???????? STM32F103C8Tx開發(fā)板的CAN組件原理框圖如下,PB8、PB9接MCU:
???????? 2.2 工程創(chuàng)建接配置
??????? 現(xiàn)以STM32L496VGTX為例創(chuàng)建CAN工程stm32L496VGT6_can,創(chuàng)建完成后,移植以前已經(jīng)實(shí)現(xiàn)過的lpuart1通信功能、按鍵功能及LED燈功能,請(qǐng)參考:
cubeIDE開發(fā), stm32調(diào)試信息串口通信輸出顯示_py_free的博客-CSDN博客_stm32串口顯示
??????? 假設(shè)已經(jīng)移植了串口調(diào)試功能并能在電腦上通過串口通信實(shí)現(xiàn)調(diào)試信息輸出。
??????? 進(jìn)入CAN配置階段,雙擊.ioc打開CubeMX配置界面,設(shè)置CAN1功能開啟,先在圖形配置界面選擇PD0、PD1為CAN_RX/TX模式,將自動(dòng)開啟CAN1功能,然后進(jìn)入CAN頁(yè)面配置參數(shù),波特率設(shè)置為250Kbits,及本次CAN網(wǎng)絡(luò)的統(tǒng)一波特率。
???????? 開啟接收中斷功能
???????? 完成后點(diǎn)擊保存輸出生成代碼
三、代碼設(shè)計(jì)
??????? 3.1 修改輸出源文件can.c
??????? 在Core/src目錄下,雙擊打開can.c文件,修改MX_CAN1_Init函數(shù),增加過濾設(shè)置、CAN開啟、中斷支持設(shè)置等功能。
/* USER CODE BEGIN 0 */
//新增
#define CAN1_ID_H 0x0000 //32位基礎(chǔ)ID設(shè)置(高16位)
#define CAN1_ID_L 0x0000 //32位基礎(chǔ)ID設(shè)置(低16位)
#define CAN1_MASK_H 0x0000 //32位屏蔽MASK設(shè)置(高16位)
#define CAN1_MASK_L 0x0000 //32位屏蔽MASK設(shè)置(低16位)
/* USER CODE END 0 */
CAN_HandleTypeDef hcan1;
/* CAN1 init function */
void MX_CAN1_Init(void)
{
/* USER CODE BEGIN CAN1_Init 0 */
//新增
CAN_FilterTypeDef CAN1_sFilterConfig;
HAL_StatusTypeDef HAL_Status;
/* USER CODE END CAN1_Init 0 */
/* USER CODE BEGIN CAN1_Init 1 */
/* USER CODE END CAN1_Init 1 */
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 20;
hcan1.Init.Mode = CAN_MODE_NORMAL;
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_8TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_7TQ;
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = DISABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = DISABLE;
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN CAN1_Init 2 */
//新增
CAN1_sFilterConfig.FilterIdHigh = CAN1_ID_H;//32位基礎(chǔ)ID設(shè)置(高16位)
CAN1_sFilterConfig.FilterIdLow = CAN1_ID_L;//32位基礎(chǔ)ID設(shè)置(低16位)
CAN1_sFilterConfig.FilterMaskIdHigh = CAN1_MASK_H;//32位屏蔽MASK設(shè)置(高16位)
CAN1_sFilterConfig.FilterMaskIdLow = CAN1_MASK_L;//32位屏蔽MASK設(shè)置(低16位)
CAN1_sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO1;//接收到的報(bào)文放入FIFO1位置
CAN1_sFilterConfig.FilterBank = 0;//過濾器0
CAN1_sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;//設(shè)為IDLIST列表模式/IDMASK屏蔽模式
CAN1_sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;//過濾器位寬度
CAN1_sFilterConfig.FilterActivation = ENABLE;//ENABLE激活過濾器,DISABLE禁止過濾器
CAN1_sFilterConfig.SlaveStartFilterBank = 0;//過濾器組設(shè)置(單個(gè)CAN總線時(shí)無(wú)用)
HAL_Status = HAL_CAN_ConfigFilter(&hcan1, &CAN1_sFilterConfig);
if ( HAL_Status!= HAL_OK)//判斷開啟是否成功
{
/* Filter configuration Error */
Error_Handler();//開啟CAN總線失敗的處理程序
}
/* Start the CAN peripheral */
HAL_Status = HAL_CAN_Start(&hcan1);
if ( HAL_Status!= HAL_OK)//這個(gè)函數(shù)和下面的函數(shù)是cubemx沒有給出的,需要手動(dòng)添加
{
/* Start Error */
Error_Handler();//開啟CAN總線失敗的處理程序
}
/* Activate CAN RX notification */
//若不使用CAN中斷,以下不需要
HAL_Status = HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO1_MSG_PENDING);
if ( HAL_Status!= HAL_OK)//選擇fifo1中斷
{
/* Notification Error */
Error_Handler();//開啟CAN總線掛起中斷失敗的處理程序
}
/* USER CODE END CAN1_Init 2 */
}
??????? 3.2 自定義can應(yīng)用驅(qū)動(dòng)
???????? 在ICore目錄創(chuàng)建文件夾can,并在該文件夾下創(chuàng)建can1.h和can1.c源文件。
??????? can1.h
#ifndef CAN_CAN1_H_
#define CAN_CAN1_H_
#include "stm32l4xx_hal.h" //HAL庫(kù)文件聲明
extern CAN_HandleTypeDef hcan;//聲明的HAL庫(kù)結(jié)構(gòu)體
#define CAN1_REC_LEN 256//定義CAN1最大接收字節(jié)數(shù)
extern uint8_t CAN1_RX_BUF[CAN1_REC_LEN];//接收緩沖,末字節(jié)為換行符
extern uint16_t CAN1_RX_STA;//接收狀態(tài)標(biāo)記
uint8_t CAN1_SendNormalData(CAN_HandleTypeDef* hcan,uint16_t ID,uint8_t *pData,uint16_t Len);//CAN發(fā)送函數(shù)
void CAN1_printf (char *fmt, ...);//CAN總線通信,使用CAN1,這是CAN專用的printf函數(shù)
#endif /* CAN_CAN1_H_ */
??????? can1.c,該驅(qū)動(dòng)通過CAN1_printf函數(shù)實(shí)現(xiàn)向CAN發(fā)送數(shù)據(jù),通過重寫stm32l4xx_hal_can.h/c文件中的HAL_CAN_RxFifo1MsgPendingCallback函數(shù)實(shí)現(xiàn)CAN數(shù)據(jù)接收。
#include "can1.h" //庫(kù)文件聲明
#include "main.h"
#include <string.h>//用于字符串處理的庫(kù)
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
CAN_HandleTypeDef hcan;//聲明的HAL庫(kù)結(jié)構(gòu)體
CAN_TxHeaderTypeDef TxMeg;//CAN發(fā)送設(shè)置相關(guān)結(jié)構(gòu)體
CAN_RxHeaderTypeDef RxMeg;//CAN接收設(shè)置相關(guān)結(jié)構(gòu)體
uint8_t CAN1_RX_BUF[CAN1_REC_LEN];//接收緩沖,最大CAN1_REC_LEN個(gè)字節(jié).末字節(jié)為換行符
uint16_t CAN1_RX_STA;//接收狀態(tài)標(biāo)記
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan) //接收回調(diào)函數(shù)(函數(shù)名不可改)
{
uint8_t Data[8];//接收緩存數(shù)組
HAL_StatusTypeDef HAL_RetVal;//判斷狀態(tài)的枚舉
HAL_RetVal=HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO1,&RxMeg,Data);//接收郵箱中的數(shù)據(jù)
if (HAL_OK==HAL_RetVal){//判斷接收是否成功
//接收成功后的數(shù)據(jù)處理程序,寫在此處。(數(shù)據(jù)在Data數(shù)組中)
//以下2行是采用簡(jiǎn)單的寄存器查尋方式處理接收數(shù)據(jù),每次只接收1位。在實(shí)際項(xiàng)目中的復(fù)雜接收程序可自行編寫。
CAN1_RX_BUF[0]=Data[0];//將接收到的數(shù)據(jù)放入緩存數(shù)組(因只用到1個(gè)數(shù)據(jù),所以只存放在數(shù)據(jù)[0]位置)
CAN1_RX_STA++;//數(shù)據(jù)接收標(biāo)志位加1
}
}
//CAN發(fā)送數(shù)據(jù)函數(shù)(參數(shù):總線名,ID,數(shù)據(jù)數(shù)組,數(shù)量。返回值:0成功HAL_OK,1參數(shù)錯(cuò)誤HAL_ERROR,2發(fā)送失敗HAL_BUSY)
//示例:CAN1_SendNormalData(&hcan1,0,CAN_buffer,8);//CAN發(fā)送數(shù)據(jù)函數(shù)
uint8_t CAN1_SendNormalData(CAN_HandleTypeDef* hcan,uint16_t ID,uint8_t *pData,uint16_t Len)
{
HAL_StatusTypeDef HAL_RetVal;//判斷狀態(tài)的枚舉
uint16_t SendTimes,SendCNT=0;
uint8_t FreeTxNum=0;
uint8_t FreeLevelCount=0;
uint32_t CAN_TX_BOX0;
TxMeg.StdId=ID;
TxMeg.IDE = CAN_ID_STD;//擴(kuò)展幀標(biāo)識(shí)(STD標(biāo)準(zhǔn)幀/EXT擴(kuò)展幀)
TxMeg.RTR = CAN_RTR_DATA;//遠(yuǎn)程幀標(biāo)識(shí)(DATA數(shù)據(jù)幀/REMOTE遠(yuǎn)程幀)
if(!hcan||!pData||!Len){
printf("\n\rCAN發(fā)送失??!\n\r"); //串口發(fā)送
return HAL_ERROR;//如果總線名、數(shù)據(jù)、數(shù)量任何一個(gè)為0則返回值為1
}
SendTimes=Len/8+(Len%8?1:0);
FreeTxNum=HAL_CAN_GetTxMailboxesFreeLevel(hcan);//得出空閑郵箱的數(shù)量
TxMeg.DLC=8;
while(SendTimes--){//循環(huán)判斷分批發(fā)送是否結(jié)束
if(0==SendTimes){//如果分批發(fā)送結(jié)束
if(Len%8)TxMeg.DLC=Len%8;//則加入最后不足8個(gè)的數(shù)據(jù)內(nèi)容
}
FreeLevelCount = 0;//防止死循環(huán)
while(0 == FreeTxNum&&FreeLevelCount<10){
FreeLevelCount++;
HAL_Delay(1);
FreeTxNum = HAL_CAN_GetTxMailboxesFreeLevel(hcan);
}
HAL_Delay(1);//延時(shí)防止速度過快導(dǎo)致的發(fā)送失敗
//開始發(fā)送數(shù)據(jù)(參數(shù):總線名,設(shè)置參數(shù),數(shù)據(jù),郵箱號(hào))
HAL_RetVal=HAL_CAN_AddTxMessage(hcan,&TxMeg,pData+SendCNT,&CAN_TX_BOX0);
if(HAL_RetVal!=HAL_OK){
printf("\n\rCAN總線忙碌!\n\r"); //串口發(fā)送
return HAL_BUSY;//如果發(fā)送失敗,則返回值為2
}
SendCNT+=8;
}
return HAL_OK;//如果發(fā)送成功結(jié)束,返回值為0
}
//CAN總線通信,使用CAN1,這是CAN專用的printf函數(shù)
//調(diào)用方法:CAN1_printf("123"); //向UART8發(fā)送字符123
void CAN1_printf (char *fmt, ...)
{
char buff[CAN1_REC_LEN+1]; //用于存放轉(zhuǎn)換后的數(shù)據(jù) [長(zhǎng)度]
uint16_t i=0;
va_list arg_ptr;
va_start(arg_ptr, fmt);
vsnprintf(buff, CAN1_REC_LEN+1, fmt, arg_ptr);//數(shù)據(jù)轉(zhuǎn)換
i=strlen(buff);//得出數(shù)據(jù)長(zhǎng)度
if(strlen(buff)>CAN1_REC_LEN)i=CAN1_REC_LEN;//如果長(zhǎng)度大于最大值,則長(zhǎng)度等于最大值(多出部分忽略)
CAN1_SendNormalData(&hcan,0x11,(uint8_t *)buff,i);//CAN發(fā)送數(shù)據(jù)函數(shù)(ID為0x11)
va_end(arg_ptr);
}
?3.3 CAN調(diào)用實(shí)現(xiàn)
??????? 在main.c文件中,加入各驅(qū)動(dòng)文件的頭文件引用
/* USER CODE BEGIN Includes */
#include "../../ICore/key/key.h"
#include "../../ICore/led/led.h"
#include "../../ICore/print/print.h"
#include "../../ICore/usart/usart.h"
#include "../../ICore/can/can1.h"
/* USER CODE END Includes */
???????? 在main函數(shù)中,加入各驅(qū)動(dòng)的初始化化實(shí)現(xiàn),CAN的初始化以及生產(chǎn)代碼自動(dòng)調(diào)用
/* USER CODE BEGIN 2 */
ResetPrintInit(&hlpuart1);
HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再開啟接收中斷
HLPUSART_RX_STA = 0;
/* USER CODE END 2 */
??????? 在main函數(shù)循環(huán)體中,實(shí)現(xiàn)CAN調(diào)用
/* USER CODE BEGIN WHILE */
while (1)
{
if(HLPUSART_RX_STA&0xC000){//溢出或換行,重新開始
printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
HLPUSART_RX_STA=0;//接收錯(cuò)誤,重新開始
HAL_Delay(100);//等待
}
if(CAN1_RX_STA!=0)//CAN判斷中斷接收標(biāo)志位【處理從CAN外部設(shè)備接收的字符】
{
//CAN1_printf("%c",CAN1_RX_BUF[0]); //CAN總線發(fā)送
printf("CAN1 Receive:%c",CAN1_RX_BUF[0]); //lpuart1總線發(fā)送
CAN1_RX_STA=0;//清除標(biāo)志位
}
if(KEY_1())//按下KEY1判斷
{
CAN1_printf("A");//向CAN1發(fā)送字符A
}
if(KEY_2())//按下KEY2判斷
{
CAN1_printf("B");//向CAN1發(fā)送字符B
}
/* USER CODE END WHILE */
四、編譯及測(cè)試
??????? 4.1 編譯及測(cè)試
???????? 編譯工程,STM32L496VGx支持ST-Link,直接在CubeIDE配置運(yùn)行及下載程序。
???????? 同樣方法基于STM32F103C8Tx芯片創(chuàng)建工程、配置CAN及代碼編譯,其CAN配置如下
???????? 完成工程編譯后,加載測(cè)試
???????? 4.2 測(cè)試
??????? 打開串口工具,連接STM32L496芯片的工程lpuart1串口,在STM32F103C8Tx開發(fā)板上按鍵KEY1、KEY2,查看串口輸出情況。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-414359.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-414359.html
到了這里,關(guān)于STM32CubeIDE開發(fā)(二十六), STM32的CAN總線開發(fā)要點(diǎn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!