STM32基于HAL库带FreeRTOS系统的Freemodbus移植

移植前提

下载所需源码

github地址
本项目地址

可能的win10 IAR设置

设置快捷键
ctrl+shift+l变为find in file,原ctrl+shift+f与win10输入法冲突会切换繁体输入

从站注意定义寄存器数量大小

在这里插入图片描述

效果查询报文

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200406184232910.png

效果回复报文

在这里插入图片描述

移植事件、定时器、串口

对应实现
在这里插入图片描述
开关临界区
e_port.c

void EnterCriticalSection(void)
{
    taskENTER_CRITICAL();
}

void ExitCriticalSection(void)
{
    taskEXIT_CRITICAL();
}

事件移植

portevent.c

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
volatile uint32_t Modbus_Event_ALL = 0;
void Set_Event_Port(void);   
/* ----------------------- Variables ----------------------------------------*/
static StaticEventGroup_t   xSlaveOsEvent;      /*  事件存储,事件组  */
static EventGroupHandle_t   slave_event_Handle; /*  事件标志组句柄    */
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortEventInit( void )
{
    /*创建事件组,成功返回句柄*/
    printf("创建事件组,成功返回句柄\n");
    slave_event_Handle = xEventGroupCreateStatic(&xSlaveOsEvent);
    if(slave_event_Handle == NULL)
    {
        printf("创建事件组 失败!\n");
    }
    return TRUE;
}

BOOL
xMBPortEventPost( eMBEventType eEvent )
{
    /*设置事件标志组 eEvent 置1*/
    printf("设置事件标志组 eEvent:0x%04X\n",eEvent);
    Modbus_Event_ALL |= eEvent;
        
    return TRUE;
}

BOOL
xMBPortEventGet( eMBEventType * eEvent )
{
    /* waiting forever OS event */
    uint32_t recvedEvent;
    recvedEvent = xEventGroupGetBits(slave_event_Handle);
    switch (recvedEvent)
    {
    case EV_READY:
        *eEvent = EV_READY;
        printf("读取事件标志组 EV_READY\n");
        break;
    case EV_FRAME_RECEIVED:
        *eEvent = EV_FRAME_RECEIVED;
        printf("读取事件标志组 EV_FRAME_RECEIVED\n");
        break;
    case EV_EXECUTE:
        *eEvent = EV_EXECUTE;
        printf("读取事件标志组 EV_EXECUTE\n");
        break;
    case EV_FRAME_SENT:
        *eEvent = EV_FRAME_SENT;
        printf("读取事件标志组 EV_FRAME_SENT\n");
        break;
    }
    xEventGroupClearBits(slave_event_Handle ,recvedEvent);
    return TRUE;
}

/**
  ******************************************************************
  * @brief   循环设置事件接口,原中断中设置事件存在问题
  * @author  aron566
  * @version v1.0
  * @date    2020/4/5
  ******************************************************************
  */
void Set_Event_Port(void)
{
    uint32_t ret = 0;
    if(Modbus_Event_ALL)
    {
        ret = xEventGroupSetBits(slave_event_Handle, Modbus_Event_ALL);
        if(ret != Modbus_Event_ALL)
        {
            printf("设置事件失败\n");
        }
        else
        {
            Modbus_Event_ALL = 0;
        }
    }
}

串口移植

串口使用的是带有环形缓冲区,实现方法参考博文
portserial.c

/* ----------------------- Static variables ---------------------------------*/
/* software simulation serial transmit IRQ handler thread stack */
static uint32_t serial_soft_trans_irq_stack[128];
/* software simulation serial transmit IRQ handler thread */
static osThreadId SlaveSerial_soft_trans_irq_Handle;
static osStaticThreadDef_t slave_transControlBlock;


/* serial event */
static StaticEventGroup_t   Slaveevent_serial;           /*事件存储,事件组*/
static EventGroupHandle_t   Slaveevent_serial_Handle;    /*事件标志组句柄*/
/* modbus slave serial device */
static UART_HandleTypeDef *huart_x;
/* ----------------------- Defines ------------------------------------------*/
/* serial transmit event */
#define EVENT_SERIAL_TRANS_START    (1<<0)

/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void);

static void prvvUARTRxISR(void);
static BOOL serial_rx_ind(UART_HandleTypeDef *dev, uint16_t size);
static void serial_soft_trans_irq(void const *parameter);
void Slave_Serial_rx_ind(uint16_t size);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
        eMBParity eParity)
{
    /**
     * set 485 mode receive and transmit control IO
     * @note MODBUS_SLAVE_RT_CONTROL_PIN_INDEX need be defined by user
     */

    /* set serial name */
    switch (ucPORT)
    {
      case 1:
        huart_x = &huart1;
        break;
      case 2:
        huart_x = &huart2;
        break;
      case 3:
        
        break;
      default:
        return FALSE;
        break;
    }
    /*创建事件组,成功返回句柄*/
    Slaveevent_serial_Handle = xEventGroupCreateStatic(&Slaveevent_serial);
    if(Slaveevent_serial_Handle == NULL)
    {
        printf("创建事件组 失败!\n");
    }
    printf("创建串口事件组 Slaveevent_serial_Handle\n");
    osThreadStaticDef(slave_trans, serial_soft_trans_irq, osPriorityNormal, 0, 128, serial_soft_trans_irq_stack, &slave_transControlBlock);
    SlaveSerial_soft_trans_irq_Handle = osThreadCreate(osThread(slave_trans), NULL);
    return TRUE;
}

void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
//    uint32_t recvedEvent;
    if (xRxEnable)
    {
        /* enable RX interrupt */
//        __HAL_UART_ENABLE_IT(huart_x, UART_FLAG_IDLE);
        printf("开启串口接收中断 UART_IT_RXNE\n");
        /* switch 485 to receive mode */
        /*拉低RS485_SEL脚,RS485为接收状态*/
        HAL_GPIO_WritePin(RS485_SEL_GPIO_Port, RS485_SEL_Pin, GPIO_PIN_RESET);		
    }
    else
    {
        /* switch 485 to transmit mode */
        /*拉高RS485_SEL脚,RS485为发送状态*/
        HAL_GPIO_WritePin(RS485_SEL_GPIO_Port, RS485_SEL_Pin, GPIO_PIN_SET);		
        /* disable RX interrupt */
        printf("关闭串口接收中断 UART_FLAG_IDLE\n");
//        HAL_UART_AbortReceive_IT(huart_x);
//        __HAL_UART_DISABLE_IT(huart_x ,UART_FLAG_IDLE);

    }
    if (xTxEnable)
    {
        /* start serial transmit */
//        __HAL_UART_ENABLE_IT(huart_x ,UART_IT_TXE);
        printf("开启串口发送中断 UART_IT_TXE\n");
        /*设置事件标志组 EVENT_SERIAL_TRANS_START 置1*/
        xEventGroupSetBits(Slaveevent_serial_Handle, EVENT_SERIAL_TRANS_START);    
    }
    else
    {
        /* stop serial transmit */
//        recvedEvent = xEventGroupGetBits(Slaveevent_serial_Handle);
        printf("关闭串口发送中断 UART_IT_TXE\n");
//        HAL_UART_AbortTransmit_IT(huart_x);
//        __HAL_UART_DISABLE_IT(huart_x ,UART_IT_TXE);
    }
}

void vMBPortClose(void)
{
    HAL_UART_Abort(huart_x);
}

BOOL xMBPortSerialPutByte(CHAR ucByte)
{
    HAL_UART_Transmit_IT(huart_x,(uint8_t *)&ucByte, 1);
    return TRUE;
}

BOOL xMBPortSerialGetByte(CHAR * pucByte)
{
//    HAL_UART_Receive_IT(huart_x, (uint8_t*)pucByte, 1);
/*这里使用环形缓冲区,作为数据的提取*/
    CQ_getData(cb, (uint8_t*)pucByte, 1);
    return TRUE;
}

/* 
 * Create an interrupt handler for the transmit buffer empty interrupt
 * (or an equivalent) for your target processor. This function should then
 * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
 * a new character can be sent. The protocol stack will then call 
 * xMBPortSerialPutByte( ) to send the character.
 */
void prvvUARTTxReadyISR(void)
{
    pxMBFrameCBTransmitterEmpty();
}

/* 
 * Create an interrupt handler for the receive interrupt for your target
 * processor. This function should then call pxMBFrameCBByteReceived( ). The
 * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
 * character.
 */
void prvvUARTRxISR(void)
{
    pxMBFrameCBByteReceived();
}

/**
 * Software simulation serial transmit IRQ handler.
 *
 * @param parameter parameter
 */
static void serial_soft_trans_irq(void const *parameter) 
{
    uint32_t recved_event;
    
    while (1)
    {
        /* waiting for serial transmit start */
        recved_event = xEventGroupGetBits(Slaveevent_serial_Handle);
        /* execute modbus callback */
        if(recved_event == EVENT_SERIAL_TRANS_START)
        {
            prvvUARTTxReadyISR();
            /*这里本应清除事件位,由于协议栈使用的是单字节发送,需要检测此事件标志位否则发送完一字节就不发了,偷懒没有清除,后期可以优化成发完清除标志*/
//            xEventGroupClearBits(Slaveevent_serial_Handle ,EVENT_SERIAL_TRANS_START);
        }
        osDelay(1);
    }
}

/**
 * This function is serial receive callback function
 *
 * @param dev the device of serial
 * @param size the data size that receive
 *
 * @return return RT_EOK
 */
static BOOL serial_rx_ind(UART_HandleTypeDef *dev, uint16_t size) {
    prvvUARTRxISR();
    return TRUE;
}

void Slave_Serial_rx_ind(uint16_t size)
{
    serial_rx_ind(huart_x ,size);
}

定时器移植

porttimer.c
硬件设置:50us定时
在这里插入图片描述

/* ----------------------- static functions ---------------------------------*/
static TIM_HandleTypeDef timer;
static void prvvTIMERExpiredISR(void);
void Slave_timer_timeout_ind(void* parameter);
uint32_t slave_timer_tick;
static USHORT RT_TICK_PER_SECOND = 50;

extern uint32_t TIM2CurrentTicks;
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
{
    timer = htim2;
    slave_timer_tick = (50 * usTim1Timerout50us) / RT_TICK_PER_SECOND;
    return TRUE;
}

void vMBPortTimersEnable()
{
    printf("开启定时器\n");
    TIM2CurrentTicks = 0;
    __HAL_TIM_SET_COUNTER(&timer, 0);
    HAL_TIM_Base_Start_IT(&timer);
    
}

void vMBPortTimersDisable()
{
    printf("关闭定时器\n");
    HAL_TIM_Base_Stop_IT(&timer);
}

void prvvTIMERExpiredISR(void)
{
    (void) pxMBPortCBTimerExpired();
}

void Slave_timer_timeout_ind(void* parameter)
{
    prvvTIMERExpiredISR();
}

中断
在这里插入图片描述

线程中调用

eMBInit和eMBEnable调用顺序别搞反

    eMBInit(MB_RTU, 1, 1, 115200, MB_PAR_NONE);
    eMBEnable();
    /* Infinite loop */
    for(;;)
    {
        eMBPoll();
        Set_Event_Port();
        /*缓冲区数据不为空,则调用协议栈取数据*/
        if(CQ_getLength(cb))
        {
            Slave_Serial_rx_ind(1);
        }
        osDelay(1);
    }

Master移植类似参考从机协议portxx.c文件修改修改名称即可,问题不大

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: STM32 HAL库可以与FreeRTOSFreeModbus相结合使用,以实现IAR IAR作为开发环境。 FreeRTOS是一个开源的实时操作系统,可以优化处理器资源使用,提供任务调度、时间管理、IPC等功能。STM32 HAL库提供与FreeRTOS的适配层,使得在STM32芯片上可以轻松地使用FreeRTOSFreeModbus是一个开源的Modbus通信协议栈,用于在主机和从机之间进行通信。通过使用HAL库的串口驱动功能,可以实现STM32作为Modbus从机或主机。 将HAL库FreeRTOS集成到IAR开发环境中,可以按照以下步骤进行: 1. 创建一个新的项目,并包括HAL库FreeRTOS的源码文件。可以从ST官网下载最新版本的HAL库FreeRTOS。 2. 配置IAR工程,包括编译器选项、链接器脚本等。确保HAL库FreeRTOS的路径正确,并添加需要的头文件和库文件。 3. 在main函数中初始化HAL库FreeRTOSHAL库提供了相应的初始化函数和配置选项,可以根据具体的需求进行设置。在FreeRTOS中,可以创建任务、定时器、队列等。 4. 在任务中添加FreeModbus库的代码。根据需要,可以实现STM32作为Modbus从机或主机的功能。在从机模式下,可以使用HAL库中的串口驱动来接收和发送Modbus数据。 5. 编译和下载代码到STM32芯片。使用IAR进行编译和链接,并通过JTAG/SWD调试器将代码下载到芯片上。 通过以上步骤,即可实现STM32 HAL库FreeRTOSFreeModbus的结合使用,从而在IAR开发环境中实现相应的功能。 ### 回答2: STM32 HAL库可以与FreeRTOSFreeModbus(从机和主机)一起使用来开发IAR嵌入式系统。 首先,STM32 HAL库为开发者提供了许多硬件抽象层函数,可以轻松控制STM32系列微控制器的各种外设和功能。它简化了对硬件的操作,提高了开发效率。 FreeRTOS是一个流行的实时操作系统,可用于嵌入式系统的并发和调度管理。通过与STM32 HAL库的配合使用,开发者可以在STM32微控制器上运行多个任务,并使用FreeRTOS提供的任务管理功能来调度和控制任务的执行。 FreeModbus是一种用于Modbus通信协议的开源实现。它提供了主机和从机两种模式,可以在STM32微控制器上实现Modbus通信。通过STM32 HAL库FreeModbus的集成,开发者可以使用STM32的串行通信外设来实现Modbus通信,并利用FreeModbus的函数来处理Modbus消息的接收和发送。 IAR是一种广泛使用的集成开发环境(IDE),用于开发嵌入式系统的软件。通过在IAR中配置STM32 HAL库FreeRTOSFreeModbus,开发者可以将它们整合在一起,并通过IAR的编译器和调试器来构建和调试嵌入式应用程序。 综上所述,开发者可以使用STM32 HAL库来实现FreeRTOSFreeModbus(从机和主机)功能,通过IAR进行开发。这样的设计方案可以提高开发效率和可靠性,使得在STM32微控制器上开发嵌入式系统变得更加容易和高效。 ### 回答3: STM32 HAL库可以与FreeRTOSFreeModbus库一起使用来在IAR集成开发环境中实现主机和从机的通信。 首先,需要在IAR环境中配置STM32 HAL库,并根据需要选择所需的外设和功能。然后,导入FreeRTOSFreeModbus库,并将其配置为HAL库的一部分。这可以通过在IAR中设置库包含路径和链接库来实现。 对于FreeRTOS的实现,首先需要配置任务和中断管理器。可以使用HAL库提供的任务和中断API来创建、挂起和恢复任务,并设置任务优先级。使用HAL库提供的定时器或计数器来实现任务调度。 对于FreeModbus的实现,需要配置串口或其他通信接口以与主机进行通信。可以使用HAL库提供的串口或SPI接口功能来配置通信接口。然后,可以使用FreeModbus库的函数来实现Modbus协议的从机或主机功能。这些函数包括读写寄存器、处理请求和响应等。 在主机端,可以使用HAL库提供的定时器或计数器来实现Modbus主机的发送和定时功能。在从机端,可以使用HAL库提供的中断或轮询功能来处理Modbus从机的请求和响应。同时,还需要实现处理从机地址和功能码的逻辑。 最后,可以在IAR中编译、调试和烧录代码。使用HAL库FreeRTOS库和FreeModbus库的API来编写主机和从机的应用程序代码。在应用程序中,可以实现与其他设备的通信,并处理数据传输和处理的逻辑。 通过使用STM32 HAL库FreeRTOSFreeModbus库,可以方便地在IAR环境中实现主机和从机的通信,并实现Modbus协议的功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aron566

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值