|
本帖最后由 FSL_TICS_ZJJ 于 2014-5-5 14:59 编辑
CAN是Controller Area Network的缩写,即“局域网控制器”的意思,可以归属于工业现场总线的范畴,通常称为CAN BUS,即CAN总线,是目前国际上应用最为广泛的开放式现场总线之一。CAN总线规范从CAN1.2规范发展为兼容CAN1.2规范的CAN2.0规范(CAN 2.0A为标准格式,CAN2.0B为扩展格式),目前应用的CAN器件大多符合CAN2.0规范。
CAN模块它的速率有:83.33K,125K,250K,500K等常用速率.其中83.33K速率是针对单线CAN驱动IC的(不感兴趣).其它的都是针对双线CAN驱动IC的 .CAN总线是没有主从之分的,它所有CAN器件挂于一点.要接终端电阻.这种网络结构类似星形结构 . CAN的驱动IC有普通(1040,1041)和容错(1053,1054)之分,它们的区分主要在于数字1,0的电压表示方式不一样, 所以一个总线上不能同时存在这两种驱动IC。举例 : CAN总线收发器(TJA1040) .
CAN总线协议属于多主控制 , 不分主从设备 . 所以任何一个CAN模块都可以发出数据,那么哪个发送的数据最终能发出去呢,这就涉及到总线的仲裁。同时这个数据是发给哪个器件的呢,这就涉及到数据报文的区分,它是通过设备ID来区别的.CAN 以两种形式存在,一种是具有11位ID标识符的BasicCAN,另一种是带有扩展成29位ID标识符的高级形式PeliCAN。Philips、Intel、飞思卡尔均支持BasicCAN 和PeliCAN。同时,PeliCAN 协议允许两段长度的标识符:A部分使用11位报文标识符,能够识别出2032个不同的标识符(保留十六位),此部分兼容BasicCAN;而PeliCAN (B部分)有29位,能够产生536870912个不同的标识符。
飞思卡尔MC9S08DZ96在CAN总线上模块化应用代码的编写如下:
//CAN_Device_IC CAN总线收发器是 TJA1040 速度配置
#define CAN_Boude_125k 0x49c3
#define CAN_Boude_250k 0x49c1
#define CAN_Boude_500k 0x23c1
//CAN报文格式,标准11位ID和扩展29位ID
typedef enum {
CAN_OUT_STD_MSG, //标准
CAN_OUT_XTD_MSG //扩展
} CAN_OUT_MODE;
//CAN模块的运行方式
enum CAN_Operation_Mode
{
CAN_Mode_LoopB, //自环测试模式
CAN_Mode_Listen, //监听模式
CAN_Mode_Operation, //正常运行模式
};
//存在CAN报文的数据结构
typedef struct CANMsgBase{
word CycleTime;
word TimeCount;
byte cCANID[4];
byte cDataLength;
byte cData[8];
} CANMsg;
CANMsg CANMsgTx[10];
CANMsg CANMsgRx[10];
//初始化CAN模块
void MSCAN1_Init(word Boude,enum CAN_Operation_Mode type)
{
INT16U wTemp;
TRANSCEIVER_STB_DIR = 1;
cMSCANTxBufCANIDIndex = 0xff;
CAN_TX_PIN_DIR = 1; //将TX设为输出口
TRANSCEIVER_STB_PIN = 1; //先复位1040IC,此处是对相应的CAN驱动IC来设置的
CANCTL1 = 0x80; //打开CAN模块
wTemp = 0x1000;
while(wTemp){
wTemp --;
}
TRANSCEIVER_STB_PIN = 0; //使能1040IC
wTemp = 0x1000;
CANCTL0 |=CANCTL0_INITRQ_MASK; //请求配置模式
while(!CANCTL1_INITAK){
wTemp --;
if(wTemp == 0x00) {
break;
}
}
if(wTemp == 0){
//配置CAN模块失败
cCANDrvInitFailed = TRUE;
TRANSCEIVER_STB_PIN = 0;
} else {
//成功进入配置
CANBTR1 = (byte)(Boude>>8);
CANBTR0 =(byte)Boude;
//以下为对接收到的报文进行过滤的ID寄存器设置,即不符合设置的报文不
//进入中断。此处设置为接收所有的报文
CANIDAC = 0x00; //two 32-bit acceptance filters
//below is the set of acceptance filter and its mask register,recieve all message
CANIDAR0 = 0xff;//0xff;
CANIDAR1 = 0xff;//0xff;
CANIDAR2 = 0xff;
CANIDAR3 = 0xff;
CANIDAR4 = 0xff;//0xff;
CANIDAR5 = 0xff;//0xf7;
CANIDAR6 = 0xff;
CANIDAR7 = 0xff;
CANIDMR0 = 0xff;//0xff;
CANIDMR1 = 0xff;//0xff;
CANIDMR2 = 0xff;
CANIDMR3 = 0xff;
CANIDMR4 = 0xff;//0xff;
CANIDMR5 = 0xff;//0xff;
CANIDMR6 = 0xff;
CANIDMR7 = 0xff;
cCANDrvInitFailed = FALSE;
wTemp = 0x1000;
switch(type) {
//选择工作模式
case CAN_Mode_LoopB:CANCTL1 |=CANCTL1_LOOPB_MASK;break; //进入自环模式
case CAN_Mode_Listen:CANCTL1 |=CANCTL1_LISTEN_MASK;break;//监听模式
case CAN_Mode_Operation:CANCTL1&=0xcf;break; //正常工作模式
}
CANCTL0 &=(~CANCTL0_INITRQ_MASK); //请求退出配置模式 ,并进入正常运行模式
while(CANCTL1_INITAK){
wTemp --;
if(wTemp == 0x00) {
break;
}
}
if(wTemp == 0x00){
//配置失败
cCANDrvInitFailed = TRUE;
}
CANRIER = 0x01; //接收中断
CANTIER = 0; //发送不允许中断
}
}
//发送数据
byte MSCANTxMsg(CANMsg msg)
{
INT8U cDataLen;
INT8U *pData;
byte emptyindex=0;
byte returndata=0;
if(CANTFLG_TXE) {
CANTBSEL_TX=CANTFLG_TXE;
emptyindex=1;
}
if(emptyindex)
{//the buffer 0 is empty
pData = CANTIDR_ARR;
if(msg.cCANID[0]&0x80) {
//extended
*pData = msg.cCANID[0]<<3; //IDR0 high 5bits
*pData|= msg.cCANID[1]>>5; //IDR0 low 3bits
pData++;
*pData = msg.cCANID[1]<<3;
*pData &=0xe0; //IDR1 high 5bits SRR=1;IDE=1
*pData |=0x18; //IDE=1;extended
*pData |= (msg.cCANID[1]<<1)&0x06; //IDR1 bit 1,2
*pData |= msg.cCANID[2]>>7; //IDR1 bit0
pData++;
*pData |= msg.cCANID[2]<<1; //IDR2 high 7bits
*pData |= msg.cCANID[3]>>7; //IDR2 low 1bits
pData ++;
*pData |= msg.cCANID[3]<<1; //IDR3 high 7bits
*pData &=0xfe; //RTR=0
} else{
//standard
*pData = (msg.cCANID[2]<<5); //IDR0 high 3bits
*pData|= (msg.cCANID[3]>>3); //IDR0 low 5bits
pData++;
*pData = (msg.cCANID[3]<<5); //IDR1 high 3bits
*pData &=0xe0; //RTR=0;IDE=0;
pData++;
*pData = 0x00;
pData ++;
*pData = 0x00;
}
pData = CANTDSR_ARR;
for(cDataLen = 0; cDataLen < 8; cDataLen ++)
{
*pData = msg.cData[cDataLen];
pData++;
}
CANTDLR_DLC =0x08;
CANTFLG_TXE= CANTBSEL_TX;
CANTIER_TXEIE=CANTBSEL_TX; //发送空中断
returndata=1; //成功写入则返回1
}
return returndata;
}
//只接收数据,不处理数据,中断方式
__interrupt void MSCANRxFullInt(void) //0xFFC6 0xFFC7
{
INT8U cDataLength;
INT8U *pData;
if(CANRDLR){
pData = CANRIDR_ARR;
for(cDataLength = 0; cDataLength < 4; cDataLength ++){
CANMsgRx[CANRxIndex].cCANID[cDataLength]=0;//先清0
CANMsgRx[CANRxIndex].cCANID[cDataLength] = *pData;
pData++;
}
if(CANMsgRx[CANRxIndex].cCANID[1]&0x08) {
//extended 扩展格式
CANMsgRx[CANRxIndex].cCANID[3]>>=1; //去掉RTR
CANMsgRx[CANRxIndex].cCANID[3]|=(CANMsgRx[CANRxIndex].cCANID[2]&0x01)<<7;
CANMsgRx[CANRxIndex].cCANID[2]>>=1;
CANMsgRx[CANRxIndex].cCANID[2]|=(CANMsgRx[CANRxIndex].cCANID[1]&0x01)<<7;
CANMsgRx[CANRxIndex].cCANID[1]>>=1;
CANMsgRx[CANRxIndex].cCANID[1]|=(CANMsgRx[CANRxIndex].cCANID[1]&0x70)>>2; //去掉SRR,IDE
CANMsgRx[CANRxIndex].cCANID[1]|=CANMsgRx[CANRxIndex].cCANID[0]<<=5;
CANMsgRx[CANRxIndex].cCANID[0]>>=3;
}else{
//standard 标准格式
CANMsgRx[CANRxIndex].cCANID[3]=CANMsgRx[CANRxIndex].cCANID[1]>>5;
CANMsgRx[CANRxIndex].cCANID[3]|=CANMsgRx[CANRxIndex].cCANID[0]<<3;
CANMsgRx[CANRxIndex].cCANID[2]= CANMsgRx[CANRxIndex].cCANID[0]>>5;
CANMsgRx[CANRxIndex].cCANID[0]=0;
CANMsgRx[CANRxIndex].cCANID[1]=0;
}
CANMsgRx[CANRxIndex].cDataLength = CANRDLR;
pData = CANRDSR_ARR;
for(cDataLength = 0; cDataLength < 8; cDataLength ++){
CANMsgRx[CANRxIndex].cData[cDataLength] =0;//先清0
CANMsgRx[CANRxIndex].cData[cDataLength] = *pData;
pData++;
}
}
CANRxIndex++;
CANRFLG_RXF = 1;
}
CAN协议有五种错误检测的方法:三个是报文级的,而两个是位级的。如果一个报文出错,那么错误检测的任何一个方法使节点不接收这个报文,并产生一个出错帧,使所有的帧都忽略它,并使发送节点重新发送这个报文。在报文级检查中,有CRC检查和应答隙。CRC检查是一个15位CRC,它计算描述符场和数据字节的CRC。应答场有两位,包括一个应答位和一个应答界定符。这个发送器将会把一个隐性位放在应答场。任何一个正确接收报文的节点在应答场写一个显性位,如果发送器在应答场没有读回一个显形位,它将产生一个出错帧,并重新传送报文。最后在报文级还有一个形式检查,它检查那些总是隐性位的报文场,如果检测到显形位就会产生错误,它检查帧起始、帧结束、应答界定符以及CRC界定符位。 在位级检查中,每一个位都由发送器监控,如果一个位被写进总线但读到的是它的反,错误就会产生。只有标识符场用于仲裁和应答隙是除外的,它要求显性位覆盖隐性位 . 最后的一种错误检测方法是通过位填充规则,当一个报文没有被填充,即如果在逻辑电平相同的连续5位后下一位不是前面的反,则产生一个错误。
活动错误帧包括六个显形位,它们违背了位填充规则。所有的CAN节点都认为它是一个错误并产生自己的错误帧,所以错误帧的长度可以在6位和12位之间,错误帧后是8位隐性位界定符场,而总线在重发被破坏的报文前是空闲的。要注意报文在被成功接收之前仍要争取仲裁。 |
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|