中文參考 http://blog.csdn.net/yuanlulu/article/details/7220060
控制器區域網路 (Controller Area Network, 簡稱 CAN 或 CANbus)
一種通訊協定,主要應用在汽車、工控領域。
目前版本CAN 2.0A與CAN 2.0B ,B是A的擴充。2.0B 的ID長度占29bit, 2.0A 的ID長度占11bit
節點架構
CAN Controller 通常內建於MCU內(也有獨立的ex: SJA1000),會在外接Transceiver(ex:ISO1050)轉成類比訊號。
CAN封包格式
寫基本的CAN,只需要注意仲裁欄位、控制欄位、資料欄位
Field name | Length (bits) | Purpose |
---|---|---|
Start-of-frame | 1 | Denotes the start of frame transmission |
Identifier (green) | 11 | A (unique) identifier which also represents the message priority |
Remote transmission request (RTR) | 1 | Must be dominant (0) for data frames and recessive (1) for remote request frames (see Remote Frame, below) |
Identifier extension bit (IDE) | 1 | Must be dominant (0) for base frame format with 11-bit identifiers |
Reserved bit (r0) | 1 | Reserved bit. Must be dominant (0), but accepted as either dominant or recessive. |
Data length code (DLC) (yellow) | 4 | Number of bytes of data (0–8 bytes)[a] |
Data field (red) | 0–64 (0-8 bytes) | Data to be transmitted (length in bytes dictated by DLC field) |
CRC | 15 | Cyclic redundancy check |
CRC delimiter | 1 | Must be recessive (1) |
ACK slot | 1 | Transmitter sends recessive (1) and any receiver can assert a dominant (0) |
ACK delimiter | 1 | Must be recessive (1) |
End-of-frame (EOF) | 7 | Must be recessive (1) |
CAN BUS的操作可以如同使用SOCKET。
參考Linux下範例 candsend.c candump.c
看完除了會can 的發送與接收,也可以學到命令列參數使用方法 (function: getopt_long)
以下簡單範例:
Setting :
struct can_frame frame; struct ifreq ifr; struct sockaddr_can addr; char *interface = "can0"; int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW; s = socket(family, type, proto) strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCGIFINDEX, &ifr)) { perror("CAN ioctl"); return 1; } addr.can_family = family; addr.can_ifindex = ifr.ifr_ifindex; if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("CAN bind"); return 1; }Send :
//sendcanbus(); frame.can_id = 0x0321; frame.can_dlc = 4; frame.data[0] = 0; frame.data[1] = 1; frame.data[2] = 2; frame.data[3] = 3; ret = send(s,&frame,sizeof(frame),0);Read :
//dropt the timeout packets while(nbytes = recvfrom(s,&frame,sizeof(struct can_frame),0,(struct sockaddr*)&addr,&len)>=0) { printf("\r\nrecvfrom nbytes %d",nbytes); memcpy(b,&frame,sizeof(frame)); for (i=0 ; i < sizeof(struct can_frame) ; i++) { printf(" 0x%x ",b[i]); } usleep(10000);// }
實驗測試的幾點心得:
- send() 可以用 write() 代替,recvfrom() 可用read()代替
- 通訊幾次後,將BUS移除,強迫發生timeout後,再接回bus,資料會存在can controller 內TX的buffer中,並不會移除。
- 為了取得最新資料,利用連下recvfrom()來丟棄timeout的frame。
- 連下recvfrom()兩次,有機會抓到一樣的資料,所以2次recv間要sleep()一下。
- 查找清除can buffer的方式,好像只有關掉重啟 CAN一途
>ifconfig can0 down >ifconfig can0 up
- 為了製造TX、RX比對資料錯誤的假象,將Pin CAN_H、CAN_L短路,結果CANBus 再也沒動作...
沒動作指的是send()一直下,但MCU到Transiver之間的通訊燈亮都沒亮...一樣只有 can0 down 、 can0 up 有解。因此判斷是CAN controller掛掉而已。 - 自從CAN controller GG後,心想既然可以收命令,也就有可能只是進入某種狀態
果然 進入bus-off$ ip -details -statistics link show can0
利用以下,enable CAN controller 自動重啟
$ set can0 up type can restart-ms 100
- filter 、 廣播、error mode ... CAN還有很多可以玩啊....
待續~~~~~~~~~
你用哪款CAN設備產品來收發資訊?
回覆刪除實作在TI AM3505 的板子上
刪除Datasheet 請參考 http://www.ti.com/lit/ds/sprs550f/sprs550f.pdf
想請教一下 data 讀出來的東西到底是甚麼資料? 您寫的是(data[0]=1) ,指的是0的位置讀出來僅是1而已?
回覆刪除想請教一下CAN send如何實現CAN bus有關於優先權的操作?
回覆刪除