查看: 2055|回复: 0

[原创] 【IRD-LPC1768-DEV】CAN

[复制链接]
  • TA的每日心情
    无聊
    2021-12-29 19:06
  • 签到天数: 47 天

    [LV.5]常住居民I

    49

    主题

    188

    帖子

    21

    金牌会员

    Rank: 6Rank: 6

    积分
    1371
    最后登录
    2024-3-21
    发表于 2019-3-10 15:22:48 | 显示全部楼层 |阅读模式
    (一)开发平台CAN功能综述
    关于IRD-LPC1768-DEV这款板子的CAN有一点值得注意,那就是必须要5VDC电源供电,否则即使配置成功了也无法产生波形。
    若是没有CAN调适设备的话,大可不必额外接一条从CAN1到CAN2的线缆,板子上的跳线就可以连接起来。
    我这里设置不滤波,也就是不仲裁发送的地址,全单接收。


    (二)寄存器方法配置CAN
    一开始我用宝马的例程来跑,结果用逻辑分析仪发现没有产生任何电平的跳变,然后折腾了几天数据手册,终于是捣鼓了出来:
    配置过程:
    1-使能电源
    2-使能引脚

    3-初始化控制器、时钟
    4-设置波特率
    5-使能中断
    6-设置为旁路,不滤波


    波特率就是设置LPC_CAN1的BTR位:
    1. static void CAN_cfgBaudrate (uint32_t ctrl, uint32_t baudrate)  {
    2.     LPC_CAN_T *pCAN = (ctrl == 0) ? LPC_CAN1 : LPC_CAN2;
    3.     uint32_t result = 0;
    4.     uint32_t nominal_time;

    5.     if (((SystemCoreClock/4 / 1000000) % 6) == 0)
    6.                 {
    7.       nominal_time = 12;                                                /* CCLK 为72MHz                 */
    8.     }
    9.                 else
    10.                 {
    11.       nominal_time = 10;                                                /* CCLK 为100MHz                */
    12.     }

    13.     result  = (SystemCoreClock/4 / nominal_time) / baudrate - 1;                                //波特率预分频值 BRP=2.5M/baudrate-1
    14.     result &= 0x000003FF;
    15.     result |= CAN_BIT_TIME[nominal_time];

    16.     pCAN->BTR  = result;                                  //设置波特率 25M/(BRP+1)/(3+5+2)
    17. }
    复制代码
    主要的配置:
    1. void CAN_setup(uint32_t ctrl)
    2. {
    3.         LPC_CAN_T *pCAN = (ctrl == 0) ? LPC_CAN1 : LPC_CAN2;
    4.         
    5.         //1-使能电源
    6.         //2-使能引脚
    7.         if (ctrl == 0) {
    8.       LPC_SYSCTL->PCONP       |=  (1 << 13);                                //CAN控制器1上电               */
    9.       LPC_IOCON->PINSEL[0] |=  (1 <<  0);                                //P0.0 用作 RD1 (CAN1)         */
    10.       LPC_IOCON->PINSEL[0] |=  (1 <<  2);                                //P0.1 用作 TD1 (CAN1)         */
    11.   } else {
    12.       LPC_SYSCTL->PCONP       |=  (1 << 14);                                //CAN控制器2上电               */
    13.       LPC_IOCON->PINSEL[0] |=  (1 <<  9);                                //P0.4 用作 RD2 (CAN2)        */
    14.       LPC_IOCON->PINSEL[0] |=  (1 << 11);                                //P0.5 用作 TD2 (CAN2)        */
    15.   }
    16.         
    17.         //3-初始化控制器、时钟
    18.         pCAN->MOD   = 1;                     // 进入复位模式
    19.         pCAN->IER   = 0;                                 // 关闭接收发送中断
    20.         pCAN->GSR   = 0;                                       
    21.         //pCAN->CMR = (1 << 2) | (1 << 1) | (1 << 3);      
    22.         pCAN->MOD   = 0;
    23.         
    24.         //4-设置波特率
    25.         CAN_cfgBaudrate(ctrl, 500000);
    26.         
    27.         //5-使能中断
    28. //        pCAN->IER   = 0x0003;   
    29.         
    30.         //6-设置为旁路,不滤波
    31. //        LPC_CANAF->AFMR = 2;
    32. }

    33. void CAN_Init(void)
    34. {
    35.         CAN_setup(0);
    36.         CAN_setup(1);
    37.         
    38.         //5-使能中断
    39.         NVIC_EnableIRQ(CAN_IRQn);
    40.         LPC_CAN2->IER   = 0x0003;
    41.         
    42.         //6-设置为旁路,不滤波
    43.         LPC_CANAF->AFMR = 2;
    44. }
    复制代码
    注意,这里只开启LPC_CAN2中断,如果连LPC_CAN1中断也开启的话,以后面寄存器编写的发送函数是发送不出去的,具体原因未解决,但如果用LPCOPEN库的库函数则是能成功发送。

    (三)寄存器方法发送CAN1
    发送函数:
    1. void CAN_send (uint32_t ctrl, CAN_FRAME *msg)  
    2. {
    3.   LPC_CAN_T *pCAN = (ctrl == 0) ? LPC_CAN1 : LPC_CAN2;
    4.   uint32_t CANData;

    5.   CANData = (((uint32_t) msg->len) << 16)     & 0x000F0000 |                         //数据长度
    6.             (msg->format == EXTENDED_FORMAT ) * 0x80000000 |                        //0标准帧与1扩展帧
    7.             (msg->type   == REMOTE_FRAME)     * 0x40000000;                                //0数据帧与1远程帧

    8.   if (pCAN->SR & (1<<2))  
    9.         {                                 
    10.     pCAN->TX[0].TFI  = CANData;                                        //填充帧信息
    11.     pCAN->TX[0].TID = msg->id;                                         //填充帧id                     
    12.     pCAN->TX[0].TD[0] = *(uint32_t *) &msg->data[0];                     //填充数据场前4字节
    13.     pCAN->TX[0].TD[1] = *(uint32_t *) &msg->data[4];                     //填充数据场后4字节   
    14.     //pCAN->CMR  = 0x31;                                          //使用自发自收模式      
    15.     pCAN->CMR  = 0x21;                                            //发送                        
    16.   }
    17. }
    复制代码
    具体调用测试如下:
    1. void can_send_me2(void)
    2. {
    3.         CAN_FRAME msg;
    4.         
    5.         msg.id = 0x202;
    6.         msg.len = 2;
    7.         msg.data[0] = 'J';
    8.         msg.data[1] = 'K';
    9.         msg.type = 0;                //数据帧
    10.         msg.format = 0;        //标准帧
    11.         
    12.         CAN_send(0, &msg);
    13. }
    复制代码


    (四)库函数方法发送CAN1
    一开始参考宝马的例程完全发不出来,他那个初始化函数连LPC_CAN1的中断一同打开了,而他的寄存器方法配置发送函数是没办法正常发送接收的。但当时不了情况,手头也没有专门的CAN调适设备,百般无奈之下转战LPCOPEN库函数。
    这个转变有点心酸,库函数的寄存器定义都跟keil自带的LPC17xx.h里面的不一样,改了我几天。
    但带来的效果也是立竿见影的
    1. void CAN_Init_OperChip(void)
    2. {
    3.         CAN_MSG_T send_msg_buf;
    4.         CAN_BUFFER_ID_T   TxBuf;
    5.         
    6.         //1-使能电源
    7.         LPC_SYSCTL->PCONP       |=  (1 << 13);                                //CAN控制器1上电               */
    8.         LPC_SYSCTL->PCONP       |=  (1 << 14);                                //CAN控制器2上电               */
    9.         
    10.         //2-使能引脚
    11.         LPC_IOCON->PINSEL[0] |=  (1 <<  0);                                //P0.0 用作 RD1 (CAN1)         */
    12.         LPC_IOCON->PINSEL[0] |=  (1 <<  2);  
    13.         
    14.         LPC_IOCON->PINSEL[0] |=  (1 <<  9);                                //P0.4 用作 RD2 (CAN2)        */
    15.         LPC_IOCON->PINSEL[0] |=  (1 << 11);
    16.         
    17.         //3-初始化控制器、时钟
    18.         Chip_CAN_Init(LPC_CAN1, LPC_CANAF, LPC_CANAF_RAM);
    19.         Chip_CAN_Init(LPC_CAN2, LPC_CANAF, LPC_CANAF_RAM);
    20.         
    21.         //4-设置波特率
    22.         Chip_CAN_SetBitRate(LPC_CAN1, 500000);
    23.         Chip_CAN_SetBitRate(LPC_CAN2, 500000);
    24.         
    25.         //5-设置中断
    26.         NVIC_EnableIRQ(CAN_IRQn);
    27.         LPC_CAN2->IER   = 0x0003;
    28.         
    29.         //6-设置为旁路,不滤波
    30. //        Chip_CAN_SetAFMode(LPC_CANAF, CAN_AF_BYBASS_MODE);
    31.         LPC_CANAF->AFMR = 2;
    32. }
    复制代码
    发送函数:Chip_CAN_Send,在库里面可以直接调用
    发送操作:
    1. void can_send_me(void)
    2. {
    3.         CAN_MSG_T send_msg_buf;
    4.         CAN_BUFFER_ID_T   TxBuf;
    5.         
    6.         send_msg_buf.ID = 0x201;
    7.         send_msg_buf.DLC = 4;
    8.         send_msg_buf.Type = 0;
    9.         send_msg_buf.Data[0] = 'E';
    10.         send_msg_buf.Data[1] = 'F';
    11.         send_msg_buf.Data[2] = 'G';
    12.         send_msg_buf.Data[3] = 'H';
    13.         
    14.         TxBuf = Chip_CAN_GetFreeTxBuf(LPC_CAN1);
    15.         Chip_CAN_Send(LPC_CAN1, TxBuf, &send_msg_buf);
    16.         while ((Chip_CAN_GetStatus(LPC_CAN1) & CAN_SR_TCS(TxBuf)) == 0) {}
    17. }
    复制代码


    (五)打印到串口
    中断函数:
    1. void CAN_IRQHandler(void)
    2. {
    3.         uint32_t IntStatus;
    4.         CAN_MSG_T RcvMsgBuf;
    5.         IntStatus = Chip_CAN_GetIntStatus(LPC_CAN2);

    6.         PrintCANErrorInfo(IntStatus);

    7.         // New Message came
    8.         if (IntStatus & CAN_ICR_RI) {
    9.                 Chip_CAN_Receive(LPC_CAN2, &RcvMsgBuf);
    10.                 printf("Message Received!!!\r\n");
    11.                 PrintCANMsg(&RcvMsgBuf);
    12.         }
    13. }
    复制代码

    45$XK9DTWUG)TY5MSKCC94M.png
    无论是基于库函数还是寄存器的收发都正常可用
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-26 17:05 , Processed in 0.122779 second(s), 21 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表