打印
[PIC®/AVR®/dsPIC®产品]

PIC16F887 SPI CAN 传输,操作MCP2515

[复制链接]
2113|45
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
qcliu|  楼主 | 2019-8-1 11:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 pzsh 于 2021-12-14 14:31 编辑

主函数:

#include <pic.h>
#include <mcp2515_887.h>
#include <Can_887.h>

#define uchar unsigned char
#define uint  unsigned int
#define nop() asm("nop")
#define CS            RD1        //标签为CANCSRH4
#define RESET  RD0  //标签为RESETCAN

__CONFIG (CP_OFF &WDTE_OFF& BOREN_OFF&PWRTE_OFF &FOSC_HS&WRT_OFF&LVP_OFF&CPD_OFF);

void Init_Int(void);//初始化中断
void Init_Can(void);//初始化CAN通讯
void interrupt ISR(void);//中断处理函数
void delay(unsigned int n);//毫秒延时函数
void CAN_Set_Var(uchar address,uchar mask,uchar dat);//修改寄存器的值,mask为掩码
void Init_Spi(void);//初始化SPI
void SPISendByte(unsigned char dat);//SPI 发送一个字节数据
char SPIRecvByte(void);//SPI 读取一个字节数据
void CAN_Write_SS(uchar address ,uchar Value);//往MCP2515写一个字节数
char CAN_Read_SS(uchar address);//从MCP2515读一个字节数
//void CAN_Send_End(void);//CAN发送程序
void CAN_Send(unsigned char *CAN_TX_Buf);//发送数据
void SPIReset(void);//SPI复位
void CAN_writetxb0id(unsigned int txb0id);

unsigned char dummy;
unsigned char cansentbuf[8];
unsigned char canrecbuf[8];


使用特权

评论回复
沙发
qcliu|  楼主 | 2019-8-1 11:56 | 只看该作者
void main()
{

Init_Int();//初始化中断

//SPI init
Init_Spi();//初始化SPI

//can init
RESET=0;
delay(100);
RESET=1;       
delay(100);       



Init_Can();//初始化CAN通讯

        CAN_writetxb0id(0x0025);
        cansentbuf[0]=1;
        cansentbuf[1]=0;
        cansentbuf[2]=0x29;
        cansentbuf[3]=0;
        cansentbuf[4]=0;
        cansentbuf[5]=0;       
        cansentbuf[6]=0;
        cansentbuf[7]=0;
        //        for(bats2chloop=3;bats2chloop<8;bats2chloop++)
//        {
//                cansentbuf[bats2chloop]=0;
//        }
//        cansentbuf[5]=batleft;
//        cansentbuf[6]=batright;       


/*发一帧数据*/
                CAN_Send(cansentbuf);


while(1)
        {
//发送数据
                CAN_writetxb0id(0x0025);//帧ID
//                        cansentbuf[0]=1;
//        cansentbuf[1]=0;
//        cansentbuf[2]=0x29;
//        cansentbuf[3]=0;
//        cansentbuf[4]=0;
//        cansentbuf[5]=0;       
//        cansentbuf[6]=0;
//        cansentbuf[7]=0;
CAN_Send(cansentbuf);       
       
//                CAN_Send(cansentbuf);
//                delay(100);

//        SPISendByte(0XAA);
//        SPISendByte(0X00);
//        SPISendByte(0X00);
        delay(100);
        }


}

使用特权

评论回复
板凳
qcliu|  楼主 | 2019-8-1 11:56 | 只看该作者

//初始化中断
void Init_Int(void)
{
OPTION_REG = 0b00000000;//B口弱上拉,RB0为下降沿触发中断
TRISB      = 0b00000001;//设定RB0为输入,其余为输出
INTCON     = 0b10010000;//允许RB0/INT中断
}

使用特权

评论回复
地板
qcliu|  楼主 | 2019-8-1 11:57 | 只看该作者
//初始化SPI
void Init_Spi(void)
{
TRISC=0b00010000;//RC5/SDO为输出,RD4/SDI为输入,RC3/SCK为输出

//SSPSTAT_SMP=0;//在数据输出时间的中间采样输入数据
//CKE:SPI 时钟边沿选择位   CKP = 0: STAT_CKE=1 在SCK 引脚的上升沿发送数据
//SSPSTAT=0X80;//在数据输出时间的末尾采样输入数据
SSPSTAT=0X40;//在数据输出时间的中间采样输入数据  bit 7,SMP=0,采样位

//SSPEN=1;//SPI串口使能
//CKP=0;//空闲时钟为低电平
//SSPCON+=0b0001;//SPI主控模式,时钟为Fosc/16
/*SSPEN=1;使能串行端口;CKP=2,时钟空闲状态为高电平
SSPM<3:0>=0001,主控模式,时钟=Fosc/16
*/
//SSPCON=0x31;
SSPCON=0x21;//bit 4,CKP:时钟极性选择位,0 = 时钟空闲状态为低电平

TRISD=0b00000000;//RD1输出;RD0输出;
}

使用特权

评论回复
5
qcliu|  楼主 | 2019-8-1 11:58 | 只看该作者
//中断服务程序
void interrupt ISR(void)
{
//        if(INTF==1)//如果是INT中断才执行以下程序
//        {
//       
//        INTF==1;//清中断标志位
//        }

        uchar Sta_Int,i;
        Sta_Int=CAN_Read_SS(0X2C);//读中断标志寄存器
        CAN_Write_SS(0X2C,0x00);//清除所有中断标志位
       
        /*如果为接收缓冲器0中断*/
        if(Sta_Int & 0x01)
        {
                for(i=0;i<12;i++)
                {
                //Put_Char(CAN_Read_SS(0x60+i));
                }
        //com_fs=com_fs+12       
        }       
       
}

使用特权

评论回复
6
qcliu|  楼主 | 2019-8-1 11:58 | 只看该作者
//延时(n)ms
void delay(unsigned int n)
{
        unsigned int j;
        char k;
        for(j=0;j<n;j++)
                for(k=246;k>0;k--)
                        nop();
}

使用特权

评论回复
7
qcliu|  楼主 | 2019-8-1 11:59 | 只看该作者

//SPI 读取一个字节数据
char SPIRecvByte(void)
{
//从MISO线上读取一个数据字节
        char BUF;
//        SPISendByte(0x01);
//        SPISendByte(0x80|0x00);
//        nop();//延时
//        SPISendByte(0);//给SSPBUF一个0,才能开始读取SSPBUF的数据
       
        SSPBUF=0x00;
        delay(2);       
        BUF=SSPBUF;
        delay(20);
       
        return BUF;
}

使用特权

评论回复
8
qcliu|  楼主 | 2019-8-1 12:00 | 只看该作者
//SPI 发送一个字节数据
void SPISendByte(unsigned char dat)
{
        SSPBUF=dat;//往缓冲里面写入dat
//        while(!SSPIF)//等待写入成功
//        SSPIF=0;//SSPIF清零
        delay(20);

使用特权

评论回复
9
qcliu|  楼主 | 2019-8-1 12:00 | 只看该作者
//往MCP2515指定地址addr写一个字节数据value
void CAN_Write_SS(uchar address ,uchar Value)
{       
        CS=0;
        SPISendByte(0x02);//写命令
        SPISendByte(address);//写地址
        SPISendByte(Value);//写数据       
        CS=1;
}

使用特权

评论回复
10
qcliu|  楼主 | 2019-8-1 12:01 | 只看该作者

//从MCP2515指定地址addr读取一个字节数据value
char CAN_Read_SS(uchar address)
{
        char BUF;
        CS=0;
//        delay(5);
       
        SPISendByte(0x03);//读命令
        SPISendByte(address);//读地址
        BUF=SPIRecvByte();//读一个字节数据       
        CS=1;
        return BUF;
}

使用特权

评论回复
11
qcliu|  楼主 | 2019-8-1 12:01 | 只看该作者

//SPI复位
void SPIReset(void)
{
//        CS=LOW;
//        WriteSPI(CAN_RESET);
//        CS=HIGH;
        CS=0;
        SSPBUF=0XC0;//CAN_RESET=0XC0
//        RESET=1;
//        RESET=0;
        delay(20);
//        RESET=1;
        CS=1;               
}

使用特权

评论回复
12
qcliu|  楼主 | 2019-8-1 12:01 | 只看该作者
/**修改寄存器的值**/
//mask为掩码
void CAN_Set_Var(uchar address,uchar mask,uchar dat)
{
//        CS=1;//片选
//        delay(10);
        CS=0;
        delay(10);
        SPISendByte(0x05);//位修改命令 CAN_BIT_MODIFY
//CANCTRL——CAN 控制寄存器(地址:XFh)       
        SPISendByte(address);//地址为0fH
        SPISendByte(mask);//掩码为E0H,修改CANCTRL的高三位
        SPISendByte(dat);
        CS=1;//片选
}

使用特权

评论回复
13
qcliu|  楼主 | 2019-8-1 12:02 | 只看该作者
//初始化CAN通讯
void Init_Can(void)
{
/**复位MCP2515**/
        SPIReset();
        delay(20);

/**设置为配置模式**/
//CAN_Set_Var(0x0F,0XE0,0X80);

        CAN_Write_SS(RXM0SIDH, 0x00);
        CAN_Write_SS(RXM0SIDL,0x00);
       
        CAN_Write_SS(RXF0SIDH,0x00);
        CAN_Write_SS(RXF0SIDL,0x00);

/**设置通讯速率 晶振16M 速率125K**/
//CAN_Write_SS(0x2A,0X03);
//CAN_Write_SS(0x29,0XB9);
//CAN_Write_SS(0x28,0X04);

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

        //set TXB0,设置发送缓冲器0的标识符和发送的数据,以及发送的数据长度
        CAN_Write_SS(TXB0SIDH,0x06);//设置发送缓冲器0的标准标识符,待修改***
        CAN_Write_SS(TXB0SIDL,0x00);//用到标准标识符
        CAN_Write_SS(TXB0DLC,DLC_8);//设置发送数据的长度为8个字节,DLC_1
        //CAN_Write_SS(TXB0D0,0x1E);//有待修改及确定是否使用
        //CAN_Write_SS(TXB0D1,0x10);//有待修改及确定是否使用
               
        /*set TXB1
        CAN_Write_SS(TXB1SIDH,0x50);    //Set TXB0 SIDH
        CAN_Write_SS(TXB1SIDL,0x00);    //Set TXB0 SIDL
        CAN_Write_SS(TXB1DLC,0x40 | DLC_8);    //Set DLC = 3 bytes and RTR bit*/


        //设置接收缓冲器0的标识符和初始化数据
        CAN_Write_SS(RXB0SIDH,0x00);//设置接收缓冲器0的标准标识符,待修改***
        CAN_Write_SS(RXB0SIDL,0x60);//用到标准标识符
        CAN_Write_SS(RXB0CTRL,0x60);//仅仅接收标准标识符的有效信息,FIILHIT0=0表示RXB0 ,采用FILHIT0
        CAN_Write_SS(RXB0DLC,DLC_8);//设置接收数据的长度为8个字节
       
        CAN_Write_SS(RXF0SIDH,0xFF);//初始化接收滤波器0,待修改***
        CAN_Write_SS(RXF0SIDL,0xE0);
        CAN_Write_SS(RXM0SIDH,0xFF);//初始化接收屏蔽器0,待修改***
        CAN_Write_SS(RXM0SIDL,0xE0);

        //设置接收缓冲器0中断
        CAN_Write_SS(CANINTF,0x00);//清空中断标志位
        CAN_Write_SS(CANINTE,0x01);//接收缓冲器0满中断使能位

        CAN_Write_SS(CANCTRL,REQOP_NORMAL | CLKOUT_ENABLED);//设置正常模式

        delay(10);       
          dummy=CAN_Read_SS(CANSTAT);
                if (OPMODE_NORMAL != (dummy && 0xE0))
                  CAN_Write_SS(CANCTRL,REQOP_NORMAL | CLKOUT_ENABLED);//判断进入正常工作模式
          //CAN_Write_SS(CANCTRL,0x00);//选定正常工作模式



////0x00 仅接收标准或扩展标识符
////0x60 关闭接收所有数据
//CAN_Write_SS(0x60,0X60);
//
////滤波
//CAN_Write_SS(0x00,0);
//CAN_Write_SS(0x01,0);
//CAN_Write_SS(0x02,0);
//CAN_Write_SS(0x03,0);
//
////屏蔽
//CAN_Write_SS(0x20,0);
//CAN_Write_SS(0x21,0);
//CAN_Write_SS(0x22,0);
//
////接收数据产生中断
//CAN_Write_SS(0x2B,0X01);
//
////环回模式
////CAN_Set_Var(0x0F,0XE0,0X40);
////工作模式
//CAN_Set_Var(0x0F,0XE0,0);
}

使用特权

评论回复
14
qcliu|  楼主 | 2019-8-1 12:02 | 只看该作者
void CAN_writetxb0id(unsigned int txb0id)
{       
        CAN_Write_SS(TXB0SIDH,(txb0id>>3));//设置发送缓冲器0的标准标识符,待修改***
        CAN_Write_SS(TXB0SIDL,(0x00FF&(txb0id<<5)));//用到标准标识符       
}

使用特权

评论回复
15
qcliu|  楼主 | 2019-8-1 12:02 | 只看该作者
//CAN发送数据程序
void CAN_Send(unsigned char *CAN_TX_Buf)
{
        unsigned char tempdata;
        tempdata=CAN_Read_SS(CAN_RD_STATUS);
        CAN_Write_SS(TXB0D0,CAN_TX_Buf[0]);
        CAN_Write_SS(TXB0D1,CAN_TX_Buf[1]);
        CAN_Write_SS(TXB0D2,CAN_TX_Buf[2]);
        CAN_Write_SS(TXB0D3,CAN_TX_Buf[3]);
        CAN_Write_SS(TXB0D4,CAN_TX_Buf[4]);
        CAN_Write_SS(TXB0D5,CAN_TX_Buf[5]);
        CAN_Write_SS(TXB0D6,CAN_TX_Buf[6]);
        CAN_Write_SS(TXB0D7,CAN_TX_Buf[7]);
        if(tempdata&0x04)//判断TXREQ标志位
        {
                delay(5);
                CAN_Write_SS(TXB0CTRL,0);//清除TXREQ标志位
                while(CAN_Read_SS(CAN_RD_STATUS)&0x04);//等待TXREQ清零
        }
        CS=0;
        SPISendByte(CAN_RTS_TXB0);//发送缓冲器0请求发送
        CS=1;
}

使用特权

评论回复
16
qcliu|  楼主 | 2019-8-1 12:02 | 只看该作者
头文件1:
#ifndef        __CAN_H__
#define        __CAN_H__
//        write your header here

#include <pic.h>

#define CAN_10Kbps 0x31
#define CAN_25Kbps 0x13
#define CAN_50Kbps 0x09
#define CAN_100Kbps 0x04
#define CAN_125Kbps 0x07
#define CAN_250Kbps 0x01
#define CAN_500Kbps 0x00
#endif

使用特权

评论回复
17
qcliu|  楼主 | 2019-8-1 12:03 | 只看该作者
头文件2:
#ifndef        __2515_h__
#define        __2515_h__
//        write your header here
//#pragma nolist
/*********************************************************************
*   CAN MCP2510 C definitions file                                  *
*********************************************************************
*   Filename:       2515REGS.h                                      *
*   Date:           06/17/03                                        *
*   File Version:   1.00 (Beta)                                     *
*********************************************************************
*   Functions:                                                      *
*               Header file                                         *
*********************************************************************
*   Revision History:                                               *
*    06/17/03 Updated from MCP2510.inc which was for the 756 board  *
*********************************************************************/


/*******************************************************************
*                   Register Definitions                          *
*******************************************************************/

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

使用特权

评论回复
18
qcliu|  楼主 | 2019-8-1 12:04 | 只看该作者
/*  Recieve Filters */
#define RXF0SIDH        0x00
#define RXF0SIDL        0x01
#define RXF0EID8        0x02
#define RXF0EID0        0x03
#define RXF1SIDH        0x04
#define RXF1SIDL        0x05
#define RXF1EID8        0x06
#define RXF1EID0        0x07
#define RXF2SIDH        0x08
#define RXF2SIDL        0x09
#define RXF2EID8        0x0A
#define RXF2EID0        0x0B
#define RXF3SIDH        0x10
#define RXF3SIDL        0x11
#define RXF3EID8        0x12
#define RXF3EID0        0x13
#define RXF4SIDH        0x14
#define RXF4SIDL        0x15
#define RXF4EID8        0x16
#define RXF4EID0        0x17
#define RXF5SIDH        0x18
#define RXF5SIDL        0x19
#define RXF5EID8        0x1A
#define RXF5EID0        0x1B

使用特权

评论回复
19
qcliu|  楼主 | 2019-8-1 12:04 | 只看该作者
/* Receive Masks */
#define RXM0SIDH        0x20
#define RXM0SIDL        0x21
#define RXM0EID8        0x22
#define RXM0EID0        0x23
#define RXM1SIDH        0x24
#define RXM1SIDL        0x25
#define RXM1EID8        0x26
#define RXM1EID0        0x27

使用特权

评论回复
20
qcliu|  楼主 | 2019-8-1 12:05 | 只看该作者

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

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

62

主题

3308

帖子

4

粉丝