中文參考 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有關於優先權的操作?
回覆刪除