找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5383|回复: 0
收起左侧

MCP2510 CAN通信程序(pic单片机)

[复制链接]
ID:75926 发表于 2015-4-2 23:12 | 显示全部楼层 |阅读模式
  1. // ========CAN通信程序=======
  2. #include    <PIC.h>
  3. #include    <PIC16f87x.h>
  4. #include    <mcp2510.h>            // MCP2510寄存器定义
  5. // =========常数和变量定义=========  
  6. #define    READ    0x03                // 读MCP2510指令代码
  7. #define    WRITE    0x02            // 写MCP2510指令代码
  8. #define    RESET    0xC0            // 复位MCP2510指令代码
  9. #define    RTS    0x80                // MCP2510请求发送指令代码
  10. #define    STA2510    0xA0            // 读MCP2510状态指令代码
  11. #define    BITMOD    0x05            // MCP2510位修改指令代码
  12. int    a[12];                    // SPI发送或接收数据寄存器
  13. int    b[8];                    // 发送或接收的数据
  14. int    c[8];                    // 发送或接收的数据
  15. int    i;                        // 临时变量
  16. int    count;                    // 发送接收计数器
  17. int    count1=0;                // for test
  18. int    RecID_H=0;
  19. int    RecID_L=0;
  20. int    DLC=8;
  21. void SPIINT();
  22. void TMR1INT();
  23. void CCP1INT();
  24. void SPIEXCHANGE(int count);
  25. void WAIT_SPI();
  26. void RESET2510();
  27. int  RD2510(int adress,int n);
  28. void WR2510(int adress,int n);
  29. void RTS2510(int RTSn);
  30. int  GETS2510();
  31. void BM2510(int adress,int mask,int data);
  32. void SETNORMAL();
  33. void TXCOMPLETE(int adress);
  34. void TXMSG(int DLC);
  35. int  RXMSG();
  36. void INIT2510();
  37. void INIT877();
  38. void INITSPI();
  39. void ACK();
  40. void wait();
  41. // ========主程序=======
  42. main(void)
  43. {
  44.     int l,detect=0;
  45.     SSPIE=1;
  46.     TMR1IE=1;
  47.     CCP1IE=1;
  48.     CCP2IE=1;
  49.     PEIE=1;
  50.     ei();                    // 开中断
  51.     INIT877();                // 初始化PIC16F877芯片
  52.     INITSPI();                // 初始化SPI接口
  53.     INIT2510();                // 初始化MCP2510芯片
  54.     flag1=0;
  55.     flag2=0;
  56.     CCP1CON=0x05;
  57.     CCP2CON=0x04;
  58.     while(1)    {
  59.         RXMSG();
  60.         TXMSG(8);
  61.     }
  62. }
  63. // ========中断服务程序=======
  64. // SPI中断服务子程序
  65. void SPIINT()
  66. {
  67.     SSPIF=0;
  68.     a[i++]=SSPBUF;            // 数据暂存a[]中
  69.     count-=1;
  70.     if(count>0)  SSPBUF=a[i];// 未发送完,继续
  71.     else  RE2=1;                // 否则,片选信号置高电平
  72.     return;
  73. }
  74. // TMR1中断服务子程序
  75. void TMR1INT()
  76. {
  77.     TMR1IF=0;
  78.     T1CON=0;
  79.     if(!flag1){
  80.         TMR1H=0xfe;                // 512 μs 脉冲宽度
  81.         TMR1L=0x00;
  82.         T1CON=0x01;
  83.         PORTD=0xff;                // 输出所有通道
  84.         flag1=1;
  85.     }
  86.     else    {
  87.         flag1=0;
  88.         PORTD=0;
  89.         T1CON=0;
  90.     }
  91.     return;
  92. }
  93. // CCP1中断服务子程序
  94. void CCP1INT()
  95. {
  96.     CCP1IF=0;
  97.     T1CON=0x01;
  98.     return;
  99. }
  100. // CCP2中断服务子程序
  101. void CCP2INT()
  102. {
  103.     CCP2IF=0;
  104.     T1CON=0x01;
  105.     return;
  106. }
  107. // 中断入口,保护现场,判中断类型
  108. void interrupt INTS()
  109. {
  110.     di();
  111.     if(TMR1IF)  TMR1INT();        // 定时器TMR1中断
  112.     else if(CCP1IF)  CCP1INT();    // 电压过零捕捉中断1
  113.     else if(CCP2IF)  CCP2INT();    // 电压过零捕捉中断2
  114.     else if(SSPIF)  SPIINT();        // SPI接口中断
  115.     ei();
  116. }
  117. // ========子程序=======
  118. // 启动SPI传送
  119. void SPIEXCHANGE(count)
  120. int count;
  121. {
  122.     if(count>0) {                // 有数据可送?
  123.       i=0;
  124.       RE2=0;                        // 片选位置低电平
  125.       SSPBUF=a[i];                // 送数
  126.     }
  127.     else
  128.       ;                            // 否则,空操作,并返回
  129.     return;
  130. }
  131. // 等待SPI传送完成
  132. void WAIT_SPI()
  133. {
  134.     do{
  135.       ;
  136.     }while(count>0);                // 当count!=0时,等待 to add "CLRWDT"
  137.     return;
  138. }
  139. // 对MCP2510芯片进行复位
  140. void RESET2510()
  141. {
  142.     a[0]=RESET;
  143.     count=1;
  144.     SPIEXCHANGE(count);            // 送复位指令
  145.     WAIT_SPI();
  146.     return;
  147. }
  148. // 读取从地址"adress"开始的寄存器中的数据,共n个,存放在数组b[n]中
  149. int RD2510(adress,n)
  150. int     adress;
  151. int        n;
  152. {
  153.     int j;
  154.     a[0]=READ;
  155.     a[1]=adress;
  156.     for(j=0;j<n;j++)  a[j+2]=0;
  157.     count=n+2;                    // 指令、地址和要得到的数据量n
  158.     SPIEXCHANGE(count);
  159.     WAIT_SPI();
  160.     for(j=0;j<n;j++)  b[j]=a[j+2];// 数据存到数组b[]中
  161.     return;
  162. }
  163. // 向从地址"adress"开始的寄存器写入数据,共n个,数据存放数组b[n]中
  164. void WR2510(adress,n)
  165. int        adress;
  166. int        n;
  167. {
  168.     int j;
  169.     a[0]=WRITE;
  170.     a[1]=adress;
  171.     for(j=0;j<n;j++) a[j+2]=b[j];
  172.     count=n+2;                    // 指令、地址和要写入的数据量n
  173.     SPIEXCHANGE(count);
  174.     WAIT_SPI();
  175.     return;
  176. }
  177. // MCP2510芯片请求发送程序
  178. void RTS2510(RTSn)
  179. int RTSn;
  180. {
  181.     a[0]=RTS^RTSn;
  182.     count=1;
  183.     SPIEXCHANGE(count);            // 发送MCP2510芯片,请求发送指令
  184.     WAIT_SPI();
  185.     return;
  186. }
  187. // 读取MCP2510芯片的状态
  188. int GETS2510()
  189. {
  190.     a[0]=STA2510;
  191.     a[1]=0;
  192.     count=2;
  193.     SPIEXCHANGE(count);            // 读取MCP2510芯片状态
  194.     WAIT_SPI();
  195.     b[0]=a[1];                    // 状态存到数组b[]中
  196.     return;
  197. }
  198. // 对MCP2510芯片进行位修改子程序
  199. void BM2510(adress,mask,data)
  200. int  adress;
  201. int  mask;
  202. int  data;
  203. {
  204.     a[0]=BITMOD;                    // 位修改指令
  205.     a[1]=adress;                    // 位修改寄存器地址
  206.     a[2]=mask;                    // 位修改屏蔽位
  207.     a[3]=data;                    // 位修改数据
  208.     count=4;
  209.     SPIEXCHANGE(count);
  210.     WAIT_SPI();
  211.     return;
  212. }
  213. // 设置MCP2510芯片为正常操作模式
  214. void  SETNORMAL()
  215. {
  216.     int  k=1;
  217.     BM2510(CANCTRL,0xe0,0x00);    // 设置为正常操作模式
  218.     do    {
  219.       RD2510(CANSTAT,1);
  220.       k=b[0]&0xe0;
  221.     }while(k);                    // 确认已进入正常操作模式
  222.     return;
  223. }
  224. // 对MCP2510进行初始化
  225. void INIT2510()
  226. {
  227.     RESET2510();                    // 使芯片复位
  228.     b[0]=0x02;
  229.     b[1]=0x90;
  230.     b[2]=0x07;
  231.     WR2510(CNF3,3);                // 波特率为 125 kbps
  232.     b[0]=0x00;
  233.     b[1]=0x00;
  234.     WR2510(RXM0SIDH,2);
  235.     b[0]=0x00;
  236.     b[1]=0x00;
  237.     WR2510(RXF0SIDH,2);            // RX0接收,屏蔽位为0,过滤器为0
  238.     b[0]=0x00;
  239.     WR2510(CANINTE,1);            // CAN中断不使能
  240.     SETNORMAL();                    // 设置为正常操作模式
  241.     return;
  242. }
  243. // MCP2510芯片发送完成与否判断,邮箱号为adress
  244. void TXCOMPLETE(adress)
  245. int adress;
  246. {
  247.     int k=1;
  248.     do    {
  249.       RD2510(adress,1);
  250.       k=b[0]&0x08;
  251.     }while(k);                    // 确认是否已发送完毕 to add CLRWDT
  252.     return;
  253. }
  254. // 初始化PIC16F877芯片
  255. void INIT877()
  256. {
  257.     PORTA=0;
  258.     PORTB=0;
  259.     PORTC=0;
  260.     PORTD=0;
  261.     PORTE=0;
  262.     TRISA=0xff;
  263.     TRISB=0xfd;
  264.     TRISC=0xd7;                    // SCK, SDO:输出,SDI:输入  
  265.     TRISD=0;
  266.     TRISE=0x03;                    // 片选CS信号输出
  267.     PORTA=0xff;
  268.     PORTB=0x03;                    // RST=1
  269.     PORTC=0;
  270.     PORTD=0xff;
  271.     PORTE=0x04;
  272.     return;
  273. }
  274. // 初始化SPI接口
  275. void INITSPI()
  276. {
  277.     SSPCON=0x11;
  278.     SSPEN=1;                            // SSP使能
  279.     SSPSTAT=0;
  280.     return;
  281. }
  282. // 发送数据子程序
  283. void  TXMSG(int DLC)
  284. {
  285.     for(i=0;i<DLC;i++)  b[i]=c[i];
  286.     WR2510(TXB0D0,DLC);   
  287.     b[0]=DLC;
  288.     WR2510(TXB0DLC,1);
  289.     b[0]=0x03;
  290.     b[1]=RecID_H;
  291.     b[2]=RecID_L;
  292.     WR2510(TXB0CTRL,3);
  293.     RTS2510(0x01);                    // 请求发送
  294.     TXCOMPLETE(TXB0CTRL);                 //等待发送完毕
  295.     return;
  296. }
  297. // 接收数据子程序
  298. int RXMSG()
  299. {
  300.     int k;
  301.     RD2510(CANINTF,1);
  302.     k=b[0]&0x01;
  303.     if(k==1)    {
  304.     BM2510(CANINTF,0x01,0x00);
  305.         RD2510(RXB0SIDH,2);
  306.         RecID_H=b[0];
  307.     RecID_L=b[1]&0xe0;
  308.     RD2510(RXB0DLC,1);
  309.     DLC=b[0]&0x0f;
  310.     RD2510(RXB0D0,DLC);
  311.         for(i=0;i<DLC;i++) c[i]=b[i];
  312.         return 1;
  313.     }
  314.     return 0;
  315. }
复制代码


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表