找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 6057|回復(fù): 0
收起左側(cè)

MCP2510 CAN通信程序(pic單片機)

[復(fù)制鏈接]
ID:75926 發(fā)表于 2015-4-2 23:12 | 顯示全部樓層 |閱讀模式
  1. // ========CAN通信程序=======
  2. #include    <PIC.h>
  3. #include    <PIC16f87x.h>
  4. #include    <mcp2510.h>            // MCP2510寄存器定義
  5. // =========常數(shù)和變量定義=========  
  6. #define    READ    0x03                // 讀MCP2510指令代碼
  7. #define    WRITE    0x02            // 寫MCP2510指令代碼
  8. #define    RESET    0xC0            // 復(fù)位MCP2510指令代碼
  9. #define    RTS    0x80                // MCP2510請求發(fā)送指令代碼
  10. #define    STA2510    0xA0            // 讀MCP2510狀態(tài)指令代碼
  11. #define    BITMOD    0x05            // MCP2510位修改指令代碼
  12. int    a[12];                    // SPI發(fā)送或接收數(shù)據(jù)寄存器
  13. int    b[8];                    // 發(fā)送或接收的數(shù)據(jù)
  14. int    c[8];                    // 發(fā)送或接收的數(shù)據(jù)
  15. int    i;                        // 臨時變量
  16. int    count;                    // 發(fā)送接收計數(shù)器
  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. // ========中斷服務(wù)程序=======
  64. // SPI中斷服務(wù)子程序
  65. void SPIINT()
  66. {
  67.     SSPIF=0;
  68.     a[i++]=SSPBUF;            // 數(shù)據(jù)暫存a[]中
  69.     count-=1;
  70.     if(count>0)  SSPBUF=a[i];// 未發(fā)送完,繼續(xù)
  71.     else  RE2=1;                // 否則,片選信號置高電平
  72.     return;
  73. }
  74. // TMR1中斷服務(wù)子程序
  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中斷服務(wù)子程序
  94. void CCP1INT()
  95. {
  96.     CCP1IF=0;
  97.     T1CON=0x01;
  98.     return;
  99. }
  100. // CCP2中斷服務(wù)子程序
  101. void CCP2INT()
  102. {
  103.     CCP2IF=0;
  104.     T1CON=0x01;
  105.     return;
  106. }
  107. // 中斷入口,保護現(xiàn)場,判中斷類型
  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) {                // 有數(shù)據(jù)可送?
  123.       i=0;
  124.       RE2=0;                        // 片選位置低電平
  125.       SSPBUF=a[i];                // 送數(shù)
  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芯片進行復(fù)位
  140. void RESET2510()
  141. {
  142.     a[0]=RESET;
  143.     count=1;
  144.     SPIEXCHANGE(count);            // 送復(fù)位指令
  145.     WAIT_SPI();
  146.     return;
  147. }
  148. // 讀取從地址"adress"開始的寄存器中的數(shù)據(jù),共n個,存放在數(shù)組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;                    // 指令、地址和要得到的數(shù)據(jù)量n
  158.     SPIEXCHANGE(count);
  159.     WAIT_SPI();
  160.     for(j=0;j<n;j++)  b[j]=a[j+2];// 數(shù)據(jù)存到數(shù)組b[]中
  161.     return;
  162. }
  163. // 向從地址"adress"開始的寄存器寫入數(shù)據(jù),共n個,數(shù)據(jù)存放數(shù)組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;                    // 指令、地址和要寫入的數(shù)據(jù)量n
  173.     SPIEXCHANGE(count);
  174.     WAIT_SPI();
  175.     return;
  176. }
  177. // MCP2510芯片請求發(fā)送程序
  178. void RTS2510(RTSn)
  179. int RTSn;
  180. {
  181.     a[0]=RTS^RTSn;
  182.     count=1;
  183.     SPIEXCHANGE(count);            // 發(fā)送MCP2510芯片,請求發(fā)送指令
  184.     WAIT_SPI();
  185.     return;
  186. }
  187. // 讀取MCP2510芯片的狀態(tài)
  188. int GETS2510()
  189. {
  190.     a[0]=STA2510;
  191.     a[1]=0;
  192.     count=2;
  193.     SPIEXCHANGE(count);            // 讀取MCP2510芯片狀態(tài)
  194.     WAIT_SPI();
  195.     b[0]=a[1];                    // 狀態(tài)存到數(shù)組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;                    // 位修改數(shù)據(jù)
  208.     count=4;
  209.     SPIEXCHANGE(count);
  210.     WAIT_SPI();
  211.     return;
  212. }
  213. // 設(shè)置MCP2510芯片為正常操作模式
  214. void  SETNORMAL()
  215. {
  216.     int  k=1;
  217.     BM2510(CANCTRL,0xe0,0x00);    // 設(shè)置為正常操作模式
  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();                    // 使芯片復(fù)位
  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();                    // 設(shè)置為正常操作模式
  241.     return;
  242. }
  243. // MCP2510芯片發(fā)送完成與否判斷,郵箱號為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);                    // 確認是否已發(fā)送完畢 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. // 發(fā)送數(shù)據(jù)子程序
  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);                    // 請求發(fā)送
  294.     TXCOMPLETE(TXB0CTRL);                 //等待發(fā)送完畢
  295.     return;
  296. }
  297. // 接收數(shù)據(jù)子程序
  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. }
復(fù)制代碼


相關(guān)帖子

回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表