<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 基于單片機的CAN總線通信程序

          基于單片機的CAN總線通信程序

          作者: 時間:2016-11-21 來源:網(wǎng)絡(luò) 收藏
          //------------------------------------------------------

          //CAN <==> UART的協(xié)議轉(zhuǎn)換器
          //
          //程序名稱:CAN <---> UART協(xié)議轉(zhuǎn)換程序<透明方式>
          //
          //作者:王猛
          //創(chuàng)建:2007-10-09
          //
          //說明:
          //1,單片機使用P89C61X2BA
          //--晶振11.0592MHZ
          //--CAN總線中斷使用單片機的中斷0,外部有上拉電阻,波特率可以設(shè)定
          //2,CAN總線發(fā)送采用查詢方式,接收采用中斷方式
          //3,看門狗復位時間1.2S
          //4,SJA1000晶振8MHZ,Peil模式
          //5,串口中斷接收,查詢發(fā)送,波特率可設(shè)置
          //6,×××當串口收到數(shù)據(jù)后,每8個數(shù)一組打包,通過CAN總線發(fā)送出去
          //
          //-----10.16日,重新修改程序完成以下功能-----
          //----此功能已經(jīng)改為,每收到一幀數(shù)據(jù),啟動一次CAN傳輸,傳輸字節(jié)數(shù)等于串口收到的數(shù)據(jù)
          //----串行幀的幀間界定通過當前波特率下傳輸5個字節(jié)為時間間隔,具體為當順序接收到的任
          //意兩個數(shù)據(jù),它們之間的時間間隔大于5個字節(jié)傳送時間,認為這兩個數(shù)據(jù)分屬于兩個不
          //同的幀
          //
          //7,當CAN總線每接收一幀信息后,通過串口發(fā)送出去
          //-----10.15日,改為可以識別CAN的報文字節(jié)長度,即串口只發(fā)送CAN報文長度個字節(jié)
          //8,看門狗芯片MAX1232CPA,硬件溢出時間1.2S
          //
          //-------------------------------------------------------

          本文引用地址:http://www.ex-cimer.com/article/201611/319295.htm

          #include
          #include
          #include
          #include "CANCOM.h"

          //unsigned char UART_TX_Data[8] = {0,1,2,3,4,5,6,7};
          //unsigned char CAN_TX_Data[8] = {0,1,2,3,4,5,6,7};
          unsigned char xdata UART_RX_Data[255];//串口接收到的串行幀
          unsigned char xdata CAN_TX_Data[255];//待發(fā)送的數(shù)據(jù)緩沖區(qū)
          unsigned char code ACR_ID[4] = {0,0,0,0};//CAN初始設(shè)置驗收濾波值
          unsigned char code AMR_ID[4] = {0xff,0xff,0xff,0xff};
          unsigned char CAN_TX_ID[4] = {0,0,0,0};//待發(fā)送的目標的ID
          unsigned char CAN_RX_ID[4] = {0,0,0,0};//接收到的信息來自何ID
          unsigned char CAN_RX_Data[8] = {7,6,5,4,3,2,1,0};//接受到的數(shù)據(jù)緩沖
          unsigned char code CAN_BTR0[10] = {0xdf,0xcf,0xc7,0xc3,0x43,0xc1,0xc1,0xc0,0xc0,0x80};
          unsigned char code CAN_BTR1[10] = {0x7f,0x7f,0x7f,0x7f,0x2f,0x7f,0x4d,0x3e,0x3a,0x23};
          //5K 10K 20K 40K 50K 80K 100K 200K 250K 500K
          unsigned char code UART_BTR[4] = {0xe8,0xf4,0xfa};
          // 1.2K,2.4K,4.8K

          unsigned char CAN_flag;//CAN發(fā)送標志位
          unsigned char UART_flag;//
          unsigned char CAN_ERROR_flag = NOT;//
          unsigned char CAN_DataLength = 8;//CAN信息的報文長度
          unsigned char UART_DataLength = 0;//串口接收時的當前指示
          unsigned char UART_Length = 0;//串口接收區(qū)的長度指示
          //sbit AAA = P1^4;

          void main(void)
          {
          EA = 0;
          System_init();//系統(tǒng)初始化
          Timer_init();//定時器初始化
          Interrupt_init();//中斷
          UART_ini();
          CAN_init();
          Delay(1);
          W_WDT();
          EA = 1;

          //Delay(1);
          //UART_Length = 8;
          //CAN_Transmit(0);
          //UART_Transmit();

          while (1)
          {
          W_WDT();

          if (CAN_flag == YES)
          {
          CAN_flag = NOT;
          CAN_Transmit(0);
          LED1 = !LED1;
          }
          else
          {
          CAN_flag = NOT;
          }
          /*
          if (UART_flag == YES)
          {
          UART_flag = NOT;
          //Delay(50);
          UART_Transmit();
          //Clear_Buffer(CAN_RX_Data,8);
          //LED3 = !LED3;
          }
          else
          {
          UART_flag = NOT;
          }

          */
          if ((CAN_ERROR_flag == YES))
          {
          CAN_ERROR_flag = NOT;
          CAN_init();
          }
          else
          {
          CAN_ERROR_flag = NOT;
          }
          }
          }
          //---------------------------
          //功能:系統(tǒng)設(shè)置
          //--外部數(shù)據(jù)存儲區(qū)訪問使能
          //--LED指示燈關(guān)(1=on,0=off)
          //--流程控制標志置為無效NOT
          //--清空串口,CAN的相關(guān)數(shù)據(jù)緩沖區(qū)
          //---------------------------
          void System_init(void)
          {
          CKCON = 0x00;//Fosc devide 12
          AUXR = 0x00;//0x02;//EXM enable
          LED1 = 0;//LED0-3 off指示燈,共陰接法,1時亮
          LED2 = 0;
          LED3 = 0;
          LED4 = 0;
          WDT = 1;//WDT ini

          CAN_DataLength = 8;
          UART_DataLength = 0;
          UART_Length = 0;

          CAN_flag = NOT;
          CAN_ERROR_flag = NOT;
          //UART_flag = NOT;

          Clear_Buffer(UART_RX_Data,255);
          Clear_Buffer(CAN_TX_Data,255);
          Clear_Buffer(CAN_TX_ID,4);
          Clear_Buffer(CAN_RX_ID,4);
          Clear_Buffer(CAN_RX_Data,8);

          /*
          CAN_flag = YES;
          UART_flag = YES;
          */
          }
          //-----------------------------
          //
          //軟件延時(非精確)
          //----內(nèi)置清看門狗定時器子函數(shù)
          //防止多次調(diào)用延時過長導致
          //看門狗復位
          //
          //-----------------------------
          void Delay(unsigned char time)
          {
          unsigned char i;
          unsigned int j;

          for (i = 0;i < time;i++)
          {
          W_WDT();
          for (j=0;j<30000;j++)
          {
          }
          }
          }

          //---------------------------------
          //串行口初始化設(shè)置
          //方式1,8數(shù)據(jù)位,一個停止位,無奇偶校驗
          //串口中斷允許
          //------------------------------------
          void UART_ini(void)
          {
          SCON = 0x50;//方式1,波特率可變,8bits,接受允許
          PCON&= 0x7F;//SMOD = 0
          TMOD |= 0x20;//timer1 mode 2

          TL1 = UART_BTR[2];//|f
          //|波特率=----------------------
          TH1 = UART_BTR[2];//|32*2^smod*12*(256-TL1)
          TCON |= 0x40;//start

          TI = 0;
          }

          //-----------------------------------------------
          //
          //看門狗“喂狗”程序,WDT的一個下降沿觸發(fā)一次
          //
          //-----------------------------------------------
          void W_WDT(void)//triggle WDT
          {
          unsigned char i;
          WDT = 1;
          for (i=0;i<10;i++)
          {
          }
          WDT = 0;
          }

          //---------------------------------------------------
          //
          //中斷初始化
          //
          //----外部中斷0有效,下降沿觸發(fā),用于SJA1000產(chǎn)生CAN事件中斷
          //----定時器中斷,用于判定串口接收的順序兩個字節(jié)是否分屬兩幀
          //----串口中斷,RX使用中斷,TX未使用
          //----中斷優(yōu)先級暫時未設(shè)定
          //
          //---------------------------------------------------
          void Interrupt_init(void)
          {
          //IP = 0x00;
          IT0 = 0x01; //外部0中斷沿觸發(fā)

          ET0 = 1;//定時器0中斷使能
          EX0 = 1;//外部中斷使能
          ES = 1; //串行中斷使能
          }

          //---------------------------------------------------
          //
          //定時中斷程序
          //
          //一旦中斷,說明一幀的接收已經(jīng)結(jié)束,開始啟動CAN發(fā)送程序
          //把串口接收到的數(shù)據(jù)準備好給CAN總線發(fā)送
          //RX_buffer ===> CAN_TX_buffer
          //
          //---------------------------------------------------
          void Timer0_ISR(void) interrupt 1 using 2
          {
          static unsigned char i;
          //unsigned char counter;

          //TH0 = temp_TH0;
          //TL0 = temp_TL0;

          /*counter += 1;
          if (counter == 20)//到1S了么?
          {
          //UART_flag = YES;
          }
          if (counter == 40)//到2S了么?
          {
          //CAN_flag = YES;
          counter = 0;
          }*/
          //AAA = !AAA;
          TR0 = 0;//定時器關(guān),開始次CAN信息傳送

          for (i=0;i<uart_datalength;i++)
          {
          CAN_TX_Data[i] = UART_RX_Data[i];
          }
          UART_Length = UART_DataLength;
          UART_DataLength = 0;
          CAN_flag = YES;
          }
          //---------------------------------------------------------------
          //
          //串口中斷服務(wù)程序
          //
          //----只有接收使用
          //----每收一個數(shù)重新初始化定時器
          //
          //----------------------------------------------------------------
          void RX_INT(void) interrupt 4 using 3
          {
          static unsigned char n;

          if (RI==1)
          {
          do
          {
          RI = 0;
          }
          while (RI != 0);

          //UART_RX_Data[UART_DataLength++] = SBUF;
          n = SBUF;
          UART_Send_Byte(n);

          TH0 = temp_TH0;
          TL0 = temp_TL0;
          TR0 = 1;//啟動數(shù)據(jù)間隔定時,判斷是否分屬兩幀
          }
          else
          {
          //TX
          }
          }
          //---------------------------------------------------------------
          //
          //串口發(fā)送單字節(jié)程序
          //
          //----------------------------------------------------------------
          void UART_Send_Byte(unsigned char Data)
          {
          SBUF = Data;
          while (TI == 0)//等待發(fā)送完畢
          {
          }
          TI = 0;
          }

          //---------------------------------------------------------------
          //
          //初始化定時器程序
          //
          //----定時器0方式1,定時器1方式2留給串口
          //
          //----------------------------------------------------------------
          void Timer_init(void)
          {
          TMOD |= 0x01;//使用定時器0-方式1

          TH0 = temp_TH0;
          TL0 = temp_TL0;
          //TR0 = 1;//這里不打開定時器
          }

          void CAN_init(void)
          {

          EA = 0;
          MOD_CAN1 |= 0x08;//單濾波方式
          do
          {
          MOD_CAN1 |= 0x01; //request to reset mode
          }
          while ((MOD_CAN1&0x01) != 0x01);

          CDR_CAN1 = 0xc8;//選擇PeliCAN模式,使用輸入比較器,clk_out關(guān)閉
          IER_CAN1 = 0x01;//允許發(fā)送中斷,其他中斷禁能

          ACR0_CAN1 = ACR_ID[0];
          ACR1_CAN1 = ACR_ID[1];
          ACR2_CAN1 = ACR_ID[2];
          ACR3_CAN1 = ACR_ID[3];
          AMR0_CAN1 = AMR_ID[0];
          AMR1_CAN1 = AMR_ID[1];
          AMR2_CAN1 = AMR_ID[2];
          AMR3_CAN1 = AMR_ID[3];

          //ECC_CAN1 = 0;
          //TXERR_CAN1 = 0;
          //RBSA_CAN1 = 0;

          BTR0_CAN1 = CAN_BTR0[0];
          BTR1_CAN1 = CAN_BTR1[0];
          OCR_CAN1 = 0xaa;//normal output

          W_WDT();
          do
          {
          MOD_CAN1 &= 0xfe;
          }
          while ((MOD_CAN1&0x01) != 0x00);
          EA = 1;
          }

          //-----------------------------------
          //
          //串口發(fā)送一幀接受到的CAN數(shù)據(jù)
          //
          //----長度1-8,根據(jù)接收到的CAN信息來確定
          //
          //-----------------------------------
          void UART_Transmit(void) //using 0
          {
          unsigned char i;

          LED3 = !LED3;
          for (i=0;i{
          UART_Send_Byte(CAN_RX_Data[i]);
          }
          }
          //-----------------------------------
          //
          //CAN發(fā)送接受到的一幀串口數(shù)據(jù)
          //
          //----最大長度255,根據(jù)接收到的串口信息的
          //個數(shù)來確定
          //----按每依次8個數(shù)據(jù)作為一個CAN幀的報文部分
          //不足8個或超過8的倍數(shù)的部分按實際個數(shù)作
          //為CAN報文
          //----FarmeType = 1為擴展幀,F(xiàn)armeType = 0為
          //標準幀
          //-----------------------------------
          void CAN_Transmit(bit FarmeType)
          {

          unsigned char i;
          unsigned char m;
          unsigned char can_status;
          unsigned char xdata *pointer;


          if (FarmeType == 0)//標準幀
          {
          for (m=0;m<(UART_Length/8);m++)
          {
          W_WDT();
          do//發(fā)送緩沖區(qū)空么?
          {
          can_status = SR_CAN1;
          }
          while ((can_status&0x04) != 0x04);

          TXFrameInfo1 = 0x00 + 0x08;
          pointer = &TXID1;
          for (i=0;i<2;i++)
          {
          *(pointer++) = CAN_TX_ID[i];
          }

          pointer = &TXID3;
          for (i=0;i<8;i++)
          {
          *(pointer++) = CAN_TX_Data[i+8*m];
          }
          CMR_CAN1 = Request_TX;
          W_WDT();
          }

          if ((UART_Length%8) != 0)
          {
          W_WDT();
          do //發(fā)送緩沖區(qū)空么?
          {
          can_status = SR_CAN1;
          }
          while ((can_status&0x04) != 0x04);
          TXFrameInfo1 = 0x00 + UART_Length%8;
          pointer = &TXID1;
          for (i=0;i<2;i++)
          {
          *(pointer++) = CAN_TX_ID[i];
          }

          pointer = &TXID3;
          for (i=0;i<(UART_Length%8);i++)
          {
          *(pointer++) = CAN_TX_Data[i+8*(UART_Length/8)];
          }
          CMR_CAN1 = Request_TX;
          W_WDT();
          }
          else
          {
          }
          }
          else//擴展幀
          {
          for (m=0;m<(UART_Length/8);m++)
          {
          W_WDT();
          do//發(fā)送緩沖區(qū)空么?
          {
          can_status = SR_CAN1;
          }
          while ((can_status&0x04) != 0x04);

          TXFrameInfo1 = 0x80 + 0x08;
          pointer = &TXID1;
          for (i=0;i<4;i++)
          {
          *(pointer++) = CAN_TX_ID[i];
          }

          pointer = &TXDATA1;
          for (i=0;i<8;i++)
          {
          *(pointer++) = CAN_TX_Data[i+8*m];
          }
          CMR_CAN1 = Request_TX;
          W_WDT();
          }

          if ((UART_Length%8) != 0)
          {
          W_WDT();
          do//發(fā)送緩沖區(qū)空么?
          {
          can_status = SR_CAN1;
          }
          while ((can_status&0x04) != 0x04);
          TXFrameInfo1 = 0x80 + UART_Length%8;
          pointer = &TXID1;
          for (i=0;i<4;i++)
          {
          *(pointer++) = CAN_TX_ID[i];
          }

          pointer = &TXDATA1;
          for (i=0;i<(UART_Length%8);i++)
          {
          *(pointer++) = CAN_TX_Data[i+8*(UART_Length/8)];
          }
          CMR_CAN1 = Request_TX;
          W_WDT();
          }
          else
          {
          }
          }

          UART_Length = 0;

          }

          //-----------------------------------
          //
          //CAN接收中斷服務(wù)程序
          //
          //----判斷是否是RX中斷,如果是
          //把接受到的CAN信息通過串行口發(fā)送出去
          //----其他的中斷說明CAN總線出現(xiàn)錯誤或脫離
          //
          //-----------------------------------
          void CAN_ISR(void) interrupt 0 using 1
          {
          unsigned char can_int;

          EA = 0;

          can_int = IR_CAN1;
          if ((can_int&0x01) == 0x01)//接收中斷
          {
          CAN_Receive();
          CMR_CAN1 |= ReleaseRXBuf;
          }
          else
          {
          CAN_ERROR_flag = YES;//其他中斷,暫時未用
          }

          //UART_flag = YES;
          //CAN_flag = YES;
          UART_Transmit();

          EA = 1;
          }

          //-----------------------------------
          //
          //CAN接收數(shù)據(jù)函數(shù)
          //
          //----根據(jù)接受到的幀信息,按不同的長度存儲
          //報文數(shù)據(jù)
          //
          //-----------------------------------
          void CAN_Receive(void) using 1
          {
          unsigned char i;
          unsigned char xdata *pointer;
          unsigned char Info;

          Info = RXFrameInfo1;

          if ((Info&0x80) == 0)//standard Frame
          {
          //CAN_RX_ID[0] = RXID1;
          //CAN_RX_ID[1] = RXID2;

          CAN_DataLength = Info&0x0f;
          pointer = &RXID3;
          for (i=0;i{
          CAN_RX_Data[i] = *(pointer++);
          }
          for (;i<8;i++)
          {
          CAN_RX_Data[i] = 0x00;
          }
          }
          else//Ex Frame
          {
          //CAN_RX_ID[0] = RXID1;
          //CAN_RX_ID[1] = RXID2;
          //CAN_RX_ID[2] = RXID3;
          //CAN_RX_ID[3] = RXID4;
          CAN_DataLength = Info&0x0f;
          pointer = &RXDATA1;
          for (i=0;i{
          CAN_RX_Data[i] = *(pointer++);
          //pointer += 1;
          }
          for (;i<8;i++)
          {
          CAN_RX_Data[i] = 0x00;
          }
          }
          }
          //-----------------------------------
          //
          //清0緩沖區(qū)
          //
          //----pointer,指向待清0 的緩沖區(qū)首地址
          //----length 清0 的長度
          //-----------------------------------
          void Clear_Buffer(unsigned char *pointer,unsigned char length)
          {
          unsigned char i;

          for (i=0;i{
          *(pointer++) = 0x00;
          }
          }

          另外頭文件為:

          #ifndef _CANCOM_H
          #define _CANCOM_H

          #define CS1_SJA1000 0x7f00//SJA1000 Pin /CS ----> P2.7,low level active

          #define MOD_CAN1XBYTE[CS1_SJA1000+0] //Peli
          #define CMR_CAN1XBYTE[CS1_SJA1000+1]//command
          #define SR_CAN1XBYTE[CS1_SJA1000+2] //state
          #define IR_CAN1XBYTE[CS1_SJA1000+3] //interrupt
          #define IER_CAN1XBYTE[CS1_SJA1000+4]//interrupt enable //Peli
          #define BTR0_CAN1XBYTE[CS1_SJA1000+6] //bus timing0
          #define BTR1_CAN1XBYTE[CS1_SJA1000+7] //bus timing1
          #define OCR_CAN1XBYTE[CS1_SJA1000+8]
          #define TEST_CAN1XBYTE[CS1_SJA1000+9]
          #define ECC_CAN1XBYTE[CS1_SJA1000+12]//error catch
          #define EWLR_CAN1XBYTE[CS1_SJA1000+13]//error warning limit
          #define RXERR_CAN1XBYTE[CS1_SJA1000+14]//
          #define TXERR_CAN1XBYTE[CS1_SJA1000+15]
          #define ACR0_CAN1XBYTE[CS1_SJA1000+16]
          #define ACR1_CAN1XBYTE[CS1_SJA1000+17]
          #define ACR2_CAN1XBYTE[CS1_SJA1000+18]
          #define ACR3_CAN1XBYTE[CS1_SJA1000+19]
          #define AMR0_CAN1XBYTE[CS1_SJA1000+20]
          #define AMR1_CAN1XBYTE[CS1_SJA1000+21]
          #define AMR2_CAN1XBYTE[CS1_SJA1000+22]
          #define AMR3_CAN1XBYTE[CS1_SJA1000+23]
          #define RBSA_CAN1XBYTE[CS1_SJA1000+30]//beginning of receive
          #define CDR_CAN1XBYTE[CS1_SJA1000+31]//clock devide

          #define TXFrameInfo1 XBYTE[CS1_SJA1000+16]
          #define TXID1 XBYTE[CS1_SJA1000+17]
          #define TXID2 XBYTE[CS1_SJA1000+18]
          #define TXID3 XBYTE[CS1_SJA1000+19]
          #define TXID4 XBYTE[CS1_SJA1000+20]
          #define TXDATA1 XBYTE[CS1_SJA1000+21]
          #define TXDATA2 XBYTE[CS1_SJA1000+22]
          #define TXDATA3 XBYTE[CS1_SJA1000+23]
          #define TXDATA4 XBYTE[CS1_SJA1000+24]
          #define TXDATA5 XBYTE[CS1_SJA1000+25]
          #define TXDATA6 XBYTE[CS1_SJA1000+26]
          #define TXDATA7 XBYTE[CS1_SJA1000+27]
          #define TXDATA8 XBYTE[CS1_SJA1000+28]

          #define RXFrameInfo1 XBYTE[CS1_SJA1000+16]
          #define RXID1 XBYTE[CS1_SJA1000+17]
          #define RXID2 XBYTE[CS1_SJA1000+18]
          #define RXID3 XBYTE[CS1_SJA1000+19]
          #define RXID4 XBYTE[CS1_SJA1000+20]
          #define RXDATA1 XBYTE[CS1_SJA1000+21]
          #define RXDATA2 XBYTE[CS1_SJA1000+22]
          #define RXDATA3 XBYTE[CS1_SJA1000+23]
          #define RXDATA4 XBYTE[CS1_SJA1000+24]
          #define RXDATA5 XBYTE[CS1_SJA1000+25]
          #define RXDATA6 XBYTE[CS1_SJA1000+26]
          #define RXDATA7 XBYTE[CS1_SJA1000+27]
          #define RXDATA8 XBYTE[CS1_SJA1000+28]

          #defineGoToRESET0x01
          #defineReleaseRXBuf0x04
          #defineRequest_TX0x01

          #defineNOT0
          #defineYES1
          //4800bps 5bits 1.04mS
          #define TIME_MS1
          #define temp_TH0(0 - 922*TIME_MS)/256
          #define temp_TL0(0 - 922*TIME_MS)%256

          sbit LED1 = P1^2;
          sbit LED2 = P1^3;
          sbit LED3 = P1^5;
          sbit LED4 = P1^4;
          sbit WDT = P3^4;

          void System_init(void);
          void Delay(unsigned char time);
          void W_WDT(void);
          void Interrupt_init(void);
          void CAN_init(void);
          //void CAN_Transmit(unsigned char Farmeinfo);
          void CAN_Transmit(bit FarmeType);
          void CAN_Receive(void);
          void Timer_init(void);
          void UART_ini(void);
          void UART_Send_Byte(unsigned char Data);
          void UART_Transmit(void);
          void Clear_Buffer(unsigned char *pointer,unsigned char length);

          #endif



          關(guān)鍵詞: 單片機CAN總線通信程

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();