CAN协议具有杰出的可靠性,在工业中运用广泛。这次就先了解CAN的基本功用。
开发板有两个CAN,每个CAN有8个信箱。这次内容是从CAN0的信箱0发送数据到CAN1的信箱0。
除本次运用的功用外,CAN还有长途帧、强壮的错误处理功用。
一、电路
CAN总线上的逻辑数值是用显性电平缓隐性电平表明的。“显性”的意思是指在一起传输显性电平缓隐性电平常,总线上出现的是显性电平。显性电平表明逻辑“0”,隐性电平表明逻辑“1”。
在运用CAN的进程中,需求运用一个CAN收发器进行电平的转化与解说。开发板运用的CAN收发器为SN65HVD234,其接线如下图所示:
其间CANTXx和CANRXx引脚能够复用为CAN的外设。而在运用该收发器时,需求将CANRXxEN驱动为高电平以启用收发器的接纳功用,将CANTXxRS驱动求低电平以启用发送功用。
在试验的时分,需求将这两个口(J13和J14)运用线缆衔接起来。当衔接完结而未通电时,能够测得CANH和CANL是短路状况的。
二、CAN网络参数及波特率
假定MCK为96 MHz,需求设置的CAN波特率为1000 Kbps。
CAN的波特率的设置不是那么的直接。CAN界说了一个名为“原子时刻(TQ)”的最小时刻单位;然后把一个比特的传输进程分为若干阶段(同步段、传达时刻段、相位缓冲端1、相位缓冲段2),每个阶段的时刻均是由TQ的数量表明。
SAM4中,时刻TQ用“CAN体系时钟(CSC)”表明。波特率相关的参数均经过CAN波特率寄存器(CAN_BR)设置。
TQ(CSC)设置。组成每个位时刻的TQ数量的规模为8—25。为取整,这儿将数量挑选为16。所以CAN体系时钟的频率为CAN波特率的16倍,即16 MHz。再所以需求将MCK进行6分频。依据BRP字段的效果办法,需求将BRP字段设置为5。
一起,能够计算出每个TQ的长度为62.5 ns。
同步段固定为1 TQ。
传达时刻端PROP_SEG需求依据硬件相关的信息确认,用于吸收网络的物理(发送单元、总线、接纳单元)推迟。该段的时刻需求为总物理推迟的2倍。在芯片手册的示例中,该推迟为190 ns。所以该段的时长需求设置为380 ns,即约6 TQ。将PROPAG字段设置为5即可到达意图。
剩余的16-1-6=9 TQ,均用与相位缓冲段。在Atmel的CAN中,需求2 TQ确认总线的电平。因为采样点坐落相位缓冲段2的开端,所以它的长度不能少于2 TQ 。这儿使两个阶段尽量等长,所以让相位缓冲段1设置为4 TQ,段2设置为5 TQ。将PHASE1和PHASE2别离设置为3和4即可。
再补偿宽度。最小可装备为1 TQ,最多可装备为相位缓冲段1和4 TQ间的较小值。这儿装备为4 TQ。将SJW段设置为3即可。
详细设置代码如下:
const uint32_t can_br = CAN_BR_BRP(5)
CAN_BR_PROPAG(5)
CAN_BR_PHASE1(3)
CAN_BR_PHASE2(4)
CAN_BR_SJW(3)
CAN_BR_SMP_ONCE;
CAN0->CAN_BR = can_br;
CAN1->CAN_BR = can_br;
三、CAN初始化
GPIO及PMC设置。留意将PE1和PE3驱动为高电平,PE0和PE2驱动为低电平。
网络参数设置。在启用CAN之前,需求设置好网络参数。
启用CAN。CAN使能后,需求和总线进行同步。在接连检测到11个隐性位时,CAN进入唤醒状况,且WAKEUP方位位:
CAN0->CAN_MR = CAN_MR_CANEN;
CAN1->CAN_MR = CAN_MR_CANEN;
while( ((CAN0->CAN_SR & CAN_SR_WAKEUP) == 0)
((CAN1->CAN_SR & CAN_SR_WAKEUP) == 0) );
信箱设置。经过设置CAN_MMR的MOT字段即可设置信箱的类型。因为这个设置是当即收效的,所以在设置这个字段时,需求先(或一起)完结其他相关信息的设置。一起,在修正设置时,应该先封闭信箱。
发送信箱需求先设置好的只要优先级:
#define TX_MB (CAN0->CAN_MB + 0)
TX_MB->CAN_MMR = CAN_MMR_PRIOR(0)
CAN_MMR_MOT_MB_TX;
接纳信箱需求先设置好ID相关的信息。简略起见,这儿只运用规范格局的帧,即只指定MIDvA部分,一起MIDE位指定为0(默许)。因为契合接纳条件的ID设置为1个,即需求比较接纳ID一切的位,所以将CAN_MAM的MIDvA字段悉数置1。
#define RX_MB (CAN1->CAN_MB + 0)
#define CAN_COMM_ID 5
RX_MB->CAN_MID = CAN_MID_MIDvA(CAN_COMM_ID);
RX_MB->CAN_MAM = CAN_MAM_MIDvA(~(uint32_t)0);
RX_MB->CAN_MMR = CAN_MMR_MOT_MB_RX;
四、数据传输
经过UART读取一个数字:
int num;
scanf("%d", &num);
经过信箱发送数据。
假定int为4字节,则经过CAN_MDL即可表明所需信息。发送时,在确认信箱可用后,需求指定好信息ID。然后向CAN_MCR写入信息长度(用byte表明),一起写入MTCR位以开端发送操作。最终,在发送完结后,CAN_MSR的MRDY位从头置位。
// 等候信箱可用
while(!(TX_MB->CAN_MSR & CAN_MSR_MRDY));
TX_MB->CAN_MID = CAN_MID_MIDvA(CAN_COMM_ID); // ID
TX_MB->CAN_MDL = num; // 低4字节数据
TX_MB->CAN_MCR = CAN_MCR_MDLC(4) // 数据长度
| CAN_MCR_MTCR; // 开端测验发送
printf("-I- Sending message from TX mailbox…\r\n");
// 等候发送完结
while(!(TX_MB->CAN_MSR & CAN_MSR_MRDY));
经过信箱接纳数据。
经过查询CAN_MSR的MRDY位能够确认是否接纳到了数据,然后在CAN_MSR的MDLC字段能够确认信息长度。在完结数据接纳后,需求向CAN_MCR写入MTCR字段以完结本次接纳,然后开端下一次信息接纳作业。
// 等候信息接纳完结
while(!(RX_MB->CAN_MSR & CAN_MSR_MRDY));
// 查看信息长度
const int rec_len =
(RX_MB->CAN_MSR & CAN_MSR_MDLC_Msk) >> CAN_MSR_MDLC_Pos;
if (rec_len == 4) {
// 读取信息并打印
printf("-I- Data read from RX mailbox: %d \r\n",
(int)RX_MB->CAN_MDL);
}
// 开端下一次接纳
RX_MB->CAN_MCR = CAN_MCR_MTCR;