一、背景:
使用LPC1769来做CAN的收发,在此对使用LPC1769的CAN控制器进行收发做个总结和记录,以备下
次开发快速上手使用。
附:LPC1768/1769除了支持最高频率不同以外,其它基本上一致。 二、正文:
先贴一张LPC1769 CAN控制器的方框图:

  .

        由上图可见,整个CAN控制器一头是CPU,另一头是CAN收发器:
     CAN收发器负责CAN数据与CAN网络的通信。CAN内核模块解析和封装要发送到CAN收发器以及从CAN
   收发器发过来的数据,此处CAN内核工作由硬件自行完成。
     CPU通过APB总线即可设置CAN控制器状态,以及读取中断信息和中断状态。
     一共有3个发送缓冲器(邮箱),这样就可以保证,最少可以发送3组并发的CAN数据;2个接收缓冲
   器(邮箱),这样就可以在CPU处理1个邮箱的接收数据的同时,还能用另一个邮箱接收网络上的数据。
     LPC1769 CAN的验收滤波器比较特殊,它是一个独立于CAN控制器的器件,也属于一种外设,不过
   比较特殊的是,它是服务于CAN控制器的外设,这么做的意义就在于,验收滤波这方面,不再需要软件来
   来做任何事情,直接由硬件来实现查表算法,节省宝贵的CPU资源,由于它也算是一个独立的外设,运用
   起来也比较复杂,而本篇篇幅有限,暂不详述,下次再另开篇博客来说。
     至此,LPC1769 CAN的结构就介绍完毕,接下说明,做哪些事情可让其开始正确收发CAN数据。
        CAN1/ 使用以下寄存器进行设置:
a)电源使能:在PCONP 寄存器中,设置PCAN1/。
注:复位时,CAN1/ 会被使能(PCAN1/=)。
b)时钟使能:在PCLK_SEL0 寄存器中选择PCLK_CAN1/ 和验收滤波器的PCLK_ACF。
注:如果所需使用的 CAN 波特率必须高于100kbit/s(参见表16.),那么就不能选择IRC
     作为时钟源。
c)唤醒:CAN 控制器能够将微控制器从掉电模式唤醒。
d)引脚:通过PINSEL 寄存器选择CAN1/ 引脚,并通过PINMODE 寄存器选择引脚模式。
e)中断:CAN 中断是通过CAN1/2IER 寄存器来使能的。中断的使能是通过在NIVC 中使
用相应的中断设置使能寄存器(Interrupt Set Enable register)来实现的。
f)CAN 控制器初始化:在CANNOD 寄存器中设置。
以上为数据手册介绍的CAN控制器初始化过程,白话点说:
"a)"CAN是LPC1769的外设器件,要让其工作,首先要设置PCONP,该寄存器的各个位来决定外设
的时钟是否打开或关闭,若某个外设不被使用,则关闭它,以达到节省功耗的目的;此处要需
       要使用CAN,所以先打开CAN的外设时钟。
"b)"其次,外设若要正常工作,则均需要一个合适的时钟频率,通PCLK_SEL0l来决定CAN的外设
时钟来源,以及大小。
"c)"为了进一步减少MCU的功耗,当CAN网络上没有数据传输时,也没有CAN中断在处理,并且对应
       的睡眠位被置“1”,CAN外设会进入睡眠状态,若CAN总线上出现了显性位,则CAN外设从睡眠
       状态被唤醒。同时,若已配置了相关位,且此时整个MCU都进入掉电或者深度睡眠模式,则CAN
       也可将MCU唤醒 
"d)"配置CAN的收发引脚,无需多言,告诉CAN控制器,从哪个引脚收发CAN数据。
"e)"配置CAN的各种中断使能条件,此处使能了发送/接收中断,错误中断;以及配置NVIC内
CAN外设中断。
"f)"配置CAN相关的参数,譬如波特率等等。
至此,CAN控制器初始化部分完成,还需要做接收和发送函数,以及中断函数,来实现CAN的收发
,和错误管理。
当然,在CAN控制器初始化部分,波特率的参数设置还有许多要说,本篇篇幅有限,暂不详述,下次
再开篇博客进行介绍。
CAN中断函数:
/*----------------- INTERRUPT SERVICE ROUTINES --------------------------*/
/*********************************************************************//**
* @brief CAN_IRQ Handler, control receive message operation
* param[in] none
* @return none
**********************************************************************/
void CAN_IRQHandler()
{
uint8_t IntStatus;
uint32_t data1;
/* get interrupt status
* Note that: Interrupt register CANICR will be reset after read.
* So function "CAN_IntGetStatus" should be call only one time
*/
// 以下函数获取的是CAN1ICR/CAN2ICR的寄存器数据,该寄存器指明了中断来源
IntStatus = CAN_IntGetStatus(LPC_CAN1);if((IntStatus>>)&0x01) {// 接收中断
}
...
// 省略的内容为,根据寄存器的各位的中断来源数据来解析中断信息。
       // IntStatus = CAN_IntGetStatus(LPC_CAN2);
       // if(...) ...
} CAN接收函数:
此函数为NXP提供的库函数,库函数下载链接在本文第三部分,该函数做的内容无非就是,在中
断内,检查两个接收邮箱内是否有信息,若有,则将信息提取。
/********************************************************************//**
* @brief Receive message data
* @param[in] CANx pointer to LPC_CAN_TypeDef, should be:
* - LPC_CAN1: CAN1 peripheral
* - LPC_CAN2: CAN2 peripheral
* @param[in] CAN_Msg point to the CAN_MSG_Type Struct, it will contain received
* message information such as: ID, DLC, RTR, ID Format
* @return Status:
* - SUCCESS: receive message successfully
* - ERROR: receive message unsuccessfully
*********************************************************************/
Status CAN_ReceiveMsg (LPC_CAN_TypeDef *CANx, CAN_MSG_Type *CAN_Msg)
{
uint32_t data; CHECK_PARAM(PARAM_CANx(CANx)); //check status of Receive Buffer
if((CANx->SR &0x00000001))
{
/* Receive message is available */
/* Read frame informations */
CAN_Msg->format = (uint8_t)(((CANx->RFS) & 0x80000000)>>);
CAN_Msg->type = (uint8_t)(((CANx->RFS) & 0x40000000)>>);
CAN_Msg->len = (uint8_t)(((CANx->RFS) & 0x000F0000)>>); /* Read CAN message identifier */
CAN_Msg->id = CANx->RID; /* Read the data if received message was DATA FRAME */
if (CAN_Msg->type == DATA_FRAME)
{
/* Read first 4 data bytes */
data = CANx->RDA;
*((uint8_t *) &CAN_Msg->dataA[])= data & 0x000000FF;
*((uint8_t *) &CAN_Msg->dataA[])= (data & 0x0000FF00)>>;;
*((uint8_t *) &CAN_Msg->dataA[])= (data & 0x00FF0000)>>;
*((uint8_t *) &CAN_Msg->dataA[])= (data & 0xFF000000)>>; /* Read second 4 data bytes */
data = CANx->RDB;
*((uint8_t *) &CAN_Msg->dataB[])= data & 0x000000FF;
*((uint8_t *) &CAN_Msg->dataB[])= (data & 0x0000FF00)>>;
*((uint8_t *) &CAN_Msg->dataB[])= (data & 0x00FF0000)>>;
*((uint8_t *) &CAN_Msg->dataB[])= (data & 0xFF000000)>>; /*release receive buffer*/
CANx->CMR = 0x04;
}
else
{
/* Received Frame is a Remote Frame, not have data, we just receive
* message information only */
CANx->CMR = 0x04; /*release receive buffer*/
return SUCCESS;
}
}
else
{
// no receive message available
return ERROR;
}
return SUCCESS;
} CAN发送函数:
该函数还是库函数,即依次查询3个发送邮箱的状态,若邮箱状态为空,则将数据填充到该邮箱
并置位发送标志,然后由CAN内核模块硬件自动发送。发送的优先级在寄存器内均可配置,不详述。
篇幅不想过长,因此查询邮箱2/3代码部分省略。
/********************************************************************//**
* @brief Send message data
* @param[in] CANx pointer to LPC_CAN_TypeDef, should be:
* - LPC_CAN1: CAN1 peripheral
* - LPC_CAN2: CAN2 peripheral
* @param[in] CAN_Msg point to the CAN_MSG_Type Structure, it contains message
* information such as: ID, DLC, RTR, ID Format
* @return Status:
* - SUCCESS: send message successfully
* - ERROR: send message unsuccessfully
*********************************************************************/
Status CAN_SendMsg (LPC_CAN_TypeDef *CANx, CAN_MSG_Type *CAN_Msg)
{
uint32_t data;
CHECK_PARAM(PARAM_CANx(CANx));
CHECK_PARAM(PARAM_ID_FORMAT(CAN_Msg->format));
if(CAN_Msg->format==STD_ID_FORMAT)
{
CHECK_PARAM(PARAM_ID_11(CAN_Msg->id));
}
else
{
CHECK_PARAM(PARAM_ID_29(CAN_Msg->id));
}
CHECK_PARAM(PARAM_DLC(CAN_Msg->len));
CHECK_PARAM(PARAM_FRAME_TYPE(CAN_Msg->type)); //Check status of Transmit Buffer 1
if (CANx->SR & (<<))
{
/* Transmit Channel 1 is available */
/* Write frame informations and frame data into its CANxTFI1,
* CANxTID1, CANxTDA1, CANxTDB1 register */
CANx->TFI1 &= ~0x000F0000;
CANx->TFI1 |= (CAN_Msg->len)<<;
if(CAN_Msg->type == REMOTE_FRAME)
{
CANx->TFI1 |= (<<); //set bit RTR
}
else
{
CANx->TFI1 &= ~(<<);
}
if(CAN_Msg->format == EXT_ID_FORMAT)
{
CANx->TFI1 |= (0x80000000); //set bit FF
}
else
{
CANx->TFI1 &= ~(0x80000000);
} /* Write CAN ID*/
CANx->TID1 = CAN_Msg->id; /*Write first 4 data bytes*/
data = (CAN_Msg->dataA[])|(((CAN_Msg->dataA[]))<<)|
           ((CAN_Msg->dataA[])<<)|((CAN_Msg->dataA[])<<);
CANx->TDA1 = data; /*Write second 4 data bytes*/
data = (CAN_Msg->dataB[])|(((CAN_Msg->dataB[]))<<)|
           ((CAN_Msg->dataB[])<<)|((CAN_Msg->dataB[])<<);
CANx->TDB1 = data; /*Write transmission request*/
// 注意该值,置位发送邮箱1,告知硬件,邮箱1的信息已经填充完毕可发送。
CANx->CMR = 0x21;
return SUCCESS;
}
//check status of Transmit Buffer 2
else if(CANx->SR & (<<))
{
/* Transmit Channel 2 is available */
/* Write frame informations and frame data into its CANxTFI2,
* CANxTID2, CANxTDA2, CANxTDB2 register */
...
/*Write transmission request*/
// 注意该值,置位发送邮箱2,告知硬件,邮箱2的信息已经填充完毕可发送。
CANx->CMR = 0x41;
return SUCCESS;
}
//check status of Transmit Buffer 3
else if (CANx->SR & (<<))
{
/* Transmit Channel 3 is available */
/* Write frame informations and frame data into its CANxTFI3,
* CANxTID3, CANxTDA3, CANxTDB3 register */
...
/*Write transmission request*/
// 注意该值,置位发送邮箱3,告知硬件,邮箱3的信息已经填充完毕可发送。
CANx->CMR = 0x81;
return SUCCESS;
}
else
{
// 所有邮箱都处于非空闲状态,无法发送
return ERROR;
}
} 至此,有了初始化部分,CAN中断函数,CAN发送、接收函数,也就实现了CAN数据的收发。
滤波以波特率以及CAN总线错误处理,下次再开博客详述。 三、参考文档
LPC175x_6x CMSIS-Compliant Standard Peripheral Firmware Driver Library (Keil, IAR, GNU)
  https://www.lpcware.com/content/nxpfile/lpc175x6x-cmsis-compliant-standard-peripheral-firmware-driver-library-keil-iar-gnu 至此,记录完毕。 记录时间:--
记录地点:深圳WZ

LPC1768/1769之CAN控制器概述(附库函数下载地址)的更多相关文章

  1. Genymotion的安装与使用(附百度云盘下载地址,全套都有,无需注册Genymotion即可使用)

    http://blog.csdn.net/scythe666/article/details/70216144 附百度云盘下载地址 :http://pan.baidu.com/s/1jHPG7h8 1 ...

  2. IntelliJ IDEA 2018.1.2 安装及汉化教程(附:下载地址)

    附:安装包及汉化包下载地址  链接:https://pan.baidu.com/s/1ysxtVH_gnBm0QnnqB5mluQ 密码: 9pqd 1.安装步骤: 选择安装地址:可以默认.本人安装在 ...

  3. SQL Server 2012 安装图解教程(附sql2012下载地址)

    在安装微软最新数据库SQL Server 2012之前,编者先确定一下安装环境:Windonws 7 SP1,32位操作系统.CPU是2.1GHz赛扬双核T3500,内存2.93GB. sql2012 ...

  4. 安装Fedora(附镜像下载地址)

    近期又试着装了一遍Fedora,强迫症迫使我写一些简单的教程,方便以后有用 先把VM配置好,然后进入Fedora 点击Skip 这几按照提示一步一步来 选个人桌面 手工分区 分区的时候注意下每个区的容 ...

  5. Spring学习(1)----入门学习(附spring-framework下载地址)

    (一)Spring是什么 Spring是一个开源框架,为了解决企业应用开发的复杂性而创建的,但现在已经不止应用于企业应用 是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架- 从大小和开销 ...

  6. SQLyog简介及其功能(附百度云盘下载地址)

    一.软件简介 SQLyog 是一个快速而简洁的图形化管理MYSQL数据库的工具,它能够在任何地点有效地管理你的数据库.SQLyog是业界著名的Webyog公司出品的一款简洁高效.功能强大的图形化MyS ...

  7. 如何写一套下拉刷新的控件?《MJRefresh原理浅析》(附Demo下载地址)

    相信大家有很多人在做项目的时候都在使用MJRefresh 控件来实现下拉刷新的功能: MJRefresh经过不断的重构与更新迭代,现在不管是功能上还是代码结构上都是相当不错的,都是很值我们去学习的. ...

  8. 设计模式之单利模式(C#语言描述,附视频下载地址)

    今天来介绍所有设计模式中结构最简单的设计模式单例模式,它的核心结构中只包含一个被称为单例类的特殊类. 要想完成单例类的设计,我们要遵循一下原则即可: 1.一个类只能有一个实例 2.确保该实例对外有一个 ...

  9. kafka 监控工具 eagle 的安装(内附高速下载地址)

    简介 如图 kafka eagle 是可视化的 kafka 监视系统,用于监控 kafka 集群 环境准备: 需要的内存:1.5G+ 支持的 kafka 版本:0.8.2.x,0.9.x,0.10.x ...

随机推荐

  1. phpqrcode 生成二维码

    这个项目需要根据信息来自动生成二维码,到网上搜了下,发现php有生成二维码的类库phpqrcode,所以打算就用这个来生成二维码 从官网下载类库源码http://sourceforge.net/pro ...

  2. 利用firebug调试功能辅助了解闭包和this

    算一算,有段时间没写博客. 上午的时候翻看以前收藏的一个系列博文<深入理解javascript原型和闭包>, 讲闭包那节:http://www.cnblogs.com/wangfupeng ...

  3. CSS控制TD内的文本超出指定宽度后不换行而用省略号代替

    <style type="text/css"> .lineOverflow { width: 100px; border:#000 solid 1px; text-ov ...

  4. 解决“只能通过Chrome网上应用商店安装该程序”的方法

    摘要 : 最近有些用户反映某个Chrome插件在安装的时候,提示"只能通过Chrome网上应用商店安装该程序",为了解决这一问题,Chrome插件网带来了相关的解决方法. 某些用户 ...

  5. 第22章 java线程(2)-线程同步

    java线程(2)-线程同步 本节主要是在前面吃苹果的基础上发现问题,然后提出三种解决方式 1.线程不安全问题 什么叫线程不安全呢 即当多线程并发访问同一个资源对象的时候,可能出现不安全的问题 对于前 ...

  6. python_面向对象编程

    一.编程范式 程序员通过特定的语法+数据结构+算法告诉计算机如果执行任务,实现这个过程有不同的编程方式,对这些不同的编程方式进行归纳总结得出来的编程方式类别,即为编程范式 编程范式:面向过程编程.面向 ...

  7. Spring BeanUtils 的对象复制 copyProperties

    Spring提供了一个非常棒的对象复制方法, 其参数的顺序和apache commons提供的同名方法是不一样的, 这个要小心. 源码 public static void copyPropertie ...

  8. c语言考前最后一天

    明天就是考验这1个多月学习c语言的总结了,所以今天是个重要的日子,明天是个神圣的日子. 但是我还很多地方不明白,特别是函数,循环,这两个都是c语言最重要的,但我却没学好,上课还 时不时走神所以现在学的 ...

  9. ActiveX控件之ActiveXObject is not defined

    ActiveX控件方便用户在网页中插入各种效果,但是并不是所有浏览器都支持该控件. ActiveX是微软独有的,只有基于IE内核的浏览器才能使用. 当出现如上错误,可以将通过该控件创建的对象定义为本地 ...

  10. jS字符串大小写转换实现方式

    toLocaleUpperCase 方法:将字符转换为大写 stringVar.tolocaleUpperCase( ) 必选的 stringVar 引用是一个 String 对象,值或文字. //转 ...