新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > CAN總線通信程序

        CAN總線通信程序

        作者: 時間:2016-12-13 來源:網絡 收藏
        //------------------------------------------------------

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

        本文引用地址:http://www.104case.com/article/201612/329224.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];//待發送的數據緩沖區
        unsigned char code ACR_ID[4] = {0,0,0,0};//CAN初始設置驗收濾波值
        unsigned char code AMR_ID[4] = {0xff,0xff,0xff,0xff};
        unsigned char CAN_TX_ID[4] = {0,0,0,0};//待發送的目標的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};//接受到的數據緩沖
        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發送標志位
        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;//串口接收區的長度指示
        //sbit AAA = P1^4;

        void main(void)
        {
        EA = 0;
        System_init();//系統初始化
        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;
        }
        }
        }
        //---------------------------
        //功能:系統設置
        //--外部數據存儲區訪問使能
        //--LED指示燈關(1=on,0=off)
        //--流程控制標志置為無效NOT
        //--清空串口,CAN的相關數據緩沖區
        //---------------------------
        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;
        */
        }
        //-----------------------------
        //
        //軟件延時(非精確)
        //----內置清看門狗定時器子函數
        //防止多次調用延時過長導致
        //看門狗復位
        //
        //-----------------------------
        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++)
        {
        }
        }
        }

        //---------------------------------
        //串行口初始化設置
        //方式1,8數據位,一個停止位,無奇偶校驗
        //串口中斷允許
        //------------------------------------
        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的一個下降沿觸發一次
        //
        //-----------------------------------------------
        void W_WDT(void)//triggle WDT
        {
        unsigned char i;
        WDT = 1;
        for (i=0;i<10;i++)
        {
        }
        WDT = 0;
        }

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

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

        //---------------------------------------------------
        //
        //定時中斷程序
        //
        //一旦中斷,說明一幀的接收已經結束,開始啟動CAN發送程序
        //把串口接收到的數據準備好給CAN總線發送
        //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;//定時器關,開始次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;
        }
        //---------------------------------------------------------------
        //
        //串口中斷服務程序
        //
        //----只有接收使用
        //----每收一個數重新初始化定時器
        //
        //----------------------------------------------------------------
        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;//啟動數據間隔定時,判斷是否分屬兩幀
        }
        else
        {
        //TX
        }
        }
        //---------------------------------------------------------------
        //
        //串口發送單字節程序
        //
        //----------------------------------------------------------------
        void UART_Send_Byte(unsigned char Data)
        {
        SBUF = Data;
        while (TI == 0)//等待發送完畢
        {
        }
        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關閉
        IER_CAN1 = 0x01;//允許發送中斷,其他中斷禁能

        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;
        }

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

        LED3 = !LED3;
        for (i=0;i{
        UART_Send_Byte(CAN_RX_Data[i]);
        }
        }
        //-----------------------------------
        //
        //CAN發送接受到的一幀串口數據
        //
        //----最大長度255,根據接收到的串口信息的
        //個數來確定
        //----按每依次8個數據作為一個CAN幀的報文部分
        //不足8個或超過8的倍數的部分按實際個數作
        //為CAN報文
        //----FarmeType = 1為擴展幀,FarmeType = 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//發送緩沖區空么?
        {
        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 //發送緩沖區空么?
        {
        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//發送緩沖區空么?
        {
        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//發送緩沖區空么?
        {
        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接收中斷服務程序
        //
        //----判斷是否是RX中斷,如果是
        //把接受到的CAN信息通過串行口發送出去
        //----其他的中斷說明CAN總線出現錯誤或脫離
        //
        //-----------------------------------
        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接收數據函數
        //
        //----根據接受到的幀信息,按不同的長度存儲
        //報文數據
        //
        //-----------------------------------
        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緩沖區
        //
        //----pointer,指向待清0 的緩沖區首地址
        //----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



        關鍵詞: CAN總線通信程

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 甘德县| 汝城县| 武隆县| 邹城市| 青田县| 三穗县| 奎屯市| 咸阳市| 营山县| 泸州市| 定结县| 鄂州市| 西充县| 建瓯市| 楚雄市| 光山县| 清苑县| 贵港市| 灵寿县| 老河口市| 崇州市| 陈巴尔虎旗| 扶余县| 西林县| 贵德县| 漠河县| 上高县| 盐边县| 苗栗市| 雷州市| 积石山| 南和县| 天镇县| 宝应县| 郓城县| 章丘市| 新沂市| 西乌珠穆沁旗| 萝北县| 邢台市| 岐山县|