关于can的通信的学习心得笔记

CAN总线应用场合非常广泛:

        在当前的汽车工业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统被开发了出来,车上的电子控制系统越来越多,譬如发动机管理控制、变速箱控制、汽车仪表、空调、车门控制、灯光控制、气囊控制、转向控制、胎压监测、制动系统、雷达、自适应巡航、电子防盗系统等(如图:)

 什么是CAN?

        CAN 是 Controller Area Network 的缩写(以下称为 CAN),即控制器局域网络,是 ISO 国际标准化的串行通信协议

CAN 的特点(好处):

(1)、多主控制

                简单来说:在总线空闲时,所有的单元都可开始发送消息(多主控制)

(2)、优先级消息发送

        两个以上的单元同时开始发送消息时,根据标识符(Identifier 以下称为 ID)决定优先级。ID 并不是表示发送的目的地址,而是表示访问总线的消息的优先级。

(3) 、系统的柔软性

                设备怎加便捷,没有地址概念,因此在总线上增加单元时,连接在总线上的其它单元的
软硬件及应用层都不需要改变

(4) 、通讯速度

        在同一网络中,所有单元必须设定成统一的通信速度。即使有一个单元的通信速度与其它的不一样,此单元也会输出错误信号,妨碍整个网络的通信。不同网络间则可以有不同的通信速度

(5)、具有错误检测功能·错误通知功能·错误恢复功能

        正在发送消息的单元一旦检测出错误,会强制结束当前的发送。强制结束发送的单元会不断反复地重新发送此消息直到成功发送为止(错误恢复功能)。

(6)、CAN 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没有限制的

         注意:但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少。

CAN如何发送数据?相比有什么差异呢?

        CAN 总线电平分为显性电平隐性电平两种。显性电平表示逻辑“0”,此时 CAN_H 电平比 CAN_L 高,分别为 3.5V 和 1.5V,电位差为 2V。隐形电平表示逻辑“1”,此时 CAN_H 和 CAN_L 电压都为 2.5V 左右,电位差为 0V。CAN 总线就通过显性和隐形电平的变化来将具体的数据发送出去,如下图所示:

 CAN通信模型是什么样的?

 如图所示:

        CAN 能够使用多种物理介质,例如双绞线、光纤等。最常用的就是双绞线。信号使用差分电压传送,两条信号线被称为“CAN_H”和“CAN_L”,途中所有的 CAN 节点单元都采用 CAN_H 和 CAN_L 这两根线连接在一起,CAN_H 接 CAN_H、CAN_L接 CAN_L,CAN 总线两端要各接一个 120Ω的端接电阻,用于匹配总线阻抗,吸收信号反射及回拨,提高数据通信的抗干扰能力以及可靠性。

数据帧是使用最多的帧类型,这里重点介绍一下数据帧,数据帧结构如下图所示:

 图中 D 表示显性电平 0、R 表示隐性电平 1,D/R 表示显性或隐性,也就是 0 或 1,我们来简单分析一下数据帧的这 7 个段。

数据帧由 7 个段构成:
(1) 、帧起始  ——表示数据帧开始的段。
(2)、 仲裁段  ——表示该帧优先级的段。(判断id来仲裁优先级)
(3) 、控制段  ——表示数据的字节数及保留位的段。
(4) 、数据段  ——数据的内容,可发送 0~8 个字节的数据。
(5) 、CRC 段 ——检查帧的传输错误的段。
(6) 、ACK 段  ——表示确认正常接收的段。
(7) 、帧结束   ——表示数据帧结束的段。

到这想必大家都了解CAN了,那么我么们来个小例子吧,在开发板linux开发板,6ull上测试的:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
int main(void)
{
    struct ifreq ifr = {0};
    struct sockaddr_can can_addr = {0};
    struct can_frame frame = {0};
    int sockfd = -1;
    int ret;
    /* 打开套接字 */
    sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if(0 > sockfd) {
    perror("socket error");
    exit(EXIT_FAILURE);
}
/* 指定 can0 设备 */
strcpy(ifr.ifr_name, "can0");
ioctl(sockfd, SIOCGIFINDEX, &ifr);
can_addr.can_family = AF_CAN;
can_addr.can_ifindex = ifr.ifr_ifindex;
/* 将 can0 与套接字进行绑定 */
ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
if (0 > ret)
 {
    perror("bind error");
    close(sockfd);
    exit(EXIT_FAILURE);

}
/* 设置过滤规则:不接受任何报文、仅发送数据 */
setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
/* 发送数据 */
frame.data[0] = 0xA0;
frame.data[1] = 0xB0;
frame.data[2] = 0xC0;
frame.data[3] = 0xD0;
frame.data[4] = 0xE0;
frame.data[5] = 0xF0;
frame.can_dlc = 6; //一次发送 6 个字节数据
frame.can_id = 0x123;//帧 ID 为 0x123,标准帧
for ( ; ; )
{
    ret = write(sockfd, &frame, sizeof(frame)); //发送数据
    if(sizeof(frame) != ret) 
    { //如果 ret 不等于帧长度,就说明发送失败
        perror("write error");
        goto out;
    }
    sleep(1); //一秒钟发送一次
}
out:
/* 关闭套接字 */
close(sockfd);
exit(EXIT_SUCCESS);
}

交叉编译运行后的结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值