(二)CAN通信协议代码-基础版

(1)CAN初始化函数


/* -------------------------- Filter global --------------------------*/
#define STDID 0
#define EXTID 1

/* 过滤器编号 */
static u8 filterNumber = 0;

/* 内部函数声明 */
void myCanFilterList(u8 can_dev, uint32_t* p_canId, int size, int flag);
u8 myCanFilterMask(u8 can_dev, uint32_t* p_canIdMask, int size, int flag);
u8 canIdSeparation(u8 can_dev, uint32_t* p_canId, int size, u8 filterMode);
u8 myFilter(u8 can_dev, u32* p_canId, u8 filterMode, u8 filterScale);

/* --- CANx 设备属性设置 --- */
typedef struct __can_port_t {
    u32 can_dev;
    gpio_pin_t tpin;
    gpio_pin_t rpin;
    u32 pin_map;
    u32 can_rcc;
    CAN_TypeDef* can_channel;
    u8 irq;
    u8 pre_priority;
    u8 sub_priority;
    u8 can_res;
    u32 IT_flag;
} can_port_t;

static can_port_t can_port[CAN_DEV_CNT] = {
    [CAN_DEV1] = {
        .can_dev = CAN_DEV1,
        .tpin = { GPIO_Pin_12, RCC_APB2Periph_GPIOA, GPIOA }, // CAN1_TX PA12
        .rpin = { GPIO_Pin_11, RCC_APB2Periph_GPIOA, GPIOA }, // CAN1_RX PA11
        .pin_map = 0,
        .can_rcc = RCC_APB1Periph_CAN1,
        .can_channel = CAN1,
        .irq = CAN1_RX0_IRQn,
        .pre_priority = 0,
        .sub_priority = 0,
        .IT_flag = CAN_IT_FMP0,
    },
    [CAN_DEV2] = {
        .can_dev = CAN_DEV2,
        .tpin = { GPIO_Pin_13, RCC_APB2Periph_GPIOB, GPIOB }, // CAN2_TX PB13
        .rpin = { GPIO_Pin_12, RCC_APB2Periph_GPIOB, GPIOB }, // CAN2_RX PB12
        .pin_map = 0,
        .can_rcc = RCC_APB1Periph_CAN2,
        .can_channel = CAN2,
        .irq = CAN1_RX1_IRQn,
        .pre_priority = 0,
        .sub_priority = 0,
        .IT_flag = CAN_IT_FMP1,
    }
};

/*--- 常用CAN波特率 ---*/
typedef struct __can_tq_t {
    u16 can_baudrate;
    u16 can_prescaler;
    u8 can_syn_jump_width;
    u8 can_time_bit_seg1;
    u8 can_time_bit_seg2;
    u8 can_res;
}can_tq_t;

typedef enum __can_baud_t{
    CAN_BAUD_5KHZ,
    CAN_BAUD_10KHZ,
    CAN_BAUD_20KHZ,
    CAN_BAUD_40KHZ,
    CAN_BAUD_50KHZ,
    CAN_BAUD_80KHZ,
    CAN_BAUD_100KHZ,
    CAN_BAUD_125KHZ,
    CAN_BAUD_200KHZ,
    CAN_BAUD_250KHZ,
    CAN_BAUD_400KHZ,
    CAN_BAUD_500KHZ,
    CAN_BAUD_666KHZ,
    CAN_BAUD_800KHZ,
    CAN_BAUD_1000KHZ,
    CAN_BAUD_NUM
}can_baud_t;

/*CAN 波特率,预分频值,SJW,BS1,BS2 */
static can_tq_t can_baud_array[CAN_BAUD_NUM] = {
    [CAN_BAUD_5KHZ]    =  {5,    400, CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_10KHZ]   =  {10,   200, CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_20KHZ]   =  {20,   100, CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_40KHZ]   =  {40,   50,  CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_50KHZ]   =  {50,   40,  CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_80KHZ]   =  {80,   25,  CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_100KHZ]  =  {100,  20,  CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_125KHZ]  =  {125,  16,  CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_200KHZ]  =  {200,  10,  CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_250KHZ]  =  {250,  36,  CAN_SJW_2tq, CAN_BS1_2tq, CAN_BS2_1tq},
    [CAN_BAUD_400KHZ]  =  {400,  5,   CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_500KHZ]  =  {500,  4,   CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_666KHZ]  =  {666,  3,   CAN_SJW_2tq, CAN_BS1_9tq, CAN_BS2_8tq},
    [CAN_BAUD_800KHZ]  =  {800,  11,  CAN_SJW_2tq, CAN_BS1_2tq, CAN_BS2_1tq},
    [CAN_BAUD_1000KHZ] =  {1000, 9,   CAN_SJW_2tq, CAN_BS1_2tq, CAN_BS2_1tq}
};

/*--- 设置CAN波特率 ---*/
int canBaudSet(u32 BaudRate)
{   
    can_tq_t* pcanbaud = can_baud_array;
    u8 c_i;
    u8 canBaudNum;

    for (c_i = 0; c_i < CAN_BAUD_NUM; c_i++) {
        if(pcanbaud->can_baudrate == BaudRate) {
            canBaudNum = c_i;
            break;
        }
        pcanbaud++;
    }
    if (c_i >= CAN_BAUD_NUM) {
        _debug(SYS_INFO, "Setting BaudRate param is unqualified \n");
        return -1;
    }

    return canBaudNum;
}

/** ------------------------ CAN 初始化 ------------------------- *
 * @brief  CAN初始化、配置GPIO为复用功能、CAN过滤器Filter初始化
 * @param  can_dev can设备号
 *         can_mode 工作模式,正常/环回/静默
 *         BaudRate 波特率,注意单位:KHZ
 * @retval 成功 0
 *         失败 1
 * ------------------------------------------------------------ */
u8 can_dev_init(u8 can_dev, u8 can_mode, u32 BaudRate)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    CAN_InitTypeDef CAN_InitStructure;
    can_port_t* pparam = &can_port[can_dev];

    _debug(SYS_INFO, "CAN%d Init start ...\n", pparam->can_dev + 1);

    /* 使能GPIO、CANx外设复用功能时钟使能 */
    RCC_APB1PeriphClockCmd(pparam->can_rcc, ENABLE);
    RCC_APB2PeriphClockCmd(pparam->rpin.gpio_rcc | pparam->tpin.gpio_rcc, ENABLE);
    if (pparam->pin_map != 0) {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    }

    /* GPIO 复用功能初始化:Rx */
    GPIO_InitStructure.GPIO_Pin = pparam->rpin.pin_bit;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
    GPIO_Init(pparam->rpin.gpio_port, &GPIO_InitStructure);

    /* GPIO 复用功能初始化:Tx */
    GPIO_InitStructure.GPIO_Pin = pparam->tpin.pin_bit;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
    GPIO_Init(pparam->tpin.gpio_port, &GPIO_InitStructure);

    /* CAN 初始化 */
    u8 ret_can;
    u8 canBaudNo;
    can_tq_t* pcanbaud = NULL;

    canBaudNo = canBaudSet(BaudRate);
    if (canBaudNo == -1) {
        _debug(SYS_INFO, "Setting BaudRate param is unqualified \n");
        return 1;
    }
    pcanbaud = &can_baud_array[canBaudNo];
    CAN_InitStructure.CAN_Prescaler = pcanbaud->can_prescaler;
    CAN_InitStructure.CAN_SJW = pcanbaud->can_syn_jump_width;
    CAN_InitStructure.CAN_BS1 = pcanbaud->can_time_bit_seg1;
    CAN_InitStructure.CAN_BS2 = pcanbaud->can_time_bit_seg2;
    _debug(SYS_INFO, "BaudRate = %dKHZ, can_prescaler = %d, CAN_SJW_%dtq, CAN_BS1_%dtq, CAN_BS2_%dtq \n",
        pcanbaud->can_baudrate, 
        pcanbaud->can_prescaler, 
        pcanbaud->can_syn_jump_width + 1, 
        pcanbaud->can_time_bit_seg1 + 1, 
        pcanbaud->can_time_bit_seg2 + 1);

    CAN_InitStructure.CAN_Mode = can_mode;
    CAN_InitStructure.CAN_TTCM = DISABLE; // can_time_trigger_communication;
    CAN_InitStructure.CAN_ABOM = DISABLE; // can_auto_bus_off;
    CAN_InitStructure.CAN_AWUM = DISABLE; // can_auto_wakeup;
    CAN_InitStructure.CAN_NART = ENABLE;  // can_no_auto_retransmit;(开启不自动重发)
    CAN_InitStructure.CAN_RFLM = DISABLE; // can_recv_fifo_lock;
    CAN_InitStructure.CAN_TXFP = DISABLE; // can_transmit_fifo_priority;
    ret_can = CAN_Init(pparam->can_channel, &CAN_InitStructure);
    if (ret_can == 0) {
        _debug(SYS_EMERG, "CAN%d Initialize is fail ...\n", pparam->can_dev + 1);
        return 1; 
    }

#if 0
    /* CAN接收中断参数配置 */
    NVIC_InitTypeDef NVIC_InitStructure;
    CAN_ITConfig(pparam->can_channel, pparam->IT_flag, ENABLE);                    // FIFO消息挂号中断允许
    NVIC_InitStructure.NVIC_IRQChannel = pparam->irq;                              // 设置IRQ通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = pparam->pre_priority;   // 设置抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = pparam->sub_priority;          // 设置响应优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                // 使能IRQ通道
    NVIC_Init(&NVIC_InitStructure);                                                // 初始化CAN中断配置
#endif

    _debug(SYS_INFO, "CAN%d Init end ...\n", pparam->can_dev + 1);
    return 0;
}

/*--------------------------- CANx 去初始化 ---------------------------*/
void can_uninit(u8 can_dev)
{
    can_port_t* pparam = &can_port[can_dev];
    clearFilter(can_dev);                              // 所有过滤器的id都失效
    CAN_DeInit(pparam->can_channel);                   // 复位默认值
    RCC_APB1PeriphClockCmd(pparam->can_rcc, DISABLE);  // 禁止(关闭)CAN_RCC时钟
}

void CAN1_RX0_IRQHandler(void)
{
    CAN_Receive_Msg(CAN_DEV1);
    _debug(SYS_INFO, "CAN1 RX0_IRQHandler...\n");
}

void CAN2_RX0_IRQHandler(void)
{
    CAN_Receive_Msg(CAN_DEV2);
    _debug(SYS_INFO, "CAN2 RX0_IRQHandler...\n");
}


(2)CAN过滤器函数


/*------------------------- 列表模式配置can_id ------------------------*/
/**
  * @brief CAN过滤器 标识符列表模式添加can_id
  * @param can_dev       
  *        p_canList    指向32位地址的指针;
  *                     最高位设置为0表示stdid,11位标准id(0x00 ~ 0x7FF) eg: id = 0x12
  *                     最高位设置为1表示extid,29位扩展id(0x00 ~ 0x1FFF FFFF) eg: id = 0x80000001
  *        size         过滤器的id总数
  * @retval 成功 0
  *         失败 1
  */
u8 myCAN_Filter_List(u8 can_dev, uint32_t* p_canList, int size)
{
    can_port_t* pparam = &can_port[can_dev];
    if ((pparam->can_channel != CAN1) && (pparam->can_channel != CAN2)) {
        _debug(SYS_EMERG, "Can channel is error!\n");
        return 1;
    }
    canIdSeparation(can_dev, p_canList, size, CAN_FilterMode_IdList);
    return 0;
}

/**
  * @brief CAN过滤器 列表模式(默认canId = 0为通用id地址,即id = 0,默认可以通过过滤器)
  * @param can_dev  
  *        p_canId  指向id数组
  *        size     id的个数
  *        flag     过滤器标识符id格式:0-标准id,1-扩展id
  * @retval None
  */
void myCanFilterList(u8 can_dev, uint32_t* p_canId, int size, int flag)
{
    u8 i = 0;
    u8 position; // 保存整数(取整 /)
    u8 remain;   // 保存余数(取余 %)
    u16 filterIdLow;
    u16 filterIdHigh;
    u16 filterMaskIdLow;
    u16 filterMaskIdHigh;
    u32 canId[2] = { 0 }; // 用于保存can过滤器组的2个32位寄存器:filterid和maskid

    switch (flag) { 
        // 标准id,列表模式:按16位宽填充filterId和maskId,最多一次填充4个stdId
        case 0: { 
            position = size / 4;
            remain = size % 4;

            for (i = 0; i < position; i++) { // 左移5位原因: 低5位id映射是 RTR IDE EXID[17:15]
                filterIdLow = *p_canId << 5; 
                p_canId++;
                filterIdHigh = *p_canId << 5;
                p_canId++;
                filterMaskIdLow = *p_canId << 5;
                p_canId++;
                filterMaskIdHigh = *p_canId << 5;
                p_canId++;

                canId[0] = (filterIdHigh << 16) | filterIdLow; // 默认ide = 0,rtr = 0:标准id,数据帧
                canId[1] = (filterMaskIdHigh << 16) | filterMaskIdLow;
                myFilter(can_dev, canId, CAN_FilterMode_IdList, CAN_FilterScale_16bit);
            }

            if (remain > 0) {
                filterIdLow = *p_canId << 5; // 在(4 - remain)的剩余区间为无id值,此时默认设置:can_id = 0
                p_canId++;
                filterIdHigh = *p_canId << 5;
                p_canId++;
                filterMaskIdLow = *p_canId << 5;
                p_canId++;
                filterMaskIdHigh = *p_canId << 5;
                p_canId++; // 不可省略

                canId[0] = (filterIdHigh << 16) | filterIdLow;
                canId[1] = (filterMaskIdHigh << 16) | filterMaskIdLow;
                myFilter(can_dev, canId, CAN_FilterMode_IdList, CAN_FilterScale_16bit);
            }
            break;
        }
        
        // 扩展id,列表模式:按32位宽填充filterId和maskId,最多一次填充2个extId
        case 1: { 
            position = size / 2;
            remain = size % 2;

            for (i = 0; i < position; i++) {
                filterIdLow = *p_canId << 3;
                filterIdHigh = (*p_canId << 3) >> 16;
                p_canId++;
                filterMaskIdLow = *p_canId << 3;
                filterMaskIdHigh = (*p_canId << 3) >> 16;
                p_canId++;

                canId[0] = (filterIdHigh << 16) | filterIdLow | (1 << 2); // 设置ide = 1,rtr = 0:扩展id,数据帧
                canId[1] = (filterMaskIdHigh << 16) | filterMaskIdLow | (1 << 2);
                myFilter(can_dev, canId, CAN_FilterMode_IdList, CAN_FilterScale_32bit);
            }

            if (remain > 0) {
                filterIdLow = *p_canId << 3;          // 在(2 - remain)的剩余区间为无id值,此时默认设置:can_id = 0
                filterIdHigh = (*p_canId << 3) >> 16;
                filterMaskIdLow = filterIdLow;        // 将剩下的一个32位寄存器,填充和上一个寄存器相同的id 
                filterMaskIdHigh = filterIdHigh;

                canId[0] = (filterIdHigh << 16) | filterIdLow | (1 << 2);
                canId[1] = (filterMaskIdHigh << 16) | filterMaskIdLow | (1 << 2);
                myFilter(can_dev, canId, CAN_FilterMode_IdList, CAN_FilterScale_32bit);
            }
            break;
        }
    }
}


/*----------------------------- 掩码模式配置can_id --------------------------------*/
/**
  * @brief CAN过滤器 标识符掩码模式 
  * @param can_dev
  *        p_canList 指向32位地址的指针;最高位设置为0表示stdid,11位标准id(0x00 ~ 0x7FF)
  *                  最高位设置为1表示extid,29位扩展id(0x00 ~ 0x1FFF FFFF)
  *        size      过滤器的id总数
  * @retval 成功 0
  *         失败 1
  */
u8 myCAN_Filter_Mask(u8 can_dev, uint32_t* p_canIdMask, int size)
{
    can_port_t* pparam = &can_port[can_dev];
    if ((pparam->can_channel != CAN1) && (pparam->can_channel != CAN2)) {
        _debug(SYS_INFO, "Can channel is error!\n");
        return 1;
    }
    canIdSeparation(can_dev, p_canIdMask, size, CAN_FilterMode_IdMask);
    return 0;
}

/**
  * @brief CAN过滤器 掩码模式
  * @param can_dev  
  *        p_canId  指定的id组
  *        size     id的个数
  *        flag     过滤器标识符id格式:0-标准id,1-扩展id
  * @retval 成功 0
  *         失败 1
  */
u8 myCanFilterMask(u8 can_dev, uint32_t* p_canIdMask, int size, int flag)
{
    u8 i = 0;
    u8 position = 0;
    u32 canId[2] = { 0 };

    if (size % 2) { // 确保掩码id:filterId和maskId成对出现
        _debug(SYS_INFO, "the number of Mask_canId is not pow(2) \n");
        return 1;
    }
   
    switch (flag) {
        // 标准id掩码模式,按32位宽处理
        case 0: 
        {
            position = size / 2;
            for (i = 0; i < position; i++) {
                canId[0] = *p_canIdMask << 21; // 默认ide = 0,rtr = 0; 标准id,数据帧
                p_canIdMask++;
                canId[1] = *p_canIdMask << 21;
                p_canIdMask++;
                printf("can_id[0] = 0x%x, can_id[1] = 0x%x\n", canId[0], canId[1]);
                myFilter(can_dev, canId, CAN_FilterMode_IdMask, CAN_FilterScale_32bit);
            }
            break;
        }

        // 扩展id掩码模式,按32位宽处理
        case 1: 
        {
            position = size / 2;
            for (i = 0; i < position; i++) {
                canId[0] = (*p_canIdMask << 3) | (1 << 2); // 设置ide = 1,rtr = 0; 扩展id,数据帧
                p_canIdMask++;
                canId[1] = (*p_canIdMask << 3) | (1 << 2);
                p_canIdMask++;
                myFilter(can_dev, canId, CAN_FilterMode_IdMask, CAN_FilterScale_32bit);
            }
            break;
        }
    }

    return 0;
}

/*----------------------- canIdSeparation 分离 ---------------------------*/
/**
  * @brief 将canId数组分离出标准id(11bits)和扩展id(29bits)
  * @param can_dev  
  *        p_canId  指向can_id数组
  *        size     id的个数
  *        filterMode 过滤器模式
  * @retval 成功 0
  *         失败 1
  */
u8 canIdSeparation(u8 can_dev, uint32_t* p_canId, int size, u8 filterMode)
{
    u8 i;
    u32 canId;
    u32 stdIdBuff[56] = { 0 }; // canId为标准id:按16位宽处理节约资源(56 = 14组过滤器 * 4个stdid)
    u32 extIdBuff[28] = { 0 }; // canId为扩展id:按32位宽处理(28 = 14 * 2个extid)
    u8 std_i = 0;              // 记录id的个数
    u8 ext_i = 0;

    /* 把标准id和扩展id分离出来后放入:stdIdBuff、extIdBuff*/
    for (i = 0; i < size; i++) {
        canId = *p_canId;
        _debug(SYS_INFO, "canId = 0x%x\n", canId);

        /* 
           整个id的值超过取值范围:
           canId & 0x7FFFFFFF:不考虑最高位,只考虑后31位; 
           & (~ 0x1FFFFFFF):不考虑低29位,如果(30:31)位有数据,则超过取值 
        */
        if ((canId & 0x7FFFFFFF) & (~ 0x1FFFFFFF)) { 
            _debug(SYS_INFO, "CAN id is unqualified, beyond scale \n");
            return 1;
        }

        /* 标准id最高位为0时,stdid取值范围超过0x7FF */
        if (((canId >> 31) == 0) && (canId & (~ 0x7FF))) {
            _debug(SYS_INFO, "CAN stdid is unqualified, beyond scale \n");
            return 1;
        }

        /* 将标准id和扩展id各自分离出来:移除低31位,只保留最高位:标识位 */
        if (canId >> 31) { // 1 = 扩展帧
            extIdBuff[ext_i] = canId & 0x7FFFFFFF; // 除去最高位(标识位),以获得扩展帧
            ext_i++;
        } else { 
            stdIdBuff[std_i] = canId;
            std_i++;
        }

        p_canId++; // canid地址自动加1
    }

    for (i = 0; i < std_i; i++) {
        _debug(SYS_INFO, "stdIdBuff[%d] = 0x%x, std_i = %d\n", i, stdIdBuff[i], std_i);
    }
    printf("---------------------------------\n");
    for (i = 0; i < ext_i; i++) {
        _debug(SYS_INFO, "extIdBuff[%d] = 0x%x, ext_i = %d\n", i, extIdBuff[i], ext_i);
    }
    _debug(SYS_INFO, "---------------------------------\n");

    /* 清除can通道的所有过滤器中的id */
    clearFilter(can_dev);

    /* 设置can_id  0:标准Id; 1:扩展Id */
    if (filterMode == CAN_FilterMode_IdList) { 
        myCanFilterList(can_dev, stdIdBuff, std_i, STDID);  
        myCanFilterList(can_dev, extIdBuff, ext_i, EXTID);

    } else {
        myCanFilterMask(can_dev, stdIdBuff, std_i, STDID);
        myCanFilterMask(can_dev, extIdBuff, ext_i, EXTID);
    }

    return 0;
}

/**--------------------------- myFilter CAN过滤器配置 ---------------------*/
/* @brief CAN过滤器,寄存器配置 
  * @param can_dev 
  *        p_canId  指定的id组
  *        size     id的个数
  *        filterMode   过滤的模式:列表/掩码
  *        filterScale  过滤器位宽
  * @retval 成功:0
  *         失败:1
  */
u8 myFilter(u8 can_dev, u32* p_canId, u8 filterMode, u8 filterScale)
{
    CAN_FilterInitTypeDef CAN_FilterInitStructure;
    can_port_t* pparam = &can_port[can_dev];
    u32 can_id[2] = {p_canId[0], p_canId[1]};
    
    // printf("canId[0] = 0x%x, canId[1] = 0x%x, filternum = %d\n", can_id[0], can_id[1], filterNumber);
    // printf("p_canId[0] = 0x%x, p_canId[1] = 0x%x, filternum = %d\n", p_canId[0], p_canId[1], filterNumber);
    /* 防止can通道分配的过滤器编号超过编号取值范围:CAN1:0 ~ 13; CAN2:14 ~ 27 */
    if (pparam->can_channel == CAN1) {
        if(filterNumber > 13) {
            _debug(SYS_INFO, "the distribution of Can Filter Number go beyond rank: CAN1 > 13\n");
            return 1;
        }
    } else { 
        CAN_SlaveStartBank(14); // 开启CAN2通道
        if(filterNumber > 27) {
            _debug(SYS_INFO, "the distribution of Can Filter Number go beyond rank:  CAN2 > 27\n");
            return 1;
        }
    }
    
    /* 一组过滤器的2个32位寄存器拆分成四个16位的基础寄存器 */
    CAN_FilterInitStructure.CAN_FilterIdLow = *p_canId;
    CAN_FilterInitStructure.CAN_FilterIdHigh = *p_canId >> 16;
    _debug(SYS_INFO, "CAN_FilterId = 0x%x\n", *p_canId);  
    p_canId++;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = *p_canId;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = *p_canId >> 16;
    _debug(SYS_INFO, "CAN_FilterMaskId = 0x%x\n", *p_canId); 
    _debug(SYS_INFO, "filterNumber = %d\n", filterNumber);
    
    if (pparam->can_channel == CAN1) { 
        CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; 
    } else { 
        CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO1; 
    }

    CAN_FilterInitStructure.CAN_FilterNumber = filterNumber; // CAN1:0 ~ 13; CAN2:14 ~ 27
    filterNumber++;
    CAN_FilterInitStructure.CAN_FilterScale = filterScale;
    CAN_FilterInitStructure.CAN_FilterMode = filterMode; 
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
    CAN_FilterInit(&CAN_FilterInitStructure);
    return 0;
}

/*------------------------ 清除CANx通道 过滤器 --------------------------*/
/* 清除can通道的所有过滤器中的id 
 * 思路:将所有过滤器组全部以掩码模式(扩展id)填充:filterid和maskid对应位全置1,不过滤任何id
 */
void clearFilter(u8 can_dev)
{   
    can_port_t* pparam = &can_port[can_dev];
    u8 i = 0;
    u32 maskId = 0xFFFFFFF8 | (0x1 << 2);
    u32 canIdClear[2] = {0};
    canIdClear[0] = maskId;
    canIdClear[1] = maskId;
    
    if(pparam->can_channel == CAN1) {
        filterNumber = 0;
    } else {
        filterNumber = 14;
    }

    // 以掩码模式,扩展id填充过滤器
    for(i = 0; i < 14; i++) {
        myFilter(can_dev, canIdClear, CAN_FilterMode_IdMask, CAN_FilterScale_32bit);
    }

    // 恢复过滤器的默认起始编码号
    if (pparam->can_channel == CAN1) {
        filterNumber = 0;
    } else {
        filterNumber = 14;
    }
}

(3)CAN 发送/接收函数

/* ------------------------ CANx 发送msg --------------------------------
* @功能:CANx 发送一组数据(固定can_id = 0x12, 标准帧, 数据帧)
* @参数:len:数据长度(最大为 8)
        msg:数据指针,数据最大为 8 个字节.
* @返回值:0, 成功;
        其他,失败;
* -------------------------------------------------------------------- */
u8 CAN_Transmit_Msg(u8 can_dev, u8* msg, u8 len)
{
    u16 i;
    u8 tx_mbox;
    CanTxMsg TxMessage;
    can_port_t* pparam = &can_port[can_dev];

    TxMessage.StdId = 0x12;
    TxMessage.ExtId = 0x12;
    TxMessage.IDE = CAN_Id_Standard;
    TxMessage.RTR = CAN_RTR_Data; 
    TxMessage.DLC = len;
    for (i = 0; i < len; i++) {
        TxMessage.Data[i] = msg[i];
    }
    _debug(SYS_INFO, "can%d translate = %s\n", pparam->can_dev + 1, msg);

    tx_mbox = CAN_Transmit(pparam->can_channel, &TxMessage);
    if (tx_mbox == CAN_TxStatus_NoMailBox) {
        _debug(SYS_INFO, "CAN%d Transmit Status is No MailBox ...\n", pparam->can_dev + 1);
        return 1;
    }

    /* 等待CAN发送一段时间;如果超时,则失败 */
    i = 0;
    while ((CAN_TransmitStatus(pparam->can_channel, tx_mbox) == CAN_TxStatus_Failed) && (i < 0xFFF)) {
        i++;
    }
    if (i >= 0xFFF) {
        _debug(SYS_INFO, "CAN%d Transmit fail, time out ...\n", pparam->can_dev + 1);
        return 1;
    }

    return 0;
}

/** ------------------------ CANx 接收msg ------------------------------
 * @brief CANx 接收一组数据(固定格式:ID = 0X12, 标准帧, 数据帧)
 * @param can_dev CAN设备号
 *        msg:数据指针,数据最大为 8 个字节
 * @retval 0:无数据被收到
 *      其他:成功接收的数据长度
 * ------------------------------------------------------------------ */
u8 CAN_Receive_Msg(u8 can_dev, u8 * msg)
{
    u32 i;
    CanRxMsg RxMessage;
    can_port_t* pparam = &can_port[can_dev];

    /* 判别是哪个接收邮箱有数据挂起 */
    if (CAN_MessagePending(pparam->can_channel, CAN_FIFO0)) {
        CAN_Receive(pparam->can_channel, CAN_FIFO0, &RxMessage);
        for (i = 0; i < RxMessage.DLC; i++) {
            msg[i] = RxMessage.Data[i];
            printf("CAN1 msg[%d]\n", i, msg[i]);
        }
        return RxMessage.DLC;
    } else if (CAN_MessagePending(pparam->can_channel, CAN_FIFO1)) {
        CAN_Receive(pparam->can_channel, CAN_FIFO1, &RxMessage);
        for (i = 0; i < RxMessage.DLC; i++) {
            msg[i] = RxMessage.Data[i];
            printf("CAN2 msg[%d]\n", i, msg[i]);
        }

        _debug(SYS_INFO, "can receive msg CAN_id = 0x%x ...\n", RxMessage.StdId);
        return RxMessage.DLC;
    }

    /* 没有接收到数据,直接退出 */
    return 0;
}

头文件

#ifndef __P_CAN_H__
#define __P_CAN_H__

/*------------- type define -----------------*/
// can_dev 参数取值范围
typedef enum {
    CAN_DEV1,
    CAN_DEV2,
    CAN_DEV_CNT
} CAN_DEV_E;

/*------------- Function --------------------*/
// BaudRate 单位为HKZ
u8 can_dev_init(u8 can_dev, u8 can_mode, u32 BaudRate);
void can_uninit(u8 can_dev);

// 过滤器函数
u8 myCAN_Filter_List(u8 can_dev, uint32_t* p_canList, int size);
u8 myCAN_Filter_Mask(u8 can_dev, uint32_t* p_canIdMask, int size);
void clearFilter(u8 can_dev);

// can发送msg,固定can_id = 0x12, 标准帧, 数据帧
u8 CAN_Transmit_Msg(u8 can_dev, u8* msg, u8 len);
u8 CAN_Receive_Msg(u8 can_dev, u8 * msg);
#endif

  • 10
    点赞
  • 96
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: OBD-II通信协议是指汽车诊断系统中使用的一种标准协议,用于通过汽车的OBD-II接口进行诊断和通信。OBD-II是On-Board Diagnostics第代的缩写,是一种由汽车制造商和环境保护机构共同制定的通信标准。 OBD-II协议规定了汽车控制模块和诊断设备之间的通信方式和数据格式。它定义了一系列的诊断命令和响应,用于读取和清除汽车的故障码、获取实时数据和执行特定的控制功能。 OBD-II协议中主要包含以下几个重要部分: 1. 物理层接口:定义了OBD-II接口的物理连接方式和电气特性,常见的有16针的OBD-II插座。 2. 数据链路层:定义了OBD-II通信的基本规则和数据传输方式,采用串行通信协议,常见的有基于CAN总线的ISO 15765-4协议。 3. 网络层:定义了OBD-II的网络地址和诊断设备的识别方式,使得诊断工具能够准确地与汽车的控制模块进行通信。 4. 应用层:定义了一系列诊断命令和响应格式,包括读取故障码、清除故障码、请求实时数据和执行控制命令等。 OBD-II通信协议的中文是针对中国市场的特定要求而发布的,主要与欧美标准相兼容。中文协议在数据格式和语言方面进行了适配,使得国内诊断设备和汽车制造商能够更好地进行通信和故障诊断。 总的来说,OBD-II通信协议是一种标准化的汽车诊断通信协议,通过定义通信方式、数据格式和诊断命令,实现了诊断设备与汽车控制模块之间的有效通信和数据交换。中文协议是对原有协议的适配,以满足中国市场的需求。 ### 回答2: OBD-II通信协议是一种用于汽车诊断的通信协议,其全称为"On-Board Diagnostics-II",即车载诊断系统第代。它是由国际标准化组织(ISO)制定的一套标准,旨在提供一个统一的汽车诊断接口。 OBD-II通信协议定义了汽车发动机及其相关系统的诊断接口和协议规范,使得车辆制造商和第三方诊断工具能够通过该接口收集和分析车辆的故障码、传感器数据和其他相关信息。该协议规定了诊断接口的物理连接方式、通信速率、命令结构以及数据格式等。 根据OBD-II通信协议的规定,诊断接口通常位于汽车驾驶室内的驾驶员侧脚下方,可通过一个标准的16针连接器与诊断工具相连。通信协议支持多种通信协议和通信速率,包括基于串行通信的ISO 9141-2、ISO 14230-KWP2000、ISO 15765-CAN等。 通过OBD-II通信协议,诊断工具可以发送特定的命令来获取车辆的故障码、实时传感器数据、状态信息等。这有助于识别并解决车辆的故障,提高驾驶安全性和燃油经济性。另外,该协议还支持诊断工具与车辆之间的双向通信,使得用户能够对某些系统参数进行编程和配置。 OBD-II通信协议在全球范围内得到广泛应用,几乎所有新款的汽车都支持该协议。该协议的出现对汽车诊断和维修领域产生了重大影响,为诊断技术的发展提供了基础。同时,它也为诊断设备的研发和市场提供了统一的接口和规范,促进了该行业的发展。 ### 回答3: OBD-II通信协议,即On-Board Diagnostics II,是指汽车诊断系统所采用的一种标准化的通信协议。它主要用于车辆的故障检测和诊断,能够通过与车辆内部的电子控制单元(ECU)进行通信,获取车辆诸多数据和故障代码。 OBD-II通信协议是由美国汽车工程师协会(SAE)制定的国际标准,于1996年开始开始在美国车辆中广泛应用。该协议规定了统一的通信参数、数据格式和诊断模式,使得不同车型和品牌的车辆之间能够进行有效的通信和诊断。 OBD-II通信协议采用了标准的16针OBD-II接口,通过该接口可以连接至诊断工具或诊断设备,实现与车辆的通信。协议规定了通信的物理层和应用层。在物理层,协议采用了电气特性、接口和通信速率的统一标准,以确保通信正常进行。在应用层,协议规定了读取和解读诸多数据和故障代码的方法,如车速、发动机转速、冷却液温度、氧传感器状况等。 OBD-II通信协议的中文是将该协议的相关规定、参数和方法翻译成中文。这使得非英语国家的技术人员、维修人员和车主能够更好地了解和应用该协议,提高诊断和维修的效率。同时,该中文也方便了相关研究和教育机构的教学和科研工作。 总之,OBD-II通信协议是一种用于汽车诊断和故障检测的标准化通信协议,通过与车辆内部的电子控制单元进行通信,获取车辆的数据和故障代码。它的中文翻译使得更多人能够理解和应用该协议,促进了汽车维修和故障诊断技术的发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值