一种简易CAN数据分析器的实现(二)【代码实现】

微信公众号关注:掌芯元器,免费为大家提供嵌入式相关的技术咨询!!!

上篇文章:

一种简易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;
            //帧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 */ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值