中文參考 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);//
}