新闻中心

EEPW首页>手机与无线通信>设计应用> μC/OSII的CAN驱动程序设计

μC/OSII的CAN驱动程序设计

作者: 时间:2010-11-25 来源:网络 收藏

  CAN控制器初始化程序(在应用层中实现,内部调用的函数也都是在该层中编写的)如下:

voidCAN20B_Init() {
  #ifCAN1_EN > 0
  while((CAN1MOD CAN_MOD_RM)!=1)
  CAN1_MOD_RM ();//进入复位模式
  CAN1_BTR ();//配置总线定时寄存器
  ID_RAM ();//配置验收滤波器
  while((CAN2MOD CAN_MOD_NM)!=1)
  CAN1_MOD_NM_SET();//进入正常模式
  CAN1_INT_EN ();//中断使能寄存器设置
  #endif
}

  为了使程序更加简洁、可读性更强,可以通过宏定义的形式进行编写。例如:

#define CAN_MOD_RM () CAN1MOD |= 1

  CAN1MOD是CAN控制器的模式寄存器,最低位置1可使CAN控制器进入复位模式。这种模式下,可以对控制器的所有寄存器进行写操作。其他对CAN控制器内部寄存器的操作可以参照LPC2368的技术手册。

4 CAN协议层

  从OSI网络模型的角度来看,现场总线网络一般实现了第1层(物理层)、第2层(数据链路层)、第7层(应用层);而CAN现场总线仅仅定义了第1层、第2层,这两层分别由CAN收发器和CAN控制器实现。没有规定应用层,本身并不完整,因此需要一个高层协议来定义CAN报文中11/29位标识符、8字节的使用。目前,已经有一些国际上标准的高层协议,例如DeviceNet协议和CANopen协议;但是这个协议规范比较复杂,理解和开发难度都比较大,对于一些并不复杂的基于的控制网络不太适合。本设计采用国内周立功CAN开发组织根据实际应用制定的简单的CAN应用层协议ICAN协议,作为软件设计的CAN协议层。ICAN协议中的29位帧标识符定义如表1所列。

表1 ICAN协议中29位帧标识符定义
按此在新窗口浏览图片

  CAN总线仲裁是从标识符的最高位(28位)开始逐位进行的。每一个发送器都对发送位的电平与被监控的总线电平进行比较:如果相同,则这个单元可以继续发送;如果发送的是“隐性”(逻辑1)电平,而监控到的却为“显性”(逻辑0)电平,那么该单元就失去了仲裁,必须退出发送状态。根据ICAN源节点编号部分可以看出,节点的地址编号越小,优先级也就越高,在仲裁时能够优先获得总线使用权。在CAN网络系统中,节点越重要,分配的地址编号的优先级相应地也越高。譬如,车载网络中的发动机电控单元就应该比定向大灯电控单元的优先级高,这样才能保证重要的报文及时传送出去。在节点接收到报文之后,应用程序依据ICAN协议解析报文标识符,并实现其指定的功能。

5 CAN应用层

  CAN应用层实现CAN控制器的所有功能。CAN设备控制驱动层、CAN接口驱动层和CAN协议层都在应用层的控制之中。应用层主要实现的任务包括:

① 初始化CAN控制器,以及与应用层相关的全局变量。
② 编写CAN控制器的中断服务程序。
③ 报文处理任务。该任务基于ICAN协议来解析报文,并实现报文指示的功能。
④ 报文发送任务。该任务存储未能发送的报文,并在发送缓冲区可用的情况下自动发送报文。

  初始化CAN控制器的程序详见第3节。由于初始化CAN控制器直接和CAN物理层及链路层的性能挂钩,因此只有依据具体应用环境正确地配置CAN控制器,才能使系统稳定地运行。

5.1 中断服务程序

  中断服务程序用来判断CAN控制器的中断类型,并作出相应的响应。具体程序如下:

voidCAN1_ISR() {
  INT32u can1_i_st;
  VICVectAddr =0x0; //更新VIC优先级硬件
  OSIntEnter();
  can1_i_st = CAN1ICR;//读中断和捕获寄存器
  if (can1_i_st!=0) {
    if(can1_i_stCAN_RI)//接收中断
      CAN1_RI_HANDLE();
    if(can1_i_stCAN_TI1){//发送中断1
      if(TX_CNT>0)
        OSSemPost(CAN_TX_OVER);
    }
    if(can1_i_stCAN_TI2) {//发送中断2
      if(TX_CNT>0)
        OSSemPost(CAN_TX_OVER;
    }
    if(can1_i_stCAN_TI3) {//发送中断3
      if(TX_CNT>0)
        OSSemPost(CAN_TX_OVER);
    }
    if(can1_i_stCAN_BEI)//总线错误中断
      CAN1_BEI_HANDLE();
  }
  OSIntExit();//中断级任务切换
}

  这里只对接收中断、发送中断以及总线错误中断进行阐述,其他类型的CAN中断处理应根据具体系统进行具体设计。

5.1.1 接收中断

  接收中断处理函数CAN1_RI_HANDLE()负责接收报文,并将报文发送到任务的消息队列中。其代码如下:

void CAN1_RI_HANDLE() {
  RI_DATA.FRAME = CAN1RFS;
  RI_DATA.ID = CAN1RID;
  RI_DATA.DataA = CAN1RDA;
  RI_DATA.DataB =CAN1RDB;
  OSQPost(CAN1_Q_RX,RI_DATA);//向消息队列发送消息
  CAN1_COMMAND_RRB();//释放接收缓冲区
}

  其中,RI_DATA为定义的结构体CAN_MSG变量;CAN1RFS、CAN1RID、CAN1RDA和CAN1RDB分别为CAN控制器存储接收报文帧信息、标识符、数据字节的寄存器。CAN_MSG结构体如下所示:

structCAN_MSG{
  INT32uFRAME;//存放报文帧信息
  INT32uID;//存放报文标识符
  INT32uDataA;//存放报文前4个字节数据
  INT32uDataB;//存放报文后4个字节数据
};

5.1.2 发送中断

  当发送中断处理函数通过TX_CNT判断出报文发送函数的消息队列中有待发送报文时,通过函数OSSemPost(CAN_TX_OVER)向其发送信号量,通知其可以发送报文了。若TX_CNT为0,说明消息队列中没有待发送的报文,则不发送信号量。

5.1.3 总线错误中断

  CAN1_BEI_HANDLE()通过查询中断和捕获寄存器来判断是何种错误类型,并将它记录下来以便于系统诊断。

  由于CAN1_RI_HANDLE()和OSSemPost()都可能就绪等待中的任务,所以为了保证系统能够严格按照优先级来执行任务。程序采用OSIntExit()函数进行中断级任务切换,在执行完中断服务程序后运行一个具有最高级别的任务,而不是返回被中断的任务。

5.2 应用层面临的问题及解决方法

  下面将结合应用层面临的实际问题,对报文处理和报文发送函数进行详细阐述。

  ① CAN节点将CAN中断设为FIQ中断,而其他中断设为不同优先级的IRQ中断。由于FIQ中断能够打断IRQ中断,所以节点在任何情况下都能尽快地响应CAN中断,提高了系统的



评论


相关推荐

技术专区

关闭