第四章-CAN通信-CAN协议解析 CAN协议报文dbc解析实例 hal库例程 CAN总线协
第四章-CAN通信4.3-实际编程
4.3.1-回环测试
软件初始化设置
https://i-blog.csdnimg.cn/direct/90c08972f134424a93b960ee662159e5.png
CAN频率相干设置
https://i-blog.csdnimg.cn/direct/67e56cdbb8d3429789123c6580fe4920.png
打开接收中断
https://i-blog.csdnimg.cn/direct/a4abb00bda2b40fea49dcd5a1cba0025.png
为了方便调试,我们初始化一下串口-PA9 PA10
https://i-blog.csdnimg.cn/direct/793f1bf097b14a428a2e97ae87876306.png
添加一下重映射
https://i-blog.csdnimg.cn/direct/11290b3b09614358a1ef5dd4cbc33778.png
/**
* @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;
}
添加一些头文件
https://i-blog.csdnimg.cn/direct/46171bbe12bf4efea37b99e33e9ef8d2.png
#include "main.h"
#include "gpio.h"
#include "can.h"
#include "usart.h"
#include "bsp_CAN.h"
#include "stdio.h"
还有MDK的设置
https://i-blog.csdnimg.cn/direct/9bbe746c05604b1b9ffdfeacb3a0e173.png
我们先编程发送功能相干配置和函数
新建bsp_CAN.c和bsp_CAN.h文件
bsp_CAN.c内容
//uint8_t CAN_SendData = {1,2,3,4,5,6,7,8};//发送的八个字节数组
uint8_t CAN_SendData = "1234567";//发送的八个字符
uint8_t CAN_RecData = {0};//接收的缓冲区
uint8_t CAN_RxFlag = 0;//CAN消息接收标志位,1-表示为接收到正确ID的消息,0-表示未接收到正确ID消息
bsp_CAN.c内容
/*******************
*@briefCAN过滤器设置、接收使能、启动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_tTxMailBox;//暂存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 ;//发送的八个字节数组
extern uint8_t CAN_RecData;//接收的缓冲区
初始化加上
https://i-blog.csdnimg.cn/direct/a4a8fb7ec06449da82adbae50f13f286.png
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
https://i-blog.csdnimg.cn/direct/acfd251ada57405c8fd28c074eaa3020.png
上面我们测试的环回模式,数据是发送回被自己收到,而且也发送到外面,但是自己不能收别人的
https://i-blog.csdnimg.cn/direct/aeb341211e304d39bbeb6b4e86f2cfc4.png
以是我们可以用逻辑分析仪测试一下
这里说逻辑分析仪测试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 够用了。
https://i-blog.csdnimg.cn/direct/9d1933267dde495db55ca25cf0c880e6.png
[*] 然后就可以开启单片机,让后逻辑分析仪单次采样
https://i-blog.csdnimg.cn/direct/d88683e15f1f428a86849b33105a6558.png
4.3.2-环回模式和筛选器
我们把CAN设置环回模式
https://i-blog.csdnimg.cn/direct/8c2f165fa298468fb8ecaebd671688ea.png
我们主要更改CAN筛选器设置、
标识符屏蔽–ID是设置要频闭的ID、然后通过标识符掩码指定对应位相等完成屏蔽。
标识符列表–就是设置可以通过的白名单,必须与设置ID完全相等才可以通过
https://i-blog.csdnimg.cn/direct/a08861f5ae4847bbb564ba34701903bb.png
下面是具体设置位置
下面的第三步一定要注意!!!
https://i-blog.csdnimg.cn/direct/27aad52bbb394645a50891359d3340d0.png
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不是我们发送的
https://i-blog.csdnimg.cn/direct/48f10f352166469f97d9a8331c8db9d2.png
然后编译烧录,发现单片机没有收到,阐明成功了
https://i-blog.csdnimg.cn/direct/daac00bfc63c4eaca319065abfc8a135.png
我们更改为0x88就可以正常收到消息了
#define PASS_ID((uint32_t)0X88) //接收过滤ID,因为我们是标准帧格式所以数值0X0-0X7FF之间
4.3.3-正常模式-双机通信
https://i-blog.csdnimg.cn/direct/69e6c91be8ab4b4fa0639f261b162bee.png
设备1 单片机主要发送
https://i-blog.csdnimg.cn/direct/e88091a1fe7340c58a9f7c12da09757e.png
https://i-blog.csdnimg.cn/direct/089f4756c0b04e93ab178dab25da85e4.png
设备2单片机接收
https://i-blog.csdnimg.cn/direct/5efe653faa1b4565a5f11bcdd86f083d.png
https://i-blog.csdnimg.cn/direct/589593de6c2e4b1ebbf486926c99de1f.png
这是接线方法
https://i-blog.csdnimg.cn/direct/2352242592624d27908552a6fd271bc7.png
然后串口软件接设备2单片机
https://i-blog.csdnimg.cn/direct/b8c50d976a504495a2e9953f01bba5b5.png
我们的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跳转到应用程序
*@paramulAddr_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
********************************************************/
https://i-blog.csdnimg.cn/direct/e33b075a05da469aadadde510c4db74c.png
https://i-blog.csdnimg.cn/direct/74278cb47b7f406ebe6aac36c14affcb.png
https://i-blog.csdnimg.cn/direct/3ce40e56c3e7437eab19edf31f131218.png
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]