微信公众号关注:掌芯元器,免费为大家提供嵌入式相关的技术咨询!!!
上篇文章:
一种简易CAN数据分析器的实现(一)【工程创建+CAN波特率计算工具】-CSDN博客
目录
四、代码功能实现
创建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;
//帧ID
rx_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; //标准帧ID
uint16_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 */