在线时间102 小时
UID3338547
注册时间2017-1-28
NXP金币49
TA的每日心情 | 无聊 2021-12-29 19:06 |
---|
签到天数: 47 天 [LV.5]常住居民I
金牌会员
- 积分
- 1371
- 最后登录
- 2024-3-21
|
(一)开发平台CAN功能综述
关于IRD-LPC1768-DEV这款板子的CAN有一点值得注意,那就是必须要5VDC电源供电,否则即使配置成功了也无法产生波形。
若是没有CAN调适设备的话,大可不必额外接一条从CAN1到CAN2的线缆,板子上的跳线就可以连接起来。
我这里设置不滤波,也就是不仲裁发送的地址,全单接收。
(二)寄存器方法配置CAN
一开始我用宝马的例程来跑,结果用逻辑分析仪发现没有产生任何电平的跳变,然后折腾了几天数据手册,终于是捣鼓了出来:
配置过程:
1-使能电源
2-使能引脚
3-初始化控制器、时钟
4-设置波特率
5-使能中断
6-设置为旁路,不滤波
波特率就是设置LPC_CAN1的BTR位:
- static void CAN_cfgBaudrate (uint32_t ctrl, uint32_t baudrate) {
- LPC_CAN_T *pCAN = (ctrl == 0) ? LPC_CAN1 : LPC_CAN2;
- uint32_t result = 0;
- uint32_t nominal_time;
- if (((SystemCoreClock/4 / 1000000) % 6) == 0)
- {
- nominal_time = 12; /* CCLK 为72MHz */
- }
- else
- {
- nominal_time = 10; /* CCLK 为100MHz */
- }
- result = (SystemCoreClock/4 / nominal_time) / baudrate - 1; //波特率预分频值 BRP=2.5M/baudrate-1
- result &= 0x000003FF;
- result |= CAN_BIT_TIME[nominal_time];
- pCAN->BTR = result; //设置波特率 25M/(BRP+1)/(3+5+2)
- }
复制代码 主要的配置:
- void CAN_setup(uint32_t ctrl)
- {
- LPC_CAN_T *pCAN = (ctrl == 0) ? LPC_CAN1 : LPC_CAN2;
-
- //1-使能电源
- //2-使能引脚
- if (ctrl == 0) {
- LPC_SYSCTL->PCONP |= (1 << 13); //CAN控制器1上电 */
- LPC_IOCON->PINSEL[0] |= (1 << 0); //P0.0 用作 RD1 (CAN1) */
- LPC_IOCON->PINSEL[0] |= (1 << 2); //P0.1 用作 TD1 (CAN1) */
- } else {
- LPC_SYSCTL->PCONP |= (1 << 14); //CAN控制器2上电 */
- LPC_IOCON->PINSEL[0] |= (1 << 9); //P0.4 用作 RD2 (CAN2) */
- LPC_IOCON->PINSEL[0] |= (1 << 11); //P0.5 用作 TD2 (CAN2) */
- }
-
- //3-初始化控制器、时钟
- pCAN->MOD = 1; // 进入复位模式
- pCAN->IER = 0; // 关闭接收发送中断
- pCAN->GSR = 0;
- //pCAN->CMR = (1 << 2) | (1 << 1) | (1 << 3);
- pCAN->MOD = 0;
-
- //4-设置波特率
- CAN_cfgBaudrate(ctrl, 500000);
-
- //5-使能中断
- // pCAN->IER = 0x0003;
-
- //6-设置为旁路,不滤波
- // LPC_CANAF->AFMR = 2;
- }
- void CAN_Init(void)
- {
- CAN_setup(0);
- CAN_setup(1);
-
- //5-使能中断
- NVIC_EnableIRQ(CAN_IRQn);
- LPC_CAN2->IER = 0x0003;
-
- //6-设置为旁路,不滤波
- LPC_CANAF->AFMR = 2;
- }
复制代码 注意,这里只开启LPC_CAN2中断,如果连LPC_CAN1中断也开启的话,以后面寄存器编写的发送函数是发送不出去的,具体原因未解决,但如果用LPCOPEN库的库函数则是能成功发送。
(三)寄存器方法发送CAN1
发送函数:
- void CAN_send (uint32_t ctrl, CAN_FRAME *msg)
- {
- LPC_CAN_T *pCAN = (ctrl == 0) ? LPC_CAN1 : LPC_CAN2;
- uint32_t CANData;
- CANData = (((uint32_t) msg->len) << 16) & 0x000F0000 | //数据长度
- (msg->format == EXTENDED_FORMAT ) * 0x80000000 | //0标准帧与1扩展帧
- (msg->type == REMOTE_FRAME) * 0x40000000; //0数据帧与1远程帧
- if (pCAN->SR & (1<<2))
- {
- pCAN->TX[0].TFI = CANData; //填充帧信息
- pCAN->TX[0].TID = msg->id; //填充帧id
- pCAN->TX[0].TD[0] = *(uint32_t *) &msg->data[0]; //填充数据场前4字节
- pCAN->TX[0].TD[1] = *(uint32_t *) &msg->data[4]; //填充数据场后4字节
- //pCAN->CMR = 0x31; //使用自发自收模式
- pCAN->CMR = 0x21; //发送
- }
- }
复制代码 具体调用测试如下:
- void can_send_me2(void)
- {
- CAN_FRAME msg;
-
- msg.id = 0x202;
- msg.len = 2;
- msg.data[0] = 'J';
- msg.data[1] = 'K';
- msg.type = 0; //数据帧
- msg.format = 0; //标准帧
-
- CAN_send(0, &msg);
- }
复制代码
(四)库函数方法发送CAN1
一开始参考宝马的例程完全发不出来,他那个初始化函数连LPC_CAN1的中断一同打开了,而他的寄存器方法配置发送函数是没办法正常发送接收的。但当时不了情况,手头也没有专门的CAN调适设备,百般无奈之下转战LPCOPEN库函数。
这个转变有点心酸,库函数的寄存器定义都跟keil自带的LPC17xx.h里面的不一样,改了我几天。
但带来的效果也是立竿见影的
- void CAN_Init_OperChip(void)
- {
- CAN_MSG_T send_msg_buf;
- CAN_BUFFER_ID_T TxBuf;
-
- //1-使能电源
- LPC_SYSCTL->PCONP |= (1 << 13); //CAN控制器1上电 */
- LPC_SYSCTL->PCONP |= (1 << 14); //CAN控制器2上电 */
-
- //2-使能引脚
- LPC_IOCON->PINSEL[0] |= (1 << 0); //P0.0 用作 RD1 (CAN1) */
- LPC_IOCON->PINSEL[0] |= (1 << 2);
-
- LPC_IOCON->PINSEL[0] |= (1 << 9); //P0.4 用作 RD2 (CAN2) */
- LPC_IOCON->PINSEL[0] |= (1 << 11);
-
- //3-初始化控制器、时钟
- Chip_CAN_Init(LPC_CAN1, LPC_CANAF, LPC_CANAF_RAM);
- Chip_CAN_Init(LPC_CAN2, LPC_CANAF, LPC_CANAF_RAM);
-
- //4-设置波特率
- Chip_CAN_SetBitRate(LPC_CAN1, 500000);
- Chip_CAN_SetBitRate(LPC_CAN2, 500000);
-
- //5-设置中断
- NVIC_EnableIRQ(CAN_IRQn);
- LPC_CAN2->IER = 0x0003;
-
- //6-设置为旁路,不滤波
- // Chip_CAN_SetAFMode(LPC_CANAF, CAN_AF_BYBASS_MODE);
- LPC_CANAF->AFMR = 2;
- }
复制代码 发送函数:Chip_CAN_Send,在库里面可以直接调用
发送操作:
- void can_send_me(void)
- {
- CAN_MSG_T send_msg_buf;
- CAN_BUFFER_ID_T TxBuf;
-
- send_msg_buf.ID = 0x201;
- send_msg_buf.DLC = 4;
- send_msg_buf.Type = 0;
- send_msg_buf.Data[0] = 'E';
- send_msg_buf.Data[1] = 'F';
- send_msg_buf.Data[2] = 'G';
- send_msg_buf.Data[3] = 'H';
-
- TxBuf = Chip_CAN_GetFreeTxBuf(LPC_CAN1);
- Chip_CAN_Send(LPC_CAN1, TxBuf, &send_msg_buf);
- while ((Chip_CAN_GetStatus(LPC_CAN1) & CAN_SR_TCS(TxBuf)) == 0) {}
- }
复制代码
(五)打印到串口
中断函数:
- void CAN_IRQHandler(void)
- {
- uint32_t IntStatus;
- CAN_MSG_T RcvMsgBuf;
- IntStatus = Chip_CAN_GetIntStatus(LPC_CAN2);
- PrintCANErrorInfo(IntStatus);
- // New Message came
- if (IntStatus & CAN_ICR_RI) {
- Chip_CAN_Receive(LPC_CAN2, &RcvMsgBuf);
- printf("Message Received!!!\r\n");
- PrintCANMsg(&RcvMsgBuf);
- }
- }
复制代码
无论是基于库函数还是寄存器的收发都正常可用
|
|