📄 can_sja1000.c
字号:
#include<REG52.h>
#include<absacc.h>
#include<intrins.h>
#include"SJA1000_Def.h"
//控制器STC89C52RC 特殊功能寄存器说明
sbit Int0 = 0xB2;
sbit P2_7 = P2^7;
//控制器STC89C52RC CAN 控制器SJA1000
#define CS_SJA1000 P2_7 //SJA1000 的片选
#define SJAIntInp Int0 //SJA1000 的外部中断0
#define SAJIntEn EX0 //外部中断0 使能标志
sbit LED_RED = P2^1;
sbit LED_GRE = P2^2; //LED
sbit SJA_RST = P2^3; //SJA1000复位管脚
sbit SJA_CS = P2^0; //SJA1000片选管脚
//---------------------------------------------------------------
//数码管显示数据
unsigned char Seg_Led[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92, // 0, 1, 2, 3, 4, 5
0x82,0xf8,0x80,0x90,0xff}; // 6, 7, 8, 9, off
//---------------------------------------------------------------
//全局变量声明
bit RXD_Cflag = 0; // CAN有无数据接收; 0无 ,1有
bit TXD_Cflag = 0; // CAN有无数据需要发送; 0无 ,1有
unsigned char xdata Can_TxBuf[15]={0};//CAN(SJA1000)发送缓冲区
unsigned char xdata Can_RxBuf[15]={0};//CAN(SJA1000)接收缓冲区
unsigned char Show_rx_data = 0x00;//显示接收到的数据在数码管3-4
unsigned char Show_tx_data = 0x00;//显示发送到的数据在数码管1-2
unsigned char Txd_Cdata = 0x00;//CAN总线要发送的数据
unsigned char Rxd_Cdata = 0x00;//CAN总线要接收的数据
//---------------------------------------------------------------
//函数声明
void SJA1000_Init(void); // 初始化CAN总线芯片
void PeliCanTxMes(void); // CAN发送子函数
void Rxd_deal(void); // 接收处理函数
void Txd_deal(void); // 发送处理函数
void Delay(unsigned char delay_time);
void led_seg7(unsigned char from,unsigned char number);//显示子函数
//---------------------------------------------------------------
//SJA1000外部中断函数
void SJA1000_IRQ(void) interrupt 0 using 2
{
unsigned char temp;
EA=0; //关总中断
CANInterrupt = InterruptReg;//将中断寄存器值附给位存储区变量
//----------------------------------------
//接受中断处理
if(RI_BitVar)
{
Can_RxBuf[0] = RxFramInFo;
Can_RxBuf[1] = RxBuffer1;
Can_RxBuf[2] = RxBuffer2;
Can_RxBuf[3] = RxBuffer3;
Can_RxBuf[4] = RxBuffer4;
Can_RxBuf[5] = RxBuffer5;
Can_RxBuf[6] = RxBuffer6;
Can_RxBuf[7] = RxBuffer7;
Can_RxBuf[8] = RxBuffer8;
Can_RxBuf[9] = RxBuffer9;
Can_RxBuf[10] = RxBuffer10;
Can_RxBuf[11] = RxBuffer11;
Can_RxBuf[12] = RxBuffer12;
RXD_Cflag = 1;//置有接收标志
CommandReg = CommandReg|CDO_Bit;//清除数据超载位
temp = ArbLostCapReg;//释放仲裁丢失捕捉寄存器
temp = ErrCodeCapReg;//释放错误代码捕捉寄存器
}
//----------------------------------------
//发送中断处理
if(TI_BitVar)
{
}
//----------------------------------------
//错误报警中断处理
if(EI_BitVar)
{
}
//----------------------------------------
//数据溢出中断处理
if(DOI_BitVar)
{
}
//----------------------------------------
//唤醒中断处理
if(WUI_BitVar)
{
}
//----------------------------------------
//错误消极中断处理
if(EPI_BitVar)
{
}
//----------------------------------------
//仲裁丢失中断处理
if(ALI_BitVar)
{
}
//----------------------------------------
//总线错误中断处理
if(BEI_BitVar)
{
}
EA = 1;//开总中断
}
//----------------------------------------------------------------
//外部中断0(启动数据发送)
void INT0_Counter( void ) interrupt 0 using 1
{//INT0按键为计数按键
if(Show_tx_data++>99) //存储计数结果,并为待发送的数据
Show_tx_data=0;
TXD_Cflag = 1; //CAN总线要发送数据标志位
Txd_Cdata = Show_tx_data;//CAN总线要发送的数据
}
//-----------------------------------------------------------------
//主函数体
void main(void)
{
//CPU初始化
SJA_RST = 1;//CAN总线复位管脚
SJA_CS = 0; //CAN总线片选有效
SCON = 0x50; //串口方式1
PCON = 0x80; //串口波特率加速
TMOD = 0x21;
TH1=0xFD; //19200bps
TL1=0xFD;
TR1 = 0;
TI = 0;
RI = 0;
ES = 1;//打开串口中断
EX1 = 1;
IT1 = 0;//CAN总线接收中断
IT0 = 1;//外部中断0负边沿触发
EX0 = 1;//打开外部中断0
EA = 1; //打开总中断
SJA_CS = 1;//CAN总线片选无效
SJA1000_Init();
_nop_();
_nop_();
while(1)
{
Rxd_deal();//接收处理程序
Txd_deal();//发送处理程序
led_seg7(1,Show_tx_data);
led_seg7(3,Show_rx_data);
}
}
//-----------------------------------------------------------------
//函数部分
/*----------------- SJA1000 初始化 --------------------*/
void SJA1000_Init(void)
{
//定义中断优先级和控制电平激活
PX0=PRIORITY_HIGH; //设CAN 有一个高优先级中断
IT0=INTLEVELACT; //中断0为电平激活
//使能SJA1000 的通讯接口
CS_SJA1000=ENABLE_N; //SJA1000 接口使能
//通讯连接的定义结束
//初始化SJA1000 的所有内部寄存器因为一些寄存器在仅复位模式期间可被写所以在写入
//之前必须检查上电后SJA1000 被设定为复位模式如果复位模式已被置位在循环里面可以检查到
//中断禁能如果使用上电后不需要
EA=DISABLE; //所有中断禁能
SAJIntEn=DISABLE; //来自SJA100 的外部中断禁能
//设定复位模式/请求位在上电后SJA1000 处于BasicCAN 模式
//在超时和出现错误信号后跳出循环
while((ModeControlReg & RM_RR_Bit)==ClrByte)
{
//其他位而不是复位模式/请求位没有改变
ModeControlReg = ModeControlReg|RM_RR_Bit;
}
//硬件设定时钟分频寄存器
//选择PeliCAN 模式
//旁路CAN 输入比较器作为外部收发器使用
//配置时钟分频寄存器
ClockDivideReg = CANMode_Bit|CBP_Bit|DivBy2;
//配置模式寄存器
ModeControlReg = ModeControlReg|AFM_Bit;
//写SJA1000 中断使能/控制寄存器
InterruptEnReg = ClrIntEnSJA;
//定义验收代码和屏蔽
AcceptCode0Reg = ClrByte;
AcceptCode1Reg = ClrByte;
AcceptCode2Reg = ClrByte;
AcceptCode3Reg = ClrByte;
AccepMask0Reg = DontCare; //接收任何标识符
AccepMask0Reg = DontCare; //接收任何标识符
AccepMask0Reg = DontCare; //接收任何标识符
AccepMask0Reg = DontCare; //接收任何标识符
//配置总线定时
//位频率1Mbit/s@24MHz 总线被采样一次
BusTiming0Reg = SJW_kB_16|Prec_kB_16;
BusTiming1Reg = TSEG2_kB_16|TSEG1_kB_16;
//配置CAN 输出TX1 悬空TX0 推挽
//正常输出模式
OutControlReg = Tx1Float|Tx0PshPull|NormalMode;
//离开复位模式/请求也就是转向操作模式
//STC89C52RC 的中断使能
//但SJA1000 的CAN 中断禁能这可以在一个系统里面分别完成
//清除复位模式位选择单验收滤波器模式
//关闭自我测试模式和仅听模式
//清除休眠模式唤醒
//等待直到RM_RR_Bit 清零
//在超时和出现错误后跳出循环
do
{
ModeControlReg = ClrByte;
}while((ModeControlReg&RM_RR_Bit) != ClrByte);
SAJIntEn = ENABLE; //SJA1000 的外部中断使能
EA = ENABLE; //所有中断使能
}
/*------------------ SJA1000 初始化结束 -----------------*/
/*-----------------Peli CAN Send Message-----------------*/
void PeliCanTxMes(void)
{
//if()//扩展侦格式
//{
//等待直到发送缓冲器被释放
do
{
//等待时启动查询定时器并运行一些任务
//在超时和出现错误后跳出循环
;
}while((StatusReg & TBS_Bit) != TBS_Bit);
//释放发送缓冲器信息可写入缓冲器
//在这个例子里会发送一个标准帧信息
TxFramInFo = 0x88; //EFF(data) DLC8
TxBuffer1 = 0xA5; //标识符1 A5 1010 0101
TxBuffer2 = 0x20; //标识符2 20 0010 0000
TxBuffer3 = 0xA5; //标识符1 A5 1010 0101
TxBuffer4 = 0x20; //标识符2 20 0010 0000
TxBuffer5 = 0x51; //data1 =51
TxBuffer6 = 0x52; //data1 =52
TxBuffer7 = 0x53; //data1 =53
TxBuffer8 = 0x54; //data1 =54
TxBuffer9 = 0x55; //data1 =55
TxBuffer10 = 0x56; //data1 =56
TxBuffer11 = 0x57; //data1 =57
TxBuffer12 = 0x58; //data8 =58
//启动发送
CommandReg = TR_Bit; //置位发送请求位
//}
//else//标准侦格式
//{
//等待直到发送缓冲器被释放
// Do
// {
//等待时启动查询定时器并运行一些任务
//在超时和出现错误后跳出循环
;
// }while((statusReg & TBS_Bit) != TBS_Bit)
//释放发送缓冲器信息可写入缓冲器
//在这个例子里会发送一个标准帧信息
// TxFrameInfo = 0x08; //SFF(data) DLC8
// TxBuffer1 = 0xA5; //标识符1 A5 1010 0101
// TxBuffer2 = 0x20; //标识符2 20 0010 0000
// TxBuffer3 = 0x51; //data1 =51
// TxBuffer4 = 0x52; //data2 =52
// TxBuffer5 = 0x53; //data3 =53
// TxBuffer6 = 0x54; //data4 =54
// TxBuffer7 = 0x55; //data5 =55
// TxBuffer8 = 0x56; //data6 =56
// TxBuffer9 = 0x57; //data7 =57
// TxBuffer10 = 0x58; //data8 =58
//启动发送
// CommandReg = TR_Bit; //置位发送请求位
//}
}
/*--------------------Peli CAN send Message End------------------*/
/*---------------------------------------------------------------
//采用查询的方式接受
void PeliCanRxMes(void)
{
InterruptEnReg RIE_Bit//接收中断使能
if()//扩展贞格式
{
//从SJA1000 读中断寄存器的内容并临时保存所有中断标志被清除在PeliCAN 模式里
//接收中断RI 被首先清除当给出释放缓冲器命令时
CANInterrupt = InterruptReg
//检查接收中断和读一个或所有接收到的信息
iI( RI_VarBit) YES //检测到接收中断
{
//从SJA1000 得到接收缓冲器的内容并将它存入控制器的内部存储器
//可以立刻对帧信息和数据长度代码解码并适当地取出
//释放接收缓冲器接收中断标志被清除新的信息将产生一个新中断
ommandReg RRB_Bit //释放接收缓冲器
}
}
else//标准贞格式
{
//从SJA1000 读中断寄存器的内容并临时保存所有中断标志被清除在PeliCAN 模式里
//接收中断RI 被首先清除当给出释放缓冲器命令时
CANInterrupt = InterruptReg
//检查接收中断和读一个或所有接收到的信息
If (RI_VarBit YES) //检测到接收中断
{
//从SJA1000 得到接收缓冲器的内容并将它存入控制器的内部存储器
//可以立刻对帧信息和数据长度代码解码并适当地取出
//释放接收缓冲器接收中断标志被清除新的信息将产生一个新中断
CommandReg RRB_Bit //释放接收缓冲器
}
}
}*/
//------------------------------------------------------------------------
//接收处理程序
void Rxd_deal(void)
{
if( RXD_Cflag )
{//如果CAN总线收到数据,数码管3-4显示,RS232将收到的数据发送给PC机
RXD_Cflag = 0;
Rxd_Cdata = Can_RxBuf[5];
Show_rx_data = Rxd_Cdata;//
}
}
//-------------------------------------------------------------------------
//发送处理函数,主要是准备数据,并且调用发送函数
void Txd_deal(void)
{
if( TXD_Cflag == 1 )
{
TXD_Cflag = 0;
Can_TxBuf[5] = Txd_Cdata;
PeliCanTxMes();
}
}
//----------------------------------------------------------------------------
//from(1_4):数码管显示起始位置(从右到左),number:显示的数
void led_seg7(unsigned char from,unsigned char number)
{
unsigned char digit,temp_l;
unsigned char temp_h=0x7f;
temp_h = _cror_(temp_h,from-1); //确定从哪一位开始显示,即确定高四位
temp_h = temp_h & 0xf0; //取高四位
temp_l = P2 & 0x0f; //取P2的低四位
P2 = temp_h | temp_l; //设定P2口
if(number==0)
{
P0 = Seg_Led[0];
Delay(5);
P0 = 0xff;
}
else
{
while(number)
{
digit = number%10 ;
number /= 10;
P0 = Seg_Led[digit] ;
Delay(5);
temp_h = P2 & 0xf0; //取P2的高四位
temp_h = temp_h | 0x0f; //拼装 temp_h,进行位选
temp_h = _cror_(temp_h,1);
temp_h = temp_h & 0xf0; //取高四位
temp_l = P2 & 0x0f; //取P2的低四位
P0 = 0xff;
P2 = temp_h | temp_l; //设定P2口
}//while结束
}//else结束
}
void Delay(unsigned char delay_time)
{//延时程序
while(delay_time--)
{;}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -