一、背景:使用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/2 使用以下寄存器进行设置:a)电源使能:在PCONP 寄存器中,设置PCAN1/2。注:复位时,CAN1/2 会被使能(PCAN1/2=0)。b)时钟使能:在PCLK_SEL0 寄存器中选择PCLK_CAN1/2 和验收滤波器的PCLK_ACF。注:如果所需使用的 CAN 波特率必须高于100kbit/s(参见表16.12),那么就不能选择IRC     作为时钟源。c)唤醒:CAN 控制器能够将微控制器从掉电模式唤醒。d)引脚:通过PINSEL 寄存器选择CAN1/2 引脚,并通过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>>0)&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 Bufferif((CANx->SR &0x00000001)){/* Receive message is available *//* Read frame informations */CAN_Msg->format   = (uint8_t)(((CANx->RFS) & 0x80000000)>>31);CAN_Msg->type     = (uint8_t)(((CANx->RFS) & 0x40000000)>>30);CAN_Msg->len      = (uint8_t)(((CANx->RFS) & 0x000F0000)>>16);/* 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[0])= data & 0x000000FF;*((uint8_t *) &CAN_Msg->dataA[1])= (data & 0x0000FF00)>>8;;*((uint8_t *) &CAN_Msg->dataA[2])= (data & 0x00FF0000)>>16;*((uint8_t *) &CAN_Msg->dataA[3])= (data & 0xFF000000)>>24;/* Read second 4 data bytes */data = CANx->RDB;*((uint8_t *) &CAN_Msg->dataB[0])= data & 0x000000FF;*((uint8_t *) &CAN_Msg->dataB[1])= (data & 0x0000FF00)>>8;*((uint8_t *) &CAN_Msg->dataB[2])= (data & 0x00FF0000)>>16;*((uint8_t *) &CAN_Msg->dataB[3])= (data & 0xFF000000)>>24;/*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 availablereturn 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 1if (CANx->SR & (1<<2)){/* 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)<<16;if(CAN_Msg->type == REMOTE_FRAME){CANx->TFI1 |= (1<<30); //set bit RTR
            }else{CANx->TFI1 &= ~(1<<30);}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[0])|(((CAN_Msg->dataA[1]))<<8)|             ((CAN_Msg->dataA[2])<<16)|((CAN_Msg->dataA[3])<<24);CANx->TDA1 = data;/*Write second 4 data bytes*/data = (CAN_Msg->dataB[0])|(((CAN_Msg->dataB[1]))<<8)|            ((CAN_Msg->dataB[2])<<16)|((CAN_Msg->dataB[3])<<24);CANx->TDB1 = data;/*Write transmission request*/// 注意该值,置位发送邮箱1,告知硬件,邮箱1的信息已经填充完毕可发送。CANx->CMR = 0x21;return SUCCESS;}//check status of Transmit Buffer 2else if(CANx->SR & (1<<10)){/* 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 3else if (CANx->SR & (1<<18)){/* 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

至此,记录完毕。记录时间:2016-11-28
记录地点:深圳WZ

转载于:https://www.cnblogs.com/ChYQ/p/6110713.html

LPC1768/1769之CAN控制器概述(附库函数下载地址)相关推荐

  1. 收藏!程序员必备的软件开发工具大全!(附高速下载地址)

    对于每一位开发者而言,软件开发工具的重要性显然不言而喻.事实上,除了个人能力之外,它们也在团队的效率及实际生产力层面扮演着关键性角色. 今天阿晨就把自己的私货全部掏出来整理在下面! 内附高速下载地址! ...

  2. 【教程转载】 火狐浏览器 实用插件一览(附插件下载地址)

    [教程转载] 火狐浏览器 实用插件一览(附插件下载地址)简单介绍一下: 火狐浏览器(firefox)最大的优点就是安全.快速.稳定. 有些人抱怨火狐的功能太少,有些网页不能正常浏览. 没关系,这些都不 ...

  3. 技术经典图书(附电子版下载地址)

    本人大学期间专业是数学与应用数学, 2011年毕业, 做过C开发, 系统运维和测试, 这3年我读了很多书, 电子书和纸质的, 这些书中有很多很经典的图书和资料, 平时也喜欢和同事,朋友分享一些对他们有 ...

  4. python编程入门与案例详解pdf-这些年我读过的技术经典图书(附电子版下载地址)...

    C技术资料 1.<> 作者: 谭浩强 这是我推荐的第一本书, 也是我接触的第一本书, 为什么把它放在第一位, 因为我觉得这本书对我的影响很大, 感觉这本书的最大特点是: 内容很全面, 内容 ...

  5. Python经典面试题100道(附PDF下载地址)

    最近肝了一个月,整理了下经典的 Python 经典习题 100 道,有基础的,也有进阶的,用习题来巩固知识点,不枯燥,为了方便大家查阅,我把这 100 道题整理成了 PDF 文档,大家可以下载到电脑或 ...

  6. Microsoft Edge浏览器最新版已经换成开源Chromium引擎了,附官方下载地址

    基于 Chromium 的新版 Microsoft Edge  已于 2020 年 1 月 15 日发布.它与 Windows 和 macOS 的所有受支持版本兼容.下载新版浏览器将替换 Window ...

  7. php做一个网页的源代码,用HTML5做一个个人网站此文仅展示个人主页界面。内附源代码下载地址...

    下载说明: 1.再好的作品都不如将来要做的作品.在每一次的设计当中都能有所收获,才是设计师在web开发中最得益的. 2.本站所有作品均是杨青个人设计.如果发现模板有错,请尽情谅解. 3.如果遇到什么问 ...

  8. 【华为大咖分享】12.从Change、merge到New Challenge--华为内源平台到研发云平台的发展历程(后附PPT下载地址)

    文:华为云DevCloud 表伟 完整版PPT下载请访问原文地址:https://bbs.huaweicloud.com/forum/thread-12724-1-1.html 华为云DevCloud ...

  9. 【华为大咖分享】11.五星级软件工程师的高效秘诀(后附PPT下载地址)

    文:华为云DevCloud 徐毅 完整版PPT下载请访问原文地址:https://bbs.huaweicloud.com/forum/thread-12639-1-1.html 华为云DevCloud ...

最新文章

  1. EJS 什么是EJS后缀文件 EJS怎么用
  2. SQL JOIN\SQL INNER JOIN 关键字\SQL LEFT JOIN 关键字\SQL RIGHT JOIN 关键字\SQL FULL JOIN 关键字...
  3. PHP IE中下载附件问题
  4. python提高文件读取速度_Python提高了HDF5文件的读取速度
  5. 九问国产操作系统,九大掌门人万字回应!
  6. 服务器TIME_WAIT和CLOSE_WAIT分析和解决办法
  7. C#获取IP和整数IP方法
  8. (原創) 开启Notebook时,建议从天版中间开启 (日記)
  9. Mac Big sur如何设置触控板滚动不带惯性?
  10. 数据清洗与数据预处理浅析
  11. .net 4.5 新特性 async await 一般处理程序实例
  12. 学习HTML 笔记A3 :HTML标题、段落、文本格式化
  13. Python 正则表达式(RegEx)
  14. 伪元素写竖线_[CSS] 用伪元素:after实现分割线和气泡
  15. java连接jpi方式_Java数据库连接(Java Database Connectivity)
  16. 常用逻辑电平标准总结
  17. Object不能直接转成int
  18. UDP打洞、P2P组网方式研究
  19. JS一百只鸡卖一百块钱,公鸡5元,母鸡3元,三只小鸡一元
  20. 生成10位随机数(PHP)

热门文章

  1. 教你如何提高信用额度
  2. RS485通信----基本原理+电路图
  3. linux 查看用户名
  4. Java题目:寻找自幂数
  5. 计算电话费练习【20171121】
  6. Unity3D手游开发日记(3) - 场景加载进度条的完美方案
  7. HTML+CSS+JAVASCRIPT 高仿低配网页版网易云音乐播放器 1
  8. 聊聊C++标准库,准标准库中关于时间的概念和用法
  9. 如何绘画Q版古风人物,超简单超实用,一学就会!
  10. 常用的进制之间相互转换