SJA1000 CAN驅(qū)動(dòng)程序演示實(shí)驗(yàn)
序庫SJA1000_PEI.LIB 的基本函數(shù),實(shí)現(xiàn)實(shí)驗(yàn)板上CAN 節(jié)點(diǎn)的初始化以及CAN 節(jié)點(diǎn)數(shù)據(jù)
收發(fā)測(cè)試。
二.實(shí)驗(yàn)設(shè)備及器件
PC 機(jī) 一臺(tái)
DP-51PROC 單片機(jī)綜合仿真實(shí)驗(yàn)儀 一臺(tái)
CAN PARK 模塊 一臺(tái)
CAN 連接線 一根
三.實(shí)驗(yàn)步驟
1、 將CAN-bus PARK 插入到A6 區(qū)中,用導(dǎo)線連接A6 區(qū)的P1_IO2 到A2 區(qū)的P10,
連接A6 區(qū)的P1_CS1 到A2 區(qū)的A15。
2、 使用導(dǎo)線把A2 區(qū)的P16 和P17 分別于D5 區(qū)的SCL 和SDA 相連。使用導(dǎo)線把D5
區(qū)的/RST 與VCC 相連。
3、 由于本程序使用中斷方式響應(yīng)SJA1000 中斷,故將A5 區(qū)的P1_INT 接到A2 區(qū)的
INT0。
4、 利用CAN 連接線將兩臺(tái)已經(jīng)安裝了CAN-Bus 模塊的DP-51PROC 連接起來,以組
成簡單的CAN 網(wǎng)絡(luò)實(shí)現(xiàn)CAN 的接收和發(fā)送。
5、 本驅(qū)動(dòng)程序已經(jīng)將輸出文件路徑設(shè)置為“E:Temp”,用戶可自行更改輸出文件路徑。
將路徑“E:Temp”中的CAN. hex 文件下載到兩臺(tái)DP-51PROC 中運(yùn)行。
四.實(shí)驗(yàn)參考程序主要部分
/******************************************************
*描述: 獨(dú)立的CAN 控制器SJA1000PeliCAN 在small rtos 中的應(yīng)用示例
*文件名: PELIRTOS.c
*應(yīng)用語言: KEIL C51
*應(yīng)用系統(tǒng): small rtos
*版本 : V1.0
*廣州周立功單片機(jī)發(fā)展有限公司 保留所有的版權(quán)
****************************************************/
#define _TIME_MODULE_H
#define _SERIAL_H
/********************************************************
** 導(dǎo)入頭文件
******************************************************/
#include "INCLUDES.h"
#include "Sja1000_peli.h"
sfr IPH=0xb7;本文引用地址:http://m.butianyuan.cn/article/201612/329641.htm
sbit RESET_PIN=P1^0;
// 驗(yàn)收代碼/屏蔽寄存器的內(nèi)容(4+4)
uint8 xdata Send_CAN_Filter[8]={0xf0,0xf0,0xf0,0xff,0xff,0xff,0xff,0xff};
// 幀信息和標(biāo)示碼(1+4)分別對(duì)應(yīng) TX,TX1,TX2,TX3,TX4
uint8 xdata Send_CAN_Info_ID[3]={0xc7,0x0A,0x0B};
uint8 xdata Recv_CAN_Info_ID[3];
// 待發(fā)送數(shù)據(jù)(8)
uint8 xdata
Send_CAN_Data[13]={0xc7,0x0A,0x0B,0x04,0x05,0x06,0x07,0x08,0x07,0x08,0x07,0x08,
0x08};
uint8 xdata Recv_CAN_Data[14];
uint8 xdata time_Counter=0;
uint8 xdata BTR0,BTR1;
uint16 xdata *p;
uint8 xdata disp_buf[8];
void CAN_Send(void);
void display(void);
void CAN_Rcv(void);
void TimeSum(void);
void Delay_ms(uint8 j);
void SJA1000_Config_Normal(void);
void Init(void)
{
CKCON=1; //應(yīng)用6clock
TMOD = (TMOD & 0XF0) | 0X01;
TCON=TCON|0x04; //MCU 的INT1 下降沿觸發(fā),INT0 電平觸發(fā)
TH0 = (65536 - (11059200 / 12) / 100) / 256;
TL0 = (65536 - (11059200 / 12) / 100) % 256;
TR0 = 1;
ET0 = 1;
TF0 = 0;
}
/****************************************************************
**函數(shù)名稱:void CAN_Init(void)
**功能描述:復(fù)位SJA1000,并設(shè)置其工作在正常模式
*****************************************************************/
void CAN_Init(void)
{
RESET_PIN=0; //將SJA1000 的復(fù)位線與P1.0 相連接
Delay_ms(1);
RESET_PIN=1; //控制P1.0 來實(shí)現(xiàn)SJA1000 的復(fù)位
SJA_CS_Point=&CAN_SJA_BaseAdr;
SJA1000_Config_Normal();
WriteSJAReg(REG_CAN_IER,RIE_BIT); //使能SJA1000 接收中斷
EX0=1;
}
/**************************************************************
** 函數(shù)原型: void Delay_ms(uchar j)
** 功能描述: 該函數(shù)用于不精確的延時(shí)。在12M,6CLK 下,大約延時(shí)j*1ms
***************************************************************/
void Delay_ms(uint8 j)
{
uint8 k,l;
for(l=0;l<=j;l++)
{
for(k=0;k<=250;k++)
{
;
}
}
}
/************************************************************
** 函數(shù)原型: void SJA1000_Config_Normal(void)
** 功能描述: 對(duì)SJA1000 的正常模式的初始化配置
***************************************************************/
void SJA1000_Config_Normal(void)
{
BTR0=0x00;
BTR1=0x14; //設(shè)置為80k 波特率通信
SJAEntryResetMode(); //進(jìn)入復(fù)位模式
WriteSJAReg(REG_CAN_CDR,0xc8); //配置時(shí)鐘分頻寄存器,選擇PeliCAN 模式
WriteSJAReg(REG_CAN_MOD,0x01); //配置模式寄存器,選擇雙濾波、正常模式
WriteSJARegBlock(16,Send_CAN_Filter,8); //配置驗(yàn)收代碼/屏蔽寄存器
WriteSJAReg(REG_CAN_BTR0,BTR0); //配置總線定時(shí)器0
WriteSJAReg(REG_CAN_BTR1,BTR1); //配置總線定時(shí)器1
WriteSJAReg(REG_CAN_OCR,0x1a); //配置輸出管腳
SJAQuitResetMode(); //退出復(fù)位模式,進(jìn)入工作模式
}
/*********************************************************** 函數(shù)原型: void CAN_Data_Send(void)
** 功能描述: SJA1000 的單次發(fā)送子函數(shù)(注意在這個(gè)函數(shù)的末尾要置位接收中斷)
*************************************************************/
void CAN_Data_Send(void)
{
// 發(fā)送數(shù)據(jù)
WriteSJAReg(REG_CAN_IER,0x02); //使能SJA1000 發(fā)送中斷位
WriteSJARegBlock(16,Send_CAN_Data,13);
WriteSJAReg(REG_CAN_CMR,1); //使能發(fā)送請(qǐng)求
Delay_ms(10);
WriteSJAReg(REG_CAN_IER,RIE_BIT); //使能SJA1000 接收中斷
}
/**************************************************************
** 函數(shù)原型: void SJA1000_INT0 (void) interrupt 0
** 功能描述: SJA1000 中斷響應(yīng)函數(shù)
***************************************************************/
void SJA1000_INT0(void) interrupt 0
{
OS_INT_ENTER();
EX0 = 0;
OSIntSendSignal(0); //無條件的令CAN 接收中斷處理任務(wù)(CAN_Rcv ())處于就緒狀
態(tài)
//由于CAN_Rcv ()的優(yōu)先級(jí)最高,故中斷退出后立刻執(zhí)行
CAN_Rcv ().
OSIntExit();
}
void main(void)
{
uint8 i ;
OSInit();
Init();
CAN_Init();
//初始化顯示緩存
for(i=0;i<8;i++)
{
disp_buf[i]=31;
}
//創(chuàng)建任務(wù)
OSTaskCreate(CAN_Rcv, NULL, 0);
OSTaskCreate(display, NULL, 1);
OSTaskCreate(CAN_Send, NULL, 2);
OSTaskCreate(TimeSum, NULL, 3);
while(1)
{
PCON = PCON | 0x01; //令CPU 進(jìn)入睡眠狀態(tài)
}
}
/*****************************************************************
**鍵值發(fā)送任務(wù)
*****************************************************************/
void CAN_Send(void)
{
uint8 key_data;
while(1)
{
key_data = ZLG7290_GetKey();
if(key_data)
{
Send_CAN_Data[3] = key_data;
CAN_Data_Send();
disp_buf[4] = key_data % 10;
disp_buf[5] = (key_data / 10) % 10;
}
OSWait(K_TMO,5);
}
}
/****************************************************************
**顯示任務(wù)
*****************************************************************/
void display(void)
{
while(1)
{
OSWait(K_TMO,5);
OS_ENTER_CRITICAL();
ZLG7290_SendBuf(&disp_buf[0], 8);
OS_EXIT_CRITICAL();
}
}
/***************************************************************
**CAN 接收中斷處理任務(wù)
***************************************************************/
void CAN_Rcv(void)
{
while(1)
{
OSWait(K_SIG, 0); //掛起當(dāng)前任務(wù),等待喚醒信號(hào)
if(ReadSJAReg(REG_CAN_IR)&0x01)
{
//數(shù)據(jù)接收一定在釋放緩沖區(qū)之前,釋放后數(shù)據(jù)不確定
ReadSJARegBlock(16,Recv_CAN_Data,13);
WriteSJAReg(REG_CAN_CMR,4); //釋放SJA1000 接收緩沖區(qū)
disp_buf[0] = Recv_CAN_Data[3] % 10;
disp_buf[1] = (Recv_CAN_Data[3] / 10) % 10;
}
EX0 = 1;
}
}
/*****************************************************
* *計(jì)數(shù)任務(wù)
***************************************************************/
void TimeSum(void)
{
while(1)
{
OSWait(K_TMO, 5);
disp_buf[7]++;
if(disp_buf[7] > 9)
{
disp_buf[7] = 0;
}
}
}
五.實(shí)驗(yàn)例程簡析
本驅(qū)動(dòng)程序采用中斷方式接收CAN 總線數(shù)據(jù)。采用中斷的方式,可以提高系統(tǒng)的實(shí)時(shí)性。特別的在接收數(shù)據(jù)的時(shí)候,采用中斷方式可以在效率和實(shí)時(shí)性上比采用非中斷方式得到很大的提高。
按下D5 區(qū)的按鍵時(shí),左邊的LED 將顯示按鍵鍵值,同時(shí)程序調(diào)用CAN_Data_Send ( )
將檢測(cè)到的鍵值通過CAN 總線發(fā)送到另一臺(tái)實(shí)驗(yàn)儀上。實(shí)驗(yàn)儀將從CAN 總線上接收到的
鍵值數(shù)據(jù)顯示在D5 區(qū)的右邊LED 上。
D5 區(qū)中最右邊的LED 管循環(huán)地顯示0~9,目的是為了顯示系統(tǒng)正在運(yùn)行。
有關(guān)SJA1000_PEI 庫的使用請(qǐng)閱讀配套光盤中的《SJA1000_PEI 庫說明及其使用》文檔。
評(píng)論