新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 基于PIC的LIN總線設計

        基于PIC的LIN總線設計

        作者: 時間:2016-11-18 來源:網絡 收藏
        簡介:

        1.主節點

        本文引用地址:http://www.104case.com/article/201611/315945.htm

        主節點資源:4個按鍵,采用9600波特率的UART,在發送同步間隔場時用4800!收發芯片:MCP201

        2.從節點

        從節點資源:UART,CCP捕捉 首先用接收引腳狀態判斷是否同步間隔場,用定時器1進行計時判斷同步間隔場是否合格,判斷合格后,用CCP模塊捕捉同步頭55H,同時計算波特率,之后打開UART進行數據接收!

        程序如下:

        1.MASTER

        // LIN 總線設計
        //---------------------------------------------
        // 文件名: MASTER.c
        // 版本: V1.0
        // 日期: 25/12/06
        // 功能: LIN總線主節點
        // 編譯環境: HiTech PIC C compiler v.8.05
        // 使用MCU: PIC16F877
        // 通信速率: 9600
        //---------------協議說明---------------------
        //數據發送按照USART方式發送
        //Lin協議說明:
        //1.電平定義:
        // 顯性電平:邏輯0
        // 隱性電平:邏輯1
        //2.數據組成
        // 同步間隔場:至少13位的顯性電平,以及1個位的界定符(隱性電平)
        // 同步場:0x55主機發送,從機通過定時器捕捉方式來計時計算波特率
        // 數據場:
        // a.標識符場:定義了報文的內容和長度,最高兩位是奇偶校驗位
        // 位5和6是數據長度標識,低四位是地址標識符
        // b.命令場:由2.4.8個數據字節組成,外加一個數據校驗場
        // 保留標識符:(廣播標識符)
        // "0x3c"主機請求,用于主機廣播命令,所有從機都接收
        // "0x3d"從機響應,觸發所有從機節點順序向主機傳送數據
        // 第一個數據場的00-7F保留,其余自由分配(程序里沒有遵循,實驗嘛呵呵)
        //---------------------------------------------
        #include
        //---------------------------------------------
        //--------------常量定義----------------------
        #define Key1 RA0
        #define Key2 RA1
        #define Key3 RA2
        #define Key4 RA3
        #define CS RB1


        #define STATUSIT(avr,s) ((unsigned)(&avr)*8+(s)) //絕對尋址定義
        static bit C @ STATUSIT(STATUS,0); //對進位位進行定義
        //----------------內存定義--------------------
        unsigned char send[10]; //定義數據數組
        unsigned char Counter; //發送個數計數
        //--------------函數定義----------------------
        void Picint(void); //初始化
        void KeyScan(void); //鍵盤掃描
        void Work1(void); //事件處理1
        void Work2(void); //事件處理2
        void Work3(void); //事件處理3
        void Work4(void); //事件處理4
        void interrupt SDI(void); //中斷函數
        void Delay(unsigned int m); //延時函數
        void Send(void); //數據發送
        void SendSync(void); //同步間隔場和同步頭發送
        void SendData(unsigned char asd); //發送數據場
        unsigned char CheckSum(unsigned char as); //校驗和計算
        void qushu();
        //*********************************************
        //主函數
        //*********************************************
        void main()
        {
        Picint();
        while(1)
        {
        KeyScan(); //鍵盤掃描等待處理
        }
        }

        //*********************************************
        //初始化函數
        //*********************************************
        void Picint()
        {
        INTCON=0; //中斷定義
        ADCON1=0x07; //定義A口為數字ioput模式
        TRISA0=1; //鍵盤接口定義
        TRISA1=1;
        TRISA2=1;
        TRISA3=1;
        TRISB0=1; //中斷定義端口
        TRISB1=0; //片選引腳

        TXSTA=0x04; //USART模塊設置,使用高速波特率設置
        RCSTA=0x80; //使能串口,并沒有開啟接收和發送

        TRISC7=1; //數據輸入
        TRISC6=0; //數據發送
        CS=1; //片選
        RC6=1;
        }
        //*********************************************
        //數據發送 USART
        //*********************************************
        void Send()
        {
        //TXEN=1; //發送使能
        SendSync(); //發送同步間隔場和同步頭
        SendData(Counter); //發送的字節的數量
        TXEN=0; //發送禁止
        }
        //*********************************************
        //同步間隔場和同步頭發送
        //*********************************************
        void SendSync()
        {
        SPBRG=0x33; //同步間隔場按照4800發送
        Delay(20);
        TXEN=1;
        Delay(20);
        TXREG=0x80; //同步間隔場
        while(1) //等待發送完畢
        {
        if(TXIF==1) break;
        }
        Delay(150);
        SPBRG=0x19; //修改波特率為9600
        Delay(50);
        TXREG=0x55; //發送同步頭,用于從機進行波特率計算
        while(1)
        {
        if(TXIF==1) break;
        }
        Delay(300); //延時準備發送數據
        }
        //*********************************************
        //發送數據場
        //*********************************************
        void SendData(unsigned char asd)
        {
        unsigned char i;
        TXREG=send[0]; //發送地址字節
        while(1)
        {
        if(TXIF==1) break;
        }
        Delay(250); //延時,供從節點判斷是否是自己的地址
        for(i=0;i {
        TXREG=send[i+1]; //發送數據字節,以及校驗字節
        while(1)
        {
        if(TXIF==1) break;
        }
        Delay(100);
        }
        }
        //*********************************************
        //校驗和計算
        //*********************************************
        unsigned char CheckSum(unsigned char as)
        {
        //校驗和說明:
        //是所有命令字節的和,但是如果相加的話產生進位位怎進位位加到和的最低位,最后結果取反
        //從節點接收后同樣計算命令字節和,而后與校驗字節相加,其和必須等于0xFF;
        unsigned char z,y;
        y=0;
        asm("bcf _STATUS,0"); //清進位位
        for(z=0;z {
        y=y+send[z+1];
        if(C)
        {
        C=0; //清除進位位供下次使用
        y=y+1; //如果進位位為1,則加到結果的最低位
        }
        }
        y=~y; //按位取反
        return y; //返回校驗和
        }
        //*********************************************
        //鍵盤掃描函數
        //*********************************************
        void KeyScan()
        {
        if(Key1)
        {
        Delay(8000); //延時消抖
        if(Key1) //確認鍵盤按下
        {
        while(Key1) //等待鍵盤釋放
        {}
        Work1(); //調用處理事件
        }
        }
        //----------------------------------------------
        if(Key2)
        {
        Delay(8000); //延時消抖
        if(Key2) //確認鍵盤按下
        {
        while(Key2) //等待鍵盤釋放
        {}
        Work2(); //調用處理事件
        }
        }
        //----------------------------------------------
        if(Key3)
        {
        Delay(8000); //延時消抖
        if(Key3) //確認鍵盤按下
        {
        while(Key3) //等待鍵盤釋放
        {}
        Work3(); //調用處理事件
        }
        }
        //----------------------------------------------
        if(Key4)
        {
        Delay(8000); //延時消抖
        if(Key4) //確認鍵盤按下
        {
        while(Key4) //等待鍵盤釋放
        {}
        Work4(); //調用處理事件
        }
        }
        }
        //*********************************************
        //事件處理
        //*********************************************
        void Work1()
        {
        send[0]=0xc1; //地址字節01,加上奇偶校驗為c1
        send[1]=0x12; //命令字節1
        send[2]=0x13; //命令字節2
        Counter=3;
        send[3]=CheckSum(Counter-1); //校驗和計算
        Send();
        }
        //---------------------------------------------
        void Work2()
        {
        send[0]=0xc1; //地址字節01,加上奇偶校驗為c1
        send[1]=0x22; //命令字節1
        send[2]=0x23;
        Counter=3;
        send[3]=CheckSum(Counter-1); //校驗和計算
        Send();
        }
        //---------------------------------------------
        void Work3()
        {
        send[0]=0xc1; //地址字節01,加上奇偶校驗為c1
        send[1]=0x32; //命令字節1
        send[2]=0x33;
        Counter=3;
        send[3]=CheckSum(Counter-1); //校驗和計算
        Send();
        }
        //---------------------------------------------
        void Work4()
        {
        send[0]=0xc1; //地址字節01,加上奇偶校驗為c1
        send[1]=0x42; //命令字節1
        send[2]=0x43;
        Counter=3;
        send[3]=CheckSum(Counter-1); //校驗和計算
        Send();
        }
        //*********************************************
        //延時函數
        //*********************************************
        void Delay( unsigned int m)
        {
        unsigned int i;
        for(i=0;i<=m;i++)
        {}
        }

        2.SLAVE

        // Lin總線
        //---------------------------------------------
        // 文件名: slave(mew).c
        // 版本: V1.0
        // 日期: 13/12/06
        // 功能: Lin 總線從節點
        // 編譯環境: HiTech PIC C compiler v.8.05
        // 使用MCU: PIC16F876(主頻4M)
        // 接收說明:
        // 首先判斷同步間隔場:符合要求進行下面操作,否則不予理睬并記錄錯誤
        // 同步間隔采集合格:采集同步頭,主節點發送0x55,接收5個下降沿用于計算波特率
        // 波特率計算成功:串口接收打開,進行ID接收,判斷是否自己ID不是放棄接收后面數據
        // ID校驗成功:繼續接收后面數據場,并進行校驗,合格則進行相應操作,不合格記錄錯誤
        // 初始化,進行下一個同步頭接收
        //
        //--------------------------------------------
        #include
        //--------------------------------------------
        //---------------常量定義----------------------
        #define TSync 1000 //同步間隔時間定義
        #define FRest 0 //狀態復位0
        #define FSync 1 //同步間隔場檢測
        #define FSync1 2 //同步間隔場檢測狀態1
        #define FTow 3 //同步頭接收
        #define FId 4 //地址字節接收
        #define FData 5 //數據接收

        #define CS RC1 //片選引腳,高有效
        #define RFIN RC2 //同步間隔場和同步場輸入端
        #define Jiance RB7 //檢測引腳,測試時候用


        //--------------數據定義-----------------------
        unsigned char Data[9]; //數據接收數組
        bank1 unsigned int TimeData[5]; //CCP1捕捉時間記錄函數

        unsigned char RFdata; //狀態判斷
        unsigned char FallCount; //同步頭的下降沿計數
        unsigned int Sytime; //同步頭總時間保存
        unsigned char RFstate; //接收狀態指示
        unsigned char Towallow; //波特率計算允許標志
        unsigned char DataCount; //接收數據字節個數寄存器

        unsigned char y;

        volatile bit IDcheck; //數據校驗合格標志
        volatile bit Operate; //操作允許標志
        volatile bit DatCheck; //數據和校驗成功標志

        //bank1 unsigned char Stat @ 0x8f; //
        unsigned char IDmoment ; //ID號暫時保存
        //#define AVR(adr,biti) ((unsigned)(&adr)*8+(biti))
        //#define ID0 AVR(Stat,0) //位定義
        //#define ID1 AVR(Stat,1)
        //#define ID2 AVR(Stat,2)
        //#define ID3 AVR(Stat,3)
        //#define ID4 AVR(Stat,4)
        //#define ID5 AVR(Stat,5)
        //#define ID6 AVR(Stat,6)
        //#define ID7 AVR(Stat,7)

        union
        {
        struct
        {
        unsigned b0:1; //0位,冒號后面的是占的位數
        unsigned b1:1;
        unsigned b2:1;
        unsigned b3:1;
        unsigned b4:1;
        unsigned b5:1;
        unsigned b6:1;
        unsigned b7:1;
        }onebit;
        unsigned char allbit;
        }all;
        #define ID0 all.onebit.b0
        #define ID1 all.onebit.b1
        #define ID2 all.onebit.b2
        #define ID3 all.onebit.b3
        #define ID4 all.onebit.b4
        #define ID5 all.onebit.b5
        #define ID6 all.onebit.b6
        #define ID7 all.onebit.b7
        #define Stat all.allbit
        /*
        上面位定義也可以用絕對尋址位操作(但不建議)
        或者結構和聯合體

        應用方法:
        all.onebit.b0=1; //給位0置1
        all.allbit=0; //字節清0
        */
        #define STATUSIT(avr,s) ((unsigned)(&avr)*8+(s)) //絕對尋址定義
        static bit C @ STATUSIT(STATUS,0); //對進位位進行定義

        union //16位時間計數器
        {
        unsigned int Counter;
        unsigned char Time[2];
        }ASD;
        #define TimeL ASD.Time[0]
        #define TimeH ASD.Time[1]
        //--------------函數定義-----------------------
        void Picint(void); //初始化
        void Delay(void); //延時
        void DataIn(void); //數據輸入判斷
        void interrupt SDI(void); //中斷函數
        void DataClear(void); //數組清0
        void Dispose(void); //數據處理函數
        void DataCdc(unsigned char asd); //數據校驗
        //---------------------------------------------
        //********************************************
        //主函數
        //********************************************
        void main()
        {
        Picint();
        while(1)
        {
        DataIn(); //數據查詢
        if(Operate) //是否允許操作,進行相應操作
        {
        DataCdc(DataCount); //數據校驗是否合格
        if(DatCheck)
        {
        Dispose();
        }
        }
        }
        }
        //********************************************
        //數據處理函數
        //********************************************
        void Dispose() //實驗,并沒具體做什么操作
        {
        if((Data[0]==0x12)&(Data[1]==0x13))
        {
        RB7=1;
        }
        if(Data[0]==0x22)
        {
        RB7=0;
        }
        }
        //********************************************
        //數據校驗
        //********************************************
        void DataCdc(unsigned char asd) //計算數據校驗和
        {
        unsigned char x,y;
        DatCheck=0;
        y=0;
        asm("bcf _STATUS,0"); //清進位位
        for(x=0;x<(asd-1);x++)
        {
        y=y+Data[x];
        if(C)
        {
        C=0;
        y=y+1;
        }
        }
        y=y+Data[asd-1];
        if(y==0xff) //校驗成功
        {
        DatCheck=1;
        }
        }
        //********************************************
        //中斷函數
        //********************************************
        void interrupt SDI() //用捕捉方式進行下降沿計數,計算同步頭
        {
        if(CCP1IE&CCP1IF) //確認中斷
        {
        CCP1IF=0; //清中斷標志
        TimeL=CCPR1L; //取數
        TimeH=CCPR1H; //
        TimeData[FallCount]=ASD.Counter; //寫入數組
        FallCount++;
        if(FallCount==5)
        {
        CCP1CON=0x00; //禁止CCP1捕捉
        CCP1IE=0; //禁止CCP1中斷
        CCP1IF=0; //清中斷標志
        FallCount=0;
        Towallow=1; //波特率計算允許
        TMR1ON=0;
        TMR1L=0;
        TMR1H=0;
        }
        }
        }
        //********************************************
        //數據輸入
        //********************************************
        void DataIn()
        {
        switch(RFstate)
        {
        case FSync: //同步間隔場檢測
        RFdata=RFIN; //采樣值
        if(RFdata==0) //下降沿檢測
        {
        TMR1L=0;
        TMR1H=0;
        TMR1ON=1; //開啟定時器1
        RFstate=FSync1; //轉向狀態1
        }
        break;

        case FSync1:
        RFdata=RFIN;
        if(RFdata==0)
        {
        if(TMR1IF) //在很長時間內如果主機的同步間隔場沒有完成產生錯誤
        {
        TMR1IF=0;
        TMR1ON=0;
        TMR1L=0;
        TMR1H=0;
        RFstate=FRest; //狀態機復位
        }
        }
        else
        {
        TMR1ON=0; //關閉定時器
        TimeL=TMR1L; //取出計數值
        TimeH=TMR1H;
        TMR1L=0; //計數器清0
        TMR1H=0;
        if(ASD.Counter>=TSync)
        {
        RFstate=FTow; //間隔場接收成功,下面接收同步頭
        TMR1ON=1;
        CCP1IE=1; //使能CCP1中斷
        CCP1IF=0; //清中斷標志
        CCP1CON=0x04; //配置捕捉方式,捕捉下降沿
        }
        else
        {
        RFstate=FRest; //否則指向復位
        }
        }
        break;

        case FTow: //同步頭接收
        if(Towallow)
        {
        unsigned char i;
        // SPBRG=0x19; //波特率設置
        // RFstate=FId; //指向ID場接收
        // CREN=1; //使能接收
        Sytime=0;
        for(i=0;i<4;i++) //循環計算總數據
        {
        Sytime=Sytime+(TimeData[i+1]-TimeData[i]);
        }
        Sytime=Sytime>>3; //除8計算
        Sytime=(Sytime>>2)-1;
        i=(unsigned char)Sytime;//強制轉換為字節型數據,設定波特率
        if((i<=30)&(i>=20)) //給定計算范圍
        {
        SPBRG=0x19; //波特率設置
        RFstate=FId; //指向ID場接收
        CREN=1; //使能接收
        }
        else
        {
        RFstate=FRest; //狀態復位
        }
        }
        break;

        case FId:
        while(1) //等待數據接收
        {
        if(RCIF==1) break;
        }
        IDmoment=RCREG; //數據讀取,清中斷標
        Stat=IDmoment;
        if((Stat&0x0f)==0x01) //判斷是否是自己的ID地址,如果是自己的ID地址,校驗暫時沒加
        {
        Stat=IDmoment;
        if((ID4==0)&(ID5==0))
        {
        DataCount=3; //兩個數據接收,同時還有1個校驗字節
        }
        if((ID4==1)&(ID5==0))
        {
        DataCount=3; //兩個數據接收,同時還有1個校驗字節
        }
        if((ID4==0)&(ID5==1))
        {
        DataCount=5; //四個數據接收,同時還有1個校驗字節
        }
        if((ID4==1)&(ID5==1))
        {
        DataCount=9; //八個數據接收,同時還有1個校驗字節
        }
        RFstate=FData; //指向數據接收
        }
        else
        {
        RFstate=FRest; //復位
        }
        break;

        case FData: //數據接收
        for(y=0;y {
        while(1)
        {
        if(RCIF==1) break;
        }
        Data[y]=RCREG; //讀取一個數據
        }
        RFstate=FRest; //復位,數據接收完畢
        Operate=1; //允許操作

        break;

        default:
        RFstate=FSync; //指向同步頭接收
        Towallow=0; //波特率計算禁止
        FallCount=0;
        CCP1CON=0x00; //CCP禁止
        TXEN=0; //禁止發送
        CREN=0; //異步模式禁止接收
        DataCount=0; //數據長度清0
        Operate=0;
        }
        }
        //********************************************
        //初始化
        //********************************************
        void Picint()
        {
        INTCON=0; //清中斷源
        GIE=1; //開總中斷
        PEIE=1; //開外部中斷
        RCIE=0; //禁止串口接收中斷
        ADCON1=0x07; //定義A口為數字ioput模
        //TRISA= 0xFF; //定義端口輸入輸出模式
        TRISC1=0; //片選輸出端口
        TRISC2=1; //捕捉模塊1輸入端

        TRISB7=0; //測試使用的輸出引腳
        RB7=0;

        SPBRG=0x19; //定義波特率
        TXSTA=0x04; //使能高速波特率,異步模式
        RCSTA=0x80; //使能串口,禁止連續接收
        TRISC6=1; //串口使能后這兩位必須設置為輸入高阻抗狀態
        TRISC7=1;

        T1CON=0x00; //定時器1初始化,用于捕捉功能
        TMR1L=0x00;
        TMR1H=0x00;
        TMR1IE=0; //中斷標志以及中斷清除
        TMR1IF=0;

        CS=1; //片選置高

        RFstate=FRest; //狀態機復位
        Operate;

        DataClear(); //數組清0
        }
        //********************************************
        //數組清0 函數
        //********************************************
        void DataClear()
        {
        for(y=0;y<9;y++)
        {
        Data[y]=0;
        }
        }



        關鍵詞: PICLIN總

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 上蔡县| 阜新市| 汤原县| 即墨市| 高碑店市| 静乐县| 定结县| 黄骅市| 衡南县| 兰州市| 乌拉特中旗| 米泉市| 高雄县| 洪泽县| 临清市| 南部县| 安西县| 绥德县| 华坪县| 栖霞市| 涟水县| 宁河县| 合川市| 阿合奇县| 赤峰市| 宝鸡市| 新野县| 呼和浩特市| 邵阳县| 沙河市| 崇义县| 呈贡县| 延津县| 治多县| 景德镇市| 陕西省| 鹤岗市| 闽侯县| 广宁县| 县级市| 阜宁县|