[原创] HC32F4A0开发板CAN通讯测试

changweilin   2024-3-24 23:40 楼主

HC32F4A0开发板CAN通讯测试

1概述

1.1开发板接口

        该开发板有2个CAN接口,支持CAN2.0B,最高支持CAN FD,使用的接口芯片型号为:MCP2542,CAN2.0B控制器中应用程序可通过1个PTB和3 STB将发送数据送至总线,由发送调度器决定邮箱发送顺序。通过8个接收缓冲器获取总线数据。3个STB以及8个RB可以理解为一个3级FIFO和一个8级FIFO,FIFO完全由硬件控制;本次测试主要测试经典CAN的收发并将收发数据显示在屏幕上。

1.2开发板原理图

        CAN芯片的接口及外围电路如图1所示。
232458y894zqnxgnemg85x.jpg
图1 CAN接口外围电路示意图

1.3测试设备

        本次测试所用设备如表1所示,开发板和CAN盒之间使用屏蔽双绞线连接,在CAN盒连接端跨接120Ω的匹配电阻防止信号反射,设备实物图连接图如图2所示:

测试设备 单位 数量
EV_F4A0_LQ176_REV1.0开发板
ARM仿真器
5V电源适配器
ZLG USBCANFD-200U
ALIENTEK 4.3’TFTLCD
RIGOL DHO804示波器
表1 测试设备
232458a50jtk5d10dtt72d.jpg
图2 开发板实物连接图

2代码编写

产生发送数据

static void LoadData()
{
	uint8_t i;
	for (i = 0U; i < CAN_TX_DATA_SIZE; i++) {
        stcTx1.au8Data[i] = i + 0x0AU;
        stcTx2.au8Data[i] = i + 0x3aU;
    }
	stcTx1.u32Ctrl = 0x0UL;
    stcTx1.u32ID   = CAN_TX_ID1;
    stcTx1.IDE     = CAN_TX_ID1_IDE;
    stcTx1.DLC     = CAN_TX_DLC;

    stcTx2.u32Ctrl = 0x0UL;
    stcTx2.u32ID   = CAN_TX_ID2;
    stcTx2.IDE     = CAN_TX_ID2_IDE;
    stcTx2.DLC     = CAN_TX_DLC;
}

发送数据并显示

static void CanTx(uint16_t u16Width,uint16_t u16Height)
{
    uint8_t i;

    if (BSP_KEY_GetStatus(BSP_KEY_1) == SET) {
        if (m_u8TxStart == 0U) {
            m_u8TxProcess++;
            if (m_u8TxProcess > CAN_TX_PROCESS_STB) {
                m_u8TxProcess = CAN_TX_PROCESS_PTB;
            }
            switch (m_u8TxProcess) {
                case CAN_TX_PROCESS_PTB:
                    /* Transmit one frame via PTB */
                    (void)CAN_FillTxFrame(CAN_UNIT, CAN_TX_BUF_PTB, &stcTx1);
                    CAN_StartTx(CAN_UNIT, CAN_TX_REQ_PTB);
					//lcd_show_xnum(140,20,m_astRxFrame[0].u32ID,4,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(120,100,stcTx1.au8Data[0],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(150,100,stcTx1.au8Data[1],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(180,100,stcTx1.au8Data[2],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(210,100,stcTx1.au8Data[3],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(240,100,stcTx1.au8Data[4],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(270,100,stcTx1.au8Data[5],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(300,100,stcTx1.au8Data[6],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(330,100,stcTx1.au8Data[7],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
                    break;
                case CAN_TX_PROCESS_STB:
                    /* Transmit one frame via STB */
                    (void)CAN_FillTxFrame(CAN_UNIT, CAN_TX_BUF_STB, &stcTx2);
                    CAN_StartTx(CAN_UNIT, CAN_TX_REQ_STB_ONE);
					lcd_show_xnum(120,100,stcTx2.au8Data[0],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(150,100,stcTx2.au8Data[1],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(180,100,stcTx2.au8Data[2],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(210,100,stcTx2.au8Data[3],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(240,100,stcTx2.au8Data[4],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(270,100,stcTx2.au8Data[5],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(300,100,stcTx2.au8Data[6],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
					lcd_show_xnum(330,100,stcTx2.au8Data[7],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
                    break;           
            }
            m_u32TxTick = CAN_TX_TIMEOUT_MS;
            m_u8TxStart = 1U;
        } else {
        }
    }
}

接收数据并显示

static void CanRx(uint16_t u16Width,uint16_t u16Height)
{
    uint8_t i;
    uint8_t j;
    uint8_t u8RxFrameNum = 0U;
    int32_t i32Ret;

    /* Get all received frames. */
    do {
        i32Ret = CAN_GetRxFrame(CAN_UNIT, &m_astRxFrame[u8RxFrameNum]);
        if (i32Ret == LL_OK) {
            u8RxFrameNum++;
        }
    } while (i32Ret == LL_OK);
	
	lcd_show_xnum(140,20,m_astRxFrame[0].u32ID,4,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
	lcd_show_xnum(120,60,m_astRxFrame[0].au8Data[0],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
	lcd_show_xnum(150,60,m_astRxFrame[0].au8Data[1],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
	lcd_show_xnum(180,60,m_astRxFrame[0].au8Data[2],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
	lcd_show_xnum(210,60,m_astRxFrame[0].au8Data[3],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
	lcd_show_xnum(240,60,m_astRxFrame[0].au8Data[4],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
	lcd_show_xnum(270,60,m_astRxFrame[0].au8Data[5],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
	lcd_show_xnum(300,60,m_astRxFrame[0].au8Data[6],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
	lcd_show_xnum(330,60,m_astRxFrame[0].au8Data[7],2,24,0,LCD_COLOR_BLACK,u16Width,u16Height);
    /* Handle received frames. */
    for (i = 0U; i < u8RxFrameNum; i++) {
        for (j = 0; j < (uint8_t)m_astRxFrame[i].DLC; j++) {
            
            m_astRxFrame[i].au8Data[j] = 2U;
        }
    }
}

过滤器设置

#define CAN_FILTER1_ID                  (0x101UL)
#define CAN_FILTER1_ID_MASK             (0x0UL)
#define CAN_FILTER1_ID_TYPE             (CAN_ID_STD) 

主函数

int32_t main(void)
{
    uint16_t u16Width;
    uint16_t u16Height;
	
    /* MCU Peripheral registers write unprotected */
    LL_PERIPH_WE(LL_PERIPH_ALL);
    /* Initialize system clock: */
    BSP_CLK_Init();
	CLK_SetClockDiv(CLK_BUS_EXCLK, CLK_EXCLK_DIV8);
	BSP_IO_Init();
	//BSP_LED_Init();
    BSP_LCD_IO_Init();
	BSP_KEY_Init();
	BSP_LCD_RSTCmd(EIO_PIN_RESET); /* RST# to low */
    DDL_DelayMS(50UL);
    BSP_LCD_RSTCmd(EIO_PIN_SET);  /* RST# to high */
    DDL_DelayMS(50UL);
	BSP_NT35510_Init();
	BSP_NT35510_Clear(LCD_COLOR_WHITE);
	BSP_LCD_BKLCmd(EIO_PIN_SET);

    /* Set LCD cursor */
    BSP_NT35510_SetCursor(0U, 0U);
    /* Turn on LCD backlight */
    BSP_LCD_BKLCmd(EIO_PIN_SET);
	CanCommClockConfig();
    CanPinConfig();
    CanInitConfig();
    CanIrqConfig();
    CanPhyEnable();
    
	(void)SysTick_Init(1000U);
    /* Clear LCD screen */

    /* MCU Peripheral registers write protected */
    LL_PERIPH_WP(LL_PERIPH_ALL);

    u16Width = BSP_NT35510_GetPixelWidth();
    u16Height = BSP_NT35510_GetPixelHeight();
    LoadData();
	lcd_show_string(20,20,u16Width,u16Height,24,"CAN_RX_ID:",LCD_COLOR_BLACK,u16Width,u16Height);
	lcd_show_string(20,60,u16Width,u16Height,24,"RX_DATA:",LCD_COLOR_BLACK,u16Width,u16Height);
	lcd_show_string(20,100,u16Width,u16Height,24,"TX_DATA:",LCD_COLOR_BLACK,u16Width,u16Height);
	for (;;) {
        if (m_u8RxFlag != 0U) {
            /* Read frames here or in CAN_IrqCallback */
            CanRx(u16Width,u16Height);
            m_u8RxFlag = 0U;
        }
        CanTx(u16Width,u16Height);
    }
}

3实验现象

3.1实验现象分析

        本实验通过按键来触发CAN数据的发送,每次按下按键会以不同的方式发送不同的数据,发送的数据会在LCD显示屏上实时更新,同时使用ZLG CANpro显示接收到的数据,并且给开发板发送数据,开发板会将收到的数据和CANID显示在显示屏上。

3.2CAN发送

        首次按下按键K1发送的数据如图3所示,CAN盒接收到的数据如图4所示,再次按下按键K1,发送的数据如图5所示,CAN盒接收到的数据如图6所示。使用示波器抓取发送的数据如图7、8所示;实验现象和编写代码的预期一致。
232458yzuti6u6wku1tkii.jpg
图3 第一次按下按键数据显示
232458klkjw2lwohu0luus.png
图4 第一次按下按键CAN盒接收数据显示
232458r2w2ofnwg9go2929.jpg
图5 第二次按下按键数据显示
232458a3m4l3iqqzo0qlk4.png
图6 第二次按下按键CAN盒接收数据显示
232458li365zyi5292ttgs.png
图7 第一次发送波形
232458vi23zef399cwmq5t.png
图8 第二次发送波形

3.3CAN接收

        使用CANPRO软件发送数据,设置如图9所示,LCD显示屏会将接收到的CANID和CAN数据显示在屏幕上,如图10所示,程序中设置了过滤器仅能接接收ID为101的数据,因此当修改CANID为102时显示屏上的ID并不更新,证明过滤器正常工作。
232458ymmzl09ojrc0r07z.png
图9 CAN发送设置
232458hkzyhjnop0npnl3m.jpg
图10 开发板接收到的CAN数据
232458zicuz6u0rm0fuuuz.png
图11 修改ID和数据后设置
232458fa7shqmhvll77r4l.png
图12 数据发送成功
        如图11、12所示修改CANID和数据后发送成功,但显示屏未更新数据和ID,证明过滤器正常工作。

4实验过程

        can盒发送过程:

can发送

       can盒接收过程

can接收

 

5总结

        开发板CAN接口的相关例程十分详细,进行一定修改后配合前期的LCD相关函数即可进行使用,能够满足接口快速开发的需求。
 
本帖最后由 changweilin 于 2024-3-24 23:39 编辑

回复评论 (1)

楼主的这种CAN的收发并将收发数据显示在屏幕上的测试,确实是比较经典的测试方法

点赞  2024-3-26 07:32
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复