|
//----------------------------------------------------------
// 51單片機實驗板CAN通信器件SJA1000驅動代碼
// ... ...
// 2016.11
// 推薦的測試方案以及對應的測試代碼片段之一:
// 兩個實驗板互相通信
// 跨接器連接:P32,P36,P37, P20,P21,P22, P25,P26,P27, P0全部
// 若連接距離較遠,雙方應將 TR 跨接器連接起來
// void main(void)
// {
// uchar i;
// SJA1000_Init(10000, 0x0, 0xffffffff);
// KS108_Init();
// KS108_Disp_Str(0, 0, (uchar*)".....SJA1000 Test....");
// KS108_Disp_Str(0, 2, (uchar*)"Frame_Info:");
// KS108_Disp_Str(0, 3, (uchar*)"Frame_ID: ");
// KS108_Disp_Str(0, 4, (uchar*)"L Hi");
// KS108_Disp_Str(0, 6, (uchar*)"Link:P0, P20~2, P25~7");
// KS108_Disp_Str(0, 7, (uchar*)"P32,P36~7, TR,if need");
// for(i=0; i<8; i++) SJA1000_Rec_Dat[i] = 2*i;
// RX_Info = 0x88;
// SJA1000_Transmit(RX_Info, 0x0, SJA1000_Rec_Dat);
// while(1)
// {
// if(SJA1000_Received)
// {
// SJA1000_Received = 0;
// KS108_Disp_Byte_Hex(11, 2, RX_Info);
// KS108_Disp_Long_Hex(11, 3, SJA1000_Rec_ID);
// SJA1000_Transmit(RX_Info, SJA1000_Rec_ID, SJA1000_Rec_Dat);
// for(i=0; i<(RX_Info&0x0f); i++)
// KS108_Disp_Byte_Hex(i*2+2, 4, SJA1000_Rec_Dat[i]);
// }
// }
// }
// 推薦的進一步的實驗:遠程溫度測量傳輸/調溫控制.......
//----------------------------------------------------------
#include "..\include\AT89X52.H"
#include "..\include\global.h"
#include "..\INCLUDE\SJA1000.H"
sfr AUXR = 0x8e;//STC51的sfr,bit1=0/1<=>使能/禁能內部擴展RAM
#define SJA1000RST P2_5
//--------------------CAN寄存器地址-------------------------
#define CANB 0x00
pdata uchar CAN_MOD _at_(CANB+0); //模式寄存器
pdata uchar CAN_CMR _at_(CANB+1); //命令寄存器
pdata uchar CAN_SR _at_(CANB+2); //狀態寄存器
pdata uchar CAN_IR _at_(CANB+3); //中斷寄存器
pdata uchar CAN_IER _at_(CANB+4); //中斷使能寄存器
pdata uchar CAN_BRT0 _at_(CANB+6); //總線定時0寄存器
pdata uchar CAN_BRT1 _at_(CANB+7); //總線定時1寄存器
pdata uchar CAN_OCR _at_(CANB+8); //輸出控制寄存器
pdata uchar CAN_ALE _at_(CANB+11); //仲裁丟失捕捉寄存器
pdata uchar CAN_ECC _at_(CANB+12); //錯誤代碼捕捉寄存器
pdata uchar CAN_EWLR _at_(CANB+13); //錯誤報警限制寄存器
pdata uchar CAN_RXERR _at_(CANB+14); //接收錯誤計數器
pdata uchar CAN_TXERR _at_(CANB+15); //發送錯誤計數器
pdata uchar CAN_TXB[13] _at_(CANB+16); //發送緩沖器,工作寫
#define CAN_RXB CAN_TXB //接收緩沖器,工作讀
pdata uchar CAN_ACR[4] _at_(CANB+16);//驗收代碼寄存器0,復位讀/寫
pdata uchar CAN_AMR[4] _at_(CANB+20);//驗收屏蔽寄存器0,復位讀/寫
pdata uchar CAN_RMC _at_(CANB+29); //RX信息計數器
pdata uchar CAN_RBSA _at_(CANB+30); //RX緩沖器
pdata uchar CAN_CDR _at_(CANB+31); //時鐘分頻器
idata uchar RX_Info;
idata ulong SJA1000_Rec_ID;
idata uchar SJA1000_Rec_Dat[8];
bit SJA1000_Received;
//----------------------------------------------------------
// 函數: SJA1000_CS(...)
// 功能: 設置SJA1000片選有效/無效,片選有效時使用外部擴展RAM
// 當片選無效時恢復使用內部擴展RAM
// 形參: v<===>0/1片選有效/無效
// 全局變量引用: 無
// 全局變量修改: 無
// 返回: 無
// 說明: SJA1000以"51單片機外部擴展RAM" 形式與51單片機實施連
// 接,采用頁尋址方式. SJA1000的片選信號由P2_0~P2_2經過
// 3-8線譯碼器產生. P0端口以數據總線/地址總線形式使用,
// 從而P3_6~P3_7作為標準讀寫信號引腳使用,但所有端口(包
// 括P0和P3端口)在與其它器件的連接關系中又可能以通用IO
// 方式使用,故需做特別處理. 此外實驗板所使用的單片機內
// 部含有寶貴的1024字節擴展RAM, 通過單片機內特殊功能寄
// 存器AUXR的設置, 可在"外部擴展RAM(即SJA1000)"和"內部
// 擴展RAM"之間切換,當SJA1000片選有效時, 暫時關閉"內部
// 擴展RAM",當SJA1000片選無效時, 恢復使用"內部擴展RAM"
// 注意: 由于實驗板的特殊結構, 對SJA1000的片選信號處理應做特
// 殊處理,注意對51單片機讀寫信號的處理.
//----------------------------------------------------------
void SJA1000_CS(uchar v)
{
P2 |= 0x07; //P2<==XXXX X111
if(v==0)
{
P3_6 = 1; //在SJA1000片選有效之前保證寫信號無效
P3_7 = 1; //在SJA1000片選有效之前保證讀信號無效
P2 &= 0xfe; //P2<==XXXX X110
AUXR = 0x02; //使用外部擴展RAM即本芯片SJA1000
}
else AUXR = 0x00; //使用內部擴展RAM
}
//----------------------------------------------------------
// 波特率與設置參數對照表
// SJA1000的主時鐘16MHz,28個標準波特率
// 按"最接近且小于等于"的原則規約到標準波特率上
//----------------------------------------------------------
ulong code baudrates[] = //28個最常用位速率
{
1000000,800000, 500000, 400000, 320000, 250000, 200000,
160000, 125000, 100000, 80000, 64000, 62500, 50000,
40000, 32000, 31250, 25000, 20000, 16000, 15625,
12800, 12500, 10000, 8000, 6400, 6250, 5000
};
uint code brconst[] = //28個最常用位速率的時間參數
{
0x4014, 0x4016, 0x401C, 0x802F, 0xC07F, 0x411C, 0x812F,
0xC17F, 0x431C, 0x832F, 0xC37F, 0xC47F, 0x471C, 0x872F,
0xC77F, 0xC97F, 0x4F1C, 0x8F2F, 0xCF7F, 0xD37F, 0x5F1C,
0xD87F, 0x9F2F, 0xDF7F, 0xE77F, 0xF17F, 0xBF2F, 0xFF7F
};
//----------------------------------------------------------
// 函數: SJA1000_Init(...)
// 功能: 對SJA1000實施加電初始化,設置通信波特率,設置驗收碼和
// 驗收屏蔽碼以及驗收濾波器長度,配置SJA1000接收中斷
// 形參: baudrate<==>通信波特率
// ID<===>驗收碼
// IDMASK<===>驗收屏蔽碼
// 全局變量引用: 無
// 全局變量修改: 無
// 返回: 無
// 說明: 無
// 注意: 由于實驗板的特殊結構, 對SJA1000的片選信號處理應做特
// 殊處理
//----------------------------------------------------------
void SJA1000_Init(ulong baudrate, ulong ID, ulong IDMASK)
{
uchar i=0xff;
EA=0;
IT0 = 1;
EX0 = 1;
SJA1000_CS(0); //SJA1000片選有效,使用外部擴展RAM
SJA1000RST = 0;
i=0xff;while(i--) ;
SJA1000RST = 1;
i=0xff;while(i--) ;
i = 0;
while((i != 27) && (baudrates[i] > baudrate)) i++;
CAN_MOD = 0x01; //進入復位狀態
CAN_OCR = 0x1a; //設置輸出控制寄存器:同相驅動,正常輸出
CAN_BRT1 = brconst[i]&0xff; //設置總線定時寄存器1
CAN_BRT0 = ((brconst[i])>>8)&0xff; //設置總線定時寄存器0
CAN_CDR = 0xc8; //bit7=1:PeliCAN模式,關閉CLKOUT輸出
for(i=0; i<4; i++) //設置驗收代碼寄存器/驗收屏蔽碼寄存器
{
CAN_ACR[i] = (ID>>24) & 0xff;
CAN_AMR[i] = (IDMASK>>24) & 0xff;
ID <<= 8;
IDMASK <<= 8;
}
CAN_IER = 0x01; //設置中斷使能寄存器,允許接收中斷
i = CAN_MOD;
while(i != 0x08)
{
CAN_MOD = 0x08; //單濾波器模式
i = CAN_MOD;
}
EA = 1;
SJA1000_CS(1); //SJA1000片選無效,使用內部擴展RAM
}
//----------------------------------------------------------
// 函數: SJA1000_Transmit(...)
// 功能: SJA1000幀發送函數.可發送標準幀和擴展幀兩種幀格式,每
// 種幀格式都支持數據幀類型和遠程幀類型
// 形參: ra_info<==>幀屬性字段(含幀格式/幀類型/數據長度定義)
// ^bit7^ ^bit6^ ^bit3--bit0^
// ID<===>被發送幀的幀ID. 標準幀的ID==ID的bit10--bit0
// 擴展幀的ID==ID的bit28--bit0
// buf<==>指向被發送幀數據緩沖區的指針
// 全局變量引用: 無
// 全局變量修改: 無
// 返回: 0/1<===>發送失敗/成功
// 說明: 為加快速度,采取以代碼空間換時間的策略, 盡量不用循環
// 注意: 由于實驗板的特殊結構, 對SJA1000的片選信號處理應做特
// 殊處理
//----------------------------------------------------------
uchar SJA1000_Transmit(uchar rx_info, ulong ID, uchar* buf)
{
uchar i, j, len;
SJA1000_CS(0); //SJA1000片選有效,使用外部擴展RAM
rx_info &= 0xcf; //高半字節僅僅保留幀格式/幀類型位
if( (rx_info&0x0f) > 8 )
rx_info = (rx_info & 0xf0) + 8; //幀長度最大為8
len =rx_info & 0x0f;
CAN_MOD = 8;
j = CAN_SR;
if((j & 0x04) == 0x04) //若果CAN的當前發送緩沖區可用
{
CAN_TXB[0] = rx_info; //寫幀格式/類型/長度字段
if(rx_info & 0x80) //如果是擴展幀
{
CAN_TXB[1] = (ID>>21)&0xff; //寫幀ID
CAN_TXB[2] = (ID>>13)&0xff;
CAN_TXB[3] = (ID>> 5)&0xff;
CAN_TXB[4] = (ID<< 3)&0xff;
for(i=0; i<len; i++) //寫數據
CAN_TXB[i+5] = buf[i];
}
else //如果是標準幀
{
CAN_TXB[1] = (ID>>3)&0xff; //寫幀ID
CAN_TXB[2] = (ID<<5)&0xff;
for(i=0; i<len; i++) //寫數據
CAN_TXB[i+3] = buf[i];
}
CAN_CMR = 0x01; //啟動發送
SJA1000_CS(1); //SJA1000片選無效,使用內部RAM
return 1; //返回正常標志
}
else //若果CAN的當前發送緩沖區不可用
{
SJA1000_CS(1); //SJA1000片選無效,使用內部RAM
return 0; //返回出錯標志
}
}
//----------------------------------------------------------
// 函數: int0_ISR()
// 功能: 外部中斷0的中斷服務函數.外部中斷0由SJA1000產生,在初
// 始化SJA1000時打開了接收中斷,考慮到SJA1000具有故障處
// 理/脫線自動恢復的能力,故未打開與錯誤相關的中斷
// 形參: 無
// 全局變量引用: 無
// 全局變量修改: SJA1000_Received <==> "幀接收到"標志
// RX_Info <==> 幀信息字段
// SJA1000_Rec_ID <==> 幀的ID
// SJA1000_Rec_Dat[]<==> 幀的數據緩沖區
// 返回: 無
// 說明: 為加快速度,采取以代碼空間換時間的策略, 盡量不用循環
// 注意: 由于實驗板的特殊結構, 對SJA1000的片選信號處理應做特
// 殊處理
//----------------------------------------------------------
void int0_ISR(void) interrupt 0 //外部中斷0,CAN中斷
{
uchar temp, x, i;
x = AUXR; //備份擴展RAM占用模式
SJA1000_CS(0); //SJA1000片選有效,使用外部擴展RAM
temp = CAN_IR; //取CAN中斷寄存器
temp = CAN_SR; //取CAN狀態寄存器
if( (temp & 0x01) == 0x01 ) //如果是接收中斷
{
SJA1000_Received = 1; //設置收到幀標志
RX_Info = CAN_RXB[0]; //取幀信息字段(格式/類型/長度)
//下一行:取幀ID(擴展幀或標準幀中共同的部分)
SJA1000_Rec_ID = (CAN_RXB[1]<<8) + CAN_RXB[2];
if(RX_Info & 0x80) //如果是擴展幀
{
SJA1000_Rec_ID <<= 0x08;
SJA1000_Rec_ID += CAN_RXB[3];
SJA1000_Rec_ID <<= 0x08;
SJA1000_Rec_ID += CAN_RXB[4];
SJA1000_Rec_ID >>= 0x03; //以上取幀ID
for(i=0; i<(RX_Info&0x0f); i++) //以下取數據字段
SJA1000_Rec_Dat[i] = CAN_RXB[i+5];
}
else //如果是標準幀
{
SJA1000_Rec_ID >>= 0x05; //取幀ID
for(i=0; i<(RX_Info&0x0f); i++) //以下取數據字段
SJA1000_Rec_Dat[i] = CAN_RXB[i+3];
}
CAN_CMR=0x0c;//清除數據溢出,釋放當前幀所占FIFO緩沖區
}
SJA1000_CS(1); //SJA1000片選無效,使用內部擴展RAM
AUXR = x; //恢復擴展RAM占用模式
}
|
|