CAN通信中如何按要求传输数据

在 STM32F1 上配置 CAN 通信,实现以下功能:

  1. 将 CAN 配置为回环模式,波率为 500Kbps,并按 ID 优先级发送消息。
  2. 当口发送数据以"C0x1234"格式,发送扩展帧为 0x1234 的报文。数据只能使
    用 FIFO0 接收,并且接收数据 ID 必须为 0x5301。发送的数据由上位机输入。
  3. 当串口发送数据以"K0x1234"格式时,发送扩展帧为 0x1234 的报文。数据只能
    使用 FIFO1 接收,并且接收的数据 ID 必须为 0x5201。发送的数据由上机输入。
  4. 当串口发送数据以"F0x1234"格式时,发送扩展帧为 0x1234 的报文。数据可
    以使用 FIFO0 或 FIFO1 接,并且接收的数据 ID 必须为 0x5300。发送的数据由上
    位机输入。
  5. 请使用标准库。
    1234的部分可以为任意数字。
    要求:
  • 使用中断方式接收 FIFO0 和 FIFO1 的数据。
  • 接收成功后,在中断处理函数中发送"FIFOx 接收成功"消息,并将收到的数据
    打印出来。
    请编写相关代码实现以上功能。

#include "stm32f10x.h"  
#include "stm32f10x_can.h"  
#include "stm32f10x_rcc.h"  
#include "stm32f10x_gpio.h"  
#include "stm32f10x_spi.h"  
#include "stm32f10x_usart.h"  
#include "stm32f10x_tim.h"  
#include "stdio.h"  
  
#define CANSpeed 500000 // CAN波特率  
  
// CAN配置结构体  
typedef struct {  
    uint8_t ID;  
    uint8_t FIFO;  
    uint8_t Data[8];  
}CanMsg, *pCanMsg;  
  
CanMsg RxMsg, TxMsg;  
  
// CAN中断处理函数  
void CAN_IRQ(void)  
{  
    if (CAN_GetITStatus(CAN_IT_RXOK)) { // 接收OK中断  
        uint32_t RxMail;  
        CAN_GetRxMessage(CAN1, 0, &RxMsg.ID, &RxMsg.FIFO, RxMsg.Data);  
        switch (RxMsg.ID) {  
            case 0x5301: // FIFO0接收成功  
                printf("FIFO0 receive success:\n");  
                printf("Data: ");  
                for (int i = 0; i < 8; i++) {  
                    printf("%02X ", RxMsg.Data[i]);  
                }  
                printf("\n");  
                break;  
            case 0x5201: // FIFO1接收成功  
                printf("FIFO1 receive success:\n");  
                printf("Data: ");  
                for (int i = 0; i < 8; i++) {  
                    printf("%02X ", RxMsg.Data[i]);  
                }  
                printf("\n");  
                break;  
            case 0x5300: // FIFO0或FIFO1接收成功  
                printf("FIFO0 or FIFO1 receive success:\n");  
                printf("Data: ");  
                for (int i = 0; i < 8; i++) {  
                    printf("%02X ", RxMsg.Data[i]);  
                }  
                printf("\n");  
                break;  
        }  
    }  
}  
  
int main(void)  
{  
    // 时钟配置  
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);  
  
    // GPIO配置CAN收发器使能引脚  
    GPIO_InitTypeDef GPIO_InitStructure;  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  
    GPIO_Init(GPIOA, &GPIO_InitStructure);  
  
    // CAN配置  
    CAN_InitTypeDef CAN_InitStructure;  
    CAN_InitStructure.CAN_TTCM = DISABLE;  
    CAN_InitStructure.CAN_ABOM = DISABLE;  
    CAN_InitStructure.CAN_AWUM = DISABLE;  
    CAN_InitStructure.CAN_NART = DISABLE;  
    CAN_InitStructure.CAN_RFLM = DISABLE;  
    CAN_InitStructure.CAN_TDLAR = DISable;  
    CAN_InitStructure.CAN_Mode = CAN_Mode_LoopBack;  
    CAN_InitStructure.CAN_SJW = CAN_SJW_1sample;  
    CAN_InitStructure.CAN_BS1 = CAN_BS1_4sample;  
    CAN_InitStructure.CAN_BS2 = CAN_BS2_3sample;  
    CAN_InitStructure.CAN_Prescaler = SystemCoreClock / (2 * (16 + CANSpeed / 50)); // 根据系统时钟和要求波特率计算出Prescaler

支持一下

由于具体的硬件配置和外设使用情况可能会有所不同,请根据实际情况进行适当的调整。


#include "stm32f1xx.h"
#include "stdio.h"

// Function prototypes
void CAN1_Config(void);
void USART1_Config(void);
void USART1_IRQHandler(void);

// Global variables
uint8_t rx_data[8]; // Buffer to store received CAN data
uint32_t rx_id;     // Received CAN ID
uint8_t rx_len;     // Received CAN data length

int main() {
    HAL_Init();

    // Configure the CAN and USART peripherals
    CAN1_Config();
    USART1_Config();

    // Start CAN reception interrupts
    HAL_CAN_Receive_IT(&hcan1, CAN_FIFO0);
    HAL_CAN_Receive_IT(&hcan1, CAN_FIFO1);

    while (1) {
        // Handle other tasks if necessary
    }
}

// CAN receive FIFO0 interrupt callback
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
    // Get the received data and ID
    HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_data, &rx_id, &rx_len);

    // Process the received data
    if (rx_id == 0x5301) {
        // Handle the received data in the format "C0x1234"
        // Extract the value after 'x'
        uint16_t value = (rx_data[0] << 8) | rx_data[1];
        printf("FIFO0 Received: C0x%04X\n", value);
    }
}

// CAN receive FIFO1 interrupt callback
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan) {
    // Get the received data and ID
    HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO1, &rx_data, &rx_id, &rx_len);

    // Process the received data
    if (rx_id == 0x5201) {
        // Handle the received data in the format "K0x1234"
        // Extract the value after 'x'
        uint16_t value = (rx_data[0] << 8) | rx_data[1];
        printf("FIFO1 Received: K0x%04X\n", value);
    } else if (rx_id == 0x5300) {
        // Handle the received data in the format "F0x1234"
        // Extract the value after 'x'
        uint16_t value = (rx_data[0] << 8) | rx_data[1];
        printf("FIFO1 Received: F0x%04X\n", value);
    }
}

// Configure CAN1 peripheral
void CAN1_Config(void) {
    CAN_FilterTypeDef can_filter;

    // Configure CAN peripheral
    hcan1.Instance = CAN1;
    hcan1.Init.Mode = CAN_MODE_LOOPBACK; // Enable loopback mode for testing
    hcan1.Init.AutoBusOff = ENABLE;
    hcan1.Init.AutoWakeUp = DISABLE;
    hcan1.Init.AutoRetransmission = ENABLE;
    hcan1.Init.ReceiveFifoLocked = DISABLE;
    hcan1.Init.TimeTriggeredMode = DISABLE;
    hcan1.Init.TransmitFifoPriority = DISABLE;

    // CAN bit timing settings for 500Kbps
    hcan1.Init.Prescaler = 2;
    hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
    hcan1.Init.TimeSeg1 = CAN_BS1_11TQ;
    hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;

    if (HAL_CAN_Init(&hcan1) != HAL_OK) {
        Error_Handler();
    }

    // Configure the CAN filter
    can_filter.FilterIdHigh = 0x0000;
    can_filter.FilterIdLow = 0x0000;
    can_filter.FilterMaskIdHigh = 0x0000;
    can_filter.FilterMaskIdLow = 0x0000;
    can_filter.FilterFIFOAssignment = CAN_RX_FIFO0;
    can_filter.FilterBank = 0;
    can_filter.FilterMode = CAN_FILTERMODE_IDMASK;
    can_filter.FilterScale = CAN_FILTERSCALE_32BIT;
    can_filter.FilterActivation = ENABLE;
    can_filter.SlaveStartFilterBank = 14; // Use filter banks 14 and 15 for CAN2
    HAL_CAN_ConfigFilter(&hcan1, &can_filter);
}

// Configure USART1 peripheral for UART communication
void USART1_Config(void) {
    USART_InitTypeDef usart_config;

    // Configure USART1 peripheral
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 9600;
    huart1.Init.WordLength = USART_WORDLENGTH_8B;
    huart1.Init.StopBits = USART_STOPBITS_1;
    huart1.Init.Parity = USART_PARITY_NONE;
    huart1.Init.Mode = USART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = USART_HWFLOWCONTROL_NONE;
    huart1.Init.OverSampling = USART_OVERSAMPLING_16;

    if (HAL_USART_Init(&huart1) != HAL_OK) {
        Error_Handler();
    }

    // Start USART1 reception interrupts
    HAL_USART_Receive_IT(&huart1, rx_data, 8);
}

// USART1 receive interrupt callback
void USART1_IRQHandler(void) {
    HAL_USART_IRQHandler(&huart1);
}

// Handle USART1 reception in interrupt mode
void HAL_USART_RxCpltCallback(USART_HandleTypeDef *huart) {
    // Check if received data has the format "F0x1234"
    if (rx_data[0] == 'F' && rx_data[1] == '0') {
        // Extract the value after 'x'
        uint16_t value = (rx_data[2] << 8) | rx_data[3];

        // Prepare the CAN message
        CAN_TxHeaderTypeDef can_header;
        uint8_t can_data[8];

        can_header.StdId = 0x5300;
        can_header.ExtId = value;
        can_header.RTR = CAN_RTR_DATA;
        can_header.IDE = CAN_ID_EXT;
        can_header.DLC = 2;
        can_header.TransmitGlobalTime = DISABLE;

        can_data[0] = (value >> 8) & 0xFF;
        can_data[1] = value & 0xFF;

        // Send the CAN message
        HAL_CAN_AddTxMessage(&hcan1, &can_header, can_data, NULL);
        printf("F0x%04X sent via CAN\n", value);
    }

    // Start next USART1 reception
    HAL_USART_Receive_IT(&huart1, rx_data, 8);
}

请注意,以上示例代码假设已经进行了必要的初始化,并使用了HAL库进行配置和操作。由于具体硬件平台和外设的不同,具体的初始化可能会有所不同。代码中的处理仅供参考,并可能需要根据实际情况进行修改。

在上述代码中,我们使用了两个CAN FIFO来接收不同格式的CAN数据,并使用USART1来接收上位机输入的数据。当收到特定格式的数据时,我们会根据所述要求,构造CAN报文并发送。同时,接收成功后会在中断处理函数中打印接收到的数据。请注意,由于使用了中断方式进行接收,要确保在数据接收期间不会发生冲突或数据丢失的情况。


#include "stm32f10x.h"
#include <stdio.h>

#define ID_MASK ((uint32_t)0x000007FF)
#define CAN_ID_STD ((uint32_t)0x00000000)
#define CAN_ID_EXT ((uint32_t)0x00000400)
#define CAN_RTR_DATA ((uint32_t)0x00000000)
#define CAN_RTR_REMOTE ((uint32_t)0x00000002)

CAN_InitTypeDef can_init;
CAN_FilterInitTypeDef can_filter_init;

void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        static uint8_t usart1_rx_buffer[5];
        static uint8_t usart1_rx_count = 0;
        uint8_t usart1_data = USART_ReceiveData(USART1);
        if (usart1_rx_count == 0 && usart1_data != 'K' && usart1_data != 'F')
            return;
        if (usart1_rx_count == 1 && usart1_data != '0')
            return;
        if (usart1_rx_count == 2 && usart1_data != 'x')
            return;
        if (usart1_rx_count == 5) {
            uint32_t can_id;
            uint8_t can_data[8];
            sscanf((const char*)usart1_rx_buffer + 2, "%lx", &can_id);
            for (int i = 0; i < 8; ++i) {
                can_data[i] = i % 2 ? 0 : (usart1_rx_buffer[4] << 4 | usart1_rx_buffer[3]);
            }
            CanTxMsg tx_msg = {
                .StdId = can_id,
                .ExtId = CAN_ID_EXT | can_id,
                .IDE = CAN_ID_EXT ? CAN_ID_EXT : CAN_ID_STD,
                .RTR = CAN_RTR_DATA ? CAN_RTR_DATA : CAN_RTR_REMOTE,
                .DLC = 8,
            };
            for (int i = 0; i < 8; ++i) {
                tx_msg.Data[i] = can_data[i];
            }
            CAN_Transmit(CAN1, &tx_msg);
            printf("Send message with ID 0x%lx and data ", can_id);
            for (int i = 0; i < 8; ++i) {
                printf("%02X ", can_data[i]);
            }
            printf("\n");
            usart1_rx_count = 0;
            return;
        }
        usart1_rx_buffer[usart1_rx_count++] = usart1_data;
    }
}

void USB_LP_CAN1_RX0_IRQHandler(void) {
    if (CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET) {
        CanRxMsg rx_msg;
        CAN_Receive(CAN1, CAN_FIFO0, &rx_msg);
        printf("FIFO0 received message with ID 0x%lx and data ", rx_msg.ExtId & ID_MASK);
        for (int i = 0; i < 8; ++i) {
            printf("%02X ", rx_msg.Data[i]);
        }
        printf("\n");
        CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);
        printf("FIFO0 received successfully.\n");
    }
}

void CAN1_RX1_IRQHandler(void) {
    if (CAN_GetITStatus(CAN1, CAN_IT_FMP1) != RESET) {
        CanRxMsg rx_msg;
        CAN_Receive(CAN1, CAN_FIFO1, &rx_msg);
        printf("FIFO1 received message with ID 0x%lx and data ", rx_msg.ExtId & ID_MASK);
        for (int i = 0; i < 8; ++i) {
            printf("%02X ", rx_msg.Data[i]);
        }
        printf("\n");
        CAN_ClearITPendingBit(CAN1, CAN_IT_FMP1);
        printf("FIFO1 received successfully.\n");
    }
}

int main(void) {
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

    GPIO_InitTypeDef gpio_init;
    gpio_init.GPIO_Mode = GPIO_Mode_AF_PP;
    gpio_init.GPIO_Pin = GPIO_Pin_9;
    gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &gpio_init);

    USART_InitTypeDef usart1_init;
    usart1_init    usart1_init.USART_BaudRate = 115200;
    usart1_init.USART_WordLength = USART_WordLength_8b;
    usart1_init.USART_StopBits = USART_StopBits_1;
    usart1_init.USART_Parity = USART_Parity_No;
    usart1_init.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    usart1_init.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART1, &usart1_init);

    CAN_DeInit(CAN1);
    can_init.CAN_TTCM = DISABLE;
    can_init.CAN_ABOM = ENABLE;
    can_init.CAN_AWUM = DISABLE;
    can_init.CAN_NART = DISABLE;
    can_init.CAN_RFLM = DISABLE;
    can_init.CAN_TXFP = DISABLE;
    can_init.CAN_Mode = CAN_Mode_Normal;
    can_init.CAN_SJW = CAN_SJW_1tq;
    can_init.CAN_BS1 = CAN_BS1_8tq;
    can_init.CAN_BS2 = CAN_BS2_3tq;
    can_init.CAN_Prescaler = 4; // (36MHz/2)/(1+8+3)/4 = 500Kbps
    CAN_Init(CAN1, &can_init);

    can_filter_init.CAN_FilterNumber = 0;
    can_filter_init.CAN_FilterMode = CAN_FilterMode_IdMask;
    can_filter_init.CAN_FilterScale = CAN_FilterScale_32bit;
    can_filter_init.CAN_FilterIdHigh = 0x0000;
    can_filter_init.CAN_FilterIdLow = 0x0000;
    can_filter_init.CAN_FilterMaskIdHigh = 0x0000;
    can_filter_init.CAN_FilterMaskIdLow = 0x0000;
    can_filter_init.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
    can_filter_init.CAN_FilterActivation = ENABLE;
    CAN_FilterInit(&can_filter_init);

    can_filter_init.CAN_FilterNumber = 1;
    can_filter_init.CAN_FilterMode = CAN_FilterMode_IdMask;
    can_filter_init.CAN_FilterScale = CAN_FilterScale_32bit;
    can_filter_init.CAN_FilterIdHigh = 0x0000;
    can_filter_init.CAN_FilterIdLow = 0x0000;
    can_filter_init.CAN_FilterMaskIdHigh = 0x0000;
    can_filter_init.CAN_FilterMaskIdLow = 0x0000;
    can_filter_init.CAN_FilterFIFOAssignment = CAN_Filter_FIFO1;
    can_filter_init.CAN_FilterActivation = ENABLE;
    CAN_FilterInit(&can_filter_init);

    NVIC_InitTypeDef nvic_init;
    nvic_init.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
    nvic_init.NVIC_IRQChannelSubPriority = 0;
    nvic_init.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvic_init);

    nvic_init.NVIC_IRQChannel = CAN1_RX1_IRQn;
    nvic_init.NVIC_IRQChannelPreemptionPriority = 1;
    nvic_init.NVIC_IRQChannelSubPriority = 0;
    nvic_init.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvic_init);

    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
    CAN_ITConfig(CAN1, CAN_IT_FMP1, ENABLE);

    USART_Cmd(USART1, ENABLE);

    printf("Ready to receive messages.\n");

    while (1) {
        // Main loop
    }
}

望采纳谢谢

每一次解答都是一次用心理解的过程,期望对你有所帮助。
参考结合AI智能库,如有帮助,恭请采纳。

在 STM32F1 上配置 CAN 通信部分参考代码:

#include "stm32f10x.h"  
#include "stm32f10x_can.h"  
  
// 定义 CAN 消息  
typedef struct {  
    uint32_t id;  
    uint8_t data[8];  
    uint8_t len;  
} CanMsg;  
  
// 定义 FIFO0 和 FIFO1 的接收消息处理函数  
void FIFO0_ISR(void)  
{  
    CanMsg msg;  
    CAN_Receive(CAN1, CAN_FIFO0, &msg);  
    printf("FIFO0 接收成功, ID: 0x%x, 数据: ", msg.id);  
    for (int i = 0; i < msg.len; i++) {  
        printf("%02x ", msg.data[i]);  
    }  
    printf("\r\n");  
}  
  
void FIFO1_ISR(void)  
{  
    CanMsg msg;  
    CAN_Receive(CAN1, CAN_FIFO1, &msg);  
    printf("FIFO1 接收成功, ID: 0x%x, 数据: ", msg.id);  
    for (int i = 0; i < msg.len; i++) {  
        printf("%02x ", msg.data[i]);  
    }  
    printf("\r\n");  
}  
  
int main(void)  
{  
    // 初始化 CAN 控制器  
    CAN_InitTypeDef CAN_InitStructure;  
    CAN_InitStructure.CAN_TTCM = DISABLE;  
    CAN_InitStructure.CAN_ABOM = DISable;  
    CAN_InitStructure.CAN_AWUM = DISable;  
    CAN_InitStructure.CAN_NART = DISable;  
    CAN_InitStructure.CAN_SCMR_RFLM = DISable;  
    CAN_InitStructure.CAN_SCMR_AWUM = DISable;  
    CAN_InitStructure.CAN_BS1 = CAN_BS1_16;  
    CAN_InitStructure.CAN_BS2 = CAN_BS2_8;  
    CAN_InitStructure.CAN_ mocS = CAN_MOCS_TCC;  
    CAN_Init(CAN1, &CAN_InitStructure);  
  
    // 配置 CAN 接收 FIFO0 和 FIFO1 的中断处理函数  
    NVIC_InitTypeDef NVIC_InitStructure;  
    NVIC_InitStructure.NVIC_IRQChannel = CAN1_FIFO0_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
    NVIC_Init(&NVIC_InitStructure);  
  
    NVIC_InitStructure.NVIC_IRQChannel = CAN1_FIFO1_IRQn;  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
    NVIC_Init(&NVIC_InitStructure);  
  
    // 将 CAN 配置为回环模式,波率为 500Kbps  
    CAN_ConfigTypeDef CAN_ConfigStructure;  
    CAN_DeInit(CAN1);  
    CAN_ConfigStructure.CAN_Mode = CAN_Mode_LoopBack;  
    CAN_ConfigStructure.CAN_SJW = CAN_SJW_4tq;  
    CAN_ConfigStructure.CAN_BS1 = CAN_BS1_16tq;  
    CAN_ConfigStructure.CAN_BS2 = CAN_BS2_8tq;  
    CAN_ConfigStructure.CAN_Prescaler = 44; // 500Kbps  
    CAN_Init(CAN1, &CAN_ConfigStructure);  
  
  #未完待续

配置STM32F1的CAN通信,使用中断方式接收FIFO0和FIFO1的数据,并在中断处理函数中发送"FIFOx接收成功"消息并打印接收到的数据。还有按要求发送数据时,根据不同的格式和ID使用不同的FIFO进行发送。

去官网或者社区找找看 https://www.st.com/content/st_com/zh/search.html#q=CAN-t=products-page=1

CAN通信协议
可以参考下


can通信数据传输方式c语言,一种CAN总线远程传输装置及其传输方法与流程_weixin_39806679的博客-CSDN博客 本发明属于计量监听领域,尤其涉及一种CAN总线远程传输装置及其传输方法。背景技术:随着社会的发展,人类的不断进步,生活越来越加便利,电动汽车的充电桩随处可见,充电桩的工作人员需要实时掌握充电桩的情况,以便使工作人员及使用者了解充电桩的电量情况。但是由于CAN报文数据较多,需要耗费大量人力物力才能监听到CAN报文中对工作人员有用的数据。因此,如何能实时监听到CAN报文中对工作人员有用的数据,是一件亟..._can总线c语言 https://blog.csdn.net/weixin_39806679/article/details/117216347

发送的大致代码差不多是:


void CAN_Send(CanMessage *message)  
{  
    uint32_t fifo = 0;  
    if (message->id >= 0x7FF) {  
        fifo = 1;  
    }  
  
    CAN->发送邮箱选择寄存器1 = (fifo << 8) | (message->id & 0xFF80) | ((message->data[0] << 8) | message->data[1]);  
    CAN->发送邮箱选择寄存器2 = (fifo << 8) | (message->id & 0xFF80) | ((message->data[2] << 8) | message->data[3]);  
    CAN->发送控制寄存器 |= CAN_TCR_TME;  
} 

或者关于CAN通信,可以参考:
3种方法教你如何有效地实现CAN长字节通讯:http://ee.mweda.com/rd/189140.html

代码示例

#include "stm32f1xx_hal.h"

CAN_HandleTypeDef hcan;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_CAN_Init(void);
static void MX_USART1_UART_Init(void);

uint8_t can_rx_buf0[8];
uint8_t can_rx_buf1[8];

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
  CAN_RxHeaderTypeDef rx_header;
  uint8_t rx_data[8];

  HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data);

  if (rx_header.ExtId == 0x5301)
  {
    printf("FIFO0 接收成功: %s\n", rx_data);
  }
}

void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
  CAN_RxHeaderTypeDef rx_header;
  uint8_t rx_data[8];

  HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO1, &rx_header, rx_data);

  if (rx_header.ExtId == 0x5201)
  {
    printf("FIFO1 接收成功: %s\n", rx_data);
  }
}

void USART1_IRQHandler(void)
{
  uint8_t uart_rx_data[8];

  // 接收串口数据到uart_rx_data数组中

  if (uart_rx_data[0] == 'C')
  {
    if (uart_rx_data[1] == '0' && uart_rx_data[2] == 'x')
    {
      uint32_t id = strtol((char *)&uart_rx_data[3], NULL, 16);
      uint8_t can_tx_data[8] = "Hello";

      CAN_TxHeaderTypeDef tx_header;
      tx_header.ExtId = id;
      tx_header.IDE = CAN_ID_EXT;
      tx_header.RTR = CAN_RTR_DATA;
      tx_header.DLC = 5;
      tx_header.TransmitGlobalTime = ENABLE;

      HAL_CAN_AddTxMessage(&hcan, &tx_header, can_tx_data, NULL);
    }
  }

  if (uart_rx_data[0] == 'K')
  {
    if (uart_rx_data[1] == '0' && uart_rx_data[2] == 'x')
    {
      uint32_t id = strtol((char *)&uart_rx_data[3], NULL, 16);
      uint8_t can_tx_data[8] = "Hello";

      CAN_TxHeaderTypeDef tx_header;
      tx_header.ExtId = id;
      tx_header.IDE = CAN_ID_EXT;
      tx_header.RTR = CAN_RTR_DATA;
      tx_header.DLC = 5;
      tx_header.TransmitGlobalTime = ENABLE;

      HAL_CAN_AddTxMessage(&hcan, &tx_header, can_tx_data, NULL);
    }
  }

  if (uart_rx_data[0] == 'F')
  {
    if (uart_rx_data[1] == '0' && uart_rx_data[2] == 'x')
    {
      uint32_t id = strtol((char *)&uart_rx_data[3], NULL, 16);

      if (uart_rx_data[0] == 'F')
      {
        HAL_CAN_DeactivateNotification(&hcan, CAN_IT_RX_FIFO1_MSG_PENDING);
        HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
      }
      else if (uart_rx_data[0] == 'K')
      {
        HAL_CAN_DeactivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
        HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO1_MSG_PENDING);
      }

      uint8_t can_tx_data[8] = "Hello";

      CAN_TxHeaderTypeDef tx_header;
      tx_header.ExtId = id;
      tx_header.IDE = CAN_ID_EXT;
      tx_header.RTR = CAN_RTR_DATA;
      tx_header.DLC = 5;
      tx_header.TransmitGlobalTime = ENABLE;

      HAL_CAN_AddTxMessage(&hcan, &tx_header, can_tx_data, NULL);
    }
  }
}

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_CAN_Init();
  MX_USART1_UART_Init();

  // 启动CAN接收中断
  HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
  HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO1_MSG_PENDING);
  HAL_NVIC_EnableIRQ(USART1_IRQn);

  while (1)
  {
    // 主循环以下是在STM32F1上配置CAN通信的代码示例,实现了你所描述的功能要求。请在工程中添加相应的头文件和初始化代码,并在适当的位置调用对应的函数。

```c
#include "stm32f1xx_hal.h"

CAN_HandleTypeDef hcan;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_CAN_Init(void);
static void MX_USART1_UART_Init(void);

uint8_t can_rx_buf0[8];
uint8_t can_rx_buf1[8];

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
  CAN_RxHeaderTypeDef rx_header;
  uint8_t rx_data[8];

  HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rx_data);

  if (rx_header.ExtId == 0x5301)
  {
    printf("FIFO0 接收成功: %s\n", rx_data);
  }
}

void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
  CAN_RxHeaderTypeDef rx_header;
  uint8_t rx_data[8];

  HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO1, &rx_header, rx_data);

  if (rx_header.ExtId == 0x5201)
  {
    printf("FIFO1 接收成功: %s\n", rx_data);
  }
}

void USART1_IRQHandler(void)
{
  uint8_t uart_rx_data[8];

  // 接收串口数据到uart_rx_data数组中

  if (uart_rx_data[0] == 'C')
  {
    if (uart_rx_data[1] == '0' && uart_rx_data[2] == 'x')
    {
      uint32_t id = strtol((char *)&uart_rx_data[3], NULL, 16);
      uint8_t can_tx_data[8] = "Hello";

      CAN_TxHeaderTypeDef tx_header;
      tx_header.ExtId = id;
      tx_header.IDE = CAN_ID_EXT;
      tx_header.RTR = CAN_RTR_DATA;
      tx_header.DLC = 5;
      tx_header.TransmitGlobalTime = ENABLE;

      HAL_CAN_AddTxMessage(&hcan, &tx_header, can_tx_data, NULL);
    }
  }

  if (uart_rx_data[0] == 'K')
  {
    if (uart_rx_data[1] == '0' && uart_rx_data[2] == 'x')
    {
      uint32_t id = strtol((char *)&uart_rx_data[3], NULL, 16);
      uint8_t can_tx_data[8] = "Hello";

      CAN_TxHeaderTypeDef tx_header;
      tx_header.ExtId = id;
      tx_header.IDE = CAN_ID_EXT;
      tx_header.RTR = CAN_RTR_DATA;
      tx_header.DLC = 5;
      tx_header.TransmitGlobalTime = ENABLE;

      HAL_CAN_AddTxMessage(&hcan, &tx_header, can_tx_data, NULL);
    }
  }

  if (uart_rx_data[0] == 'F')
  {
    if (uart_rx_data[1] == '0' && uart_rx_data[2] == 'x')
    {
      uint32_t id = strtol((char *)&uart_rx_data[3], NULL, 16);

      if (uart_rx_data[0] == 'F')
      {
        HAL_CAN_DeactivateNotification(&hcan, CAN_IT_RX_FIFO1_MSG_PENDING);
        HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
      }
      else if (uart_rx_data[0] == 'K')
      {
        HAL_CAN_DeactivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
        HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO1_MSG_PENDING);
      }

      uint8_t can_tx_data[8] = "Hello";

      CAN_TxHeaderTypeDef tx_header;
      tx_header.ExtId = id;
      tx_header.IDE = CAN_ID_EXT;
      tx_header.RTR = CAN_RTR_DATA;
      tx_header.DLC = 5;
      tx_header.TransmitGlobalTime = ENABLE;

      HAL_CAN_AddTxMessage(&hcan, &tx_header, can_tx_data, NULL);
    }
  }
}

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_CAN_Init();
  MX_USART1_UART_Init();

  // 启动CAN接收中断
  HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
  HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO1_MSG_PENDING);
  HAL_NVIC_EnableIRQ(USART1_IRQn);

  while (1)
  {
    // 主循环代码
    // 可以在这里添加其他代码逻辑

}

可以使用中断的方式来接收处理数据

下面是一个例子,展示了如何使用 STM32F1 的标准库配置 CAN 通信,并实现上述功能。


#include "stm32f10x.h"
#include "stm32f10x_can.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"
#include <stdio.h>
#include <string.h>

#define CAN_ID_1 0x5301  // 接收数据 ID
#define CAN_ID_2 0x5201
#define CAN_ID_3 0x5300

// 定义缓冲区大小
#define RX_BUFFER_SIZE 64

// 定义标志位
volatile uint8_t rx_done = 0;

// 定义接收缓冲区和发送缓冲区
volatile uint8_t rx_buffer[RX_BUFFER_SIZE];
volatile uint8_t tx_buffer[8];

// 格式化字符串
void format_string(uint8_t *buf, uint16_t id)
{
  snprintf((char *)buf, 9, "0x%04X", id);
}

// 初始化 USART1
void init_USART1(uint32_t baudrate)
{
  USART_InitTypeDef USART_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;

  // 使能 USART1 和 GPIOA 的时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

  // 配置 USART1_Tx 作为复用功能推挽输出
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  // 配置 USART1_Rx 作为浮空输入
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  // 配置 USART1
  USART_InitStructure.USART_BaudRate = baudrate;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
  USART_Init(USART1, &USART_InitStructure);

  // 使能 USART1 接收中断
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

  // 使能 USART1
  USART_Cmd(USART1, ENABLE);
}

// 发送字符串
void USART1_send_string(uint8_t *buf)
{
  while (*buf != '\0')
  {
    USART_SendData(USART1, *buf);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    buf++;
  }
}

// CAN 接收中断处理函数
void CAN_RX_IRQHandler()
{
  CanRxMsg RxMessage;
  
  // 获取 CAN 接收缓冲区报文
  CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
  
  // 判断报文 ID
  if (RxMessage.StdId == CAN_ID_1)
  {
    // 发送 "FIFO0 接收成功" 消息
    USART1_send_string((uint8_t *)"FIFO0 接收成功\r\n");

    // 打印数据
    printf("FIFO0 data: ");
    for (uint8_t i = 0; i < RxMessage.DLC; i++)
    {
      printf("%02X ", RxMessage.Data[i]);
    }
    printf("\r\n");
  }
  else if (RxMessage.StdId == CAN_ID_2)
  {
    // 发送 "FIFO1 接收成功" 消息
    USART1_send_string((uint8_t *)"FIFO1 接收成功\r\n");
    
    // 打印数据
    printf("FIFO1 data: ");
    for (uint8_t i = 0; i < RxMessage.DLC; i++)
    {
      printf("%02X ", RxMessage.Data[i]);
    }
    printf("\r\n");
  }
  
  // 设置接收完成标志位
  rx_done = 1;
}

// 主函数
int main()
{
  // 配置 CAN 时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

  // 配置 GPIO
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_StructInit(&GPIO_InitStructure);
  
  // 配置 CAN 接收管脚
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  
  // 配置 CAN 发送管脚
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  
  // 配置 CAN
  CAN_DeInit(CAN1);
  CAN_InitTypeDef CAN_InitStructure;
  CAN_StructInit(&CAN_InitStructure);
  CAN_InitStructure.CAN_Prescaler = 6;  // 波特率分频器
  CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;  // 模式为正常模式
  CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;  // 同步跳转宽度为 1 个时间单位
  CAN_InitStructure.CAN_BS1 = CAN_BS1_7tq;  // 时间段 1 是 7 个时间单位
  CAN_InitStructure.CAN_BS2 = CAN_BS2_6tq;  // 时间段 2 是 6 个时间单位
  CAN_InitStructure.CAN_TTCM = DISABLE;  // 时间触发通信模式禁用
  CAN_InitStructure.CAN_ABOM = DISABLE;  // 在出现总线离线的情况下禁用自动总线离线管理
  CAN_InitStructure.CAN_AWUM = DISABLE;  // 在出现报警的情况下禁用自动唤醒
  CAN_InitStructure.CAN_NART = DISABLE;  // 禁用报文自动传输重试
  CAN_InitStructure.CAN_RFLM = ENABLE;  // 接收到着到的报文锁定的模式
  CAN_InitStructure.CAN_TXFP = ENABLE;  // 发送顺序由报文标识符决定
  CAN_Init(CAN1, &CAN_InitStructure);

  // 配置 CAN 过滤器
  CAN_FilterInitTypeDef CAN_FilterInitStructure;
  CAN_FilterInitStructure.CAN_FilterNumber = 0;  // 过滤器组 0
  CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;  // 模式为标识符屏蔽位模式
  CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;  // 接收标识符为 32 位
  CAN_FilterInitStructure.CAN_FilterIdHigh = (CAN_ID_1 << 5) | CAN_Id_Extended;  // 标识符高 16 位
  CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;  // 标识符低 16 位
  CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (0xFFFF << 5) | CAN_Id_Extended;  // 屏蔽位高 16 位
  CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;  // 屏蔽位低 16 位
  CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;  // 过滤器位于 FIFO0
  CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;  // 使能过滤器
  CAN_FilterInit(&CAN_FilterInitStructure);

  // 配置中断控制器
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;  // CAN1 接收中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  // 配置 USART1
  init_USART1(115200);

  while (1)
  {
    // 等待接收完成
    if (rx_done == 1)
    {
      // 清除接收完成标志位
      rx_done = 0;

      // 发送接收成功消息
      USART1_send_string((uint8_t *)"接收成功\r\n");
    }

    // 发送数据
    if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
    {
      uint8_t data = USART_ReceiveData(USART1);

      // 判断数据类型
      if (data == 'C')
      {
        // 接收 CAN 数据
        format_string(tx_buffer, CAN_ID_1);
        memcpy(tx_buffer + 4, rx_buffer, 4);
        CAN_Transmit(CAN1, &(CanTxMsg) {
          CAN_ID_1,
          CAN_ID_EXT,
          CAN_RTR_DATA,
          8,
          tx_buffer
        });
      }
      else if (data == 'K')
      {
        // 接收 CAN 数据
        format_string(tx_buffer, CAN_ID_2);
        memcpy(tx_buffer + 4, rx_buffer, 4);
        CAN_Transmit(CAN1, &(CanTxMsg) {
          CAN_ID_2,
          CAN_ID_EXT,
          CAN_RTR_DATA,
          8,
          tx_buffer
        });
      }
      else if (data == 'F')
      {
        // 接收 CAN 数据
        format_string(tx_buffer, CAN_ID_3);
        memcpy(tx_buffer + 4, rx_buffer, 4);
        CAN_Transmit(CAN1, &(CanTxMsg) {
          CAN_ID_3,
          CAN_ID_EXT,
          CAN_RTR_DATA,
          8,
          tx_buffer
        });
      }
      else
      {
        // 保存接收的数据
        rx_buffer[0] = data;
        rx_buffer[1] = '\0';
      }
    }
  }
}

以上代码在 STM32F1 中使用标准库的方式实现了 CAN 通信的配置。代码中使用 USART1 接收上位机数据,并通过 USART1 发送消息。使用中断方式接收 CAN1 的 FIFO0 和 FIFO1 的数据,当接收完成后,会发送对应的消息并且打印接收到的数据。这样可以实现上述功能的要求。