微信公众号关注:掌芯元器,免费为大家提供嵌入式相关的技术咨询!!!
上篇文章:
一种简易CAN数据分析器的实现(一)【工程创建+CAN波特率计算工具】-CSDN博客
目录
四、代码功能实现
1、main.c
2、usart_drive.c
3、usart_drive.h
4、can_drive.c
5、can_drive.h
四、代码功能实现
创建4个文件,分别是usart_drive.c、usart_drive.h、can_drive.c、can_drive.h,下面直接附上代码,直接将代码添加至相应的文件即可。代码实现大体流程为:
- UART数据接收及处理 + CAN数据发送
- PC端串口调试助手发来消息,消息到来时,触发串口接收事件中断,之后进入中断回调函数,在回调函数中存储本次接收的数据量,使能数据接收标志,使能串口接收中断,以便后期可以不断使用串口中断接收数据。这里重点说一下为什么设计接收标志,它的目的是什么?有什么作用?数据接收标志的目的是串口接收到数据之后,数据处理相关的代码不在回调函数中执行,数据处理需要一段时间,这段时间内中断一直处于占用状态,其它中断到来时,程序将无响应。中断标志是全局变量,将串口相关的数据处理代码,放到主线程中,也就是main函数的while循环中。从串口接收到的数据按照设计的数据格式存储到对应的缓冲区中,然后将帧类型、帧格式、帧ID、数据长度、数据在串口调试助手上打印出来,让使用者明确自己实际发送了什么,用作后期查看。同时将数据发给CAN外设,然后CAN外设将数据发送出去(帧ID为大端格式,注意CAN报文的发送为大端格式,使用者发送报文时需要注意)。
- CAN数据接收及处理 + UART数据发送
- CAN外设检测到CAN数据到来之后,触发CAN数据接收中断,本例程采用FIFO1接收数据,接收到数据之后,进入中断回调函数,再将这些数据放到接收数据缓冲区中,并记录接收轮数,使能CAN数据接收标志,然后将接收数据缓冲区中的数据通过串口打印到串口调试助手中,并初始化缓冲区以及标志位等等。
- 串口调试助手中的数据显示格式为:
- 发送:out num: 发送轮数 Frame type:DATA Frame format:STD FrameID:帧 ID datalength:数据量 data:(发送的数据)xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx ...(每8位数据为一组展示)
- 接收:in num: 接收轮数 FrameID:帧 ID datalength:数据量 data:(接收的数据)xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx ...(每8位数据为一组展示)
1、main.c
#include "usart_drive.h"
#include "can_drive.h"extern DataType rx_data;
extern CAN_TxHeaderTypeDef TxHeader;
uint16_t tmp = 0 ;int main(void)
{/* USER CODE BEGIN 1 */
uint32_t TxMailbox0 = CAN_TX_MAILBOX0 ;
uint32_t TxMailbox1 = CAN_TX_MAILBOX1 ;
uint32_t TxMailbox2 = CAN_TX_MAILBOX2 ;/* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();MX_CAN_Init();/* USER CODE BEGIN 2 */can_filterconfig_and_init();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */HAL_UARTEx_ReceiveToIdle_IT(&huart1,rx_data.data,sizeof(rx_data.data));while (1){/*******************************************UART数据接收及处理 + CAN数据发送***********************************************/if(recv_flag ==1){//帧数据长度 = 串口接收的数据量 - 2(帧ID 2);rx_data.Length = data_size - 2; tmp = (rx_data.Length) / 24;//帧IDrx_data.std_id = (rx_data.data[0]<<8)|rx_data.data[1];printf("out\tnum:%d\tFrame type:DATA\tFrame format:STD\tFrameID:%x\tdatalength:%d\t data:", rx_data.num ,rx_data.std_id , rx_data.Length );for(int i = 0 ; i < rx_data.Length ; i++ ){printf("%x ",rx_data.data[i+2]);}printf("\t\n");//CAN发送设置HAL_CAN_ActivateNotification(&hcan,CAN_IT_TX_MAILBOX_EMPTY);if(rx_data.Length == 24){HAL_CAN_TxMessageConfig(0,rx_data.std_id,CAN_ID_STD,CAN_RTR_DATA,8);HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-8],&TxMailbox0);HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-16],&TxMailbox1); HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-24],&TxMailbox2); HAL_Delay(1);}else if((rx_data.Length % 24)>16&&(rx_data.Length % 24)<24){HAL_CAN_TxMessageConfig(0,rx_data.std_id,CAN_ID_STD,CAN_RTR_DATA,8);for(int i = 0 ; i < tmp ; i++ ){HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-8-(i*24)],&TxMailbox0);HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-16-(i*24)],&TxMailbox1); HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-24-(i*24)],&TxMailbox2); HAL_Delay(1);}HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size - 8],&TxMailbox0);HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size - 16],&TxMailbox1);HAL_CAN_TxMessageConfig(0,rx_data.std_id,CAN_ID_STD,CAN_RTR_DATA,(rx_data.Length % 24)-16);HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[2],&TxMailbox1);}else if((rx_data.Length % 24)>8&&(rx_data.Length % 24)<=16){HAL_CAN_TxMessageConfig(0,rx_data.std_id,CAN_ID_STD,CAN_RTR_DATA,8);for(int i = 0 ; i < tmp ; i++ ){HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-8-(i*24)],&TxMailbox0);HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-16-(i*24)],&TxMailbox1); HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-24-(i*24)],&TxMailbox2); HAL_Delay(1);}HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size - 8],&TxMailbox1);HAL_CAN_TxMessageConfig(0,rx_data.std_id,CAN_ID_STD,CAN_RTR_DATA,((rx_data.Length % 24)-8));HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[2],&TxMailbox2);}else if((rx_data.Length % 24) <= 8 ){HAL_CAN_TxMessageConfig(0,rx_data.std_id,CAN_ID_STD,CAN_RTR_DATA,8);for(int i = 0 ; i < tmp ; i++ ){HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-8-(i*24)],&TxMailbox0);HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-16-(i*24)],&TxMailbox1); HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[data_size-24-(i*24)],&TxMailbox2); HAL_Delay(1);}HAL_CAN_TxMessageConfig(0,rx_data.std_id,CAN_ID_STD,CAN_RTR_DATA,(rx_data.Length % 24));HAL_CAN_AddTxMessage(&hcan,&TxHeader,&rx_data.data[2],&TxMailbox0);}//数据初始化for(int i = 0 ; i < data_size ; i++ ){rx_data.data[i] = 0;}tmp = 0;rx_data.Length = 0;rx_data.std_id = 0;rx_data.num ++;recv_flag = 0;}
/*******************************************CAN数据接收处理***********************************************/if(can_it_flag == 1){printf("in\tnum:%d\tFrameID:%x\tdatalength:%d\t data:", can_rx_mun ,RxHeader.StdId , RxHeader.DLC );for (size_t i = 0; i < (8*can_rx_mun); i++){if((i%8) == 0){printf("\t");}printf("%x ",can_data[i]);can_data[i] = 0;}printf("\t\n");can_it_flag = 0;can_updata = 0;can_rx_mun = 0;}HAL_GPIO_TogglePin(led_GPIO_Port,led_Pin);HAL_Delay(500);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}
2、usart_drive.c
#include "usart_drive.h"
#include "usart.h"
//缓存串口接收数据的数据量
uint16_t data_size = 0;
//串口接收标志
uint8_t recv_flag = 0;
/****************** printf重定向 *******************/
int fputc(int ch, FILE *f)
{ HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);while(__HAL_UART_GET_FLAG(&huart1 , UART_FLAG_TXE ) == RESET);return ch;
}int fgetc(FILE *f)
{uint8_t ch = 0;HAL_UART_Receive(&huart1,&ch,1,0xFFFF);while(__HAL_UART_GET_FLAG(&huart1 , UART_FLAG_RXNE ) == RESET);return ch;
}
/*********** 串口数据接收中断回调函数 ***************/
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if(huart == &huart1){data_size = Size;recv_flag = 1;HAL_UARTEx_ReceiveToIdle_IT(&huart1,rx_data.data,sizeof(rx_data.data));}
}
3、usart_drive.h
#ifndef USART_DRIVE_H
#define USART_DRIVE_H#ifdef __cplusplus
extern "C" {
#endif
#include "stdio.h"
#include "stdint.h"extern uint16_t data_size;
extern uint8_t recv_flag;
//接收的数据格式为:标准数据帧ID(xx xx) + 数据(xx xx xx xx xx . . .)
//比如CAN ID为0x123,发送数据为(十六进制):1 2 3 4 5 6 7 8 9 10 11 12,则直接在串口调试助手输入1 23 1 2 3 4 5 6 7 8 9 10 11 12即可
//接收数据缓存区结构体定义
typedef struct datatype
{uint16_t num; //接收数据次数uint16_t std_id; //标准帧IDuint16_t Length; //接收数据量uint8_t data[2048]; //接收数据缓冲区,定义为2K,根据自己需要定义即可
}DataType;#ifdef __cplusplus
}
#endif
#endif /*USART_DRIVE_H */
4、can_drive.c
#include "can_drive.h"CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
//CAN接收数据缓冲区
uint8_t can_data[512] = {0};
//CAN接收数据的轮数
uint32_t can_rx_mun = 0;
//CAN接收数据更新记录
uint32_t can_updata = 0;
//CAN接收中断触发标志
uint16_t can_it_flag = 0;//CAN发送报文结构体配置函数
HAL_StatusTypeDef HAL_CAN_TxMessageConfig(uint32_t EXTID, uint32_t STDID, uint8_t IDE, uint8_t RTR, uint8_t DLC)
{TxHeader.ExtId = EXTID;TxHeader.RTR = RTR;TxHeader.IDE = IDE;TxHeader.DLC = DLC;TxHeader.TransmitGlobalTime = DISABLE;TxHeader.StdId = STDID;if(HAL_CAN_Start(&hcan) != HAL_OK) //启动CAN{return HAL_ERROR;}return HAL_OK;
}void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan)
{}
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan)
{printf("can error!!! \n");
}
//CAN过滤器初始化
void can_filterconfig_and_init(void)
{
//例程选择不使用过滤器CAN_FilterTypeDef filter;filter.FilterIdHigh = 0x0000;filter.FilterIdLow = 0x0000;filter.FilterMaskIdHigh = 0x0000;filter.FilterMaskIdLow = 0x0000;filter.FilterFIFOAssignment = CAN_FILTER_FIFO1;filter.FilterActivation = ENABLE;filter.FilterMode = CAN_FILTERMODE_IDMASK;filter.FilterScale = CAN_FILTERSCALE_32BIT;filter.FilterBank = 0;//filter.SlaveStartFilterBank =14;if(HAL_CAN_ConfigFilter(&hcan,&filter) != HAL_OK){Error_Handler();} if(HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO1_MSG_PENDING) != HAL_OK){Error_Handler();} if(HAL_CAN_Start(&hcan) != HAL_OK){Error_Handler();}
}void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan)
{uint8_t RxData[8] = {0};HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO1,&RxHeader,RxData);for(int i = 0; i < 8; i++){can_data[(can_rx_mun * 8) + i] = RxData[i];}can_rx_mun++;can_it_flag = 1;}
5、can_drive.h
#ifndef CAN_DRIVE_H
#define CAN_DRIVE_H#ifdef __cplusplus
extern "C" {
#endif#include "can.h"
#include "usart.h"extern CAN_TxHeaderTypeDef TxHeader;
extern CAN_RxHeaderTypeDef RxHeader;
extern uint8_t can_data[512]; //CAN接收数据缓冲区
extern uint32_t can_rx_mun; //数据接收轮数
extern uint32_t can_updata; //CAN接收数据更新记录
extern uint16_t can_it_flag; //CAN接收中断触发标志HAL_StatusTypeDef HAL_CAN_TxMessageConfig(uint32_t EXTID, uint32_t STDID, uint8_t IDE, uint8_t RTR, uint8_t DLC);void can_filterconfig_and_init(void);#ifdef __cplusplus
}
#endif
#endif /* CAN_DRIVE_H */