學(xué)習CAN應用設計中的心得體會(huì )(轉)

發(fā)布時(shí)間:2010-1-5 09:55    發(fā)布者:李寬
關(guān)鍵詞: CAN , 設計 , 心得體會(huì ) , 學(xué)習 , 應用
我在學(xué)習CAN應用設計中的一點(diǎn)心得體會(huì ),也算是走了一些彎路,現在把它寫(xiě)出來(lái)和大家共同交流。

       不知道各位注意到?jīng)]有,大多數情況下,SJA1000是與8250+51系列單片機的方式來(lái)做CAN的控制應用。如果是1M/s的通訊速度的話(huà),實(shí)際上的流量只有大概500多K的樣子,此點(diǎn)希望大家在以后的應用設計中需要考慮周到。

       上訴問(wèn)題產(chǎn)生的原因是SJA1000的發(fā)送緩沖區只有1個(gè),應用程序在判斷發(fā)送完一幀數據后,需要計算下一幀需要裝載的數據長(cháng)度,然后根據長(cháng)度再裝載相應的數據到緩沖區,這個(gè)過(guò)程要消耗掉了一定的時(shí)間(特別是標準51內核的單片機),因此CAN總線(xiàn)上的數據流實(shí)際上是發(fā)送一幀就有一個(gè)比較長(cháng)的空閑區(單片機裝載數據的時(shí)間),這樣一來(lái)就浪費了總線(xiàn)資源。微芯的MCP2510有3個(gè)發(fā)送緩沖區,在5V的電源下以5Mb/s的SPI端口讀寫(xiě)數據,可以較好的解決這個(gè)問(wèn)題,但是多數的51單片機都無(wú)SPI,這樣也給單片機的選擇上帶來(lái)了一定的麻煩。具體選擇怎樣的方案,只能看各自的應用情況來(lái)定了!
  
       sja1000調試經(jīng)驗
    
       去年年底的時(shí)候,一個(gè)公司給我打電話(huà),問(wèn)我最近有沒(méi)有空,說(shuō)要請我幫忙做一個(gè)基于CAN總線(xiàn)通訊的東西,我去看了看,是一個(gè)數據采集系統,下面是一系列數據采集的智能板卡,上位機是基于 WINBOND的一塊486的工業(yè)嵌入式控制板,操作系統使用的是WINCE。智能板卡通過(guò)工業(yè)底板和數據線(xiàn)兩種方式和上位機通訊,通信協(xié)議選擇的是 CAN,其中底板上的通信選用高速波特率(1Mbps),數據線(xiàn)選用低速(100kbps)。

       去公司的時(shí)候,公司給了我一個(gè)參考的東西,采用SST單片機+SJA1000的方案構成的智能板卡,同時(shí)告訴我可以自己設計方案?紤]到SST的東西沒(méi)有用過(guò),P8X591是PLCC封裝的,燒寫(xiě)起來(lái)不方便,于是我設計了如下的方案:
       1、智能板卡上的通訊采用AT89S51+兩塊SJA1000的方式進(jìn)行;
       2、上位機通過(guò)PC104總線(xiàn)和一塊CAN控制板卡連接,CAN控制板卡上同樣采用AT89S51+兩塊SJA1000的方案。AT89S51和上位機通過(guò)PC104總線(xiàn)共享內存(使用IDT的雙口RAM);
       3、采用西門(mén)子的組態(tài)軟件進(jìn)行WINCE下的板卡驅動(dòng)開(kāi)發(fā);

       由于以前沒(méi)有做過(guò)CAN的東西,于是決定了先調試CAN通信,然后設計板卡的方案。方案確定之后,首先是上www.zlgmcu.com上下載了全部的SJA1000和PCA82C250的資料。然后開(kāi)始設計電路板。采用了SJA1000應用指南中推薦的方案,采用SJA1000的時(shí)鐘輸出為AT89S51的時(shí)鐘,沒(méi)有采用光電隔離芯片,把TX1接地,TX0和RX0分別連接到PCA82C250的TXD和RXD引腳上,RX1連接到 PCA82C250的VR上;加上了5歐姆的限流電阻和120歐姆的匹配電阻(用110歐姆替代),另外加上了一個(gè)調試用的串口。沒(méi)有注意而且要命的是把 SJA1000的復位引腳和單片機的復位引腳連接到了一起。

       第一次的板子用的加急,用了三天,結果那次的板子做的極差——連銅皮都翻起來(lái)了;我馬上讓那個(gè)電路板廠(chǎng)重新做了三塊。在做板的過(guò)程中我發(fā)現了復位引腳的錯誤,SJA1000的文檔上提供的是一個(gè)復位電路,但是沒(méi)有給出電路的詳細組成,于是我就誤以為和單片機的復位電路是一樣的了。在設計這塊電路板的時(shí)候,最擔心的事情就是SJA1000的輸出時(shí)鐘能不能夠驅動(dòng)AT89S51,如果不能夠驅動(dòng),那么一切就OVER了,可惜的是我的擔心成為了現實(shí),板子焊好之后系統不工作,在SJA1000的時(shí)鐘輸入引腳上有信號輸入,而且輸出時(shí)鐘也正常,但是單片機就是不工作。于是我先把SJA1000 的復位引腳連線(xiàn)割斷,連接到了AT89S51的IO引腳上,再把S51的XTAL的兩個(gè)引腳連接到SJA晶體的上,可惜系統還是不工作,這次電路板設計失敗了。

       在總結了第一次失敗的經(jīng)驗后,參看了21IC上的一個(gè)設計,決定把AT89S51和SJA的晶體分開(kāi)。并且用單片機的一個(gè)IO引腳來(lái)控制對SJA的復位。

       第二次的電路板比較成功,焊接好了之后首先測試單片機的串口和LED指示燈,一切OK。然后就開(kāi)始測試SJA。ZLG提供了一個(gè) BASIC模式下的參考例程,我看了一下,然后又找了本《現場(chǎng)總線(xiàn)CAN的原理和測試》把SJA的寄存器詳細看了看(由于開(kāi)始的時(shí)候比較忙,所以直到這個(gè)時(shí)候才算是仔細看了看SJA的內部,至于CAN的基礎協(xié)議我是根本沒(méi)有看,這給我后面帶來(lái)了極大的麻煩)。然后就參考ZLG的程序開(kāi)始寫(xiě)SJA的測試程序,那個(gè)程序寫(xiě)的很大,也很全,因為我想快點(diǎn)把東西給做出來(lái),于是弄了一個(gè)1000多行的程序,以前我的調試程序一般都很小的。寫(xiě)好程序之后就開(kāi)始測試,首先測試的是測試寄存器,然后一步步測試下去,在BASIC模式下所有的寄存器都正常,但是在發(fā)送的時(shí)候是總是不正常,啟動(dòng)發(fā)送之后就一直在發(fā)送,狀態(tài)寄存器的標志位一直處在發(fā)送的狀態(tài)下,然后就是報總線(xiàn)錯誤,不知道是怎么會(huì )事情,很郁悶,上bbs看了一下。bullfrog告訴我單個(gè)CAN節點(diǎn)發(fā)送是成功不了的,如果沒(méi)有收到接受CAN節點(diǎn)的應答,發(fā)送節點(diǎn)就會(huì )一直發(fā)送,直到超出錯誤計數器的允許值使得總線(xiàn)關(guān)閉。同時(shí)在精華區發(fā)現在peli模式下有 ECC(錯誤寄存器),可以跟蹤錯誤,于是開(kāi)始看peli模式操作過(guò)程。這個(gè)東西比較麻煩,zlg沒(méi)有提供公開(kāi)的c代碼,我找了一個(gè)匯編的作為參考。

       我第一步的目標是自發(fā)送,在peli模式下有自發(fā)送這種模式,在有匹配電阻的情況下可以進(jìn)行單個(gè)節點(diǎn)的接收和發(fā)送。第一次調試的時(shí)候沒(méi)有成功,給北京zlg打電話(huà),北京分公司說(shuō)讓我給廣州打電話(huà),給廣州打電話(huà),幾個(gè)問(wèn)題都得到了很好的解答(在此謝謝zlg的工程師了):
       1、自發(fā)送的時(shí)候必須加上匹配電阻;
       2、5歐的限流電阻可以不需要;
       3、每次發(fā)送完成之后
       4、建議使用中止發(fā)送來(lái)進(jìn)行單步發(fā)送;

       另外他告訴我可以在zlg的論壇上找到很多很有用的東西。
聽(tīng)了他的建議,我第一件事情就是檢查我的電路板,檢查的結果讓我大吃一驚——我的ch和cl竟然是短路的,萬(wàn)用表的狂叫不止。一步步檢查,發(fā)現那個(gè)110歐的匹配電阻有問(wèn)題,萬(wàn)用表碰上去就叫,于是把那個(gè)電阻剪下來(lái),量量還是短路。于是我懷疑把5歐的限流電阻當成了110歐的電阻,于是把匹配電阻都去掉了。沒(méi)有想到的是當我把新的110歐電阻拿來(lái)的時(shí)候,萬(wàn)用表還是叫,這時(shí)候才發(fā)現這塊萬(wàn)用表在300歐姆以下都要叫,可憐我又打理了n長(cháng)時(shí)間的電路板......再仔細閱讀了一次peli模式下的操作指南,又仔細閱讀了 zlg提供的初始化規范,發(fā)現在子發(fā)送的時(shí)候發(fā)送的命令應該是0x10或者是0x12(即CMR寄存器里面有一個(gè)專(zhuān)門(mén)的控制位是用來(lái)控制自發(fā)送的,和普通的發(fā)送命令位是不同的)。在發(fā)現了這個(gè)問(wèn)題之后,自發(fā)送一切順利的通過(guò)了。

       接下來(lái)就是兩個(gè)節點(diǎn)的互調了,我首先用自發(fā)送程序把兩個(gè)節點(diǎn)都調試了一下,保證單個(gè)節點(diǎn)發(fā)送硬件沒(méi)有任何問(wèn)題。然后就用雙絞線(xiàn)通過(guò)接線(xiàn)端子把兩個(gè)系統連接到了一起。第一次調試采用的是1M的波特率(由于ZLG只給出了16M晶體下的BTR0和BTR1的初始值,我在ZLG的論壇上找到了一個(gè)網(wǎng)友自己計算的數值,后來(lái)證明這個(gè)東西有些問(wèn)題),沒(méi)有成功。發(fā)送節點(diǎn)通過(guò)串口利用串口調試助手來(lái)控制發(fā)送,接收節點(diǎn)通過(guò)仿真器觀(guān)察數據。雖然沒(méi)有發(fā)送成功,但是通過(guò)串口的反饋數據和仿真器的觀(guān)察窗,可以看到ECC寄存器都發(fā)生了變化,證明數據線(xiàn)上有數據過(guò)去(由于我沒(méi)有示波器,只有采用這種辦法)。于是我改變了兩次波特率,最低到了5k,都沒(méi)有成功,最后我從21IC上的一篇應用文章上找到了兩個(gè)參數,這次就成功了,通訊速率20k,F在一切穩定,在寫(xiě)這篇文章的時(shí)候哪幾個(gè)LED正歡快的閃爍著(zhù)。


       最后,總結幾個(gè)經(jīng)驗:
       1、一定要詳細的閱讀sja的手冊和CAN的相關(guān)知識;
       2、 SJA的復位是低電平,而且不是用一個(gè)非們把單片機的RST反相就可以的,有兩種解決方式:第一種是使用單片機的IO引腳來(lái)控制SJA的復位引腳,好處是單片機完全控制SJA的復位過(guò)程;第二種是采用適當的復位芯片,ZLG給我推薦的是CAT1161,我沒(méi)有用過(guò),其好處是同步復位。
       3、在自發(fā)送的模式下,需要匹配電阻,而且自發(fā)送的啟動(dòng)命令和普通發(fā)送的啟動(dòng)命令不相同;
       4、BRT0和BRT1的選擇,和串口通信中只要兩個(gè)的誤差一樣就可以了不同,一定要精心選擇,建議SJA的外部晶體選擇16M的,這樣有利于參考ZLG的標準數值
       5、SJA和其他外部器件連接的時(shí)候,數據線(xiàn)在373前后都可以;
       6、最好有一個(gè)示波器;
       7、不要太大意的相信萬(wàn)用表的蜂鳴器;
       8、這是從ZLG網(wǎng)站上轉載過(guò)來(lái)的peli模式下的初始化流程
    a)檢測硬件連接是否正確
    b)進(jìn)入復位狀態(tài)
  c)設置時(shí)鐘分頻寄存器
  d)設置輸出控制寄存器
  e)設置通訊波特率
  f)設置代碼驗收寄存器
  g)設置代碼屏蔽寄存器
  h)退出復位狀態(tài)
  i)設置工作模式
  j)設置中斷使能寄存器
    
        這是一個(gè)自發(fā)收程序,采用at89s51+sja1000,分離晶體,at89s51晶體11.0592MHz。

    sja1000外部晶體為12M,通過(guò)串口進(jìn)行監控
    ******************************************************
    
    以下為頭文件定義
    copyright by alloy
    
    ******************************************************
    
    #define SJA_REG_BaseADD 0x7800
    
    #define REG_MODE XBYTE[SJA_REG_BaseADD + 0x00]
    #define REG_CMD XBYTE[SJA_REG_BaseADD + 0x01]
    #define REG_SR XBYTE[SJA_REG_BaseADD + 0x02]
    #define REG_IR XBYTE[SJA_REG_BaseADD + 0x03]
    #define REG_IR_ABLE XBYTE[SJA_REG_BaseADD + 0x04]
    #define REG_BTR0 XBYTE[SJA_REG_BaseADD + 0x06] //05保留
    #define REG_BTR1 XBYTE[SJA_REG_BaseADD + 0x07]
    #define REG_OCR XBYTE[SJA_REG_BaseADD + 0x08]
    #define REG_TEST XBYTE[SJA_REG_BaseADD + 0x09]
    #define REG_ALC XBYTE[SJA_REG_BaseADD + 0x0b] //0a保留
    #define REG_ECC XBYTE[SJA_REG_BaseADD + 0x0c]
    #define REG_EMLR XBYTE[SJA_REG_BaseADD + 0x0d]
    #define REG_RXERR XBYTE[SJA_REG_BaseADD + 0x0e]
    #define REG_TXERR XBYTE[SJA_REG_BaseADD + 0x0f]
    
    #define REG_ACR0 XBYTE[SJA_REG_BaseADD + 0x10]
    #define REG_ACR1 XBYTE[SJA_REG_BaseADD + 0x11]
    #define REG_ACR2 XBYTE[SJA_REG_BaseADD + 0x12]
    #define REG_ACR3 XBYTE[SJA_REG_BaseADD + 0x13]
    #define REG_AMR0 XBYTE[SJA_REG_BaseADD + 0x14]
    #define REG_AMR1 XBYTE[SJA_REG_BaseADD + 0x15]
    #define REG_AMR2 XBYTE[SJA_REG_BaseADD + 0x16]
    #define REG_AMR3 XBYTE[SJA_REG_BaseADD + 0x17]
    
    #define REG_RxBuffer0 XBYTE[SJA_REG_BaseADD + 0x10]
    #define REG_RxBuffer1 XBYTE[SJA_REG_BaseADD + 0x11]
    #define REG_RxBuffer2 XBYTE[SJA_REG_BaseADD + 0x12]
    #define REG_RxBuffer3 XBYTE[SJA_REG_BaseADD + 0x13]
    #define REG_RxBuffer4 XBYTE[SJA_REG_BaseADD + 0x14]
    
    #define REG_TxBuffer0 XBYTE[SJA_REG_BaseADD + 0x10]
    #define REG_TxBuffer1 XBYTE[SJA_REG_BaseADD + 0x11]
    #define REG_TxBuffer2 XBYTE[SJA_REG_BaseADD + 0x12]
    #define REG_TxBuffer3 XBYTE[SJA_REG_BaseADD + 0x13]
    #define REG_TxBuffer4 XBYTE[SJA_REG_BaseADD + 0x14]
    
    #define REG_DataBuffer1 XBYTE[SJA_REG_BaseADD + 0x15]
    #define REG_DataBuffer2 XBYTE[SJA_REG_BaseADD + 0x16]
    #define REG_DataBuffer3 XBYTE[SJA_REG_BaseADD + 0x17]
    #define REG_DataBuffer4 XBYTE[SJA_REG_BaseADD + 0x18]
    #define REG_DataBuffer5 XBYTE[SJA_REG_BaseADD + 0x19]
    #define REG_DataBuffer6 XBYTE[SJA_REG_BaseADD + 0x1a]
    #define REG_DataBuffer7 XBYTE[SJA_REG_BaseADD + 0x1b]
    #define REG_DataBuffer8 XBYTE[SJA_REG_BaseADD + 0x1c]
    
    
    #define REG_RBSA XBYTE[SJA_REG_BaseADD + 0x1e]
    #define REG_CDR XBYTE[SJA_REG_BaseADD + 0x1f]
    #define REG_Receive_Counter XBYTE[SJA_REG_BaseADD + 0x1d]
    
    #define OK 1
    #define Fail 0
    #define ON 1
    #define OFF 0
    #define True 1
    #define False 0
    
    sbit SJARst = P2 ^ 6; //復位控制
    sbit LED0 = P1 ^ 0;
    sbit LED1 = P1 ^ 1;
    sbit Key0 = P1 ^ 2;
    sbit Key1 = P1 ^ 3;
    sbit Key2 = P1 ^ 4;
    sbit Key3 = P1 ^ 5;
    
    bit step_flg;
    bit Tx_flg;
    bit Rx_flg;
    
    unsigned char step_counter;
    unsigned char Tx_counter;
    unsigned char PC_RX_Buffer;
    unsigned char temp_data1;
    unsigned char Rx_Buffer[6];
    
    void MCU_Init(void);
    void SJA_Init(void);
    void send(unsigned char S_Data);
    void Serial(void);
    void Delay(unsigned char Delay_time);
    void step(void);
    
    
    
    *******************************************************
    
    以下為c的主程序
    copyright by alloy
    
    *******************************************************
   。 nclude
   。 nclude
   。 nclude
   。 nclude
   。 nclude
    main()
    {
    
     unsigned char i;
     MCU_Init();
     SJA_Init();
     REG_MODE = 0x01; //進(jìn)入復位模式
    
     temp_data1 = REG_MODE;
     temp_data1 = temp_data1 & 0x01;
     if(temp_data1 == 0x01) //在復位模式中
     {
     REG_BTR0 = 0x85;
     REG_BTR1 = 0xb4; //100k
     REG_OCR = 0x1a;
     REG_CDR = 0xc0;
     REG_RBSA = 0x00;
    
     REG_ACR0 = 0xff;
     REG_ACR1 = 0xff;
     REG_ACR2 = 0xff;
     REG_ACR3 = 0xff;
    
     REG_AMR0 = 0xff;
     REG_AMR1 = 0xff;
     REG_AMR2 = 0xff;
     REG_AMR3 = 0xff;
    
     REG_IR_ABLE = 0xff;
     }
     REG_MODE = 0x0c; //進(jìn)入自接收模式
     REG_MODE = 0x0c;
    
     for(i = 0;i<100;i++);
     temp_data1 = REG_Receive_Counter;
     send(temp_data1);
     for(;;)
     {
     while(Tx_flg == False);
     Tx_flg = False;
     Tx_counter++;
     send(Tx_counter);
     temp_data1 = REG_SR;
     while((temp_data1 & 0x10) == 0x10);
     temp_data1 = REG_SR;
     if((temp_data1 & 0x04) == 0x04)
     {
     REG_RxBuffer0 = 0x08; //標準幀,長(cháng)度為8
     REG_RxBuffer1 = 0xff;
     REG_RxBuffer2 = 0xff;
    
     REG_RxBuffer3 = 0x01;
     REG_RxBuffer4 = 0x02;
     REG_DataBuffer1 = 0x03;
     REG_DataBuffer2 = 0x04;
     REG_DataBuffer3 = 0x05;
     REG_DataBuffer4 = 0x06;
     REG_DataBuffer5 = 0x07;
     REG_DataBuffer6 = 0x08;
     REG_DataBuffer7 = 0x09;
     REG_DataBuffer8 = 0x0a;
     }
     REG_CMD = 0x10;
     temp_data1 = REG_SR;
     temp_data1 = temp_data1 & 0x20;
     while(temp_data1 == 0x20) //檢查是否發(fā)送完成
     {
     //send(0xaa);
     temp_data1 = REG_ECC;
     send(temp_data1);
     temp_data1 = REG_SR;
     temp_data1 = temp_data1 & 0x20;
     //send(temp_data1);
     }
    
     send(0x66);
     temp_data1 = REG_ALC;
     send(temp_data1);
     temp_data1 = REG_ECC;
     send(temp_data1);
     temp_data1 = REG_SR;
     send(temp_data1);
     temp_data1 = REG_Receive_Counter;
     send(temp_data1);
    
     PC_RX_Buffer = 0x77;
     LED0 = ~LED0;
    
    // Tx_counter = 0x00;
     }
    }
    
    void MCU_Init(void)
    {
     SJARst = 1;
     LED0 = OFF;
     LED1 = OFF;
     PC_RX_Buffer = 0x77;
     step_counter = 0x00;
     step_flg = False;
     Tx_flg = False;
     temp_data1 = 0x00;
     TMOD = 0x20;
     TH1 = 0xff;
     TL1 = 0xff;
     TR1 = 1;
     SCON = 0x50;
     PCON = 0x80;
     EA = 1;
     ES = 1;
     Tx_counter = 0x00;
    
    }
    
    void SJA_Init(void)
    {
     unsigned char i;
     for(i = 0;i < 125;i++);
     SJARst = 0;
     for(i = 0;i < 125;i++);
     SJARst = 1;
     for(i = 0;i < 125;i++);
    }
    
    void send(unsigned char S_Data)
    {
     SBUF = S_Data;
     while(TI == 0);
     TI =0;
    }
    
    void Serial() interrupt 4 using 2
    {
    
     if(RI == 1)
     {
     PC_RX_Buffer = SBUF;
     RI = 0;
     if(PC_RX_Buffer == 0xaa)
     {
     send(0x13);
     Tx_flg = True;
     PC_RX_Buffer = 0x77;
     }
     else if(PC_RX_Buffer == 0x55)
     {
     send(0x14);
     Rx_flg = True;
     PC_RX_Buffer = 0x77;
     }
     else
     {
     send(0x15);
     PC_RX_Buffer = 0x77;
     }
     }
    
    }
       另外,我給大家推薦一本書(shū),還不錯的 北航出版的《現場(chǎng)總線(xiàn)CAN原理與應用技術(shù)》(饒運濤等)
本文地址:http://selenalain.com/thread-7254-1-1.html     【打印本頁(yè)】

本站部分文章為轉載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀(guān)點(diǎn)和對其真實(shí)性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問(wèn)題,我們將根據著(zhù)作權人的要求,第一時(shí)間更正或刪除。
eastljd 發(fā)表于 2012-1-3 08:05:58
謝謝
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

相關(guān)在線(xiàn)工具

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復 返回頂部 返回列表
午夜高清国产拍精品福利|亚洲色精品88色婷婷七月丁香|91久久精品无码一区|99久久国语露脸精品|动漫卡通亚洲综合专区48页