精华内容
下载资源
问答
  • 前段时间项目用到can总线,用的是树莓派,于是写了一个mcp2515的驱动。不知道为啥wiringPi集成的spi函数不能实现,于是就用了bcm2835的spi函数,实测波形稳定,效果不错。
  • 树莓派3b上完成基于MCP2515和BCM2835的SPI转CAN,实现树莓派与外界的CAN通信。代码可以直接调用CAN_Send_Buffer(unsigned char *CAN_TX_Buf,unsigned char len, unsigned char msgID)和CAN_Receive_Buffer(unsigned ...
  • 树莓派+MCP2515 实现 CAN 通信

    千次阅读 2019-12-13 10:11:35
    项目原件控制由 Adruino 转 CAN , 基础配置过程...任何带SPI口的设备都可以使用MCP2515进行通信 软件 备注 can-utils apt / can 口测试 python-can py2 py3 / python脚本 can 收发 1 连线 按照MCP251...

    项目原件控制由 AdruinoCAN , 基础配置过程。
    在这里插入图片描述

    硬件数量
    树莓派32
    杜邦线6 * 2
    MCP25152

    任何带SPI口的设备都可以使用MCP2515进行通信



    软件备注
    can-utilsapt / can 口测试
    python-canpy2 py3 / python脚本 can 收发

    1 连线

    连线细节按照MCP2515引脚连接后,有如图两点需要注意
    1 . CAN 总线可以直接用 1 所示连接
    2. 1对1 CAN 网测试需要把 2 所示穿起来才可以通信(CAN 网络需两个 120Ω总线电阻)

    2 配置CAN

    2.1 打开SPI

    sudo raspi-config
    

    Interfacing Options - SPI
    打开SPI

    2.2 配置CAN

    sudo vim /boot/config.txt
    

    dtparam=spi=on 下一行添加

    dtoverlay=mcp2515-can0,oscillator=8000000,interrupt=25,spimaxfrequency=1000000 
    
    sudo reboot 
    
    dmesg | grep -i '\(can\|spi\)'
    

    会出现如下结果
    Output
    配置网络can口 ( 仅有一个can口 )

    sudo ip link set can0 type can bitrate 500000 restart-ms 100
    sudo ifconfig can0 up
    

    添加启动项

    sudo vim /etc/network/interfaces
    

    添加

    allow-hotplug can0
    iface can0 can static
        bitrate 500000
        restart-ms 100
    

    3 测试

    3.1 使用 can-utils

    sudo apt install can-utils
    

    发送

    cansend can0 111#00000000
    

    接收

    candump can0
    

    3.2 使用 python-can

    pip3 install python-can
    
    import can 
    
    bus = can.interface.Bus(bustype='socketcan', channel='can0', bitrate=500000)
    
    msg_snd = can.Message(arbitration_id=0xc0ffee,
                          data=[0, 25, 0, 1, 3, 1, 4, 1],
                          is_extended_id=True)
                          
    # send message
    try:
            bus.send(msg_snd)
            print("Message sent on {}".format(bus.channel_info))
    except can.CanError:
            print("Message NOT sent")
    
    
    # recieve message
    msg_recv = bus.recv(0.0)
    
    展开全文
  • 树莓派3b(ubuntu16.04)使用MCP2515

    千次阅读 2016-07-18 22:18:12
    1、首先在系统上添加spi驱动(请参考以前的教程) 2、安装bcm2835 C library 树莓派3b的引脚图: 这里选用11脚作为CS信号。...4、编写MCP2515.c /******************************************

    1、首先在系统上添加spi驱动(请参考以前的教程)
    2、安装bcm2835 C library
    树莓派3b的引脚图:
    这里写图片描述
    这里选用11脚作为CS信号。
    3、下载bcm2835-1.50.tar.gz文件
    解压后在examples\spi文件夹里有spi的使用历程
    4、编写MCP2515.c
    /*********************************************************************
    * 函数名 : SPI_ReadByte
    * 描述 : 通过SPI读取一个字节数据
    * 输入 : 无
    * 输出 : 无
    * 返回值 : rByte(读取到的一个字节数据)
    * 说明 : 无
    *********************************************************************/
    unsigned char SPI_ReadByte(void)
    {
    return bcm2835_spi_transfer(0xFF);
    }

    /*********************************************************************
    * 函数名 : SPI_SendByte
    * 描述 : SPI发送一个字节数据
    * 输入 : dt:待发送的数据
    * 输出 : 无
    * 返回值 : 无
    * 说明 : 无
    *********************************************************************/
    void SPI_SendByte(unsigned char dt)
    {
    bcm2835_spi_transfer(dt);
    }

    /*********************************************************************
    * 函数名 : MCP2515_WriteByte
    * 描述 : 通过SPI向MCP2515指定地址寄存器写1个字节数据
    * 输入 : addr:MCP2515寄存器地址,dat:待写入的数据
    * 输出 : 无
    * 返回值 : 无
    * 说明 : 无
    *********************************************************************/
    void MCP2515_WriteByte(unsigned char addr,unsigned char dat)
    {
    bcm2835_gpio_write(MCP2515_CS,LOW);//置MCP2515的CS为低电平
    SPI_SendByte(CAN_WRITE); //发送写命令
    SPI_SendByte(addr); //发送地址
    SPI_SendByte(dat); //写入数据
    bcm2835_gpio_write(MCP2515_CS,HIGH);//置MCP2515的CS为高电平
    }

    /*********************************************************************
    * 函数名 : MCP2515_ReadByte
    * 描述 : 通过SPI从MCP2515指定地址寄器读1个字节数据
    * 输入 : addr:MCP2515寄存器地址
    * 输出 : 无
    * 返回值 : rByte:读取到寄存器的1个字节数据
    * 说明 : 无
    *********************************************************************/
    unsigned char MCP2515_ReadByte(unsigned char addr)
    {
    unsigned char rByte;

    bcm2835_gpio_write(MCP2515_CS,LOW);             //置MCP2515的CS为低电平
    SPI_SendByte(CAN_READ);     //发送读命令
    SPI_SendByte(addr);         //发送地址
    rByte=SPI_ReadByte();       //读取数据
    bcm2835_gpio_write(MCP2515_CS,HIGH);                //置MCP2515的CS为高电平
    return rByte;               //返回读到的一个字节数据
    

    }

    /*********************************************************************
    * 函数名 : MCP2515_Reset
    * 描述 : 发送复位指令软件复位MCP2515
    * 输入 : 无
    * 输出 : 无
    * 返回值 : 无
    * 说明 : 将内部寄存器复位为缺省状态,并将器件设定为配置模式
    *********************************************************************/
    void MCP2515_Reset(void)
    {
    bcm2835_gpio_write(MCP2515_CS,LOW); //置MCP2515的CS为低电平
    SPI_SendByte(CAN_RESET); //发送寄存器复位命令
    bcm2835_gpio_write(MCP2515_CS,HIGH); //置MCP2515的CS为高电平
    }

    /*********************************************************************
    * 函数名 : MCP2515_Init
    * 描述 : MCP2515初始化配置
    * 输入 : 无
    * 输出 : 无
    * 返回值 : 无
    * 说明 : 初始化包括:软件复位、工作波特率设置、标识符相关配置等。
    *********************************************************************/
    int MCP2515_Init(void)
    {
    unsigned char temp=0;

    if (!bcm2835_init())
    {
      printf("bcm2835_init failed. Are you running as root??\n");
      return 1;
    }
    
    if (!bcm2835_spi_begin())
    {
      printf("bcm2835_spi_begin failedg. Are you running as root??\n");
      return 1;
    }
    bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);      // The default
    bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);                   // The default 上跳沿或下跳沿的选择
    bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536); // The default  时钟速率
    bcm2835_spi_chipSelect(BCM2835_SPI_CS0);                      // The default  片选信号
    bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);      // the default
    
    bcm2835_gpio_fsel(MCP2515_CS, BCM2835_GPIO_FSEL_OUTP);
    
    MCP2515_Reset();    //发送复位指令软件复位MCP2515
    bcm2835_delay(5);
    
    //设置波特率为125Kbps
    //set CNF1,SJW=00,长度为1TQ,BRP=49,TQ=[2*(BRP+1)]/Fsoc=2*50/8M=12.5us
    MCP2515_WriteByte(CNF1,CAN_125Kbps);
    //set CNF2,SAM=0,在采样点对总线进行一次采样,PHSEG1=(2+1)TQ=3TQ,PRSEG=(0+1)TQ=1TQ
    MCP2515_WriteByte(CNF2,0x80|PHSEG1_3TQ|PRSEG_1TQ);
    //set CNF3,PHSEG2=(2+1)TQ=3TQ,同时当CANCTRL.CLKEN=1时设定CLKOUT引脚为时间输出使能位
    MCP2515_WriteByte(CNF3,PHSEG2_3TQ);
    
    MCP2515_WriteByte(TXB0SIDH,0xFF);//发送缓冲器0标准标识符高位
    MCP2515_WriteByte(TXB0SIDL,0xE0);//发送缓冲器0标准标识符低位
    
    MCP2515_WriteByte(RXB0SIDH,0x00);//清空接收缓冲器0的标准标识符高位
    MCP2515_WriteByte(RXB0SIDL,0x00);//清空接收缓冲器0的标准标识符低位
    MCP2515_WriteByte(RXB0CTRL,0x20);//仅仅接收标准标识符的有效信息
    MCP2515_WriteByte(RXB0DLC,DLC_8);//设置接收数据的长度为8个字节
    
    MCP2515_WriteByte(RXF0SIDH,0xFF);//配置验收滤波寄存器n标准标识符高位
    MCP2515_WriteByte(RXF0SIDL,0xE0);//配置验收滤波寄存器n标准标识符低位
    MCP2515_WriteByte(RXM0SIDH,0xFF);//配置验收屏蔽寄存器n标准标识符高位
    MCP2515_WriteByte(RXM0SIDL,0xE0);//配置验收屏蔽寄存器n标准标识符低位
    
    MCP2515_WriteByte(CANINTF,0x00);//清空CAN中断标志寄存器的所有位(必须由MCU清空)
    MCP2515_WriteByte(CANINTE,0x01);//配置CAN中断使能寄存器的接收缓冲器0满中断使能,其它位禁止中断
    
    MCP2515_WriteByte(CANCTRL,REQOP_LOOPBACK|CLKOUT_ENABLED);//将MCP2515设置为环回模式,退出配置模式
    
    temp=MCP2515_ReadByte(CANSTAT);//读取CAN状态寄存器的值
    if(OPMODE_NORMAL!=(temp&&0xE0))//判断MCP2515是否已经进入环回模式
    {
        MCP2515_WriteByte(CANCTRL,REQOP_LOOPBACK|CLKOUT_ENABLED);//再次将MCP2515设置为环回模式,退出配置模式
    }
    return 0;
    

    }

    void MCP2515_End(void)
    {
    bcm2835_spi_end();
    bcm2835_close();
    }
    /*********************************************************************
    * 函数名 : CAN_Send_Buffer
    * 描述 : CAN发送指定长度的数据
    * 输入 : *CAN_TX_Buf(待发送数据缓冲区指针),len(待发送数据长度)
    * 输出 : 无
    * 返回值 : 无
    * 说明 : 无
    *********************************************************************/
    void CAN_Send_Buffer(unsigned char *CAN_TX_Buf,unsigned char len)
    {
    unsigned char j,dly,count;

    count=0;
    while(count<len)
    {
        dly=0;
        while((MCP2515_ReadByte(TXB0CTRL)&0x08) && (dly<50))//快速读某些状态指令,等待TXREQ标志清零
        {
            bcm2835_delay(1);//通过软件延时约nms(不准确)
            dly++;
        }
    
        for(j=0;j<8;)
        {
            MCP2515_WriteByte(TXB0D0+j,CAN_TX_Buf[count++]);//将待发送的数据写入发送缓冲寄存器
            j++;
            if(count>=len) break;
        }
        MCP2515_WriteByte(TXB0DLC,j);//将本帧待发送的数据长度写入发送缓冲器0的发送长度寄存器
        bcm2835_gpio_write(MCP2515_CS,LOW);
        MCP2515_WriteByte(TXB0CTRL,0x08);//请求发送报文
        bcm2835_gpio_write(MCP2515_CS,HIGH);
    }
    

    }

    /*********************************************************************
    * 函数名 : CAN_Receive_Buffer
    * 描述 : CAN接收一帧数据
    * 输入 : *CAN_TX_Buf(待接收数据缓冲区指针)
    * 输出 : 无
    * 返回值 : len(接收到数据的长度,0~8字节)
    * 说明 : 无
    *********************************************************************/
    unsigned char CAN_Receive_Buffer(unsigned char *CAN_RX_Buf)
    {
    unsigned char i=0,len=0,temp=0;

    temp = MCP2515_ReadByte(CANINTF);
    if(temp & 0x01)
    {
        len=MCP2515_ReadByte(RXB0DLC);//读取接收缓冲器0接收到的数据长度(0~8个字节)
        while(i<len)
        {   
            CAN_RX_Buf[i]=MCP2515_ReadByte(RXB0D0+i);//把CAN接收到的数据放入指定缓冲区
            i++;
        }
    }
    MCP2515_WriteByte(CANINTF,0);//清除中断标志位(中断标志寄存器必须由MCU清零)
    return len;
    

    }

    5、测试程序test.c
    int main(int argc, char const *argv[])
    {
    unsigned char bufTx[8] = “87654321”;
    unsigned char len = 8;
    unsigned char bufRx[8] ;
    if(1 == MCP2515_Init()){
    return 1;
    }

    CAN_Send_Buffer(bufTx,len);
    
    len = CAN_Receive_Buffer(bufRx);
    
    printf("len = %d  bufRx=%s\n",len,bufRx);
    
    return 0;
    

    }

    6、编写makefile
    OBJECTS = test.o MCP2515.o
    LIBS = bcm2835

    all : (OBJECTS)gccotest (OBJECTS) -l$(LIBS)

    clean :
    rm *.o
    7、make all 编译生产test可执行文件
    8、sudo ./test
    这里写图片描述
    这里使用的是mcp2515的回环模式
    其他模式可以参考手册进行设置。

    展开全文
  • 检测MCP2515是否被正确挂载3. CAN 通讯设置及程序开发3.1. 系统命令3.2. c语言调用socket接口进行开发3.3. 实际效果 1. 楔 在上篇文章树莓派GPIO和PWM控制教程中,笔者详细介绍了如何使用树莓进行普通IO控制模拟,...

    1. 楔

    在上篇文章树莓派GPIO和PWM控制教程中,笔者详细介绍了如何使用树莓进行普通IO控制模拟,以及PWM 波形发送等操作,同时还提到了汽车电子常见的CAN 通讯也能够使用树莓派完成,本文针对此进行详细说明。

    使用硬件为树莓派3b+, MCP2515 spiCAN模块 ,总成本控制在300 元以内。使用树莓派4b也可以,不过近期的4b价格离谱,而且仅仅can和io的测试,3b+性能完全够用。

    操作系统使用ubuntu server ,如使用Raspberry Pi OS 也可以,本教程也可适用。需要注意的是,不能魔法上网的同学需要首先进行操作系统换源,以及python3 的换源。而其中ubuntu server arm 的系统不能够按照常用的清华源教程替换,需要使用后缀为-ports的源,笔者使用的源如下:

    • /etc/apt/sources.list

      # 默认注释了源码仓库,如有需要可自行取消注释
      deb https://mirrors.ustc.edu.cn/ubuntu-ports/ focal main restricted universe multiverse
      # deb-src https://mirrors.ustc.edu.cn/ubuntu-ports/ focal main main restricted universe multiverse
      deb https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-updates main restricted universe multiverse
      # deb-src https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-updates main restricted universe multiverse
      deb https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-backports main restricted universe multiverse
      # deb-src https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-backports main restricted universe multiverse
      deb https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-security main restricted universe multiverse
      # deb-src https://mirrors.ustc.edu.cn/ubuntu-ports/ focal-security main restricted universe multiverse
      

    2. 硬件连接和环境准备

    连接MCP2515和树莓派spi接口,并在操作系统中开启spi,整个的运行原理就是让MCP2515的CAN 通讯作为网络通讯接口,挂接到socketCAN 上,使用系统驱动spi,无需手工编写spi驱动以及can wrapper部分。针对socketCAN,网上有很多优秀的开源工具可以使用,笔者这里使用的是cantools ,可以使用dbc进行报文格式解析。

    2.1. 硬件连接

    RPi Pin    RPi Label     CAN Module
    02---------5V------------VCC
    06---------GND-----------GND
    19---------GPIO10--------MOSI (SI)
    21---------GPIO9---------MISO (SO)
    22---------GPIO25--------INT
    23---------GPIO11--------SCK
    24---------GPIO8---------CS
    

    2.2. 环境准备

    • 安装socket can工具以及cantools工具

      sudo apt install can-utils
      pip3 install cantools
      
    • 使能树莓派SPI并加载MCP2515内核驱动

      针对Ubuntu server 操作系统,在/boot/firmware/usercfg.txt文件后添加如下内容,若操作系统为Raspberry Pi OS,则在/boot/config.txt文件后添加如下内容:

      dtparam=spi=on
      dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25
      dtoverlay=spi1-1cs
      
    • 重启 sudo reboot -h now

    2.3. 检测MCP2515是否被正确挂载

    输入sudo ifconfig -a指令可以看到已经挂载了网络通讯卡CAN0,如没有ifconfig,则使用sudo apt install net-tools进行安装

    ubuntu@ubuntu:~$ sudo ifconfig -a
    can0: flags=193<UP,RUNNING,NOARP>  mtu 16
            unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 10  (UNSPEC)
            RX packets 9343435  bytes 74747480 (74.7 MB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 8  bytes 64 (64.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    eth0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
            ether b8:27:eb:c2:61:84  txqueuelen 1000  (Ethernet)
            RX packets 0  bytes 0 (0.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    

    输入 sudo ip -s -d link show can0 查看can0 通讯是否进入ready状态。

    ubuntu@ubuntu:~$ sudo ip -s -d link show can0
    3: can0: <NOARP,ECHO> mtu 16 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 10
        link/can  promiscuity 0 minmtu 0 maxmtu 0
        can state STOPPED restart-ms 0
              bitrate 1000000 sample-point 0.750
              tq 125 prop-seg 2 phase-seg1 3 phase-seg2 2 sjw 1
              mcp251x: tseg1 3..16 tseg2 2..8 sjw 1..4 brp 1..64 brp-inc 1
              clock 8000000
              re-started bus-errors arbit-lost error-warn error-pass bus-off
              0          0          0          0          0          0         numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
        RX: bytes  packets  errors  dropped overrun mcast
        74955120   9369390  0       0       0       0
        TX: bytes  packets  errors  dropped carrier collsns
        64         8        0       0       0       0
    

    3. CAN 通讯设置及程序开发

    如上步骤如果已经完成,则可进行相关CAN 通讯开发,使用python和c都可以,因为系统支持命令行进行报文发送读取及设定,所以python可以简单的调用系统命令。c的话不建议调用系统命令,而是使用socket接口进行编程。

    需注意,由于硬件限制,此方案can通讯波特率最高仅支持500Kbps

    3.1. 系统命令

    • 关闭can0

      sudo ip link set can0 down

    • 设置波特率 500K ,需注意bitrate 需要除2才是常规的通讯波特率

      sudo ip link set can0 type can bitrate 1000000

    • 开启can0

      sudo ip link set can0 up

    • 查看状态

      sudo ip -s -d link show can0

    • 接收报文命令

      candump any,0:0,#FFFFFFFF

    • 联合 cantools 使用dbc文件进行报文解码

      candump can0 | cantools decode temp.dbc

    • 发送报文命令

      cansend can0 123#1122334455667788

    • 设置回环 波特率 250K ,用于测试can通路,在没有其它硬件连接测试的情况下,可以设定成回环,自发自收

      sudo ip link set can0 type can bitrate 500000 loopback on

    3.2. c语言调用socket接口进行开发

    /**
     *-----------------------------------------------------------------------------
     * @file can_control.c
     * @brief 
     * @author Tomato
     * @version 0.1
     * @date 2021-07-22
     * @note [change history] 
     * 
     * @copyright NAAAAA
     *-----------------------------------------------------------------------------
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <net/if.h>
    #include <sys/ioctl.h>
    #include <sys/socket.h>
    #include <linux/can.h>
    #include <linux/can/raw.h>
    #define command "ip link set can0 type can bitrate 1000000"//将CAN0波特率设置为500K
    #define up "ifconfig can0 up"//打开CAN0
    #define down "ifconfig can0 down"//关闭CAN0
    
    int can_init()
    {
        //关闭CAN设备,设置波特率后,重新打开CAN设备
        system(down);
        system(command);
        system(up);
        return 0;
    }
    
    int can_send(can_frame frame)
    {
        int s, nbytes;
        struct sockaddr_can addr;
        struct ifreq ifr;
        //创建套接字
        s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
        strcpy(ifr.ifr_name, "can0" );
        //指定 can0 设备
        ioctl(s, SIOCGIFINDEX, &ifr); 
        addr.can_family = AF_CAN;
        addr.can_ifindex = ifr.ifr_ifindex;
        //将套接字与 can0 绑定
        bind(s, (struct sockaddr *)&addr, sizeof(addr));
        //发送 frame[0]
        nbytes = write(s, &frame, sizeof(frame));
        if(nbytes != sizeof(frame))
        {
            printf("Send Error frame[0]\n!");
        }
        close(s);
        return 0;
    }
    
    int can_receive(struct can_frame * r_frame,unsigned int filter_id)
    {
        int s, nbytes = 0;
        struct sockaddr_can addr;
        struct ifreq ifr;
        struct can_frame frame;
        struct can_filter rfilter;
    
        // Initial fram
        memset(&frame,0,sizeof(can_frame));
        //创建套接字
        s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
        strcpy(ifr.ifr_name, "can0" );
        //指定 can0 设备
        ioctl(s, SIOCGIFINDEX, &ifr); 
        addr.can_family = AF_CAN;
        addr.can_ifindex = ifr.ifr_ifindex;
        //将套接字与 can0 绑定
        bind(s, (struct sockaddr *)&addr, sizeof(addr));
        //设置过滤规则,取消当前注释为禁用过滤规则,即不接收所有报文,
        // 不设置此项(即如当前代码被注释)为接收所有ID的报文。
        if (filter_id != 0)
        {
            rfilter.can_id   = 0x123;
            // CAN_EFF_MASK | CAN_SFF_MASK
            rfilter.can_mask = CAN_SFF_MASK;
            setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
        }
        while (nbytes == 0)
        {
            //接收总线上的报文保存在frame中
            nbytes = read(s, &frame, sizeof(frame));
        }
        *r_frame = frame;
    #ifdef MSG_DEBUG
        printf("the nbytes:%d\n", nbytes);
        printf("length:%d", sizeof(frame));
        printf("ID=0x%X DLC=%d\n", frame.can_id, frame.can_dlc);
        printf("data0=0x%02x\n",frame.data[0]);
        printf("data1=0x%02x\n",frame.data[1]);
        printf("data2=0x%02x\n",frame.data[2]);
        printf("data3=0x%02x\n",frame.data[3]);
        printf("data4=0x%02x\n",frame.data[4]);
        printf("data5=0x%02x\n",frame.data[5]);
        printf("data6=0x%02x\n",frame.data[6]);
        printf("data7=0x%02x\n",frame.data[7]);
    #endif
        return 0;
    }
    
    int led_ctl_on(void)
    {
        struct can_frame frame;
        memset(&frame, 0, sizeof(can_frame));
        frame.can_id = 0x101;
        frame.can_dlc = 8;
        frame.data[0] = 1;
        can_send(frame);
        return 0;
    }
    
    int led_ctl_off(void)
    {
        struct can_frame frame;
        memset(&frame, 0, sizeof(can_frame));
        frame.can_id = 0x101;
        frame.can_dlc = 8;
        frame.data[0] = 2;
        can_send(frame);
        return 0;
    }
    
    float can_get_vol(void)
    {
        float vol_vle = 0;
        struct can_frame frame;
        memset(&frame, 0, sizeof(can_frame));
        // wait until can frame 100 received
        can_receive(&frame,0);
        printf("###############################\n");
        printf("length:%d", sizeof(frame));
        printf("ID=0x%X DLC=%d\n", frame.can_id, frame.can_dlc);
        printf("data0=0x%02x\n",frame.data[0]);
        printf("data1=0x%02x\n",frame.data[1]);
        printf("data2=0x%02x\n",frame.data[2]);
        printf("data3=0x%02x\n",frame.data[3]);
        printf("data4=0x%02x\n",frame.data[4]);
        printf("data5=0x%02x\n",frame.data[5]);
        printf("data6=0x%02x\n",frame.data[6]);
        printf("data7=0x%02x\n",frame.data[7]);
    
        vol_vle = (float)frame.data[0]/50;
        return vol_vle;
    }
    
    int main(int argc, char* argv[])
    {
        char control_str[15]; 
        float vol_val = 0;
    
        if (argc < 2) {
            printf("can_control service_type\n"
                "    example: ./can_control led_off/led_on/get_vol\n"
                );
            return 0;
        }
        strcpy(control_str,argv[1]);
    
        // debug
        printf("Argc : %d\n",argc);
        printf("Argv : %s\n , %s\n",argv[0], argv[1]);
    
        // can_init();
        if (strcmp(control_str,"led_off")==0)
        {
            led_ctl_off();
        }
        else if (strcmp(control_str,"led_on")==0)
        {
            led_ctl_on();
        }
        else if (strcmp(control_str,"get_vol")==0)
        {
            vol_val = can_get_vol();
            printf("Voltage is : %5.2f V\n", vol_val);
        }
        else
        {
            /* Do nothing */
        }
        return 0;
    }
    

    3.3. 实际效果

    展开全文
  • 本文介绍如何在树莓派上配置CAN总线模块MCP2515,并使用基于SocketCAN的工具Can-utils实现CAN消息的收发。 MCP2515概述: Microchip 的MCP2515 是一款独立控制器局域网络(Controller Area Network, CAN)协议...

    本文介绍如何在树莓派上配置CAN总线模块MCP2515,并使用基于SocketCAN的工具Can-utils实现CAN消息的收发。

    MCP2515概述:

    Microchip 的MCP2515 是一款独立控制器局域网络(Controller Area Network, CAN)协议控制器,完全支持CAN V2.0B 技术规范。
    该器件主要由三个部分组成:
    1. CAN 模块,包括CAN 协议引擎、验收滤波寄存
    器、验收屏蔽寄存器、发送和接收缓冲器。
    2. 用于配置该器件及其运行的控制逻辑和寄存器。
    3. SPI 协议模块。

    MCP2515芯片结构框图

    图片和芯片概述引自MCP2515参考手册

    获取硬件

    淘宝上有许多商家在售MCP2515 SPI转CAN的控制器通信模块,并且这些模块大都集成了CAN收发器。这些模块可能看起来样式不同,但是基本的针脚接法是一致的。

    模块结构图

    模块电路图

    图片引自某淘宝卖家

    接线

    RPi Pin    RPi Label     CAN Module
    02---------5V------------VCC
    06---------GND-----------GND
    19---------GPIO10--------MOSI (SI)
    21---------GPIO9---------MISO (SO)
    22---------GPIO25--------INT
    23---------GPIO11--------SCK
    24---------GPIO8---------CS

    树莓派引脚图,引自pinout.xyz

    使能树莓派SPI并加载MCP2515内核驱动

    为了激活MCP2515的驱动,需要在文件/boot/config.txt加如下几行:

    dtparam=spi=on
    dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25
    dtoverlay=spi1-1cs

    如果内核是4.4.x之前的版本,需要修改最后一行:

    dtparam=spi=on
    dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25
    dtoverlay=spi-bcm2835-overlay

    可以通过uname -a查看树莓派内核:

    MCP2515 device tree overlay的具体参数说明请参考/boot/overlays/README

    Name:   mcp2515-can0
    Info:   Configures the MCP2515 CAN controller on spi0.0
    Load:   dtoverlay=mcp2515-can0,<param>=<val>
    Params: oscillator              Clock frequency for the CAN controller (Hz)
    
            spimaxfrequency         Maximum SPI frequence (Hz)
    
            interrupt               GPIO for interrupt signa

    修改配置后重启树莓派查看MCP2515是否加载成功:

    pi@piv2:~ $ ls /sys/bus/spi/devices/spi0.0/net
    can0

    看到can0说明已经加载成功

    启动CAN接口

    使用ip link命令启动can接口:

    pi@raspberrypi:~ $ sudo ip link set can0 up type can bitrate 500000 loopback on

    bitrate 500000:比特率设置为500k,在这里比特率是波特率的两倍,所以波特率为250k

    loopback on : 将MCP2515的工作模式设置为环回模式

    10.4 环回模式
    环回模式允许器件内部的发送缓冲器和接收缓冲器之间进行报文的自发自收,而无需通过CAN 总线。此模式可用于系统开发和测试。环回模式下,确认位ACK 无效,器件接收自己发送的报文就象在接收来自其他节点的报文。环回模式是一种安静模式,即器件在此模式下不会发送任何报文(包括错误标志或确认信号)。该模式下TXCAN 引脚处于隐性状态。

    引自MCP2515中文手册。

    启动成功后可以通过ifconfig can查看can0信息:

    pi@raspberrypi:~ $ ifconfig can0
    can0: flags=193<UP,RUNNING,NOARP>  mtu 16
            unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 10  (UNSPEC)
            RX packets 23  bytes 52 (52.0 B)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 23  bytes 52 (52.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

    如果需要修改参数配置,需要先关闭can接口:

    pi@raspberrypi:~ $ sudo ip link set can0 down

    可以通过help查看支持的配置参数:

    pi@raspberrypi:~ $ ip link set can0 type can help
    Usage: ip link set DEVICE type can
            [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] |
            [ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1
              phase-seg2 PHASE-SEG2 [ sjw SJW ] ]
    
            [ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] |
            [ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1
              dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ]
    
            [ loopback { on | off } ]
            [ listen-only { on | off } ]
            [ triple-sampling { on | off } ]
            [ one-shot { on | off } ]
            [ berr-reporting { on | off } ]
            [ fd { on | off } ]
            [ fd-non-iso { on | off } ]
            [ presume-ack { on | off } ]
    
            [ restart-ms TIME-MS ]
            [ restart ]
    
            [ termination { 0..65535 } ]
    
            Where: BITRATE  := { 1..1000000 }
                      SAMPLE-POINT  := { 0.000..0.999 }
                      TQ            := { NUMBER }
                      PROP-SEG      := { 1..8 }
                      PHASE-SEG1    := { 1..8 }
                      PHASE-SEG2    := { 1..8 }
                      SJW           := { 1..4 }
                      RESTART-MS    := { 0 | NUMBER }

    如果想要开机自动挂载CAN接口,在/etc/network/interfaces添加:

    auto can0
    iface can0 can static
        bitrate 500000 

    测试收发CAN消息

    安装 SocketCAN工具 Can-utils

    pi@raspberrypi:~ $ sudo apt-get install can-utils

    使用cansend发送单条CAN消息:

    pi@raspberrypi:~ $ cansend can0 123#AABBCCDDEEFF

    使用cangen发送随机CAN消息:

    pi@raspberrypi:~ $ candump can0

    使用Python库收发CAN消息

    python-can :为不同的can控制器硬件设备提供通用的接口和一系列的消息收发工具。

    cantools : CAN数据库解析,CAN消息、诊断DID编解码,candump输出解码。

    使用cantools对candump输出解码:

    0x123在数据库DBC中的定义:

    CAN相关文章:

    DBC文件格式解析

    CANoe精选教程 | 自动化测试功能-Test Module/Test Unit

    不同格式CAN 数据库(DBC、Excel、arxml等)相互转化

    展开全文
  • wowo最近作项目用的CM4模块,其中有一个需求是要求挂接MCP2515模块到SPI1口(GPIO19,20,21)。但发现在/boot/overlays/README 中介绍如下 Name: mcp2515-can0 Info: Configures the MCP2515 CAN controller on ...
  • 树莓派3 (ubuntu)mcp2515驱动

    千次阅读 2016-08-25 22:30:44
    1、在mcp251x.c文件中添加 static struct mcp251x_platform_data mcp251x_info ={ .oscillator_frequency = 8000000, } static struct spi_board_info spi_board_info[] = { ... .modalias = “mcp2515”,
  • 树莓派3b(ubuntu16.04)安装mcp2515驱动

    千次阅读 2016-07-23 16:09:35
    1、在/lib/modules/4.1.19xx/kernel/drivers/net/can下这道can的驱动文件can-dev.ko 然后sudo insmod can-dev.ko 这个文件是mcp251x.ko的依赖文件 2、在spi目录下找到mcp251x.ko文件 然后insmod即可
  • 树莓派spi-3.2是树莓派spi文件,可以用于驱动mcp2515
  • 树莓派利用MCP2515实现SPI转CAN通信(C) 1、主要硬件 树莓派3b、ubuntu16.04、RS485_CAN_HAT、CAN分析仪 2、主要实现方法 之前使用PYTHON库工具直接实现了CAN的通信,但项目上层使用C++,也因为不知道如何去...
  • Microchip Technology’s MCP2515 is a stand-alone Controller Area Network (CAN) controller that implements the CAN specification, Version 2.0B. It is capable of transmitting and receiving both standard...
  • AT91与MCP2515实现CAN(中断方式自收发)
  • 树莓派配置文件/boot/config.txt中配置 <p style="text-align:center"><img alt="" src="https://img-ask.csdnimg.cn/upload/1622873279487.jpg" /></p> 然后在/sys/bus/spi/devices中可以看到配置spi1.2 ...
  • 使用MCP2515和TJA1050构成CAN节点通信

    千次阅读 2019-12-19 18:23:11
    使用MCP2515以及TJA1050构成CAN节点通信 使用can收发器TJA1050芯片和CAN协议控制器MCP2515构成CAN节点,这里选用PIC16F877A型号单片机作为外部输入连接装置。此次设计仅为构成节点的通信can通信节点,具体功能实现...
  •  FS2416平台使用Linux2.6.39的内核,内核中为MCP2515提供了Socket CAN驱动程序,我们只需为MCP2515芯片配置内核选项就可以使用Socket编程的方式使用MCP2515 CAN总线。 5.1Socket CAN介绍  Socket CAN是在...
  •   现象:CAN总线在线上设备热插拔或长时间运行后出现总线异常情况,... 经过观察,发现出现只能发送不能接收的情况是由于没有调用中断服务造成的,而在整个驱动中并没有其它地方会异常释放中断,所以断定为mcp25...
  • 基于MCP2515的CAN模块资料,内有调试通过的程序,配上CAN模块即可通信。
  • 树莓派AD mcp3008

    千次阅读 2016-11-04 16:55:00
    http://www.raspberrypi-spy.co.uk/2013/10/analogue-sensors-on-the-raspberry-pi-using-an-mcp3008/ #!/usr/bin/python import spidev import time import os # Open SPI bus spi = spidev.SpiDev...
  • 该库为MCP4725提供了一个类,它依赖于ncd-red-comm库进行...树莓派笔记 如果打算在Raspberry Pi上使用此功能,则必须确保: 启用了I2C(关于此问题,有很多教程根据Pi版本而有所不同。) Node,NPM和Node-red应该更新
  • mk_arcade_joystick_rpi, 在GPIO和MCP23017上,用于街机游戏杆的树莓派 内核模块 mk_arcade_joystick_rpi树莓派 GPIO游戏杆驱动程序mk_arcade_joystick_rpi完全集成在 recalbox 发行版中: 请参见 ...
  • 树莓派下使用I2C读取mpu9250,获得欧拉角YAW,PITCH,ROLL,并输出,稳定
  • 在拼装时,舵机的力度不行,改用碰撞机带减速齿轮的电机做方向盘的转向,所以用到 MCP3008 模数转换,来监测方向盘角度 (如果用舵机控制方向盘,此篇忽略) 接线图纸: CH0 上接个10Kn到20 这时要开启 SPI 功能· ...
  • 基于树莓派3的CAN总线编程

    万次阅读 热门讨论 2016-09-08 10:16:13
    简介树莓派3使用Python控制SPI接口的MCP2515 CAN模块。实现命令行控制CAN的收发。
  • MCP3208 在2013年一位日本大佬的代码: https://seinzumtode.hatenadiary.jp/entry/20130918/1379501130 针对MQ-X这类气体模块,用MQ-2去做实验(这个模块是可燃气体,那个打火机就能看出程序里的读数变化)。所以MQ...
  • 树莓派3b初始化

    2018-07-23 15:35:47
    树莓派3b初始化设置,入门级操作,简单易懂。。。。。
  • mcp3008 尝试使用wiringpi访问mcp3008 一些代码取自 灵感来自
  • FS2416使用Socket网络设备驱动和字符设备驱动两种方式向Linux内核提供MCP2515的驱动,上篇文章介绍了使用Socket方式设计的基于MCP2515的Linux CAN总线驱动程序,这篇文章主要介绍编写一个MCP2515的字符设备驱动。
  • 然鹅树莓派的接收端还是出现以上相似的错误: can0 20000004 [8] 00 04 00 00 00 00 00 00 ERRORFRAME controller-problem {rx-error-warning} 然后折腾了一整天无果,找到一个问题帖,下面的cluse网友默默说了一句...

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 180
精华内容 72
关键字:

mcp2515树莓派