第四章-CAN通信
4.3-实际编程
4.3.1-回环测试
软件初始化设置
CAN频率相干设置
打开接收中断
为了方便调试,我们初始化一下串口-PA9 PA10
添加一下重映射
- /**
- * @brief 重定向printf (重定向fputc),
- 使用时候记得勾选上魔法棒->Target->UseMicro LIB
- 可能需要在C文件加typedef struct __FILE FILE;
- 包含这个文件#include "stdio.h"
- * @param
- * @return
- */
- int fputc(int ch,FILE *stream)
- {
- HAL_UART_Transmit(&huart1,( uint8_t *)&ch,1,0xFFFF);
- return ch;
- }
复制代码 添加一些头文件
- #include "main.h"
- #include "gpio.h"
- #include "can.h"
- #include "usart.h"
- #include "bsp_CAN.h"
- #include "stdio.h"
复制代码 还有MDK的设置
我们先编程发送功能相干配置和函数
新建bsp_CAN.c和bsp_CAN.h文件
bsp_CAN.c内容
- //uint8_t CAN_SendData[8] = {1,2,3,4,5,6,7,8};//发送的八个字节数组
- uint8_t CAN_SendData[8] = "1234567";//发送的八个字符
- uint8_t CAN_RecData[8] = {0};//接收的缓冲区
- uint8_t CAN_RxFlag = 0;//CAN消息接收标志位,1-表示为接收到正确ID的消息,0-表示未接收到正确ID消息
复制代码 bsp_CAN.c内容
- /*******************
- * @brief CAN过滤器设置、接收使能、启动CAN
- * @param
- * @return
- *
- *******************/
- void CAN_Config(void)
- {
- CAN_FilterTypeDef CAN_Filter;//定义一个CAN过滤器结构体
-
- //设定CAN过滤器参数
- CAN_Filter.FilterBank = 0;//配置过滤器0
- CAN_Filter.FilterScale = CAN_FILTERSCALE_16BIT;//16位过滤器
- CAN_Filter.FilterMode = CAN_FILTERMODE_IDMASK;//标识符屏蔽模式
- //这里不做任何过滤,所以设置都是00
- CAN_Filter.FilterIdLow = 0x00; //这是FR1的设置
- CAN_Filter.FilterMaskIdLow = 0X00;
- CAN_Filter.FilterIdHigh = 0X00; //这是FR2的设置
- CAN_Filter.FilterMaskIdHigh = 0x00;
-
- CAN_Filter.FilterFIFOAssignment = CAN_RX_FIFO0;//过滤器关联到FIFO
- CAN_Filter.FilterActivation = ENABLE;//设置过滤器0、
- CAN_Filter.SlaveStartFilterBank = 14;
-
- HAL_CAN_ConfigFilter(&hcan, &CAN_Filter);//配置过滤器
-
- //使能FIFO接收到新的报文中断
- HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING);
-
- //启动CAN,这个不能少
- HAL_CAN_Start(&hcan);
- }
复制代码 bsp_CAN.c内容
- /*******************
- * @brief 发送CAN报文设置
- * @param
- * @return
- *
- *******************/
- void CAN_SetMsg(void)
- {
- uint32_t TxMailBox;//暂存HAL_CAN_AddTxMessage 函数使用那个邮箱进行发送的
- CAN_TxHeaderTypeDef CAN_TxHeader;
- CAN_TxHeader.StdId = 0X88; //这是标准标识符
- CAN_TxHeader.ExtId = 0x00; //设置扩展标识符,并没有使用
- CAN_TxHeader.IDE = CAN_ID_STD;//设置标识符为标准帧模式
- CAN_TxHeader.RTR = CAN_RTR_DATA;//设置消息的帧类型为数据帧
- CAN_TxHeader.DLC = 8;//设置要传送的帧长度 为8 字节(就是数据段有多少字节)
-
- //通过邮箱发送数据
- HAL_CAN_AddTxMessage(&hcan,&CAN_TxHeader,CAN_SendData,&TxMailBox);
-
- }
复制代码 然后在bsp_CAN.h中声明一下
- void CAN_Config(void);//设置过滤器和其他设置的激活
- void CAN_SetMsg(void);//这个是设置发送器
复制代码 我们要在main.c中使用下面变量就先声明,一下
- extern uint8_t CAN_RxFlag ; //接收标识位
- extern uint8_t CAN_SendData[8] ;//发送的八个字节数组
- extern uint8_t CAN_RecData[8];//接收的缓冲区
复制代码 初始化加上
- CAN_Config();//CAN过滤器设置、接收使能、启动CAN
复制代码 然后main的循环时如许的
- while (1)
- {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- HAL_Delay(500);
- HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
- CAN_SetMsg();
- if(CAN_RxFlag == 1){
- CAN_RxFlag = 0;
- printf("发送的是:%s\r\n",CAN_SendData);
- printf("接收的是:%s\r\n",CAN_RecData);
- }
- else printf("没有接收,没有发送\r\n");
-
- }
复制代码 打开串口助手,波特率115200
上面我们测试的环回模式,数据是发送回被自己收到,而且也发送到外面,但是自己不能收别人的
以是我们可以用逻辑分析仪测试一下
这里说逻辑分析仪测试CAN的方法
- 接线
CAN模块按要求供电
单片机PA11是CAN_RX—>CAN模块的CAN_RX
单片机PA12是CAN_TX—>CAN模块的CAN_TX
CAN模块的CAN_H—>逻辑分析仪通道0
CAN模块的CAN_L—>逻辑分析仪GND
- 然后设置CAN上位机
采样率一定要高,最高CAN速率1Mbps我们刚才软件初始化的是500Kbps 我们设置分析仪20MHz 够用了。
- 然后就可以开启单片机,让后逻辑分析仪单次采样
4.3.2-环回模式和筛选器
我们把CAN设置环回模式
我们主要更改CAN筛选器设置、
标识符屏蔽–ID是设置要频闭的ID、然后通过标识符掩码指定对应位相等完成屏蔽。
标识符列表–就是设置可以通过的白名单,必须与设置ID完全相等才可以通过
下面是具体设置位置
下面的第三步一定要注意!!!
- uint8_t CAN_RxFlag = 0;//CAN消息接收标志位,1-表示为接收到正确ID的消息,0-表示未接收到正确ID消息
- #define PASS_ID ((uint32_t)0X89) //接收过滤ID,因为我们是标准帧格式所以数值0X0-0X7FF之间
复制代码- void CAN_Config(void)
- {
- CAN_FilterTypeDef CAN_Filter;//定义一个CAN过滤器结构体
- //设定CAN过滤器参数
- CAN_Filter.FilterBank = 0;//配置过滤器0
- CAN_Filter.FilterScale = CAN_FILTERSCALE_16BIT;//16位过滤器
- CAN_Filter.FilterMode = CAN_FILTERMODE_IDMASK;//标识符屏蔽模式
- //使能筛选器,硬件控制器回按照筛选器内容进行对比筛选,不满足消息就会丢弃,满足存入FIFO中
- //这里设置过滤
- CAN_Filter.FilterIdHigh = (PASS_ID <<5)|CAN_RTR_DATA|CAN_ID_STD; //这是设置第一个16位筛选器ID
- CAN_Filter.FilterMaskIdHigh = 0xFF; //这是设置第一个16位筛选器掩码
-
- CAN_Filter.FilterIdLow = 0XFF; //第二个16位筛选器ID
- CAN_Filter.FilterMaskIdLow = 0XFF; //第二个16位筛选器掩码必须是FF,如果是00 任何ID都会通过筛选
-
- CAN_Filter.FilterFIFOAssignment = CAN_RX_FIFO0;//过滤器关联到FIFO
- CAN_Filter.FilterActivation = ENABLE;//设置过滤器0、
- CAN_Filter.SlaveStartFilterBank = 14;
-
- HAL_CAN_ConfigFilter(&hcan, &CAN_Filter);//配置过滤器
- //使能FIFO接收到新的报文中断
- HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING);
- //启动CAN,这个不能少
- HAL_CAN_Start(&hcan);
- }
复制代码 我们可以先测试设置过滤器ID不是我们发送的
然后编译烧录,发现单片机没有收到,阐明成功了
我们更改为0x88就可以正常收到消息了
- #define PASS_ID ((uint32_t)0X88) //接收过滤ID,因为我们是标准帧格式所以数值0X0-0X7FF之间
复制代码 4.3.3-正常模式-双机通信

设备1 单片机主要发送


设备2单片机接收


这是接线方法

然后串口软件接设备2单片机

我们的IAP.c内容如下
- /* Includes ------------------------------------------------------------------*/
- #include "MyApp.h"
- /* Private define-------------------------------------------------------------*/
- /* Private variables----------------------------------------------------------*/
- /* Public variables-----------------------------------------------------------*/
- /* Private function prototypes------------------------------------------------*/
- /*******************
- * @brief 这是 C语言内嵌汇编
- //MSR MSP, r0 意思是将r0寄存器中的值加载到MSP(主栈寄存器,
- //复位时默认使用)寄存器中,r0中保存的是参数值,即addr的值
- //BX r14 跳转到连接寄存器保存的地址中,即退出函数,跳转到函数调用地址
- * @param
- * @return
- *
- *******************/
- __asm void MSR_MSP (uint32_t ulAddr)
- {
- MSR MSP,r0 //set Main Stack value
- BX r14
- }
- /*******************
- * @brief 跳转到应用程序
- * @param ulAddr_App:应用程序的起始端地址
- * @return
- *
- *******************/
- void IAP_ExecuteApp(uint32_t ulAddr_App)
- {
- void (*pFunApp)(void);//定义一个函数指针
-
- //检查栈顶地址是否合法
- //if(((*(__IO uint32_t*)ulAddr_App) & 0x2FFE0000) == 0x20000000)
- if(((*(__IO uint32_t *)ulAddr_App) & 0x2FFF5000) == 0x20000000)
- {
- printf("地址合法开始跳转\r\n");
- pFunApp = (iapfun) *(__IO uint32_t *)(ulAddr_App + 4); //赋值函数指针、指向新APP的复位中断函数地址
- MSR_MSP(*(__IO uint32_t *)ulAddr_App); //初始化APP堆栈指针,对APP程序的堆栈进行重构,就是重新分配RAM
- pFunApp(); //执行APP的复位中断函数,最终便会跳转到APP的main函数
- }
- else
- {
- printf("地址不合法\r\n");
- //错误栈顶地址不合法!
- }
- }
- /********************************************************
- End Of File
- ********************************************************/
复制代码 我们的IAP.h
- #ifndef __IAP_H_
- #define __IAP_H_
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
- #include "gpio.h"
- typedef void (* iapfun)(void); //定义一个函数指针(指向一个返回为空形参为空的函数)
- #define APP_Start FLASH_BASE+0x400 //这是APP开始位置
- void IAP_ExecuteApp(uint32_t ulAddr_App);
- #endif
- /********************************************************
- End Of File
- ********************************************************/
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |