天天看点

飞思卡尔16位单片机(十四)—— CAN总线模块测试

一、CAN模块介绍

       这个实验我们来研究XEP100单片机内部的CAN模块。 

       XEP100单片机的CAN的基本特性如下:

• 实施CAN协议—2.0A/B版

— 标准和扩展数据帧

— 0-8字节数据长度

— 高达1Mbps的可编程比特率

— 支持远程帧

• 5个具有FIFO存储机制的接收缓冲器

• 3个具有使用“本地优先”概念的内部优先顺序的发送缓冲器

• 灵活可掩码标识符滤波器支持2个全尺寸(32位)扩展标识符滤波器或4个16位滤波器或8个8位滤波器

• 集成低通滤波器的可编程唤醒功能

• 可编程环回模式支持自测操作

• 可编程监听模式用于CAN总线监控

• 可编程总线脱离恢复功能

• 独立的信号和中断功能适用于所有CAN接收器和发射器错误状态(警报、错误严重状态、总线脱离)

• 可编程CAN时钟源,采用总线时钟或振荡器时钟

• 内部计时器提供给接收和发送的报文的时间标签

• 三种低功耗模式:睡眠、关机和CAN使能

• 配置寄存器的全局初始化

CAN模块的结构图如下:

飞思卡尔16位单片机(十四)—— CAN总线模块测试

图中RXCAN是CAN接收器输入管脚。TXCAN是CAN发送器输出管脚。

下图显示了一个具有CAN的典型CAN系统。每个CAN节点通过收发器物理连接到CAN总线线路,收发器能够驱动CAN总线所需的大电流,并具有对故障CAN或故障节点的电流保护。

飞思卡尔16位单片机(十四)—— CAN总线模块测试

CAN的接收器和发送器的结构如下图所示。

飞思卡尔16位单片机(十四)—— CAN总线模块测试
飞思卡尔16位单片机(十四)—— CAN总线模块测试

CAN收到的报文保存在5级输入FIFO中。5个报文缓冲器被交替映射到单个存储器区域。CAN有三重发送缓冲器机制,允许提前建立多条报文,从而优化了实时性能。

CAN的报文缓冲器结构见下表

Offset Address Register Access
0x00X0 Identifier Register 0
0x00X1 Identifier Register 1
0x00X2 Identifier Register 2
0x00X3 Identifier Register 3
0x00X4 Data Segment Register 0
0x00X5 Data Segment Register 1
0x00X6 Data Segment Register 2
0x00X7 Data Segment Register 3
0x00X8 Data Segment Register 4
0x00X9 Data Segment Register 5
0x00XA Data Segment Register 6
0x00XB Data Segment Register 7
0x00XC Data Length Register
0x00XD Transmit Buffer Priority Register
0x00XE Time Stamp Register (High Byte)
0x00XF Time Stamp Register (Low Byte)

有关CAN的更加详细的信息请参见相关的CAN协议和XEP100单片机的技术资料。

        本实验的CAN接口芯片采用的是TJA1050芯片,电路的原理图如下图所示。图中L81和L82是CAN总线专用的滤波电感。J81和J82是跳线插针,用于连接120欧姆的电阻。如果CAN总线上挂接多个节点,只能保留两个120欧姆的电阻。这时需要把多余的电阻切断。就要拔下相应的跳线帽。

飞思卡尔16位单片机(十四)—— CAN总线模块测试

本实验采用CAN0发送数据,CAN1接收数据,CAN数据的格式采用标准帧格式。在开发板上通过自发自收实验来模拟真实的CAN通信过程。

二、例程测试

        本实验的例程可以从本文的资源中下载。打开例程的代码,可以发现程序有些负责,程序中将CAN模块的驱动以及LCD的驱动封装到独立的文件当中,在主文件中进行调用。由于代码比较多,我们只对CAN的驱动函数进行功能性的介绍,具体细节可以对照着芯片手册进行研究。

1、CAN初始化

CAN模块的初始化函数如下所示。

void INIT_CANx(void); 
           

这个函数的作用是对CANx模块进行初始化,将波特率设置为250kbit/s,禁止CAN滤波功能。

2、CAN发送函数

CAN模块的发送函数如下所示

Bool MSCANxSendMsg(struct can_msg msg);
           

这个函数的作用是通过CANx模块发送数据,struct can_msg msg为需要发送是数据的结构体,函数返回值为是否成功,发送成功返回true。struct can_msg msg结构体的定义如下。

struct can_msg     //发送报文的结构体
{
    unsigned int id;
    Bool RTR;
    unsigned char data[8];
    unsigned char len;
    unsigned char prty;
};
           

结构体中包含了数据帧的ID,RTR标志位,8个字节的数据,数据长度和优先级。

3、CAN接收函数

CAN模块的接收函数如下所示

Bool MSCANxGetMsg(struct can_msg *msg);
           

函数中struct can_msg *msg为指向接收到的数据结构体的指针,函数返回接收是否成功,成功返回true。

这个程序的主函数如下所示

void main(void) {
  DisableInterrupts;
  INIT_PLL();
  initialize_ect();
  INIT_PORT();
  INIT_CAN0();
  INIT_CAN1();
  LEDCPU_dir=1;
  LEDCPU=0;
  EnableInterrupts;

//填写报文内容
  msg_send.id = ID; 
  for(k=0;k<data_len_TX;k++)
  {
     msg_send.data[k] = senddata[k];
  }
  msg_send.len = data_len_TX;
  msg_send.RTR = FALSE;
  msg_send.prty = 0;

  for(;;) 
  {
      delay1ms(1000);
      if(!MSCAN0SendMsg(msg_send)) //发送过程出现错误
      {
          for(;;);
      }
      if(datain==1) 
      {
          lcd_clear();
          lcd_string(0,0,xianshi[0]);
          lcd_string(1,0,xianshi[1]);
          play_data();
          datain=0;
      }
  } 
}
           

主函数的作用是通过CAN0发送数据,首先将需要发送的数据的ID和data赋值到发送结构体中,然后在主循环中每个1秒发送一次数据。并且在接收到数据时,在lcd上显示接收到的数据。

        CAN1负责接收数据,接收采用中断的方式,中断函数如下所示。

void interrupt CAN_receive(void) 
{
      if(MSCAN1GetMsg(&msg_get)) 
      {
        // 接收新信息
         if(msg_get.id == ID && (!msg_get.RTR)) 
         {
                 LEDCPU = ~LEDCPU;
                 datain=1;       
         }
      }
      else 
      {
       for(;;);
      }
}
           

在中断函数中,主要是通过CAN1的接收函数来接收数据,接收成功后设置标志位datain。

将程序下载到单片机中,并将单片机的CAN0和CAN1接口连接在一起,运行程序,可以看到液晶上显示接收到的数据。

继续阅读