您好,登錄后才能下訂單哦!
CAN 是Controller Area Network 的縮寫
有CANH和CANL兩線,即差分信號通信。當(dāng)然設(shè)備芯片還會有電源和地等線。
在總線空閑時,所有的單元都可開始發(fā)送消息(多主控制)。
最先訪問總線的單元可獲得發(fā)送權(quán)(CSMA/CA 方式)。
多個單元同時開始發(fā)送時,發(fā)送高優(yōu)先級 ID 消息的單元可獲得發(fā)送權(quán)。
沒有目標(biāo)地址和源地址的概念,只有標(biāo)識符,根據(jù)標(biāo)識符決定優(yōu)先級,根據(jù)表示符,設(shè)備自己判斷是否接收給上層,讓上層處理。即消息是廣播的形式。
兩個以上的單元同時開始發(fā)送消息時,對各消息ID 的每個位進(jìn)行逐個仲裁比較。仲裁獲勝(被判定為優(yōu)先級最高)的單元可繼續(xù)發(fā)送消息,仲裁失利的單元則立刻停止發(fā)送而進(jìn)行接收工作。這個是與CAN總線中,多個電平同時出現(xiàn)時,顯式電平為最終值這個機(jī)理有關(guān)。所以,設(shè)備一邊發(fā)送,一遍檢查總線的實(shí)際值,即可知道是否有別的設(shè)備在同時發(fā)送了。這種不算出錯誤,而是算仲裁是否取勝。 后面CRC檢驗(yàn)錯誤等,才是錯誤。
標(biāo)準(zhǔn)格式有11 個位的標(biāo)識符(Identifier: 以下稱ID),擴(kuò)展格式有29 個位的ID。
通信是通過以下5 種類型的幀進(jìn)行的。 數(shù)據(jù)幀、 遙控幀、錯誤幀、 過載幀、 幀間隔
作為驅(qū)動開發(fā)人員,應(yīng)該了解,總線協(xié)議哪些部分是硬件實(shí)現(xiàn)的,哪些部分是軟件實(shí)現(xiàn)的。
數(shù)據(jù)幀的數(shù)據(jù)內(nèi)容和遙控幀的數(shù)據(jù)內(nèi)容,應(yīng)該是軟件填入,并由硬件進(jìn)行協(xié)助處理。錯誤幀、過載幀、幀間隔,這種東西,應(yīng)該是硬件直接處理,只是可能會轉(zhuǎn)換為一個中斷控制器的一個status來通知上層軟件邏輯,出現(xiàn)某些問題。
對于linux軟件來說,CAN host controller驅(qū)動會把硬件收到的CAN數(shù)據(jù)組織為struct can_frame 。
linux內(nèi)核代碼來看
struct can_frame {
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags /
__u8 can_dlc; / frame payload length in byte (0 … CAN_MAX_DLEN) /
__u8 data[CAN_MAX_DLEN] attribute((aligned(8)));
};
can_id就是表示符字段,并含CAN_ID + EFF/RTR/ERR flags
例如imx6的flexcan的驅(qū)動,在can_id上也指明了一些錯誤信息給上層使用。通過can_id的標(biāo)記位指明。具體看flexcan的代碼。
/
Controller Area Network Identifier structure
bit 0-28 : CAN identifier (11/29 bit)
bit 29 : error message frame flag (0 = data frame, 1 = error message)
bit 30 : remote transmission request flag (1 = rtr frame)
bit 31 : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)
*/
即linux重新定義了canid,這個與can總線上的格式不同,但意義類似。而且提供了filter機(jī)制,讓應(yīng)用層的socket只是關(guān)心某些canframe的包。注意,其他操作系統(tǒng),實(shí)現(xiàn)方式可能不同。
使用CAN分析儀,安裝驅(qū)動,并使用CANTest工具,
選擇好設(shè)備和can通道后,并設(shè)置頻率后,即可接收和發(fā)送。
CANH接CANH,CANL接CANL
此CANTest工具運(yùn)行后,并設(shè)置速率為500KHz
另外一側(cè),即設(shè)備側(cè),linux中運(yùn)行
ip link set can0 down
ip link set can0 up type can bitrate 500000
即設(shè)置為500KHz。
然后運(yùn)行
cansend can0 1F334455#11223355
linux上發(fā)送上面的數(shù)據(jù),#之前是can id,#號之后是數(shù)據(jù)。CANTest上,就會收到并顯示。
linux設(shè)備側(cè),運(yùn)行candump -l any,0:0,#FFFFFFFF,然后CANTest上發(fā)送數(shù)據(jù)。
然后candump會告訴你保存到哪個文件,你即可
cat這個文件看到內(nèi)容。
linux側(cè)的can使用介紹,具體可以看Documentation/networking/can.txt
linux CAN應(yīng)用開發(fā)涉及的api:參考candump和cansend的代碼
struct sockaddr_can addr;
struct iovec iov;
struct msghdr msg;
struct cmsghdr cmsg;
struct can_filter rfilter;
can_err_mask_t err_mask;
struct canfd_frame frame;
struct ifreq ifr;
socket(PF_CAN, SOCK_RAW, CAN_RAW);
ioctl(s[i], SIOCGIFINDEX, &ifr)
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER,&err_mask, sizeof(err_mask)); //根據(jù)需要
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_JOIN_FILTERS,&join_filter, sizeof(join_filter)) //根據(jù)需要
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER,rfilter, numfilter sizeof(struct can_filter)); //根據(jù)需要, 設(shè)置filter,過濾某些CAN_ID的數(shù)據(jù)
setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)); //根據(jù)需要
bind(s[i], (struct sockaddr )&addr, sizeof(addr))
select(s[currmax-1]+1, &rdfs, NULL, NULL, timeout_current)
recvmsg(s[i], &msg, 0); //或者recv()
close(s[i]);
ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name);
ioctl(s, SIOCGIFMTU, &ifr)
bind(s, (struct sockaddr *)&addr, sizeof(addr)
write(s, &frame, required_mtu)
由于linux暴露給上層的CAN網(wǎng)絡(luò)設(shè)備只支持
socket(PF_CAN, SOCK_RAW, CAN_RAW);
而android上層使用的是java,所以需要native層的service把此種socket轉(zhuǎn)為另外的tcp或者udp或者進(jìn)程間通信機(jī)制的socket才能發(fā)給java上層。
具體請參考我的免費(fèi)的linux各種驅(qū)動開發(fā)課程如下:
https://edu.51cto.com/course/17138.html
另外我的相關(guān)培訓(xùn)視頻請看:
歡迎觀看我發(fā)布的各個課程: https://edu.51cto.com/lecturer/8896847.html
我的新的更多優(yōu)惠的打包課程鏈接如下:
https://edu.51cto.com/sd/0a9d4
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。