新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > AVR單片機實現了232到CAN轉換

        AVR單片機實現了232到CAN轉換

        作者: 時間:2016-11-27 來源:網絡 收藏
        #define TXREQ_SET 0x08
        #define TXREQ_CLEAR 0x00
        #define TXP_HIGHEST 0x03
        #define TXP_INTER_HIGH 0x02
        #define TXP_INTER_LOW 0x01
        #define TXP_LOWEST 0x00
        #define DLC_0 0x00
        #define DLC_1 0x01
        #define DLC_2 0x02
        #define DLC_3 0x03
        #define DLC_4 0x04
        #define DLC_5 0x05
        #define DLC_6 0x06
        #define DLC_7 0x07
        #define DLC_8 0x08
        #define CAN_RESET 0xC0
        #define CAN_READ 0x03
        #define CAN_WRITE 0x02
        #define CAN_RTS 0x80
        #define CAN_RTS_TXB0 0x81
        #define CAN_RTS_TXB1 0x82
        #define CAN_RTS_TXB2 0x84
        #define CAN_RD_STATUS 0xA0
        #define CAN_BIT_MODIFY 0x05
        #define CAN_RX_STATUS 0xB0
        #define CAN_RD_RX_BUFF 0x90
        #define CAN_LOAD_TX 0X40
        #define DUMMY_BYTE 0x00
        #define TXB0 0x31
        #define TXB1 0x41
        #define TXB2 0x51
        #define RXB0 0x61
        #define RXB1 0x71
        #define EXIDE_SET 0x08
        #define EXIDE_RESET 0x00
        uchar can_boud=0x07;//MCP2515在16M晶振情況,can_boud=0x00總線波特率為1M,0x01=500K,0x03=250K,0x07=125K;公式:16M/(16*(1+X))
        uint bps=38400;//定義avr單片機串口波特率
        uchar eflag=0;//是不是擴展幀,為1則表示接收到的是擴展幀,0表示標準幀
        uchar Tdate[10]={0};//存放要發送標準幀的數據,最大10位,前2位是ID號,后8位是數據位
        uchar TID[2]={0,0};//存放要發送標準幀的ID號
        uchar Rdate[8]={0};//存放接收到的數據
        uchar RESID[4];//存放接收到的數據幀的ID號,標準幀只用到RESID[0],RESID[1],擴展幀全部用到
        uchar bytetime;//232與CAN透明轉換時,根據不同的波特率確定所要延時的時間,
        uint usart_number=0;//計數當前所接收的串行數據的那一組數據流的數據個數,串口傳來的數據存放在Tdate中等待用CAN標準幀發送
        uchar state;//2515狀態(包括發送接收中斷標志位和各請求發送位),具體見數據手冊
        uchar DLC=8;//接收到數據的長度
        //
        //
        void delay(uchar k)//
        {uint i=0;
        while(k--){for(i=0;i<8000;i++);}
        }
        //##############################################################################
        void Set_CS(uchar level) //
        {if(level) PORTB|=0x10; //
        else PORTB&=0xef; //
        }
        //##############################################################################
        //
        //
        void WriteSPI(uchar order)
        { uchar clear;
        Set_CS(0); //
        SPDR=order; //2515讀指令為0x03
        while(!(SPSR&0x80)); //等待SPIF置位,等數據發送完畢
        clear=SPSR;
        clear=SPDR;//
        Set_CS(1); //
        }
        //
        uchar Read_state(uchar order)//讀狀態命令,order=0xa0,0xa1,
        { uchar clear;
        Set_CS(0); //
        SPDR=order; //
        while(!(SPSR&0x80)); //等待SPIF置位,等數據發送完畢
        clear=SPSR;
        clear=SPDR;//
        SPDR=0; //空數據
        while(!(SPSR&0x80));//等待SPIF置位,等數據發送完畢
        clear=SPSR;
        clear=SPDR; //通過先讀SPSR,緊接著訪問SPDR來對SPIF清零
        Set_CS(1); //
        return clear;
        }
        //
        uchar Read_Byte(uchar Address)
        {uchar clear;
        uchar date;
        Set_CS(0); //使能SPI器件
        SPDR=0x03; //送2515讀指令為0x03
        while(!(SPSR&0x80)); //等待SPIF置位,等數據發送完畢
        clear=SPSR;
        clear=SPDR; //通過先讀SPSR,緊接著訪問SPDR來對SPIF清零
        SPDR=Address; //送地址
        while(!(SPSR&0x80));
        clear=SPSR;
        clear=SPDR;
        SPDR=0x00; //發空數據,啟動數據發送以接收數據
        while(!(SPSR&0x80));
        clear=SPSR;
        clear=SPDR;
        date=SPDR; //接收數據
        Set_CS(1); //關SPI器件DS1722
        return date;
        }
        //
        void Write_Byte(uchar Address,uchar Data)
        {uchar clear;
        Set_CS(0); //使能SPI器件2515
        SPDR=0x02; //送2515寫命令為0x02
        while(!(SPSR&0x80));//等待SPIF置位,等數據發送完畢
        clear=SPSR;
        clear=SPDR;
        SPDR=Address; //送地址,啟動SPI時鐘
        while(!(SPSR&0x80));//等待SPIF置位,等數據發送完畢
        clear=SPSR;
        clear=SPDR; //通過先讀SPSR,緊接著訪問SPDR來對SPIF清零
        SPDR=Data;
        while(!(SPSR&0x80));
        clear=SPSR;
        clear=SPDR;
        Set_CS(1); //關SPI器件
        }
        //
        //###########################對CAN的一些操作####################################
        //
        void load_Standard_ID_dates(uchar num)//給標準幀裝載ID和數據
        //選用發送緩沖器0,num:要發送的個數(最大8個)
        {
        uchar i,j,T0=0x36;
        uchar TIDH,TIDL;
        i=TID[1]>>3;j=TID[0]<<5;j=j+i;i=TID[1]<<5;
        TIDL=i;TIDH=j;//將數組TID中的值轉化為TIDH,TIDL以便給TXB0SIDH,TXB0SIDL附值
        Write_Byte(CANCTRL,0x80);//CAN工作在配置模式
        Write_Byte(CNF1,can_boud);
        Write_Byte(TXB0SIDH,TIDH);
        Write_Byte(TXB0SIDL,TIDL);
        Write_Byte(TXB0DLC,num);//
        for(i=2;i
        }
        //##############################################################################
        void Receive_all_ID_process(void)//結合MCP2515數據手冊來看
        {uchar k;
        k=RESID[1];//先判斷接收到的是不是標準幀,因為標準幀和擴展幀的ID處理不一樣
        if((k&0x08)==0)
        {//如果是標準處理方法
        RESID[1]=RESID[1]>>5;
        k=RESID[0]&0x1f;//借用k
        k=k<<3;
        RESID[1]=RESID[1]+k;
        RESID[0]=RESID[0]>>5;
        }
        else
        {//擴展幀處理方法,RESID[3]、RESID[4]不變
        k=k>>5;
        k=k<<2;
        RESID[1]=RESID[1]&0x03;
        RESID[1]=RESID[1]+k;
        k=RESID[0];
        k=k<<5;
        RESID[1]=RESID[1]+k;
        RESID[0]=RESID[0]>>3;//將RXB0SIDH,RXB0SIDL轉化
        }
        }
        //##############################################################################
        //##############################USART初始化程序###########################//
        void usart_init(void)
        {
        UCSRB=(1<
        UBRRL=(fosc/16/(bps+1))%6;
        UBRRH=(fosc/16/(bps+1))/256;
        UCSRC=(1<
        bytetime=215983/bps;//215983=1000000*20/92.6,92.6=1024/11.0592,定時器分頻為1024
        bytetime=255-bytetime;//計算不同的波特率所要延時的初值,要附值給TCNT0,實現透明轉換中用到
        }
        //##########################串行通信##########################//
        void putchar(uchar c)
        {while(!(UCSRA&(1<
        UDR=c;}
        //##############################中斷服務程序##################################//
        void INT1_17(void)
        {
        uchar i,j,k,R0=0x66;
        GICR &=0x7f;
        state=Read_state(0xa0);
        //WriteSPI(0xa0);//讀取2515狀態指令,狀態值附值給state
        if((state&0x01)!=0)
        {//判斷是不是接收緩沖器0滿產生的中斷
        k=Read_Byte(RXB0SIDL);//為了判斷是標準幀還是擴展幀
        if((k&0x08)==0)eflag=0;//置標準幀標志
        else eflag=1;//置擴展幀標志
        DLC=Read_Byte(RXB0DLC);
        DLC &=0x0f;
        RESID[0]=Read_Byte(RXB0SIDH);
        RESID[1]=Read_Byte(RXB0SIDL);
        RESID[2]=Read_Byte(RXB0EID8);
        RESID[3]=Read_Byte(RXB0EID0);//先讀取所有ID
        Receive_all_ID_process();//處理RESID
        for(i=0;i
        if(eflag==0)
        {//如果是標準幀
        putchar(RESID[0]);
        putchar(RESID[1]);//先送標準幀ID號
        }
        else
        {//如果是擴展幀
        putchar(RESID[0]);
        putchar(RESID[1]);
        putchar(RESID[2]);
        putchar(RESID[3]);//先送擴展幀ID號
        }
        putchar(DLC);
        for(i=0;i
        }
        Write_Byte(CANINTF,0x00);//接收完一次必須對中斷標志位清0
        GICR |=0x80;
        }
        //####################################
        void Usart_receive(void)//定義接收中斷服務程序
        {Tdate[usart_number]=UDR;
        usart_number++;
        TIMSK=0x05;//打開T1,T0中斷屏蔽
        TCCR0=0x05;//設T0分頻數為1024
        TCNT0=bytetime;//設T0時間常數,從此值開始計數
        }
        //##############定時器中斷0,串行數據流控制
        void Timer0(void)
        {TIMSK=0x00;//關T0中斷屏蔽
        TCNT0=0x00;//
        TCCR0=0x00;//T0停止計數
        if((usart_number>2)&&(usart_number<11))
        {
        TID[0]=Tdate[0];TID[1]=Tdate[1];
        load_Standard_ID_dates(usart_number-2);//對2515發送緩沖器0和ID寄存器進行數據裝載
        usart_number=0;
        Write_Byte(CANCTRL,0x00);//選定工作模式
        WriteSPI(CAN_RTS_TXB0);//發送緩沖器0請求發送
        }
        else usart_number=0;
        }
        //##############################CAN(2515)初始化程序###########################//
        void CAN_Initialize(void)
        {
        WriteSPI(CAN_RESET);
        delay(20);
        Write_Byte(CANCTRL,0x80);//CAN工作在配置模式
        Write_Byte(CNF1,can_boud);
        Write_Byte(CNF2,0x80 | PHSEG1_3TQ | PRSEG_1TQ);//Set CNF2
        Write_Byte(CNF3,PHSEG2_3TQ);
        //0x80+0x10+0x00,相位緩沖段2由CNF3確定,相位緩沖段1為3TQ,傳播段為1TQ
        Write_Byte(RXB0CTRL,0xf0);//接收類型選擇,接收所有報文
        Write_Byte(CANINTF,0x00);//接收完一次必須對中斷標志位清0
        Write_Byte(CANINTE,0x01);//接收緩沖器0滿中斷使能
        Write_Byte(CANCTRL,0x00);//選定正常工作模式
        }
        //##############################系統初始化程序################################//
        void AVR_Initialize(void) //初始化
        {
        DDRB=0xff; //SPI口
        PORTB=0xff;
        DDRD=0xf0;//將外部中斷引腳設定為輸入
        PORTD=0x7f;
        SPCR=0b01011100;//關中斷(SPIE=0),使能SPI(SPE=1),MSB首先發送(DORD=0)
        //選擇微機為主機模式(MSTR=1)
        //空閑時SCK 為高電平(CPOL=1)
        //在SCK 的結束沿采樣(CPHA=1)以保證數據穩定
        //SPR1=0和SPR0=0,SCK=fosc/4
        SPSR |=0x01;//SPI的速度加倍
        MCUCR=0x0a;//設置外部中斷的中斷觸發方式為下降沿觸發
        GICR=0xc0;//通用中斷控制寄存器設置,打開中斷INT0和INT1
        SREG=0x80;//開全局中斷
        }
        //##################################主程序####################################//
        void main()
        {
        AVR_Initialize(); //I/O口及中斷初始化
        CAN_Initialize();
        usart_init();
        UCSRB |=0x80;//接收中斷使能
        }


        上一頁 1 2 下一頁

        關鍵詞: AVR單片機232CAN轉

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 兴化市| 柘城县| 修水县| 岑巩县| 彭山县| 光泽县| 奉节县| 柏乡县| 大丰市| 阜南县| 合阳县| 皋兰县| 曲松县| 重庆市| 青海省| 唐山市| 英吉沙县| 桐乡市| 周至县| 凤庆县| 万盛区| 信丰县| 克东县| 乾安县| 榆中县| 嘉祥县| 锦州市| 邻水| 蛟河市| 罗定市| 务川| 建阳市| 台江县| 张家口市| 潮州市| 班玛县| 朝阳区| 乌拉特后旗| 万荣县| 襄汾县| 灯塔市|