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

  .

  1. 由上图可见,整个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数据。
  1. CAN1/ 使用以下寄存器进行设置:
  2. a)电源使能:在PCONP 寄存器中,设置PCAN1/。
  3. 注:复位时,CAN1/ 会被使能(PCAN1/=)。
  4. b)时钟使能:在PCLK_SEL0 寄存器中选择PCLK_CAN1/ 和验收滤波器的PCLK_ACF
  5. 注:如果所需使用的 CAN 波特率必须高于100kbit/s(参见表16.),那么就不能选择IRC
         作为时钟源。
  6. c)唤醒:CAN 控制器能够将微控制器从掉电模式唤醒。
  7. d)引脚:通过PINSEL 寄存器选择CAN1/ 引脚,并通过PINMODE 寄存器选择引脚模式。
  8. e)中断:CAN 中断是通过CAN1/2IER 寄存器来使能的。中断的使能是通过在NIVC 中使
  9. 用相应的中断设置使能寄存器(Interrupt Set Enable register)来实现的。
  10. fCAN 控制器初始化:在CANNOD 寄存器中设置。
  11. 以上为数据手册介绍的CAN控制器初始化过程,白话点说:
  12. "a)"CANLPC1769的外设器件,要让其工作,首先要设置PCONP,该寄存器的各个位来决定外设
  13. 的时钟是否打开或关闭,若某个外设不被使用,则关闭它,以达到节省功耗的目的;此处要需
           要使用CAN,所以先打开CAN的外设时钟。
  14. "b)"其次,外设若要正常工作,则均需要一个合适的时钟频率,通PCLK_SEL0l来决定CAN的外设
  15. 时钟来源,以及大小。
  16. "c)"为了进一步减少MCU的功耗,当CAN网络上没有数据传输时,也没有CAN中断在处理,并且对应
           的睡眠位被置“1”,CAN外设会进入睡眠状态,若CAN总线上出现了显性位,则CAN外设从睡眠
           状态被唤醒。同时,若已配置了相关位,且此时整个MCU都进入掉电或者深度睡眠模式,则CAN
           也可将MCU唤醒 
  17. "d)"配置CAN的收发引脚,无需多言,告诉CAN控制器,从哪个引脚收发CAN数据。
  18. "e)"配置CAN的各种中断使能条件,此处使能了发送/接收中断,错误中断;以及配置NVIC
  19. CAN外设中断。
  20. "f)"配置CAN相关的参数,譬如波特率等等。
  21. 至此,CAN控制器初始化部分完成,还需要做接收和发送函数,以及中断函数,来实现CAN的收发
  22. ,和错误管理。
  23. 当然,在CAN控制器初始化部分,波特率的参数设置还有许多要说,本篇篇幅有限,暂不详述,下次
  24. 再开篇博客进行介绍。
  25. CAN中断函数:
  26. /*----------------- INTERRUPT SERVICE ROUTINES --------------------------*/
  27. /*********************************************************************//**
  28. * @brief CAN_IRQ Handler, control receive message operation
  29. * param[in] none
  30. * @return none
  31. **********************************************************************/
  32. void CAN_IRQHandler()
  33. {
  34. uint8_t IntStatus;
  35. uint32_t data1;
  36. /* get interrupt status
  37. * Note that: Interrupt register CANICR will be reset after read.
  38. * So function "CAN_IntGetStatus" should be call only one time
  39. */
  40. // 以下函数获取的是CAN1ICR/CAN2ICR的寄存器数据,该寄存器指明了中断来源
  41. IntStatus = CAN_IntGetStatus(LPC_CAN1);if((IntStatus>>)&0x01) {// 接收中断
  42. }
  43. ...
  44. // 省略的内容为,根据寄存器的各位的中断来源数据来解析中断信息。
           // IntStatus = CAN_IntGetStatus(LPC_CAN2);
           // if(...) ...
  45. }
  46.  
  47. CAN接收函数:
  48. 此函数为NXP提供的库函数,库函数下载链接在本文第三部分,该函数做的内容无非就是,在中
  49. 断内,检查两个接收邮箱内是否有信息,若有,则将信息提取。
  50. /********************************************************************//**
  51. * @brief Receive message data
  52. * @param[in] CANx pointer to LPC_CAN_TypeDef, should be:
  53. * - LPC_CAN1: CAN1 peripheral
  54. * - LPC_CAN2: CAN2 peripheral
  55. * @param[in] CAN_Msg point to the CAN_MSG_Type Struct, it will contain received
  56. * message information such as: ID, DLC, RTR, ID Format
  57. * @return Status:
  58. * - SUCCESS: receive message successfully
  59. * - ERROR: receive message unsuccessfully
  60. *********************************************************************/
  61. Status CAN_ReceiveMsg (LPC_CAN_TypeDef *CANx, CAN_MSG_Type *CAN_Msg)
  62. {
  63. uint32_t data;
  64.  
  65. CHECK_PARAM(PARAM_CANx(CANx));
  66.  
  67. //check status of Receive Buffer
  68. if((CANx->SR &0x00000001))
  69. {
  70. /* Receive message is available */
  71. /* Read frame informations */
  72. CAN_Msg->format = (uint8_t)(((CANx->RFS) & 0x80000000)>>);
  73. CAN_Msg->type = (uint8_t)(((CANx->RFS) & 0x40000000)>>);
  74. CAN_Msg->len = (uint8_t)(((CANx->RFS) & 0x000F0000)>>);
  75.  
  76. /* Read CAN message identifier */
  77. CAN_Msg->id = CANx->RID;
  78.  
  79. /* Read the data if received message was DATA FRAME */
  80. if (CAN_Msg->type == DATA_FRAME)
  81. {
  82. /* Read first 4 data bytes */
  83. data = CANx->RDA;
  84. *((uint8_t *) &CAN_Msg->dataA[])= data & 0x000000FF;
  85. *((uint8_t *) &CAN_Msg->dataA[])= (data & 0x0000FF00)>>;;
  86. *((uint8_t *) &CAN_Msg->dataA[])= (data & 0x00FF0000)>>;
  87. *((uint8_t *) &CAN_Msg->dataA[])= (data & 0xFF000000)>>;
  88.  
  89. /* Read second 4 data bytes */
  90. data = CANx->RDB;
  91. *((uint8_t *) &CAN_Msg->dataB[])= data & 0x000000FF;
  92. *((uint8_t *) &CAN_Msg->dataB[])= (data & 0x0000FF00)>>;
  93. *((uint8_t *) &CAN_Msg->dataB[])= (data & 0x00FF0000)>>;
  94. *((uint8_t *) &CAN_Msg->dataB[])= (data & 0xFF000000)>>;
  95.  
  96. /*release receive buffer*/
  97. CANx->CMR = 0x04;
  98. }
  99. else
  100. {
  101. /* Received Frame is a Remote Frame, not have data, we just receive
  102. * message information only */
  103. CANx->CMR = 0x04; /*release receive buffer*/
  104. return SUCCESS;
  105. }
  106. }
  107. else
  108. {
  109. // no receive message available
  110. return ERROR;
  111. }
  112. return SUCCESS;
  113. }
  114.  
  115. CAN发送函数:
  116. 该函数还是库函数,即依次查询3个发送邮箱的状态,若邮箱状态为空,则将数据填充到该邮箱
  117. 并置位发送标志,然后由CAN内核模块硬件自动发送。发送的优先级在寄存器内均可配置,不详述。
  118. 篇幅不想过长,因此查询邮箱2/3代码部分省略。
  119. /********************************************************************//**
  120. * @brief Send message data
  121. * @param[in] CANx pointer to LPC_CAN_TypeDef, should be:
  122. * - LPC_CAN1: CAN1 peripheral
  123. * - LPC_CAN2: CAN2 peripheral
  124. * @param[in] CAN_Msg point to the CAN_MSG_Type Structure, it contains message
  125. * information such as: ID, DLC, RTR, ID Format
  126. * @return Status:
  127. * - SUCCESS: send message successfully
  128. * - ERROR: send message unsuccessfully
  129. *********************************************************************/
  130. Status CAN_SendMsg (LPC_CAN_TypeDef *CANx, CAN_MSG_Type *CAN_Msg)
  131. {
  132. uint32_t data;
  133. CHECK_PARAM(PARAM_CANx(CANx));
  134. CHECK_PARAM(PARAM_ID_FORMAT(CAN_Msg->format));
  135. if(CAN_Msg->format==STD_ID_FORMAT)
  136. {
  137. CHECK_PARAM(PARAM_ID_11(CAN_Msg->id));
  138. }
  139. else
  140. {
  141. CHECK_PARAM(PARAM_ID_29(CAN_Msg->id));
  142. }
  143. CHECK_PARAM(PARAM_DLC(CAN_Msg->len));
  144. CHECK_PARAM(PARAM_FRAME_TYPE(CAN_Msg->type));
  145.  
  146. //Check status of Transmit Buffer 1
  147. if (CANx->SR & (<<))
  148. {
  149. /* Transmit Channel 1 is available */
  150. /* Write frame informations and frame data into its CANxTFI1,
  151. * CANxTID1, CANxTDA1, CANxTDB1 register */
  152. CANx->TFI1 &= ~0x000F0000;
  153. CANx->TFI1 |= (CAN_Msg->len)<<;
  154. if(CAN_Msg->type == REMOTE_FRAME)
  155. {
  156. CANx->TFI1 |= (<<); //set bit RTR
  157. }
  158. else
  159. {
  160. CANx->TFI1 &= ~(<<);
  161. }
  162. if(CAN_Msg->format == EXT_ID_FORMAT)
  163. {
  164. CANx->TFI1 |= (0x80000000); //set bit FF
  165. }
  166. else
  167. {
  168. CANx->TFI1 &= ~(0x80000000);
  169. }
  170.  
  171. /* Write CAN ID*/
  172. CANx->TID1 = CAN_Msg->id;
  173.  
  174. /*Write first 4 data bytes*/
  175. data = (CAN_Msg->dataA[])|(((CAN_Msg->dataA[]))<<)|
               ((CAN_Msg->dataA[])<<)|((CAN_Msg->dataA[])<<);
  176. CANx->TDA1 = data;
  177.  
  178. /*Write second 4 data bytes*/
  179. data = (CAN_Msg->dataB[])|(((CAN_Msg->dataB[]))<<)|
               ((CAN_Msg->dataB[])<<)|((CAN_Msg->dataB[])<<);
  180. CANx->TDB1 = data;
  181.  
  182. /*Write transmission request*/
  183. // 注意该值,置位发送邮箱1,告知硬件,邮箱1的信息已经填充完毕可发送。
  184. CANx->CMR = 0x21;
  185. return SUCCESS;
  186. }
  187. //check status of Transmit Buffer 2
  188. else if(CANx->SR & (<<))
  189. {
  190. /* Transmit Channel 2 is available */
  191. /* Write frame informations and frame data into its CANxTFI2,
  192. * CANxTID2, CANxTDA2, CANxTDB2 register */
  193. ...
  194. /*Write transmission request*/
  195. // 注意该值,置位发送邮箱2,告知硬件,邮箱2的信息已经填充完毕可发送。
  196. CANx->CMR = 0x41;
  197. return SUCCESS;
  198. }
  199. //check status of Transmit Buffer 3
  200. else if (CANx->SR & (<<))
  201. {
  202. /* Transmit Channel 3 is available */
  203. /* Write frame informations and frame data into its CANxTFI3,
  204. * CANxTID3, CANxTDA3, CANxTDB3 register */
  205. ...
  206. /*Write transmission request*/
  207. // 注意该值,置位发送邮箱3,告知硬件,邮箱3的信息已经填充完毕可发送。
  208. CANx->CMR = 0x81;
  209. return SUCCESS;
  210. }
  211. else
  212. {
  213. // 所有邮箱都处于非空闲状态,无法发送
  214. return ERROR;
  215. }
  216. }
  217.  
  218. 至此,有了初始化部分,CAN中断函数,CAN发送、接收函数,也就实现了CAN数据的收发。
  219. 滤波以波特率以及CAN总线错误处理,下次再开博客详述。
  220.  
  221. 三、参考文档
  222. LPC175x_6x CMSIS-Compliant Standard Peripheral Firmware Driver Library (Keil, IAR, GNU)
  223.   https://www.lpcware.com/content/nxpfile/lpc175x6x-cmsis-compliant-standard-peripheral-firmware-driver-library-keil-iar-gnu
  224.  
  225. 至此,记录完毕。
  226.  
  227. 记录时间:--
  228. 记录地点:深圳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. 报表工具如何实现多次导入Excel

    很多人在开发报表的时候会遇到将多张表样相同的excel导入到模板,然后提交至数据库中.但问题是很多情况,在线导入不支持一次性选择多个excel,一次只能选择一个excel,也不能将多个excel中的数 ...

  2. opencv_haar分类器的训练

    本文为作者原创,未经允许不得转载:原文由作者发表在博客园: http://www.cnblogs.com/panxiaochun/p/5345412.html 因为工作的原因,本人需要用到分类器来检测 ...

  3. NOIP复习赛20161117

    题目链接:http://files.cnblogs.com/files/candy99/%E9%A2%98%E7%9B%AE1117.pdf A n个等比数列求和公式(都感觉数列忘光了) %1e9+7 ...

  4. UVA10048 Audiophobia[Floyd变形]

    UVA - 10048 Audiophobia Consider yourself lucky! Consider yourself lucky to be still breathing and h ...

  5. Vc6.0头文件的定义

    Vc6.0头文件的定义 #ifndef __HEADER__ #define __HEADER__ int fun(int i); #endif

  6. SQLMAP参数介绍

    转自:http://zhan.renren.com/bugpower?gid=3602888498044629629&checked=true SQLMAP参数介绍 sqlmap的使用方式:p ...

  7. fMRI: spatial smoothing

    Source: Brain voyager support Theoretical Background Spatial smoothing means that data points are av ...

  8. Openjudge 1.13-28:出现次数超过一半的数

    总时间限制:  1000ms 内存限制:  65536kB 描述 给出一个含有n(0 < n <= 1000)个整数的数组,请找出其中出现次数超过一半的数. 数组中的数大于-50且小于50 ...

  9. JAVA格物致知基础篇:你所不知道的返回码

    上篇我们主要讲解利用Jersey组件如何来写一个能保证基本运行的Rest Service, 之所以说能够基本运行是因为接口暴露及其简易,一旦遇到其他的情况了,就无法正确的处理我们的请求.同时,这个接口 ...

  10. 怎样让 Web 项目暴露在外的服务坚不可摧?

    Web 项目一般给特定人群使用,有些是局域网用户量不足1K的内部系统,也有些广域网用户上万的中型项目,当然还有用户上亿的大型项目. 这些大大小小的 Web 项目都会有用户登录的存在,登录后有特定的权限 ...