基于RT-Thread Studio+STM32F407ZGT6+FreeModbusTcpSlave的移植

一、RT-Thread Studio新建项目

根据自己硬件参数设置,此工程基于RT-Thread 5.1.0,此时编译会发现编译报错

 这是由于RT-Thread 新老版本的不兼容报错,可以通过配置项目中的RT-Thread Settings-->组件-->旧版本兼容支持性打开,再次编译即可正常编译通过

/*
 * Copyright (c) 2006-2024, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-07-10     RT-Thread    first version
 */

#include <rtthread.h>
#include <board.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

rt_thread_t Modbus_Thread_tid;
rt_thread_t Led_Thread_tid;

#define LED0 GET_PIN(F,9)
#define LED1 GET_PIN(F,10)

void LED_Init()
{
    rt_pin_mode(LED0,PIN_MODE_OUTPUT);
    rt_pin_mode(LED1,PIN_MODE_OUTPUT);
    rt_pin_write(LED0, PIN_LOW);
    rt_pin_write(LED0, PIN_LOW);
}

void Led_Thread_entry(void *parameter)
{
    while(1)
    {
        rt_thread_mdelay(100);
    }
}

void Modbus_Thread_entry(void *parameter)
{
    while(1)
    {
        rt_pin_write(LED0, !(rt_pin_read(LED0)));
        rt_thread_mdelay(1000);
    }
}


int main(void)
{
    LED_Init();

    Modbus_Thread_tid =rt_thread_create("Modbus_Thread",Modbus_Thread_entry,RT_NULL,2048,23,5);
    if(Modbus_Thread_tid != RT_NULL)
    {
        rt_thread_startup(Modbus_Thread_tid);
    }

    Led_Thread_tid =rt_thread_create("Led_Thread",Led_Thread_entry,RT_NULL,2048,23,5);
    if(Led_Thread_tid != RT_NULL)
    {
        rt_thread_startup(Led_Thread_tid);
    }

    return RT_EOK;
}

修改main函数,这里开启了两个线程以及LED的简单使用,在添加Freemodbus之前,需要先配置LAN8720+LWIP,首先在board.h中开启ETH相关的宏chushihua

#define BSP_USING_ETH
#ifdef BSP_USING_ETH
#define PHY_USING_LAN8720A
/*#define PHY_USING_DM9161CEP*/
/*#define PHY_USING_DP83848C*/
#endif

初始化引脚和时钟,将HAL_ETH_MspInit函数复制到自己工程的board.c文件的末尾,使之参与编译

void HAL_ETH_MspInit(ETH_HandleTypeDef* heth)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(heth->Instance==ETH)
  {
  /* USER CODE BEGIN ETH_MspInit 0 */

  /* USER CODE END ETH_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_ETH_CLK_ENABLE();

    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOG_CLK_ENABLE();
    /**ETH GPIO Configuration
    PC1     ------> ETH_MDC
    PA1     ------> ETH_REF_CLK
    PA2     ------> ETH_MDIO
    PA7     ------> ETH_CRS_DV
    PC4     ------> ETH_RXD0
    PC5     ------> ETH_RXD1
    PG11     ------> ETH_TX_EN
    PG13     ------> ETH_TXD0
    PG14     ------> ETH_TXD1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_13|GPIO_PIN_14;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
    HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  /* USER CODE BEGIN ETH_MspInit 1 */

  /* USER CODE END ETH_MspInit 1 */
  }

}

在stm32f4xx_hal_conf.h文件中打开对ETH的支持,也就是取消掉#define HAL_ETH_MODULE_ENABLED这个宏定义的注释

/* #define HAL_DAC_MODULE_ENABLED   */
/* #define HAL_DCMI_MODULE_ENABLED   */
/* #define HAL_DMA2D_MODULE_ENABLED   */
#define HAL_ETH_MODULE_ENABLED
/* #define HAL_NAND_MODULE_ENABLED   */
/* #define HAL_NOR_MODULE_ENABLED   */
/* #define HAL_PCCARD_MODULE_ENABLED   */

在drv_eth.c文件中会调用phy_reset函数,该函数需要根据自己实际情况实现

#define RESET_IO GET_PIN(D, 3)

void phy_reset(void)
{
    rt_pin_write(RESET_IO, PIN_LOW);
    rt_thread_mdelay(50);
    rt_pin_write(RESET_IO, PIN_HIGH);
}

int phy_init(void)
{
    rt_pin_mode(RESET_IO, PIN_MODE_OUTPUT);
    rt_pin_write(RESET_IO, PIN_HIGH);
    return RT_EOK;
}
INIT_BOARD_EXPORT(phy_init);

配置项目中的RT-Thread Settings-->组件-->网络-->使能Lwip堆栈

 使用静态地址,所以需要将通过DHCP分配IP地址关闭,编译下载程序后,将自己ip与电路板ip修改成同一网关,此时已经可以正常ping通电路板,但还不支持ifconfig指令,需要开启SAL

 

 二、添加freemodbus软件包

在RT-Thread Settings-->添加软件包-->搜索modbus-->添加freemodbus软件包

在RT-Thread Settings-->软件包-->Freemodbus: Modbus 主从堆栈

使能Slave mode,将Enable RTU slave mode 关闭,使能Enable TCP slave mode,同时使能Enable slave sample(打开例程),由于是TCP,所以该选型下面的串口参数设置实际不用配置

其中可以在advanced configuration中配置自己所需的寄存器数量

 ctrl+s保存RT-Thread Settings,会自动添加TCP Server 软件包,不需要去管

可以看到在packages中已经添加了对应的软件包程序,在packages-->freemodbus-latest-->samples-->sample_mb_slave.c中可以看到freemodbus的例程,

/*
 * Copyright (c) 2006-2022, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2019-06-21     flybreak     first version
 */

#include <rtthread.h>

#include "mb.h"
#include "user_mb_app.h"

#ifdef PKG_MODBUS_SLAVE_SAMPLE
#define SLAVE_ADDR      MB_SAMPLE_SLAVE_ADDR
#define PORT_NUM        MB_SLAVE_USING_PORT_NUM
#define PORT_BAUDRATE   MB_SLAVE_USING_PORT_BAUDRATE
#else
#define SLAVE_ADDR      0x01
#define PORT_NUM        2
#define PORT_BAUDRATE   115200
#endif

#define PORT_PARITY     MB_PAR_EVEN

#define MB_POLL_THREAD_PRIORITY  10
#define MB_SEND_THREAD_PRIORITY  RT_THREAD_PRIORITY_MAX - 1

#define MB_POLL_CYCLE_MS 200

extern USHORT usSRegHoldBuf[S_REG_HOLDING_NREGS];

static void send_thread_entry(void *parameter)
{
    USHORT         *usRegHoldingBuf;
    usRegHoldingBuf = usSRegHoldBuf;
    rt_base_t level;

    while (1)
    {
        /* Test Modbus Master */
        level = rt_hw_interrupt_disable();

        usRegHoldingBuf[3] = (USHORT)(rt_tick_get() / 100);

        rt_hw_interrupt_enable(level);

        rt_thread_mdelay(1000);
    }
}

static void mb_slave_poll(void *parameter)
{
    if (rt_strstr(parameter, "RTU"))
    {
#ifdef PKG_MODBUS_SLAVE_RTU
        eMBInit(MB_RTU, SLAVE_ADDR, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);
#else
        rt_kprintf("Error: Please open RTU mode first");
#endif
    }
    else if (rt_strstr(parameter, "ASCII"))
    {
#ifdef PKG_MODBUS_SLAVE_ASCII
        eMBInit(MB_ASCII, SLAVE_ADDR, PORT_NUM, PORT_BAUDRATE, PORT_PARITY);
#else
        rt_kprintf("Error: Please open ASCII mode first");
#endif
    }
    else if (rt_strstr(parameter, "TCP"))
    {
#ifdef PKG_MODBUS_SLAVE_TCP
        eMBTCPInit(0);
#else
        rt_kprintf("Error: Please open TCP mode first");
#endif
    }
    else
    {
        rt_kprintf("Error: unknown parameter");
    }
    eMBEnable();
    while (1)
    {
        eMBPoll();
        rt_thread_mdelay(MB_POLL_CYCLE_MS);
    }
}

static int mb_slave_sample(int argc, char **argv)
{
    static rt_uint8_t is_init = 0;
    rt_thread_t tid1 = RT_NULL, tid2 = RT_NULL;

    if (is_init > 0)
    {
        rt_kprintf("sample is running\n");
        return -RT_ERROR;
    }
    if (argc < 2)
    {
        rt_kprintf("Usage: mb_slave_sample RTU/ASCII/TCP\n");
        return -1;
    }

    tid1 = rt_thread_create("md_s_poll", mb_slave_poll, argv[1], 1024, MB_POLL_THREAD_PRIORITY, 10);
    if (tid1 != RT_NULL)
    {
        rt_thread_startup(tid1);
    }
    else
    {
        goto __exit;
    }

    tid2 = rt_thread_create("md_s_send", send_thread_entry, RT_NULL, 512, MB_SEND_THREAD_PRIORITY, 10);
    if (tid2 != RT_NULL)
    {
        rt_thread_startup(tid2);
    }
    else
    {
        goto __exit;
    }

    is_init = 1;
    return RT_EOK;

__exit:
    if (tid1)
        rt_thread_delete(tid1);
    if (tid2)
        rt_thread_delete(tid2);

    return -RT_ERROR;
}
MSH_CMD_EXPORT(mb_slave_sample, run a modbus slave sample);

可以看到在mb_slave_sample函数中,使能了mb_slave_poll和send_thread_entry两个线程

static void send_thread_entry(void *parameter)
{
    USHORT         *usRegHoldingBuf;
    usRegHoldingBuf = usSRegHoldBuf;
    rt_base_t level;

    while (1)
    {
        /* Test Modbus Master */
        level = rt_hw_interrupt_disable();

        usRegHoldingBuf[3] = (USHORT)(rt_tick_get() / 100);

        rt_hw_interrupt_enable(level);

        rt_thread_mdelay(1000);
    }
}

send_thread_entry函数为不断改变usRegHoldingBuf[3]的值

static void mb_slave_poll(void *parameter)
{
 if (rt_strstr(parameter, "TCP"))
    {
#ifdef PKG_MODBUS_SLAVE_TCP
        eMBTCPInit(0);
#else
        rt_kprintf("Error: Please open TCP mode first");
#endif
    }
    else
    {
        rt_kprintf("Error: unknown parameter");
    }
    eMBEnable();
    while (1)
    {
        eMBPoll();
        rt_thread_mdelay(MB_POLL_CYCLE_MS);
    }
}

mb_slave_poll函数中剔除掉RTU和ASCII的例程后,如上代码所示,再次精简后代码如下

static void mb_slave_poll(void *parameter)
{

    eMBTCPInit(0);
    eMBEnable();
    while (1)
    {
        eMBPoll();
        rt_thread_mdelay(MB_POLL_CYCLE_MS);
    }
}

eMBTCPInit(0);//配置TCPPort

eMBEnable();//使能

eMBPoll();//轮询

修改main.c中代码增加

#include <mb.h>
#include <user_mb_app.h>

void modbus_Init()
{
    eMBTCPInit(502);
    eMBEnable();
}

void Led_Thread_entry(void *parameter)
{
    while(1)
    {
        eMBPoll();
        rt_thread_mdelay(100);
    }
}

int main(void)
{
    LED_Init();
    modbus_Init();

    Modbus_Thread_tid =rt_thread_create("Modbus_Thread",Modbus_Thread_entry,RT_NULL,2048,23,5);
    if(Modbus_Thread_tid != RT_NULL)
    {
        rt_thread_startup(Modbus_Thread_tid);
    }

    Led_Thread_tid =rt_thread_create("Led_Thread",Led_Thread_entry,RT_NULL,2048,23,5);
    if(Led_Thread_tid != RT_NULL)
    {
        rt_thread_startup(Led_Thread_tid);
    }

    return RT_EOK;
}

 编译下载

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值