搜索

[活动专区] 【AutoChips MCU 评测报告】+CAN基本收发通讯

[复制链接]
98|4
 楼主 | 2020-11-12 10:25 | 显示全部楼层 |阅读模式
今天我们测试一下AC7811的CAN功能。这里用的简易版本的USB-CAN(诺比特机器人)工具。
我们先把例程下载到MCU,例程写的非常好,架构很清晰,把收发放在一个定时器里面:
该实验主要功能:
上电后LED2,LED3处于熄灭状态,CAN配置正常模式,可接收可发送数据.
上电后,CAN以100ms的周期发送数据,连续发送2s时间后停止发送数据2s时间,依次循环.
当CAN接收到数据时,LED2以50ms的频率闪烁,300ms内没有接收到任何数据,LED2立即熄灭.
当CAN发送数据时,LED3以50ms的频率闪烁,当停止发送数据时,LED3立即熄灭.

CAN相关配置:      
CAN比特率为500K,标准数据帧格式,收发ID:
  1. //2个允许接收的节点ID:
  2. #define CAN1_RECV_DATA_ID1                        (0x220)
  3. #define CAN1_RECV_DATA_ID2                        (0x230)
  4. //一个标记本身的发送ID
  5. #define CAN1_SEND_DATA_ID1                        (0x430)
复制代码


CAN初始化代码:
  1. void CAN_InitHardwr(void)
  2. {
  3.         CAN_Config canConfig = {0};
  4.         CAN_BaudrateConfig canBandrateConfig = {0};
  5.        
  6.         GPIO_SetFunc(CAN1_TX, GPIO_FUNC_1);//设置CAN1引脚复用功能
  7.         GPIO_SetFunc(CAN1_RX, GPIO_FUNC_1);
  8.         GPIO_SetDir(CAN1_STB, GPIO_OUTPUT);//设置CAN1收发器控制为IO控制
  9.         CAN1_TRASCVER_NML;//使能CAN收发器
  10.        
  11.         /*
  12.         设置波特率为500K,采样点为81.25%.
  13.         tSeg1 = (S_SEG_1 + 2); tSeg2 = (S_SEG_2 + 1).
  14.         BandRate         = (48M / (S_PRESC + 1) / ((S_SEG_1 + 2) + (S_SEG_2 + 1)))
  15.         SamplePoint = (tSeg1 / (tSeg1 + tSeg2)).
  16.         在已经知道波特率与采样点的情况下,经过计算后:tSeg1 = 13,tSeg2 = 3.
  17.          */
  18.         canBandrateConfig.S_PRESC         = 5;//分频后时钟为8M.
  19.         canBandrateConfig.S_SEG_1         = 11;
  20.         canBandrateConfig.S_SEG_2         = 2;
  21.         canBandrateConfig.S_SJW         = 2;//满足S_SJW <= tSeg2即可.
  22.        
  23.         /*
  24.         16个过滤器中,可随意选择使用哪个,并制定其过滤模式,制定其过滤ID的类型.
  25.         如果一个过滤器只需要接收一个ID,直接可将其设置CODE模式,然后根据ID类型设置过滤类型.
  26.         如果一个过滤器需要接收多个ID,将其设置为MASK模式,并根据这几个ID的实际类型设置过滤ID类型,如果既有STD又有EXT,则应选择FILTER_IDE_STD_EXT_BOTH.
  27.        
  28.         此处加宏是为了更清楚的说明各种设置是否有效,在实际应用中,可将各种组合放在一起使用.
  29.          */
  30.         #if (RECV_FRM_KIND_SEL == ONLY_RECV_STD_FRM)
  31.         CAN_SetFilterParam( 0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, CAN1_RECV_DATA_ID1);//使用CODE模式只接收STD帧
  32.         CAN_SetFilterParam( 1, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, CAN1_RECV_DATA_ID2);//使用CODE模式只接收STD帧
  33.         #endif
  34.         #if (RECV_FRM_KIND_SEL == ONLY_RECV_EXT_FRM)
  35.         CAN_SetFilterParam( 0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_EXT_ONLY, CAN1_RECV_DATA_ID11);//使用CODE模式只接收EXT帧
  36.         CAN_SetFilterParam( 1, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_EXT_ONLY, CAN1_RECV_DATA_ID12);//使用CODE模式只接收EXT帧
  37.         #endif
  38.         #if (RECV_FRM_KIND_SEL == RECV_STD_EXT_BOTH_FRM)
  39.         CAN_SetFilterParam( 0, 1, CAN_FILTER_MASK_MODE, FILTER_IDE_STD_EXT_BOTH, (CAN1_RECV_DATA_ID1 & CAN1_RECV_DATA_ID11));//使用MASK模式接收两种帧
  40.         CAN_SetFilterParam( 1, 1, CAN_FILTER_MASK_MODE, FILTER_IDE_STD_EXT_BOTH, (CAN1_RECV_DATA_ID2 & CAN1_RECV_DATA_ID12));//使用MASK模式接收两种帧
  41.         #endif
  42.        
  43.         canConfig.interruptEnable = TRUE;//使能中断
  44.         canConfig.TSSS = TRUE;//使用次发送缓冲区发送
  45.         canConfig.canMode = CAN_MODE_NORMAL;
  46.         canConfig.autoReset = TRUE;//CAN BUSOFF后,自动恢复
  47.         canConfig.filterList = g_canFilterTab;//赋值过滤器设置list
  48.        
  49.         CAN_SetEventCallBack(CAN1, CAN1_IRQnCallBack);
  50.         CAN_Initialize(CAN1, &canConfig, &canBandrateConfig);
  51. }
复制代码
其中最关键的就是波特率和采样率的计时,详细可看参考手册,同时手册也给出了常见的通讯波特率的设置表格:
A2.png
我们开始先配置USB-CAN的通讯相关的配置:
A3.png
A4.png
我们来验证一下,查看源码到底发送了什么。是否与接收到的匹配:
  1. uint8_t                                        g_sendCANDataBuf[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
复制代码
跟接受的数据一直,ID也是与#define CAN1_SEND_DATA_ID1        (0x430)匹配。
我们发送数据化,LED2会闪烁一会,然后熄灭。现象也正常。
下面我们稍微修改下,我们打印出接收的数据,并进行分析,如果就是到的数组第一个元素数值为1,就打开LED2,为2就关闭LED2。
直接在void CAN_CheckDataDealPrd(void)函数里面修改,接收部分的代码:
  1. if (g_recvedCANDataRdy)//数据接收后,处理
  2.         {
  3.                 //复制数据到处理缓冲区,获取长度,ID信息
  4.                
  5.                 g_recvedCANDataRdy = FALSE;
  6.                
  7.                 //处理CAN数据
  8.                 printf("CAN RECEVIE DATA IS : 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x \r\n",g_recvCANMsgInfo.Data[0],
  9.                         g_recvCANMsgInfo.Data[1],g_recvCANMsgInfo.Data[2],g_recvCANMsgInfo.Data[3],g_recvCANMsgInfo.Data[4],
  10.                   g_recvCANMsgInfo.Data[5],g_recvCANMsgInfo.Data[6],g_recvCANMsgInfo.Data[7]);

  11.                 if(g_recvCANMsgInfo.Data[0]==1) {LED2_ON; printf("LED2 is on! \r\n");};
  12.                 if(g_recvCANMsgInfo.Data[0]==2) {LED2_OFF;printf("LED2 is off!\r\n");};
  13. //                if (g_blinkLED2Flag == FALSE)//只有在当前没有闪烁灯的情况下,启动闪烁
  14. //                {
  15. //                        g_blinkLED2Flag = TRUE;
  16. //                        g_blinkLED2TimeCnt = 0;
  17. //                }
  18.                
  19.                 g_recvStopTimeCnt = 0;
  20.         }
  21. //        else
  22. //        {
  23. //                if ((g_blinkLED2Flag) && (g_recvStopTimeCnt > 299))//300ms内没有接收到任何数据,停止闪烁
  24. //                {
  25. //                        g_blinkLED2Flag = FALSE;
  26. //                       
  27. //                        LED2_OFF;
  28. //                }
  29. //        }
复制代码
编译下载,分别发送2串数据,现象如下:
A5.png
同时LED也亮灭受控。
在这个架构上,我们就能完成一套基于CAN标志帧的简易通讯控制系统了。



使用特权

评论回复
| 2020-11-16 08:12 | 显示全部楼层
感谢楼主分享使用经验。

使用特权

评论回复
| 2020-11-17 15:33 | 显示全部楼层
这个经验不错的,我认为需要好好学习一下技术思维。

使用特权

评论回复
| 2020-11-18 09:14 | 显示全部楼层
技术大牛,多多指教

使用特权

评论回复
| 2020-11-18 09:30 | 显示全部楼层
这个真的是技术大牛,厉害。学习了。

使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 我要提问 投诉建议 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

在线客服 快速回复 返回顶部 返回列表