6)CAN控制器初始化:在CANNOD寄存器中设置
2.CAN总线特点:
(1) 数据通信没有主从之分,任意一个节点可以向任何其他(一个或多个)节点发起数据通信,靠各个节点信息优先级先后顺序来决定通信次序,高优先级节点信息在134μs通信;
(2) 多个节点同时发起通信时,优先级低的避让优先级高的,不会对通信线路造成拥塞;
(3) 通信距离最远可达10KM(速率低于5Kbps)速率可达到1Mbps(通信距离小于40M);
(4)CAN总线传输介质可以是双绞线,同轴电缆。CAN总线适用于大数据量短距离通信或者长距离小数据量
3.CAN总线是基于报文的协议
CAN总线上报文所包含的内容只有优先级标志区和欲传送的数据内容。所有节点都会接收到在总线上传送的报文,并在正确接后发出应答确认。至于该报文是否要做进一步的处理或被丢弃将完全取决于接收节点本身。一旦有新的节点接入到总线中,它就开始接收信息,判别信息标识,然后决定是否作处理或直接丢弃。报文中的位流是按非归零码的方法编码的,即一个完整的电平要么是显性(逻辑0),要么是隐性(逻辑1)。在隐性状态下,CAN_H和CAN_L被固定于平均电压电平,Vdiff近似为零。在总线空闲或隐性位期间发送隐性状态。显性状态以大于最小阀值的差分电压表示,其电气特性如下:
其报文有两种不同的帧格式,不同之处为识别符场的长度不同:具有11位识别符的帧称之为标准帧;而含有29位识别符的帧为扩展帧。构成一帧的帧起始、仲裁场、控制场、数据场和CRC序列均借助于位填充规则进行编码,当发送器在发送的位流中检测到5位连续的相同数值,将自动的在实际发送的位流中插入一个补码位。而数据帧和远程帧的其余位场则采用固定格式,不进行填充,出错帧和超载帧同样是固定格式。数据帧是最常用的帧类型,其由7个不同的位场组成,即帧起始、仲裁场、控制场、数据场、CRC场、应答场和帧结束。数据长度可以为0。在CAN技术规范2.0中其数据帧的组成如下:
在CAN技术规范2.0B中存在两种不同的帧格式,其主要区别在于标识符的长度,具有11位标识符的帧称为标准帧,具有29位的标识符的称为扩展帧。标准帧和扩展帧格式如下,其中SRR代表远程请求,RTR代表远程发送请求位,IDE代表标识位扩展位
1)帧起始(SOF)标志:数据帧和远程帧的起始,它由一个显性位构成,只有在总线处于空闲状态是,才允许单元开始发送,所有单元都必须同步于首先开始发送的哪个单元的帧起始前沿。
2)仲裁场:由标识符和远程发送请求位(RTR)组成
3)控制场:由保留位(r0,r1)和数据长度码(DLC)组成,保留位必须发送显性位,数据长度码指定数据场的字节数目,其允许数目为0-8,不使用其他数值。
4)数据场:数据帧中被发送的数据组成,它包括0-8个字节(由DLC决定),从最高位开始发送
总线仲裁原理:
只要总线空闲,任何挂载在总线上的节点都可以开始发送报文。具有较高优先权的报文可以获得总线访问权,当有多个节点同时想总线发送报文时,就会发生总线冲突,为了确保报文的完整性及正确性,使用总线仲裁的机制,当具有相同识别副的数据帧和远程帧同时发送时数据帧优先于远程帧。
4.CAN波特率计算方法
F(Baud) = F/(BRP* (1+TSEG2+TSEG1));
总线时钟40MHZ,设置CAN波特率为500KHZ
40MHZ/500KHZ=80
80 = BRP *(1+TSEG2+TSEG1) =10 * 8;
所以设置BRP =8,TSEG2=4,TSEG1=5. SJW=0x01对应寄存器值
CAN0BTR0=0x47;
CAN0BTR1=0x43;
5.库函数程序初始化
void CAN1_Init(void)
{
/* Pin configuration */
PINSEL_ConfigPin (0, 0, 1);//P0.0 as RD1
PINSEL_ConfigPin (0, 1, 1);//P0.1 as TD1
/* Initialize CAN1 */
CAN_Init(CAN_ID_1, 250000);
/* Enable Interrupt */
CAN_IRQCmd(CAN_ID_1, CANINT_RIE, ENABLE);
/* Initialize transmit and receive message for Bypass operation */
CAN1_InitMessage();
}
6.寄存器初始化程序
void CAN_Init(unsigned char Ch, unsigned long Baud)
{
unsigned long regaddr;
uint16_t i;
i = i;
switch(Ch){ /* 配置CAN控制器引脚 */
case 0:
LPC_SC->PCONP |= 0x01L<<13; /* 打开CAN控制器电源 */
LPC_IOCON->P0_0 &= ~0x07;
LPC_IOCON->P0_0 |= 0x01; /* 选择RD1 */
LPC_IOCON->P0_1 &= ~0x07;
LPC_IOCON->P0_1 |= 0x01; /* 选择TD1 */
break;
case 1:
LPC_SC->PCONP |= 0x01L<<14; /* 打开CAN控制器电源 */
LPC_IOCON->P0_4 &= ~0x07;
LPC_IOCON->P0_4 |= 0x02; /* 选择RD2 */
LPC_IOCON->P0_5 &= ~0x07;
LPC_IOCON->P0_5 |= 0x02; /* 选择TD2 */
break;
default:
break;
}
Enter_SWRst(Ch);
regaddr = (unsigned long)(&LPC_CAN1->BTR)+Ch*CANOFFSET;
RGE(regaddr) = Baud;
LPC_CANAF->AFMR = 0x01; // 设置为关闭模式
if(Ch == 0){
LPC_CAN1->CMR |= (1 << 1) | (1 << 2) | (1 << 3); // 释放接收缓冲区
LPC_CAN1->IER |= (1<<0); // 接收中断使能
LPC_CAN1->GSR |= (0<<0);
i = LPC_CAN1->ICR; // 清中断标志
} else{
LPC_CAN2->CMR |= (1 << 1) | (1 << 2) | (1 << 3);
LPC_CAN2->IER |= (1<<0);
LPC_CAN2->GSR |= (0<<0);
i = LPC_CAN2->ICR;
}
LPC_CANAF->AFMR = 0x02; // 设置为旁路模式
Quit_SWRst(Ch);
}
#define RGE(Address) (*((volatile unsigned long*)Address))
unsigned char Enter_SWRst(unsigned char Ch)
{
unsigned long regaddr;
REG_CANMOD regmod;
regaddr = (unsigned long)(&LPC_CAN1->MOD)+Ch*CANOFFSET;
regmod.DWord = RGE(regaddr); /* 读取LPC_CAN1->MOD寄存器 */
regmod.Bits.RM = 1; /* RM位置"1" */
RGE(regaddr) = regmod.DWord; /* 回写LPC_CAN1->MOD寄存器 */
regmod.DWord = RGE(regaddr); /* 验证写入值 */
return (0 != regmod.Bits.RM)? 1:0;
}
unsigned char Quit_SWRst(unsigned char Ch)
{
unsigned long regaddr;
REG_CANMOD regmod;
regaddr = (unsigned long)(&LPC_CAN1->MOD)+Ch*CANOFFSET;
regmod.DWord = RGE(regaddr); /* 读取LPC_CAN1->MOD寄存器 */
regmod.Bits.RM = 0; /* RM位置"0" */
RGE(regaddr) = regmod.DWord; /* 回写LPC_CAN1->MOD寄存器 */
regmod.DWord = RGE(regaddr); /* 验证写入值 */
return (0 != regmod.Bits.RM)? 0:1;
}
typedef union _canmod_
{
unsigned long DWord;
struct {
unsigned int RM :1; /* 定义RM位(复位位) */
unsigned int LOM :1; /*定义LOM位(只听模式位) */
/*
* 定义STM位 "0"发送的信息必须被应答才被认可
* "1"自测试模式,CANCMR的SRR位一起使用,可以达到自发自收的效果
*/
unsigned int STM :1;
/*
* 定义TPM位 "0"3个发送缓冲区的优先级由各自的CAN ID决定
* "1"3个发送缓冲区的优先级由各自的Tx优先级域决定
*/
unsigned int TPM :1;
unsigned int SM :1; /* 定义SM位(睡眠模式位) */
unsigned int RPM :1;
/*
* 定义RPM位 "0"如果传输的是显性位,Rx和Tx脚为低电平
* "1"翻转极性模式--如果传输的是显性位,Rx脚为高电平
*/
unsigned int RSV1 :1; /* 保留位 */
unsigned int TM :1; /* 定义TM位(测试模式) */
unsigned int RSV24 :24; /* 保留位 */
}Bits;
}REG_CANMOD;