在理解了CAN總線的自通信程序后,再來探討CAN總線間的相互通信變得容易了許多。對于是自通信還是相互通信,這個肯定是需要對寄存器進行必要的設置的,分析PIAE的兩個程序后不難發現,自通信和互通信需要設置的知識模式寄存器,這個是在SJA1000的初始化時進行設定的。 SJA1000的初始化程序我根據習慣,直接把它獨立成一個子程序了。如下,是工作于自通信時的初始化程序。 /////////////////////////////////////////////// //函數:init_sja1000 //說明:獨立CAN控制器SJA1000的初始化 //入口:無 //返回:無 /////////////////////////////////////////////// void init_sja1000(void) { uchar state; uchar ACRR[4]; uchar AMRR[4]; // 接收代碼寄存器 ACRR[0] = 0xff; ACRR[1] = 0x22; ACRR[2] = 0x33; ACRR[3] = 0x44; // 接收屏蔽寄存器,只接收主機發送的信息 AMRR[0] = 0xff; AMRR[1] = 0Xff; AMRR[2] = 0xff; AMRR[3] = 0xff; // 使用do--while語句確保進入復位模式 do { // 設置MOD.0=1--進入復位模式,以便設置相應的寄存器 MODR = 0x09; state = MODR; } while( !(state & 0x01) ); // 對SJA1000部分寄存器進行初始化設置 CDR = 0x88; // CDR為時鐘分頻器,CDR.3=1--時鐘關閉, //CDR.7=0---basic CAN, CDR.7=1---Peli CAN BTR0 = 0x31; // 總線定時寄存器0 ;總線波特率設定 BTR1 = 0x1c; // 總線定時寄存器1 ;總線波特率設定 IER = 0x01; // IER.0=1--接收中斷使能; IER.1=0--關閉發送中斷使能 OCR = 0xaa; // 配置輸出控制寄存器 CMR = 0x04; // 釋放接收緩沖器 // 初始化接收代碼寄存器 ACR0 = ACRR[0]; ACR1 = ACRR[1]; ACR2 = ACRR[2]; ACR3 = ACRR[3]; // 初始化接收屏蔽寄存器 AMR0 = AMRR[0]; AMR1 = AMRR[1]; AMR2 = AMRR[2]; AMR3 = AMRR[3]; // 使用do--while語句確保進入自接收模式 do { //MOD.2=1--進入自接收模式,MOD.3=0--雙濾波器模式 MODR = 0x04; state = MODR; } while( !(state & 0x04) ); } 兩個數組ACRR[4]和AMRR[4]分別存儲著需要設置的接收代碼寄存器和接收屏蔽寄存器的數值。這兩個數組的設置設計者可以根據需要自己設定(在互通信時就需要在這里做文章了)。AMRR的四個值都設定為OXFF說明無論總線上傳輸的ID值是什么,也不管ACRR的數值設定是什么,這個SJA1000都照單全收(至于為什么,上節關于驗收濾波的日志做了詳細討論了)。 然后進入設定模式寄存器進入復位模式。在復位模式下,可以對SJA1000部分寄存器進行初始化設置,并且把剛才兩個數組的數據存入接收代碼寄存器和接收屏蔽寄存器里,自此初始化算是完成了。但是因為CAN總線控制器要進行自通信,所以必須對模式寄存器設定使得SJA1000進入復位模式,這就是最后的do--while語句的作用。 接下來,我們看CAN總線互相通信的初始化設置。 /////////////////////////////////////////////// //函數:init_sja1000 //說明:獨立CAN控制器SJA1000的初始化 //入口:無 //返回:無 /////////////////////////////////////////////// void init_sja1000(void) { uchar state; uchar ACRR[4]; uchar AMRR[4]; // 接收代碼寄存器 ACRR[0] = 0x11; ACRR[1] = 0x22; ACRR[2] = 0x33; ACRR[3] = 0x44; // 接收屏蔽寄存器 AMRR[0] = 0x00; AMRR[1] = 0Xff; AMRR[2] = 0x00; AMRR[3] = 0xff; // 使用do--while語句確保進入復位模式 do { // 設置MOD.0=1--進入復位模式,以便設置相應的寄存器 MODR = 0x09; state = MODR; } while( !(state & 0x01) ); // 對SJA1000部分寄存器進行初始化設置 CDR = 0x88; // CDR為時鐘分頻器,CDR.3=1--時鐘關閉, //CDR.7=0---basic CAN, CDR.7=1---Peli CAN BTR0 = 0x31; // 總線定時寄存器0 ;總線波特率設定 BTR1 = 0x1c; // 總線定時寄存器1 ;總線波特率設定 IER = 0x01; // IER.0=1--接收中斷使能; IER.1=0--關閉發送中斷使能 OCR = 0xaa; // 配置輸出控制寄存器 CMR = 0x04; // 釋放接收緩沖器 // 初始化接收代碼寄存器 ACR0 = ACRR[0]; ACR1 = ACRR[1]; ACR2 = ACRR[2]; ACR3 = ACRR[3]; // 初始化接收屏蔽寄存器 AMR0 = AMRR[0]; AMR1 = AMRR[1]; AMR2 = AMRR[2]; AMR3 = AMRR[3]; // 使用do--while語句確保退出復位模式 do { MODR = 0x08; //MOD.3=0--雙濾波器模式 state = MODR; } while( state & 0x01 ); } 很容易可以發現,CAN互通信和自通信的初始化設置,只有最后的設置是不一樣的,自通信時把模式寄存器的自通信寄存器位置位,而互通信時只要退出復位模式(同時把自通信寄存器位清零)即可。其它的設置根據需要設定。 上面討論了自通信和互通信兩種工作方式下的寄存器設置。那么,我就在想,如果用互通信的模式下,如果發送幀的ID設定和自身接收的驗收濾波吻合,是不是也能進行自接收呢?答案是否定的,根據以上的設想做的實驗表明,在互通信模式下,CAN總線上若只有一個節點,那么CAN總線是不會達到你預想的變化的,按下鍵后紅燈會一直亮著,說明CAN總線陷入了無法接收或者正在接收的死循環跳不出來了。 另外,我還做了一個實驗。就是當CAN節點1發送的數據幀ID不僅和節點2的吻合,也和自身的驗收濾波吻合,那么當節點1的數據幀發送后是不是節點1和節點2都能接收到數據呢?結果證明這個設想是成立的。這也就說明了掛靠在CAN總線上的每一個節點,只要CAN總線上的數據幀ID和某節點驗收濾波通過,該節點就可以接收數據。 在初始化設置了模式寄存器后,下一步就是設定不同的發送幀的ID和本節點的接收代碼寄存器值和屏蔽寄存器值。我這里只有兩個節點通信,一般如果要使CAN總線上的兩個節點相互接收到對方的數據。那么根據上一節的原理設定接收代碼寄存器值和屏蔽寄存器值以及發送幀的ID值就可以了。 在看懂并且理解了PIAE工作組的CAN自通信和互通信后,我想對于CAN總線協議的工作方式算是已經入門了,剩下的就是繼續從官方或者第三方提供的datasheet里補知識,根據不同的場合和不同的應用把CAN總線控制器的寄存器設置用活來。 |