📄 can.c
字号:
/********************************************************************
* 函数库说明:CAN总线驱动函数库 *
* 版本说明: 1.0 Bate *
* 作者: andylee *
* 日期: 2006年7月 *
* 平台: mega16 16M *
* 说明: 为上层提供CAN控制器的基本读写函数,数据发送、接受函数*
********************************************************************/
#include "can.h"
#include "delay.h"
//#define DEBUG
#define TransBuffer TransmitMessage
/*********************
* 全局变量定义 *
*********************/
//unsigned char CanMode[14];
unsigned char TransmitMessage[13];
unsigned char RxBuffer[13];
#ifdef DEBUG
unsigned char temp1;
#endif
/********************************************************** **********
* 函数说明:CAN控制器引脚初始化 *
* 输入: *
* 输出:无 *
********************************************************************/
void sja_port_init(void)
{
//CAN数据线设置
PORTC=0x00;
DDRC=0xff;
PORTD=0b11000000; //INT引脚输入不上拉
DDRD =0b11111000;
//CAN 控制引脚设置
CAN_DDR|=(1<<WR)|(1<<RD)|(1<<ALE)|(1<<CS);
WR_H;
RD_H;
ALE_L;
CS_H;
}
/********************************************************************
* 函数说明:模拟CAN收发时序,写一个字节到CAN控制器 *
* 输入:data,address *
* 输出:无 *
********************************************************************/
void sja_write_data(unsigned char addr,unsigned char data)
{
RD_H;
DDRC=0xFF; //总线设置为输出
// ALE_L;
PORTC=addr;
ALE_H;
NOP();
ALE_L; //下降沿地址锁存
NOP();
PORTC=data;
CS_L;
WR_L;
NOP();
WR_H; //上升沿数据写入
NOP();
// ALE_H;
CS_H;
}
/********************************************************************
* 函数说明:模拟CAN收发时序,从CAN控制器读一个字节 *
* 输入:address *
* 输出:data *
********************************************************************/
unsigned char sja_read_data(unsigned char addr)
{
unsigned char data;
WR_H;
DDRC=0xFF; //总线设置为输出
ALE_L;
PORTC=addr;
ALE_H;
NOP();
ALE_L; //地址锁存
NOP();
PORTC=0xFF;
DDRC=0x00; //总线设置为输入,内部上拉
CS_L;
RD_L;
NOP();
RD_H;
NOP();
data=PINC;
CS_H;
return data;
}
/********************************************************************
* 函数说明:初始化SJA1000的相关寄存器:设置工作模式,波特率,验收码*
* 输入:无 *
* 输出:无 *
********************************************************************/
void sja_init(void)
{
unsigned char temp;
unsigned int k ;
CLI();
sja_write_data(MODE,0x09); //单个验收滤波,复位模式
sja_read_data(IR); //读取CAN的中断标识,除接受中断外的所有中断复位
while(!( sja_read_data(MODE)&0x01)) //检测SJA1000是否达到复位工作模式
{
sja_write_data(MODE,0x09); //进入复位工作模式
}
delay_nus(5); //延时约5us
sja_write_data(CDR,REG_CDR_DATA); //PeliCAN 模式,旁路输入比较器,禁能CLOCKOUT引脚
delay_nus(5); //延时约5us
sja_write_data(BTR0,BTR0_Rate_250k); //同步跳转宽度4;时钟4分频,波特率250Kb/s
sja_write_data(BTR1,BTR1_Rate_250k); //采样3次;时间段1,2=10,5
sja_write_data(OCR,REG_OCR_DATA); //输出控制,推拉结构,正逻辑
sja_write_data(RXERR,0x00); //收发错误寄存器清零
sja_write_data(TXERR,0x00);
sja_write_data(ECC,0x00); //错误代码捕捉寄存器清零
sja_write_data(RBSA,0x00); //缓存器起始地址寄存器设置为0
sja_write_data(ACR0,ACR0_ID); //验收屏蔽
sja_write_data(ACR1,ACR1_ID);
sja_write_data(ACR2,ACR2_ID);
sja_write_data(ACR3,ACR3_ID);
sja_write_data(AMR0,AMR0_ID);
sja_write_data(AMR1,AMR1_ID);
sja_write_data(AMR2,AMR2_ID);
sja_write_data(AMR3,AMR3_ID);
sja_write_data(IER,REG_IER_DATA); //开放接收中断
sja_write_data(CMR,COS_CMD); //清除数据溢出
delay_nus(10);
sja_write_data(CMR,RRB_CMD); //释放接收缓冲器
do
{
//sja_write_data(MODE,0x04); //设置SJA1000 工作模式;zijiance
sja_write_data(MODE,0x08); //设置SJA1000 工作模式
}
while((sja_read_data(MODE)&0x01)); //确认复位标志是否被删除
SEI();
}
/********************************************************************
* 函数说明:SJA1000中断发送服务程序,若有待发送报文则及时发送 *
* 输入:无 *
* 输出:无 *
********************************************************************/
void sja_tx_service(void)
{
unsigned char Length;
unsigned char FF,i;
if(flag.mess_wait==TRUE)
{
led_on;
flag.mess_wait=FALSE; //清报文待发送标志
FF=TransmitMessage[0]&0x80; //取贞格式
Length=TransmitMessage[0]&0x0f; //取数据长度代码
if(Length=0x08)
{
Length = 0x80;
}
sja_write_data(TXEFF,TransmitMessage[0]); //写TX贞报文
sja_write_data(TXID0,TransmitMessage[1]); //写TX标识码1
sja_write_data(TXID1,TransmitMessage[2]);
if(FF) //FF=0:标准CAN格式
{ //FF=1:扩展CAN格式
sja_write_data(TXID2,TransmitMessage[3]);
sja_write_data(TXID3,TransmitMessage[4]);
}
for (i=0;i<Length;i++)
{
if(FF)
sja_write_data(TXDATA0+i,TransmitMessage[5+i]);
else
sja_write_data(TXDATA0+i,TransmitMessage[3+i]);
}
led_off;
//置位发送请求
//sja_write_data(CMR,0x10); //发送请求命令:zijieshou
sja_write_data(CMR,0x01); //发送请求命令当错误时可重发
}
}
/********************************************************************
* 函数说明:SJA1000发送服务程序 *
* 输入:RAM中以TransmitMessage开始的CAN的发送报文 *
* 输出:无 *
********************************************************************/
void sja_tx(unsigned char *TransmitMessage)
{
unsigned char Length;
unsigned char FF,i,state;
unsigned char sreg;
sreg=SREG; //保存全局中断标志
CLI();
state=sja_read_data(SR); //读状态寄存器
while(state&(1<<4)); //正在接受则等待
// while(state&(1<<3)); //上次发送未完成则等待
if(state&(1<<2)) //判断发送缓冲是否释放
{
led_on;
FF=TransmitMessage[0]&0x80; //取贞格式
Length=TransmitMessage[0]&0x0f; //取数据长度代码
#ifdef DEBUG
rprintfCRLF();
rprintfStr("begin transmit...");
rprintfCRLF();
#endif
if(Length>8)
{
Length = 8;
}
sja_write_data(TXEFF,TransmitMessage[0]); //写TX贞报文
sja_write_data(TXID0,TransmitMessage[1]); //写TX标识码1
sja_write_data(TXID1,TransmitMessage[2]);
if(FF) //FF=0:标准CAN格式
{ //FF=1:扩展CAN格式
sja_write_data(TXID2,TransmitMessage[3]);
sja_write_data(TXID3,TransmitMessage[4]);
}
for (i=0;i<Length;i++)
{
if(FF)
sja_write_data(21+i,TransmitMessage[5+i]);
else
sja_write_data(19+i,TransmitMessage[3+i]);
}
//置位发送请求
//sja_write_data(CMR,0x10); //发送请求命令
sja_write_data(CMR,0x01); //发送请求命令当错误时可重发
led_off;
#ifdef DEBUG
rprintfStr("transmit over");
rprintfCRLF();
rprintfCRLF();
#endif
}
else //发送缓冲被锁,将数据存入RAM缓存
{
flag.mess_wait=TRUE;
}
SREG=sreg;
SEI();
}
/********************************************************************
* 函数说明:SJA1000接受中断服务函数, *
* 输入:无 *
* 输出:正确读取返回TURE否则返回FALSE 。 *
* 影响变量:接受缓冲在正确读取时被刷新 *
********************************************************************/
void sja_rx_service(void)
{
unsigned char number,i,ptr;
ptr=RXEFF;
if((sja_read_data(RXEFF)&0x40)==0x40) //如果RTR=1,为远程帧
{
sja_write_data(CMR,0x04); //则释放接收缓冲
}
else //为0,则是数据帧
{
number=(sja_read_data(RXEFF)&0x0f);//取第一个字节的低四位,即数据长度
if (number>0x08)
number=0x08;
if ((sja_read_data(RXEFF))&0x80) //判断是标准帧还是扩展帧
{
number=number+5; //扩展帧,则帧的总长度加5(13字节)
}
else
{
number=number+3; //标准帧,则帧的总长度加3(11字节)
}
for(i=0;i<number;i++) //读取数据
{
RxBuffer[i]=sja_read_data(RXEFF+i);
ptr++;
}
sja_write_data(CMR,0x04); //最后释放FXFIFO
}
}
/********************************************************************
* 函数说明:SJA1000查询方式接收函数, *
* 输入:无 *
* 输出:无 *
********************************************************************/
void Search(void)
{
unsigned char SearchStatus;
SearchStatus=sja_read_data(SR); //读取状态寄存器
#ifdef DEBUG
rprintfStr("SR: ");
rprintfu08(SearchStatus);
rprintfCRLF();
#endif
// if((SearchStatus & 0x83)) //是否存在总线关闭、错误状态、数据溢出、有数据位等状态
// {
if(SearchStatus&(1<<7))//如果总线关闭
{
#ifdef DEBUG
rprintfStr("****bus shut off****");
rprintfCRLF();
#endif
sja_read_data(IR); //读取中断寄存器,清除中断位
sja_write_data(MODE,0x08);
}
if(SearchStatus&0x02)//如果有数据溢出
{
#ifdef DEBUG
rprintfStr("****data overflow****");
rprintfCRLF();
#endif
sja_write_data(CMR,0x0c); //在命令寄存器中清除数据溢出和释放接收缓冲区
}
if(sja_read_data(IR) & 0x01)//IR.0=1,接收缓冲区有数据
{
led_on;
#ifdef DEBUG
rprintfStr("****receive buffer have data****");
rprintfCRLF();
#endif
}
// }
}
//=============================================================================
//显示缓冲区内容
void play_buffer(unsigned char *ptr)
{
unsigned char i;
for (i=0;i<13;i++)
{
rprintfu08(*ptr);
// rprintfStr("--");
ptr++;
}
rprintfCRLF();
}
//=============================================================================
//初始化换冲区,在此监控卡上只有模拟管理系统降低充电电压的情况
void buffer_init(void)
{
TransmitMessage[0]=0x88; //扩展贞,8个数据字节
TransmitMessage[1]=192; //管理系统优先级7: ID.28--ID.21=111-00-111
TransmitMessage[2]=168; //PF=255- 235 ID.20--ID.13=01011-000
TransmitMessage[3]=0x00; //PS=252- 22 ID.12--ID.5 =10110-000
TransmitMessage[4]=0x08; //As=0x11 ID.4--ID.0 =10001-000
TransmitMessage[5]=0xCC; //桢编号
TransmitMessage[6]=0x00;
TransmitMessage[7]=0x01;
TransmitMessage[8]=0xa1;
TransmitMessage[9]=0xa2;
TransmitMessage[10]=0xa3;
TransmitMessage[11]=0xa4;
TransmitMessage[12]=0xff;
}
void test_can(void)
{
rprintfCRLF();
rprintfStr("***CAN BUS DEBUG:***");
rprintfCRLF();
rprintfStr("content of transmit buffer ");
rprintfCRLF();
play_buffer(TransmitMessage);
CLI();
sja_tx(TransmitMessage);
SEI();
rprintfCRLF();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -