今天我们测试一下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:
//2个允许接收的节点ID:
#define CAN1_RECV_DATA_ID1 (0x220)
#define CAN1_RECV_DATA_ID2 (0x230)
//一个标记本身的发送ID
#define CAN1_SEND_DATA_ID1 (0x430)
CAN初始化代码:
void CAN_InitHardwr(void)
{
CAN_Config canConfig = {0};
CAN_BaudrateConfig canBandrateConfig = {0};
GPIO_SetFunc(CAN1_TX, GPIO_FUNC_1);//设置CAN1引脚复用功能
GPIO_SetFunc(CAN1_RX, GPIO_FUNC_1);
GPIO_SetDir(CAN1_STB, GPIO_OUTPUT);//设置CAN1收发器控制为IO控制
CAN1_TRASCVER_NML;//使能CAN收发器
/*
设置波特率为500K,采样点为81.25%.
tSeg1 = (S_SEG_1 + 2); tSeg2 = (S_SEG_2 + 1).
BandRate = (48M / (S_PRESC + 1) / ((S_SEG_1 + 2) + (S_SEG_2 + 1)))
SamplePoint = (tSeg1 / (tSeg1 + tSeg2)).
在已经知道波特率与采样点的情况下,经过计算后:tSeg1 = 13,tSeg2 = 3.
*/
canBandrateConfig.S_PRESC = 5;//分频后时钟为8M.
canBandrateConfig.S_SEG_1 = 11;
canBandrateConfig.S_SEG_2 = 2;
canBandrateConfig.S_SJW = 2;//满足S_SJW <= tSeg2即可.
/*
16个过滤器中,可随意选择使用哪个,并制定其过滤模式,制定其过滤ID的类型.
如果一个过滤器只需要接收一个ID,直接可将其设置CODE模式,然后根据ID类型设置过滤类型.
如果一个过滤器需要接收多个ID,将其设置为MASK模式,并根据这几个ID的实际类型设置过滤ID类型,如果既有STD又有EXT,则应选择FILTER_IDE_STD_EXT_BOTH.
此处加宏是为了更清楚的说明各种设置是否有效,在实际应用中,可将各种组合放在一起使用.
*/
#if (RECV_FRM_KIND_SEL == ONLY_RECV_STD_FRM)
CAN_SetFilterParam( 0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, CAN1_RECV_DATA_ID1);//使用CODE模式只接收STD帧
CAN_SetFilterParam( 1, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_STD_ONLY, CAN1_RECV_DATA_ID2);//使用CODE模式只接收STD帧
#endif
#if (RECV_FRM_KIND_SEL == ONLY_RECV_EXT_FRM)
CAN_SetFilterParam( 0, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_EXT_ONLY, CAN1_RECV_DATA_ID11);//使用CODE模式只接收EXT帧
CAN_SetFilterParam( 1, 1, CAN_FILTER_CODE_MODE, FILTER_IDE_EXT_ONLY, CAN1_RECV_DATA_ID12);//使用CODE模式只接收EXT帧
#endif
#if (RECV_FRM_KIND_SEL == RECV_STD_EXT_BOTH_FRM)
CAN_SetFilterParam( 0, 1, CAN_FILTER_MASK_MODE, FILTER_IDE_STD_EXT_BOTH, (CAN1_RECV_DATA_ID1 & CAN1_RECV_DATA_ID11));//使用MASK模式接收两种帧
CAN_SetFilterParam( 1, 1, CAN_FILTER_MASK_MODE, FILTER_IDE_STD_EXT_BOTH, (CAN1_RECV_DATA_ID2 & CAN1_RECV_DATA_ID12));//使用MASK模式接收两种帧
#endif
canConfig.interruptEnable = TRUE;//使能中断
canConfig.TSSS = TRUE;//使用次发送缓冲区发送
canConfig.canMode = CAN_MODE_NORMAL;
canConfig.autoReset = TRUE;//CAN BUSOFF后,自动恢复
canConfig.filterList = g_canFilterTab;//赋值过滤器设置list
CAN_SetEventCallBack(CAN1, CAN1_IRQnCallBack);
CAN_Initialize(CAN1, &canConfig, &canBandrateConfig);
}
其中最关键的就是波特率和采样率的计时,详细可看参考手册,同时手册也给出了常见的通讯波特率的设置表格:
我们开始先配置USB-CAN的通讯相关的配置:
我们来验证一下,查看源码到底发送了什么。是否与接收到的匹配:
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)函数里面修改,接收部分的代码:
if (g_recvedCANDataRdy)//数据接收后,处理
{
//复制数据到处理缓冲区,获取长度,ID信息
g_recvedCANDataRdy = FALSE;
//处理CAN数据
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],
g_recvCANMsgInfo.Data[1],g_recvCANMsgInfo.Data[2],g_recvCANMsgInfo.Data[3],g_recvCANMsgInfo.Data[4],
g_recvCANMsgInfo.Data[5],g_recvCANMsgInfo.Data[6],g_recvCANMsgInfo.Data[7]);
if(g_recvCANMsgInfo.Data[0]==1) {LED2_ON; printf("LED2 is on! \r\n");};
if(g_recvCANMsgInfo.Data[0]==2) {LED2_OFF;printf("LED2 is off!\r\n");};
// if (g_blinkLED2Flag == FALSE)//只有在当前没有闪烁灯的情况下,启动闪烁
// {
// g_blinkLED2Flag = TRUE;
// g_blinkLED2TimeCnt = 0;
// }
g_recvStopTimeCnt = 0;
}
// else
// {
// if ((g_blinkLED2Flag) && (g_recvStopTimeCnt > 299))//300ms内没有接收到任何数据,停止闪烁
// {
// g_blinkLED2Flag = FALSE;
//
// LED2_OFF;
// }
// }
编译下载,分别发送2串数据,现象如下:
同时LED也亮灭受控。
在这个架构上,我们就能完成一套基于CAN标志帧的简易通讯控制系统了。
|