一种多机通信实现方案-不带操作系统

本文介绍了一种适用于多机通信的嵌入式系统设计方案,主要涉及CAN总线和串口通信。通过驱动层、协议层、设备层和应用层的详细设计,实现了一个具有高可移植性的通信框架。协议层中定义了数据帧格式,包括Magic、Length、CRC16、Type、Sequence等字段,确保了通信的可靠性和效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在许多嵌入式项目中都会涉及板卡、设备之间的通信,其大致可以分为两类:

一类是一主多从形式,一台机器位主机,其余都是从机;其特点大致为:各个从机不会主动跟主机通信,由主机向各个从机发起通信;常见于RS485通信;

另一类是无所谓主机从机形式,典型案例如CAN总线通信;但更多场景可能是一个主控板通过网口与后台服务器通信、通过N个串口与N个控制板通信、通过一个CAN口与多个采样板通信……其特点包括:

  • 通信介质多样化;

  • 通信介质固定:一旦需求确定一般不会再增加或删除某种通信介质;

本文要描述的通信场景如下图所示:

图中主控板需要通过CAN总线与显示板、控制板、采样板等板卡通信,同时还需要通过串口1与扩展板通信、通过串口2与电源板通信。本文通过实现主控板与其它板卡通信搭建一种可移植性较高的通信框架。

一、通信架构

CAN的接收需要配置筛选器,用于筛选出本板卡感兴趣的数据帧;这里筛选方式有两种:

筛选ID设置为本机板卡ID,那么其它机器要

二、驱动层

COMDriver.h

/*******************************************************************************
 * COMDriver.h
 ******************************************************************************/

#ifndef COM_DRIVER_H_
#define COM_DRIVER_H_

#ifdef __cplusplus
extern "C" {
#endif

/*******************************************************************************
 * include
 ******************************************************************************/
#include "MC_TypeDef.h"

/*******************************************************************************
 * global type define
 ******************************************************************************/
typedef enum
{
    BOARD_MAIN = 1,
    BOARD_UI,
    BOARD_CONTROL,
    BOARD_SAMPLE,
    BOARD_POWER,
    BOARD_EXTEND,
    
    BOARD_NUM
}BOARD_ID; // 需要为每一个板卡分配一个唯一的ID

#define LOCAL_BOARD_ID  BOARD_MAIN

/*******************************************************************************
 * global variable declaration
 ******************************************************************************/

/*******************************************************************************
 * global function declaration
 ******************************************************************************/

#ifdef __cplusplus
}
#endif

#endif /* COM_DRIVER_H_ */

CAN驱动,can_ex.c:

/*******************************************************************************
 * can_ex.c
 ******************************************************************************/
#include "can.h"
#include "can_ex.h"

/*******************************************************************************
 * Private define
 ******************************************************************************/
#define ID_MASK 0x00FF
#define H_CAN   (&hcan1)

/*******************************************************************************
 * Private typedef
 ******************************************************************************/
typedef void (* Callback)(uint8_t board_id, uint8_t *p_data, uint8_t size);

/*******************************************************************************
 * Private function declaration
 ******************************************************************************/
static CAN_HandleTypeDef* getCAN(uint8_t dst_id);

static uint8_t waitTxFree(CAN_HandleTypeDef *hcan, uint8_t timeout);
static void configFilter(CAN_HandleTypeDef* hcan, uint8_t local_id);

/*******************************************************************************
 * Private variable define
 ******************************************************************************/
static Callback pFunRxCallback = NULL;

/*******************************************************************************
 * global function define
 ******************************************************************************/
void CAN_Init(void *param)
{
    pFunRxCallback = (Callback)param;
    
    configFilter(H_CAN, LOCAL_BOARD_ID);

    if (HAL_OK == HAL_CAN_Start(H_CAN))
    {
        HAL_CAN_ActivateNotification(H_CAN, CAN_IT_RX_FIFO0_MSG_PENDING); // 打开接收中断
    }
}

uint16_t CAN_Send(uint8_t dst_id, const uint8_t *p_data, uint16_t size)
{
    uint32_t txMailbox = 0;
    int16_t remain = size;
    CAN_TxHeaderTypeDef header;
    
    CAN_HandleTypeDef* hcan = getCAN(dst_id);
    if(NULL == hcan)
    {
        return 0;
    }
    
    header.ExtId = (LOCAL_BOARD_ID << 4)|dst_id;
    header.IDE   = CAN_ID_EXT;
    header.RTR   = CAN_RTR_DATA;
    header.TransmitGlobalTime = ENABLE;

    if(FALSE == waitTxFree(hcan, 100))
    {
        return 0;
    }
        
    while (remain > 0)
    {
        if(remain > 8)
        {
            header.DLC = 8;
        }
        else
        {
            header.DLC = remain;
        }
        remain -= header.DLC;
        
        if (HAL_OK != HAL_CAN_AddTxMessage(hcan, &header, (UINT8 *)p_data, &txMailbox))
        {
            return 0;
        }
        
        if(FALSE == waitTxFree(hcan, 100))
        {
            return 0;
        }
    }

    return size;
}

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    CAN_RxHeaderTypeDef header = {0};
    uint8_t data[8] = {0};
    
    if(HAL_OK == HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &header, data)) 
    {
        if(CAN_ID_EXT == header.IDE)
        {
            if(NULL != pFunRxCallback) 
            {
                uint8_t board = (header.ExtId >> 4)&ID_MASK;
                
                pFunRxCallback(board, data, header.DLC); // 根据扩展ID将接收到的数据插入对应的接收缓冲区中
            }
        }
    }
}

/*******************************************************************************
 * Private function define
 ******************************************************************************/
// 扩展ID的低4位用于表示数据的目的地(即数据是发给谁的)
// 扩展ID的其余位用于表示数据的来源地(即数据是谁发的)
// 筛选扩展帧、筛选器尺度为32位、掩码模式、筛选器分配到FIFO0上
static void configFilter(CAN_HandleTypeDef* hcan
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值