?? can_self.c
字號:
/**************************************************************************************
項 目:基于CAN總線的收發通信(節點1)
說 明:主程序部分
功 能:CAN總線上掛接兩個節點,當其中一個節點(節點1)的按鍵按下時,除了自身的數碼管1、2
顯示加一,還向節點2發送一個遠程幀;節點2接收到遠程幀后想總線發送一個數據幀,如果
節點2的按鍵被按下時,除了自身的數碼管1、2顯示加一,還會向總線發送數據幀,使得節點
2的數碼管3、4顯示與其保持一致。
// CAN主要參數: PeliCAN模式,擴展幀EFF模式
// 29位標示碼結構:發送一個遠程幀
// 本節點的接收代碼寄存器值: 0x55,0x22,0x33,0x44
// 本節點的屏蔽代碼寄存器值:0x00,0xff,0x00,0xff;可以接收節點2的數據
// 目的節點地址:0x11,0x22,0x33,0x44;可以被節點1接收
模 塊:can_self.c
作 者:PIAE GROUP
注釋修改者:特 權
修改 時間:08.6.17.
**************************************************************************************/
/***感謝PIAE工作組提供的源碼,這里特權根據自己的編程習慣做了一些修改并添加詳細注釋***/
#include <reg52.h>
#include <intrins.h>
#include "define.h"
///////////////////////////////////////////////
//函數:inter0_key (外部中斷INT0)
//說明:INT0按鍵為計數按鍵
// 每按下一次鍵,計數值加一
//入口:按鍵中斷
//返回:按鍵加一
///////////////////////////////////////////////
void inter0_key(void) interrupt 0
{
EA = 0; //關閉中斷
Txd_data++; //計數結果增1,即待發送的數據增1
TXD_flag = 1; //發送數據標志位置位,即重新發送數據以更新數碼管的顯示數值
EA = 1; //重新開啟中斷
}
///////////////////////////////////////////////
//函數:inter1_can_rxd (外部中斷INT1)
//說明:接收數據函數,在中斷服務程序中調用
//入口:無
//返回:無
///////////////////////////////////////////////
void inter1_can_rxd( void ) interrupt 2
{
uchar state;
EA = 0; //關CPU中斷
IE1 = 0; //由于是中斷INT1是電平觸發方式,所以需要軟件將INT1的中斷請求標志IE0清零
state = IR; //IR為SJA1000的中斷寄存器
if( state & 0x01) //若IR.0=1--接收中斷
{ //接收數據幀
RX_buffer[0] = RBSR0;
RX_buffer[1] = RBSR1;
RX_buffer[2] = RBSR2;
RX_buffer[3] = RBSR3;
RX_buffer[4] = RBSR4;
RX_buffer[5] = RBSR5;
RX_buffer[6] = RBSR6;
RX_buffer[7] = RBSR7;
RX_buffer[8] = RBSR8;
RX_buffer[9] = RBSR9;
RX_buffer[10] = RBSR10;
RX_buffer[11] = RBSR11;
RX_buffer[12] = RBSR12;
RXD_flag = 1; //接收標志置位,以便進入接收處理程序
CMR = 0x04; //CMR.2=1--接收完畢,釋放接收緩沖器
state = ALC; //釋放仲裁隨時捕捉寄存器(讀該寄存器即可)
state = ECC; //釋放錯誤代碼捕捉寄存器(讀該寄存器即可)
}
IER = 0x01; // IER.0=1--接收中斷使能
EA = 1; //重新開啟CPU中斷
}
///////////////////////////////////////////////
//函數:main
//說明:主函數
//入口:無
//返回:無
///////////////////////////////////////////////
void main(void)
{
init_mcu();
init_sja1000();
while(1)
{
rxd_deal(); //接收處理程序
txd_deal(); //發送處理程序
led_show(0,Txd_data); //數碼管1-2顯示發送數據子程序
led_show(1,Rxd_data); //數碼管3-4顯示接收數據子程序
}
}
///////////////////////////////////////////////
//函數:init_mcu
//說明:單片機I/O口初始化
// 主要是各中斷寄存器的初始化
//入口:無
//返回:無
///////////////////////////////////////////////
void init_mcu(void)
{
SJA_RST = 1; //CAN總線復位管腳復位無效
SJA_CS = 0; //CAN總線片選有效
EX1 = 1; //開MCU外部中斷INT1
IT1 = 0; //MCU外部中斷INT1設置為電平觸發,該中斷口連接CAN總線接收中斷口
IT0 = 1; //MCU外部中斷INT0設置為下降沿觸發
EX0 = 1; //開MCU外部中斷INT0
EA = 1; //開MCU總中斷
SJA_CS = 1; //CAN總線片選無效,使得對數據總線的操作不會影響SJA1000。
}
///////////////////////////////////////////////
//函數:init_sja1000
//說明:獨立CAN控制器SJA1000的初始化
//入口:無
//返回:無
///////////////////////////////////////////////
void init_sja1000(void)
{
uchar state;
uchar ACRR[4];
uchar AMRR[4];
// 接收代碼寄存器
ACRR[0] = 0x55;
ACRR[1] = 0x22;
ACRR[2] = 0x33;
ACRR[3] = 0x44;
// 接收屏蔽寄存器
AMRR[0] = 0x00;
AMRR[1] = 0Xff;
AMRR[2] = 0x00;
AMRR[3] = 0xff;
// 使用do--while語句確保進入復位模式
do
{
MODR = 0x09; // 設置MOD.0=1--進入復位模式,以便設置相應的寄存器
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 );
}
///////////////////////////////////////////////
//函數:rxd_deal
//說明:接收處理程序;檢測接收標志狀態位,
// 如果置位則進行接收處理
//入口:無
//返回:無
///////////////////////////////////////////////
void rxd_deal(void)
{
if( RXD_flag ) //RXD_flag=0說明無數據可以接收,RXD_flag=1說明有數據可以接收
{
EA = 0; //關閉CPU中斷
RXD_flag = 0; //RXD_flag清零,以便下次查詢
Rxd_data = RX_buffer[5]; //CAN總線要接收的數據,也是要在數碼管3-4位置顯示的數據
EA = 1; //重新開啟CPU中斷
}
}
///////////////////////////////////////////////
//函數:txd_deal
//說明:發送處理程序;檢測發送標志狀態位,
// 如果置位則進行發送數據處理
//入口:無
//返回:無
///////////////////////////////////////////////
void txd_deal(void)
{
if( TXD_flag ) //若TXD_flag=1,要求進行數據的發送處理
{
_nop_();
TXD_flag = 0; //RXD_flag清零,以便下次查詢
can_txd(); //發送數據幀
_nop_();
_nop_();
} //發送數據幀后,SJA1000將產生接收中斷
}
///////////////////////////////////////////////
//函數:can_txd
//說明:發送擴展數據幀
//入口:無
//返回:無
///////////////////////////////////////////////
void can_txd(void)
{
uchar state;
uchar TX_buffer[ N_can ] ; //N_can=13,TX_buffer數組為待傳送的數據幀
//初始化標識碼頭信息
TX_buffer[0] = 0xc8; //.7=0--擴展幀;.6=1--遠程傳送請求;
TX_buffer[1] = 0x11; //本幀信息的ID
TX_buffer[2] = 0x22;
TX_buffer[3] = 0x33;
TX_buffer[4] = 0x44;
//初始化發送數據單元
TX_buffer[5] = Txd_data; //發送的第1個字節數據,也是數碼管要顯示的數據(計數結果)
TX_buffer[6] = 0x22; //2
TX_buffer[7] = 0x33; //3
TX_buffer[8] = 0x44; //4
TX_buffer[9] = 0x55; //5
TX_buffer[10] = 0x66; //6
TX_buffer[11] = 0x77; //7
TX_buffer[12] = 0x88; //8
//初始化數據信息
EA = 0; //關中斷
//查詢SJA1000是否處于接收狀態,當SJA1000不處于接收狀態時才可繼續執行
do
{
state = SR; //SR為SJA1000的狀態寄存器
LED_RED = 0; //點亮LED1
}
while( state & 0x10 ); //SR.4=1 正在接收,等待
//查詢SJA1000是否處于發送完畢狀態
do
{
state = SR;
LED_RED = 0; //點亮LED1
}
while(!(state & 0x08)); //SR.3=0,發送請求未處理完,等待直到SR.3=1
//查詢發送緩沖器狀態
do
{
state = SR;
LED_RED = 0; //點亮LED1
}
while(!(state & 0x04)); //SR.2=0,發送緩沖器被鎖。等待直到SR.2=1
LED_RED = !LED_RED; //熄滅LED1
LED_GRE = !LED_GRE; //點亮LED2
//將待發送的一幀數據信息存入SJA1000的相應寄存器中
TBSR0 = TX_buffer[0];
TBSR1 = TX_buffer[1];
TBSR2 = TX_buffer[2];
TBSR3 = TX_buffer[3];
TBSR4 = TX_buffer[4];
TBSR5 = TX_buffer[5];
TBSR6 = TX_buffer[6];
TBSR7 = TX_buffer[7];
TBSR8 = TX_buffer[8];
TBSR9 = TX_buffer[9];
TBSR10 = TX_buffer[10];
TBSR11 = TX_buffer[11];
TBSR12 = TX_buffer[12];
CMR = 0x01; //置位發送請求
EA = 1; //重新開啟中斷
}
///////////////////////////////////////////////
//函數:delay
//說明:延時子函數
//入口:uchar time:延時時間time us
//返回:無
///////////////////////////////////////////////
void delay(uchar time)
{
while(time--);
}
///////////////////////////////////////////////
//函數:led_show
//說明:數碼管顯示函數
// 注意控制P2口的高4位時,不要影響P2口的低4位值
//入口:uchar wela: wela=1--高兩位顯示發送數據
// wela=0--低兩位顯示接收數據
// uchar number: 要顯示的數據
//返回:無
///////////////////////////////////////////////
void led_show(uchar wela,uchar number)
{
uchar digit;
uchar temp;
if(wela) //高位顯示,即數碼管1-2
{
temp = 0x7b; //temp=01111011B
}
else //低位顯示,即數碼管3-4
{
temp = 0xde; //temp=11011110B
}
//數碼管個位顯示
digit = number%10;
P0 = led[digit];
P2 = (temp | 0x0f) & P2; //開個位
delay(5);
P2 = 0xff;
P0 = 0xff; //關閉個位
//數碼管十位顯示
number /= 10;
digit = number%10;
P2 = ((temp << 4) | 0x0f) & P2; //開十位
P0 = led[digit];
delay(5);
P2 = 0xff; //關閉十位
P0 = 0xff;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -