打印
[活动专区]

【AT-START-F407测评】+MODBUS测试

[复制链接]
591|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 aple0807 于 2021-1-25 20:23 编辑

今天测试下工作中最常用的通信协议-modbus。

管脚配置:
static gpio_init_cfg_type gpio_cfg[] = 
{
    //UART1
    {GPIOA, GPIO_Mode_AF_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_9},  //u1-TX
    {GPIOA, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_10},  //u1-RX
    //ADC
    {GPIOA, GPIO_Mode_IN_ANALOG, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_0},  //ADC
    //LED
    {GPIOD, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_13 | GPIO_Pins_14 | GPIO_Pins_15}, //LED
    {GPIOD, GPIO_Mode_AF_PP, GPIO_MaxSpeed_50MHz, 0,  GPIO_Pins_15}, //LED-PWM
    //UART8
    {GPIOE, GPIO_Mode_AF_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_1},  //u8-TX
    {GPIOE, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_0},  //u8-RX
    //UART6
    {GPIOC, GPIO_Mode_AF_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_6},  //u6-TX
    {GPIOC, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_7},  //u6-RX
    //SPI1
    {GPIOA, GPIO_Mode_AF_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_5 | GPIO_Pins_7},  //SPI1-SCK MOSI
    {GPIOA, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_6},  //SPI1-MISO
    {GPIOA, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_15},  //SPI1-SS
};

    for(index=0; index < sizeof(gpio_cfg)/sizeof(gpio_init_cfg_type);index++)
    {
        GPIO_InitType GPIO_InitStructure;
        
        GPIO_InitStructure.GPIO_Mode = gpio_cfg[index].mode;
        GPIO_InitStructure.GPIO_MaxSpeed = gpio_cfg[index].speed;
        GPIO_InitStructure.GPIO_Pins = gpio_cfg[index].pin;
        GPIO_Init(gpio_cfg[index].port, &GPIO_InitStructure);
        
        if((gpio_cfg[index].mode == GPIO_Mode_OUT_OD) || (gpio_cfg[index].mode == GPIO_Mode_OUT_PP))
        {
            if(gpio_cfg[index].val_init)
            {
                GPIO_SetBits(gpio_cfg[index].port, gpio_cfg[index].pin);
            }
            else
            {
                GPIO_ResetBits(gpio_cfg[index].port, gpio_cfg[index].pin);
            }
        }
    }
      
测试开通两个通道,一路主机-UART6,一路从机-UART8。
协议解析用现成的库,只需要编写底层数据收发文件。
#include "sys_ext.h" 
#include "os_obj.h"
#include "mbapp.h"

#define mbPORT                       USART6
#define mbURT_IRQn                   USART6_IRQn
#define mbISR                        USART6_IRQHandler
#define RCU_USART                    RCC_APB2PERIPH_USART6
#define RCU_USARTRST                 RCC_APB2PERIPH_USART6
#define mbObj                        mb.obj06
#define mbCmdBuff                    mb.CmdBuff06

static volatile uint8_t alDir;

//RS485 Dir-Pin
#define mbRxEnable()  
#define mbTxEnable()  

static void mbswTimerEnable(void);

static void mbEnable(uint8_t xRxEnable, uint8_t xTxEnable);
static void mbDataSend(void);

#include "mb_fun.h"

/*****************************************************************************//*!
*
* [url=home.php?mod=space&uid=247401]@brief[/url]   port.
* [url=home.php?mod=space&uid=72445]@[/url] Pass/ Fail criteria: none
*****************************************************************************/
static void mb_port_pin_cfg(void)
{
    intx_disable();

    RCC_APB2PeriphClockCmd(RCU_USART, ENABLE);
    RCC_APB2PeriphResetCmd(RCU_USARTRST, ENABLE);
    RCC_APB2PeriphResetCmd(RCU_USARTRST, DISABLE);

    intx_enable();
}

/*****************************************************************************//*!
*
* [url=home.php?mod=space&uid=247401]@brief[/url]   RTU timer enable.
* [url=home.php?mod=space&uid=72445]@[/url] Pass/ Fail criteria: none
*****************************************************************************/
__STATIC_INLINE void mbswTimerEnable(void)
{
    mbObj.bRtuTimerOn = 1;
    mbObj.RtuTimerCnt = 0;
}

/*****************************************************************************//*!
* @brief UART0 RX interrupt routine.
* @brief   Uart interrupt.
*
* @ Pass/ Fail criteria: none
*****************************************************************************/

void mbISR()
{
    volatile uint32_t IntSt;
    volatile uint8_t Data;

    mbObj.TimeOutCnt = 0;

    IntSt = mbPORT->STS;

    if (IntSt & USART_STS_RDNE)
    {
        Data = mbPORT->DT;

        mbObj.RunSt.bits.PortSt = 1;

        if (MB_RX_RCVEND == mbObj.RcvSt)
            return;

        if (mbObj.SndSt != MB_TX_IDLE)
            return;

        mbObj.RcvSt = MB_RX_RCV;                                                    //指示正在接收数据
        mbswTimerEnable();

        if (mbObj.RcvCnt >= MB_BUFF_SIZE)
            return;                                                                  //指针越界检查

        if ((IntSt & (USART_STS_PERR | USART_STS_FERR | USART_STS_ORERR)) != 0)   //帧错误 //只读,由硬件管理
        {
            if (mbObj.RcvCnt >= 1)
            {
                mbObj.ErrSt.bits.ErrHal = 1;
            }
        }

        mbObj.AduBuff[mbObj.RcvCnt++] = Data;

    }
    else if ((mbObj.SndSize <= mbObj.SndCnt) && (IntSt & USART_STS_TRAC))
    {
        mbObj.SndSt = MB_TX_IDLE;                                               //发送结束   
        if (mbObj.RunSt.bits.MasterMode)                                         //主机进入接收等待状态
        {
            mbObj.RcvSt = MB_RX_WAIT;
        }
        mbEnable(ENABLE, DISABLE);
    }
    else if (IntSt & USART_STS_TDE)
    {
        if (mbObj.SndSize > mbObj.SndCnt)
        {
            mbPORT->DT = mbObj.AduBuff[mbObj.SndCnt++];
        }
        else                                  //写缓冲区结束
        {
            mbPORT->CTRL1 &= ~((uint32_t)(USART_CTRL1_TDEIEN));
            mbPORT->CTRL1 |= (uint32_t)(USART_CTRL1_TRACIEN);
        }
    }
    else
    {

    }
   
    cpu_data_sync();
}

/*****************************************************************************//*!
*
* @brief   mb object init.
*
* @ Pass/ Fail criteria: none
*****************************************************************************/

static void mbObjInit(mb_mode_type mbMode)
{

    mb_obj_init(&mbObj);
    mbObj.AduSend = &mbDataSend;

    mbObj.RunSt.bits.RTUMode = 1;

    mbObj.Fun.Slave.RegCoilsCB = &eMBRegCoilsCB;
    mbObj.Fun.Slave.RegDiscreteCB = &eMBRegDiscreteCB;
    mbObj.Fun.Slave.RegHoldingCB = &eMBRegHoldingCB;
    mbObj.Fun.Slave.RegInputCB = &eMBRegInputCB;

    mmb_cmd_buff_init(&mbObj, mbCmdBuff, 32, 16);
    mbObj.Fun.Master.ErrCnt = 0;

    mbObj.api = &mb_fun;
   
    //SLAVE FUNCTION INIT
    if (MB_RTU_SLAVE == mbMode)
    {

    }
    else
    {
        //MASER FUNCTION INIT
        mbObj.RunSt.bits.MasterMode = 1;

    }
}

/*****************************************************************************//*!
* @brief           com modle init .
*
* @ Pass/ Fail criteria: none
*****************************************************************************/

void mb06_Init(mb_mode_type mbMode, uint32_t ulBaudRate, mb_parity_type eParity)
{

    uint32_t usTimerT35_50us;
    USART_InitType cfg;

    mb_port_pin_cfg();
    mbObjInit(mbMode);

    cfg.USART_BaudRate = ulBaudRate;
    cfg.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    cfg.USART_HardwareFlowControl = 0;

    if (MB_PAR_NONE == eParity)
    {
        cfg.USART_Parity = USART_Parity_No;
        cfg.USART_StopBits = USART_StopBits_2;
        cfg.USART_WordLength = USART_WordLength_8b;
    }
    else if (MB_PAR_NONE_1S == eParity)
    {
        cfg.USART_Parity = USART_Parity_No;
        cfg.USART_StopBits = USART_StopBits_1;
        cfg.USART_WordLength = USART_WordLength_8b;  
    }
    else if (MB_PAR_ODD == eParity)
    {
        cfg.USART_Parity = USART_Parity_Odd;
        cfg.USART_StopBits = USART_StopBits_1;
        cfg.USART_WordLength = USART_WordLength_9b;
    }
    else
    {
        cfg.USART_Parity = USART_Parity_Even;
        cfg.USART_StopBits = USART_StopBits_1;
        cfg.USART_WordLength = USART_WordLength_9b;
    }

    if (ulBaudRate > 19200)
    {
        usTimerT35_50us = 35; /* 1800us. */
        mbObj.RtuTimerSv = 3;
    }
    else
    {
        usTimerT35_50us = (7UL * 220000UL) / (2UL * ulBaudRate);
        mbObj.RtuTimerSv = usTimerT35_50us / 20 + 2;
    }

    USART_Init(mbPORT, &cfg);

    USART_Cmd(mbPORT, ENABLE);

    nvic_irq_set(mbURT_IRQn, 0x0F, 1);

    mbEnable(ENABLE, DISABLE);
}

/*****************************************************************************//*!
*
* @brief   Uart En or Dis.
* @ Pass/ Fail criteria: none
*****************************************************************************/

static void mbEnable(uint8_t xRxEnable, uint8_t xTxEnable)
{
    volatile uint8_t u8Temp;

    if (xRxEnable)
    {
        mbRxEnable();


        mbPORT->CTRL1 &= ~((uint32_t)USART_CTRL1_TDEIEN | USART_CTRL1_TRACIEN);
        mbPORT->CTRL1 |= (uint32_t)USART_CTRL1_REN | USART_CTRL1_UEN;

        u8Temp = mbPORT->DT;
        while ((mbPORT->STS & (USART_STS_RDNE | USART_STS_ORERR)) != 0)
        {
            u8Temp = mbPORT->DT;
            __DSB();
        }

        mbPORT->CTRL1 |= USART_CTRL1_RDNEIEN;
    }
    else if (xTxEnable)
    {
        mbPORT->CTRL1 &= ~((uint32_t)USART_CTRL1_RDNEIEN | USART_CTRL1_REN);

        mbPORT->CTRL1 |= (uint32_t)USART_CTRL1_TEN | USART_CTRL1_UEN;
        mbTxEnable();

        mbPORT->DT = mbObj.AduBuff[mbObj.SndCnt++];
        mbPORT->CTRL1 |= (uint32_t)(USART_CTRL1_TDEIEN);
    }
    else
    {

    }
}

/*****************************************************************************//*!
*
* @brief   Send data.
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void mbDataSend(void)
{
    mbEnable(DISABLE, ENABLE);
}

RTU定时使用软件定时器,这样可以避免硬件资源不足,方便添加多通道。
/**
  * @brief  app timer isr
  * @param  None
  * @retval None
  */
void AdcInsertedHandle(void);

void app_timer_isr(void)
{
    APP_TIM->STS = 0;   
   
    sys_st.u_tick++;

    AdcInsertedHandle();
   
    if(com.obj01.fun)
        com.obj01.fun->timer_handle();
   
    if(mb.obj08.api)
        mb.obj08.api->rtu_timer_run();
            
    if(mb.obj06.api)
        mb.obj06.api->rtu_timer_run();
   
    cpu_data_sync();
}

modbus任务配置两条静态处理命令,分别为读取8字和写8字。
根据测试平均每秒执行指令30+次。        
        
void modbus_task (void const *argument)
{
    mb_obj_init(&mb.obj08);

    //从机配置
    mb08_Init(MB_RTU_SLAVE, mb_baud_tab[MB_BAUD_19200], MB_PAR_NONE);
    mb.obj08.SlaveId = 1;
    mb.obj08.os_event_send = mb_os_send;
    mb.obj08.os_rtu_end_event = 1;
    mb.obj08.os_timeout_event = 2;
   
    mb_obj_init(&mb.obj06);

    //主机配置
    mb06_Init(MB_RTU_MASTER, mb_baud_tab[MB_BAUD_19200], MB_PAR_NONE);
    mb.obj06.SlaveId = 1;
    mb.obj06.RtuRcvendDelaySet = 3;
    mb.obj06.rcv_end_handle_comp = rcv_end_handle_comp;
    mb.obj06.os_event_send = mb_os_send;
    mb.obj06.os_rtu_end_event = 1;
    mb.obj06.os_timeout_event = 2;
   
    mb.obj06.api->stc_cmd_req(0, 1, FUN_CODE_WRITE_MULTIPLE_REG, mb_tst.pv_w, 0, 8, 0);
    mb.obj06.api->stc_cmd_req(0, 1, FUN_CODE_READ_REG, mb_tst.pv_r, 0, 8, 0);
   
    //任务处理
    for(;;)
    {
        osSignalWait(0, ms_ticks(100));
        
        mb_poll(&mb.obj08);
        
        mb_poll(&mb.obj06);
    }
}




附上测试工程,IAR8.40版以上可用
software.rar (9.11 MB)


使用特权

评论回复
沙发
caizhiwei| | 2021-1-25 21:22 | 只看该作者
牛啊,感谢分享!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

77

主题

328

帖子

2

粉丝