基于树莓派3的CAN总线编程

时间:2022-06-06 17:39:08

简介

树莓派3使用Python控制SPI接口的MCP2515 CAN模块。实现命令行控制CAN的收发。

github地址
基于树莓派3的CAN总线编程

环境搭建

  1. Raspiberry Pi Model 3B 安装Raspbian,并使能SPI功能(默认关闭)
  2. python2.7
  3. spidev-3.2(如有更新,下载最新版本)
  4. MCP2515模块(SPI接口)

使用说明

共mcp2515.py和mcp2515_run.py两个文件,放在同一目录下,运行mcp2515_run.py。

基于树莓派3的CAN总线编程
如上图所示,命令行支持如下命令:
mcp -init //初始化,自动调用
mcp -w 1 2 3 //发送数据,这里发送了3个字节:0x01,0x02,0x03
mcp -r //读取接收缓冲区,示例中没有收到数据,为空
help //帮助信息
exit //退出命令行

源代码

mcp2515_run.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import spidev,time
import sys,cmd,shlex,types
from mcp2515 import *

spi = spidev.SpiDev(0,0)

def mcp2515_reset():
    tmpc = [0xc0]
    spi.writebytes(tmpc)

def mcp2515_writeReg(addr, val):
    buf = [0x02, addr, val]
    spi.writebytes(buf)

def mcp2515_readReg(addr):
    buf = [0x03, addr, 0x55]
    buf = spi.xfer2(buf)
    return int(buf[2])

def mcp2515_init():
    mcp2515_reset()
    time.sleep(2)
    #设置波特率为125Kbps
    #set CNF1,SJW=00,长度为1TQ,BRP=49,TQ=[2*(BRP+1)]/Fsoc=2*50/8M=12.5us
    mcp2515_writeReg(CNF1,CAN_125Kbps);
    #set CNF2,SAM=0,在采样点对总线进行一次采样,PHSEG1=(2+1)TQ=3TQ,PRSEG=(0+1)TQ=1TQ
    mcp2515_writeReg(CNF2,0x80|PHSEG1_3TQ|PRSEG_1TQ);
    #set CNF3,PHSEG2=(2+1)TQ=3TQ,同时当CANCTRL.CLKEN=1时设定CLKOUT引脚为时间输出使能位
    mcp2515_writeReg(CNF3,PHSEG2_3TQ);

    mcp2515_writeReg(TXB0SIDH,0xFF)#发送缓冲器0标准标识符高位
    mcp2515_writeReg(TXB0SIDL,0xEB)#发送缓冲器0标准标识符低位(第3位为发送拓展标识符使能位)
    mcp2515_writeReg(TXB0EID8,0xFF)#发送缓冲器0拓展标识符高位
    mcp2515_writeReg(TXB0EID0,0xFF)#发送缓冲器0拓展标识符低位

    mcp2515_writeReg(RXB0SIDH,0x00)#清空接收缓冲器0的标准标识符高位
    mcp2515_writeReg(RXB0SIDL,0x00)#清空接收缓冲器0的标准标识符低位
    mcp2515_writeReg(RXB0EID8,0x00)#清空接收缓冲器0的拓展标识符高位
    mcp2515_writeReg(RXB0EID0,0x00)#清空接收缓冲器0的拓展标识符低位
    mcp2515_writeReg(RXB0CTRL,0x40)#仅仅接收拓展标识符的有效信息
    mcp2515_writeReg(RXB0DLC,DLC_8)#设置接收数据的长度为8个字节

    mcp2515_writeReg(RXF0SIDH,0xFF)#配置验收滤波寄存器n标准标识符高位
    mcp2515_writeReg(RXF0SIDL,0xEB)#配置验收滤波寄存器n标准标识符低位(第3位为接收拓展标识符使能位)
    mcp2515_writeReg(RXF0EID8,0xFF)#配置验收滤波寄存器n拓展标识符高位
    mcp2515_writeReg(RXF0EID0,0xFF)#配置验收滤波寄存器n拓展标识符低位

    mcp2515_writeReg(RXM0SIDH,0xFF)#配置验收屏蔽寄存器n标准标识符高位
    mcp2515_writeReg(RXM0SIDL,0xE3)#配置验收屏蔽寄存器n标准标识符低位
    mcp2515_writeReg(RXM0EID8,0xFF)#配置验收滤波寄存器n拓展标识符高位
    mcp2515_writeReg(RXM0EID0,0xFF)#配置验收滤波寄存器n拓展标识符低位

    mcp2515_writeReg(CANINTF,0x00)#清空CAN中断标志寄存器的所有位(必须由MCU清空)
    mcp2515_writeReg(CANINTE,0x01)#配置CAN中断使能寄存器的接收缓冲器0满中断使能,其它位禁止中断

    mcp2515_writeReg(CANCTRL,REQOP_NORMAL|CLKOUT_ENABLED)#将MCP2515设置为正常模式,退出配置模式

    #tmpc = mcp2515_readReg(CANSTAT)#读取CAN状态寄存器的值
    #tmpd = int(tmpc[0]) & 0xe0
    #if OPMODE_NORMAL!=tmpd:#判断MCP2515是否已经进入正常模式
    # mcp2515_writeReg(CANCTRL,REQOP_NORMAL|CLKOUT_ENABLED)#再次将MCP2515设置为XX模式,退出配置模式
    print '\r\nMCP2515 Initialized.\r\n'


def mcp2515_write(buf):
    for i in range(50):
        time.sleep(2) #通过软件延时约nms(不准确)
        if not mcp2515_readReg(TXB0CTRL)&0x08:#快速读某些状态指令,等待TXREQ标志清零
            break
    N = len(buf)
    for j in range(N):
        mcp2515_writeReg(TXB0D0+j,buf[j])#将待发送的数据写入发送缓冲寄存器

    mcp2515_writeReg(TXB0DLC,N)#将本帧待发送的数据长度写入发送缓冲器0的发送长度寄存器
    mcp2515_writeReg(TXB0CTRL,0x08)#请求发送报文

def mcp2515_read():
    N = 0
    buf = []
    if mcp2515_readReg(CANINTF) & 0x01:
        N = mcp2515_readReg(RXB0DLC)#读取接收缓冲器0接收到的数据长度(0~8个字节)
        for i in range(N):
            buf.append(mcp2515_readReg(RXB0D0+i))#把CAN接收到的数据放入指定缓冲区
    mcp2515_writeReg(CANINTF,0)#清除中断标志位(中断标志寄存器必须由MCU清零)
    return buf

class MyCmd(cmd.Cmd):
    def __init__(self):
        cmd.Cmd.__init__(self)
        self.prompt='wyq@rpi2 ~ $ '
        mcp2515_init()

    def emptyline(self):
        pass

    def do_test(self,arg):
        lex = shlex.shlex(arg)
        for x in lex:
            print x

    def do_exit(self,arg):
        return True

    def do_mcp(self,arg):
        lex = shlex.shlex(arg)
        try:
            for x in lex:
                if x=='-':
                    opt = lex.next()
                    if opt.lower()=='init':
                        mcp2515_init()
                    elif opt.lower()=='w':
                        buf = []
                        for i in lex:
                            buf.append(int(i))
                        mcp2515_write(buf)
                    elif opt.lower()=='r':
                        buf = mcp2515_read()
                        print 'Received:',len(buf)
                        for i in buf:
                            print hex(int(i))
                    else:
                        pass
        except BaseException, e:
            print e

    def do_help(self,arg):
        print '基于MCP2515的CAN收发控制器'
        print 'Author:汪永强 QQ:917888229 Date:2016-8-18'
        print '发送指令: mcp -w XX YY ZZ'
        print '接收指令: mcp -r'
        print '重初始化: mcp -init'


if __name__=='__main__':
    mycmd = MyCmd()
    mycmd.cmdloop()

mcp2515.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#/* Configuration Registers */
CANSTAT         = 0x0E
CANCTRL         = 0x0F
BFPCTRL         = 0x0C
TEC             = 0x1C
REC             = 0x1D
CNF3            = 0x28
CNF2            = 0x29
CNF1            = 0x2A
CANINTE         = 0x2B
CANINTF         = 0x2C
EFLG            = 0x2D
TXRTSCTRL       = 0x0D

#/* Recieve Filters */
RXF0SIDH        = 0x00
RXF0SIDL        = 0x01
RXF0EID8        = 0x02
RXF0EID0        = 0x03
RXF1SIDH        = 0x04
RXF1SIDL        = 0x05
RXF1EID8        = 0x06
RXF1EID0        = 0x07
RXF2SIDH        = 0x08
RXF2SIDL        = 0x09
RXF2EID8        = 0x0A
RXF2EID0        = 0x0B
RXF3SIDH        = 0x10
RXF3SIDL        = 0x11
RXF3EID8        = 0x12
RXF3EID0        = 0x13
RXF4SIDH        = 0x14
RXF4SIDL        = 0x15
RXF4EID8        = 0x16
RXF4EID0        = 0x17
RXF5SIDH        = 0x18
RXF5SIDL        = 0x19
RXF5EID8        = 0x1A
RXF5EID0        = 0x1B

#/* Receive Masks */
RXM0SIDH        = 0x20
RXM0SIDL        = 0x21
RXM0EID8        = 0x22
RXM0EID0        = 0x23
RXM1SIDH        = 0x24
RXM1SIDL        = 0x25
RXM1EID8        = 0x26
RXM1EID0        = 0x27

#/* Tx Buffer 0 */
TXB0CTRL        = 0x30
TXB0SIDH        = 0x31
TXB0SIDL        = 0x32
TXB0EID8        = 0x33
TXB0EID0        = 0x34
TXB0DLC         = 0x35
TXB0D0          = 0x36
TXB0D1          = 0x37
TXB0D2          = 0x38
TXB0D3          = 0x39
TXB0D4          = 0x3A
TXB0D5          = 0x3B
TXB0D6          = 0x3C
TXB0D7          = 0x3D

#/* Tx Buffer 1 */
TXB1CTRL        = 0x40
TXB1SIDH        = 0x41
TXB1SIDL        = 0x42
TXB1EID8        = 0x43
TXB1EID0        = 0x44
TXB1DLC         = 0x45
TXB1D0          = 0x46
TXB1D1          = 0x47
TXB1D2          = 0x48
TXB1D3          = 0x49
TXB1D4          = 0x4A
TXB1D5          = 0x4B
TXB1D6          = 0x4C
TXB1D7          = 0x4D

#/* Tx Buffer 2 */
TXB2CTRL        = 0x50
TXB2SIDH        = 0x51
TXB2SIDL        = 0x52
TXB2EID8        = 0x53
TXB2EID0        = 0x54
TXB2DLC         = 0x55
TXB2D0          = 0x56
TXB2D1          = 0x57
TXB2D2          = 0x58
TXB2D3          = 0x59
TXB2D4          = 0x5A
TXB2D5          = 0x5B
TXB2D6          = 0x5C
TXB2D7          = 0x5D

#/* Rx Buffer 0 */
RXB0CTRL        = 0x60
RXB0SIDH        = 0x61
RXB0SIDL        = 0x62
RXB0EID8        = 0x63
RXB0EID0        = 0x64
RXB0DLC         = 0x65
RXB0D0          = 0x66
RXB0D1          = 0x67
RXB0D2          = 0x68
RXB0D3          = 0x69
RXB0D4          = 0x6A
RXB0D5          = 0x6B
RXB0D6          = 0x6C
RXB0D7          = 0x6D

#/* Rx Buffer 1 */
RXB1CTRL        = 0x70
RXB1SIDH        = 0x71
RXB1SIDL        = 0x72
RXB1EID8        = 0x73
RXB1EID0        = 0x74
RXB1DLC         = 0x75
RXB1D0          = 0x76
RXB1D1          = 0x77
RXB1D2          = 0x78
RXB1D3          = 0x79
RXB1D4          = 0x7A
RXB1D5          = 0x7B
RXB1D6          = 0x7C
RXB1D7          = 0x7D


#/*******************************************************************
# * Bit register masks *
# *******************************************************************/

#/* TXBnCTRL */
TXREQ           = 0x08
TXP             = 0x03

#/* RXBnCTRL */
RXM             = 0x60
BUKT            = 0x04

#/* CANCTRL */
REQOP           = 0xE0
ABAT            = 0x10
OSM             = 0x08
CLKEN           = 0x04
CLKPRE          = 0x03

#/* CANSTAT */
REQOP           = 0xE0
ICOD            = 0x0E

#/* CANINTE */
RX0IE           = 0x01
RX1IE           = 0x02
TX0IE           = 0x04
TX1IE           = 0x80
TX2IE           = 0x10
ERRIE           = 0x20
WAKIE           = 0x40
MERRE           = 0x80

#/* CANINTF */
RX0IF           = 0x01
RX1IF           = 0x02
TX0IF           = 0x04
TX1IF           = 0x80
TX2IF           = 0x10
ERRIF           = 0x20
WAKIF           = 0x40
MERRF           = 0x80

#/* BFPCTRL */
B1BFS           = 0x20
B0BFS           = 0x10
B1BFE           = 0x08
B0BFE           = 0x04
B1BFM           = 0x02
B0BFM           = 0x01

#/* CNF1 Masks */
SJW             = 0xC0
BRP             = 0x3F

#/* CNF2 Masks */
BTLMODE         = 0x80
SAM             = 0x40
PHSEG1          = 0x38
PRSEG           = 0x07

#/* CNF3 Masks */
WAKFIL          = 0x40
PHSEG2          = 0x07

#/* TXRTSCTRL Masks */
TXB2RTS         = 0x04
TXB1RTS         = 0x02
TXB0RTS         = 0x01


#/*******************************************************************
# * Bit Timing Configuration *
# *******************************************************************/

#/* CNF1 */
SJW_1TQ         = 0x40
SJW_2TQ         = 0x80
SJW_3TQ         = 0x90
SJW_4TQ         = 0xC0

#/* CNF2 */
BTLMODE_CNF3    = 0x80
BTLMODE_PH1_IPT = 0x00

SMPL_3X         = 0x40
SMPL_1X         = 0x00

PHSEG1_8TQ      = 0x38
PHSEG1_7TQ      = 0x30
PHSEG1_6TQ      = 0x28
PHSEG1_5TQ      = 0x20
PHSEG1_4TQ      = 0x18
PHSEG1_3TQ      = 0x10
PHSEG1_2TQ      = 0x08
PHSEG1_1TQ      = 0x00

PRSEG_8TQ       = 0x07
PRSEG_7TQ       = 0x06
PRSEG_6TQ       = 0x05
PRSEG_5TQ       = 0x04
PRSEG_4TQ       = 0x03
PRSEG_3TQ       = 0x02
PRSEG_2TQ       = 0x01
PRSEG_1TQ       = 0x00

#/* CNF3 */
PHSEG2_8TQ      = 0x07
PHSEG2_7TQ      = 0x06
PHSEG2_6TQ      = 0x05
PHSEG2_5TQ      = 0x04
PHSEG2_4TQ      = 0x03
PHSEG2_3TQ      = 0x02
PHSEG2_2TQ      = 0x01
PHSEG2_1TQ      = 0x00

SOF_ENABLED     = 0x80
WAKFIL_ENABLED  = 0x40
WAKFIL_DISABLED = 0x00


#/*******************************************************************
# * Control/Configuration Registers *
# *******************************************************************/

#/* CANINTE */
RX0IE_ENABLED   = 0x01
RX0IE_DISABLED  = 0x00
RX1IE_ENABLED   = 0x02
RX1IE_DISABLED  = 0x00
G_RXIE_ENABLED  = 0x03
G_RXIE_DISABLED = 0x00

TX0IE_ENABLED   = 0x04
TX0IE_DISABLED  = 0x00
TX1IE_ENABLED   = 0x08
TX2IE_DISABLED  = 0x00
TX2IE_ENABLED   = 0x10
TX2IE_DISABLED  = 0x00
G_TXIE_ENABLED  = 0x1C
G_TXIE_DISABLED = 0x00

ERRIE_ENABLED   = 0x20
ERRIE_DISABLED  = 0x00
WAKIE_ENABLED   = 0x40
WAKIE_DISABLED  = 0x00
IVRE_ENABLED    = 0x80
IVRE_DISABLED   = 0x00

#/* CANINTF */
RX0IF_SET       = 0x01
RX0IF_RESET     = 0x00
RX1IF_SET       = 0x02
RX1IF_RESET     = 0x00
TX0IF_SET       = 0x04
TX0IF_RESET     = 0x00
TX1IF_SET       = 0x08
TX2IF_RESET     = 0x00
TX2IF_SET       = 0x10
TX2IF_RESET     = 0x00
ERRIF_SET       = 0x20
ERRIF_RESET     = 0x00
WAKIF_SET       = 0x40
WAKIF_RESET     = 0x00
IVRF_SET        = 0x80
IVRF_RESET      = 0x00

#/* CANCTRL */ 
REQOP_CONFIG    = 0x80
REQOP_LISTEN    = 0x60
REQOP_LOOPBACK  = 0x40
REQOP_SLEEP     = 0x20
REQOP_NORMAL    = 0x00

ABORT           = 0x10

OSM_ENABLED     = 0x08

CLKOUT_ENABLED  = 0x04
CLKOUT_DISABLED = 0x00
CLKOUT_PRE_8    = 0x03
CLKOUT_PRE_4    = 0x02
CLKOUT_PRE_2    = 0x01
CLKOUT_PRE_1    = 0x00

#/* CANSTAT */
OPMODE_CONFIG   = 0x80
OPMODE_LISTEN   = 0x60
OPMODE_LOOPBACK = 0x40
OPMODE_SLEEP    = 0x20
OPMODE_NORMAL   = 0x00


#/* RXBnCTRL */
RXM_RCV_ALL     = 0x60
RXM_VALID_EXT   = 0x40
RXM_VALID_STD   = 0x20
RXM_VALID_ALL   = 0x00

RXRTR_REMOTE    = 0x08
RXRTR_NO_REMOTE = 0x00

BUKT_ROLLOVER    = 0x04
BUKT_NO_ROLLOVER = 0x00

FILHIT0_FLTR_1  = 0x01
FILHIT0_FLTR_0  = 0x00

FILHIT1_FLTR_5  = 0x05
FILHIT1_FLTR_4  = 0x04
FILHIT1_FLTR_3  = 0x03
FILHIT1_FLTR_2  = 0x02
FILHIT1_FLTR_1  = 0x01
FILHIT1_FLTR_0  = 0x00


#/* TXBnCTRL */
TXREQ_SET       = 0x08
TXREQ_CLEAR     = 0x00

TXP_HIGHEST     = 0x03
TXP_INTER_HIGH  = 0x02
TXP_INTER_LOW   = 0x01
TXP_LOWEST      = 0x00


#/*******************************************************************
# * Register Bit Masks *
# *******************************************************************/

DLC_0          = 0x00
DLC_1          = 0x01
DLC_2          = 0x02
DLC_3          = 0x03
DLC_4          = 0x04
DLC_5          = 0x05
DLC_6          = 0x06
DLC_7          = 0x07    
DLC_8          = 0x08


#/*******************************************************************
# * CAN SPI commands *
# *******************************************************************/

CAN_RESET       = 0xC0
CAN_READ        = 0x03
CAN_WRITE       = 0x02
CAN_RTS         = 0x80
CAN_RTS_TXB0    = 0x81
CAN_RTS_TXB1    = 0x82
CAN_RTS_TXB2    = 0x84
CAN_RD_STATUS   = 0xA0
CAN_BIT_MODIFY  = 0x05  
CAN_RX_STATUS   = 0xB0
CAN_RD_RX_BUFF  = 0x90
CAN_LOAD_TX     = 0x40  


#/*******************************************************************
# * Miscellaneous *
# *******************************************************************/

DUMMY_BYTE      = 0x00
TXB0            = 0x31
TXB1            = 0x41
TXB2            = 0x51
RXB0            = 0x61
RXB1            = 0x71
EXIDE_SET       = 0x08
EXIDE_RESET     = 0x00

#MCP2515波特率预分频
CAN_10Kbps  = 0x31
CAN_25Kbps  = 0x13
CAN_50Kbps  = 0x09
CAN_100Kbps = 0x04
CAN_125Kbps = 0x03
CAN_250Kbps = 0x01
CAN_500Kbps = 0x00