stm32移植freemodbusRTU(HAL库+Freertos)主机

modbus主机源码下载

freemodbus主机源码下载地址
注:感谢armink提供的开源主机代码。

博主移植代码
keil5+stm32l151+freertos
keil+ac6+stm32f103+freertos主机

一、移植准备

1.cubemx配置基础工程,包括串口,freertos等。
在这里插入图片描述
在这里主要用到串口二以及freertos CMSIS_V2,同时开启freertos软件定时器。

2.拷贝freertos源码到工程目录,新建一个freemodbus文件夹,拷贝modbus文件夹。
在这里插入图片描述
3.添加文件到工程,并添加头文件路径,Modbus_M为主机代码,Modbus_S为从机代码,不做分析,可看从机移植教程。
在这里插入图片描述
在这里插入图片描述

二、修改工程

同从机一样,主要修改文件为port.c portevent_m.c portserial_m.c porttimer_m.c四个文件。
1.先看 port.h文件,修改如下,主要是移除rt的相关内容,同时增加freertos的内容:

#ifndef _PORT_H
#define _PORT_H
#include "FreeRTOS.h"
#include "cmsis_os.h"
#include "cmsis_os2.h"
#include "event_groups.h"
#include "main.h"
#include "mbconfig.h"
#include "semphr.h"
#include "task.h"
#include "timers.h"
#include <assert.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include "stm32l1xx_hal.h"

#define INLINE							inline
#define PR_BEGIN_EXTERN_C extern "C" {
#define PR_END_EXTERN_C }

#define ENTER_CRITICAL_SECTION() EnterCriticalSection()
#define EXIT_CRITICAL_SECTION() ExitCriticalSection()
typedef struct _serial_fifo
{
  /* software fifo */
  volatile uint8_t *buffer;
  volatile uint16_t put_index, get_index;
} Serial_fifo;
#define FIFO_SIZE_MAX 265
typedef bool BOOL;

typedef unsigned char UCHAR;
typedef char CHAR;

typedef uint16_t USHORT;
typedef int16_t SHORT;

typedef uint32_t ULONG;
typedef int32_t LONG;

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif
#define USING_UART3
#define USING_UART2
//#define USING_UART1
void EnterCriticalSection(void);
void ExitCriticalSection(void);
void Put_in_fifo(Serial_fifo *buff, uint8_t *putdata, int length);
int Get_from_fifo(Serial_fifo *buff, uint8_t *getdata, int length);
extern __inline bool IS_IRQ(void);
#endif

2.port.c文件,参考博客使用串口环形buff接收数据:

void EnterCriticalSection(void)
{
	taskENTER_CRITICAL(); 
}

void ExitCriticalSection(void) 
{ 
	taskEXIT_CRITICAL(); 
}
/*put  bytes in buff*/
void Put_in_fifo(Serial_fifo *buff, uint8_t *putdata, int length) 
{

  portDISABLE_INTERRUPTS();
  while (length--)
   {
	    buff->buffer[buff->put_index] = *putdata;
	    buff->put_index += 1;
	    if (buff->put_index >= FIFO_SIZE_MAX)
	    {
	      buff->put_index = 0;
	    }
	    /* if the next position is read index, discard this 'read char' */
	    if (buff->put_index == buff->get_index) 
	    {
	      buff->get_index += 1;
	      if (buff->get_index >= FIFO_SIZE_MAX)
	      {
	        buff->get_index = 0;
	      }
   		}
  	}
  portENABLE_INTERRUPTS();
}
/*get  bytes from buff*/
int Get_from_fifo(Serial_fifo *buff, uint8_t *getdata, int length) 
{
  int size = length;
  /* read from software FIFO */
  while (length) 
  {
    int ch;
    /* disable interrupt */
    portDISABLE_INTERRUPTS();
    if (buff->get_index != buff->put_index)
    {
      ch = buff->buffer[buff->get_index];
      buff->get_index += 1;
      if (buff->get_index >= FIFO_SIZE_MAX)
      {
        buff->get_index = 0;
      }
    } 
    else
    {
      /* no data, enable interrupt and break out */
      portENABLE_INTERRUPTS();
      break;
    }
    *getdata = ch & 0xff;
    getdata++;
    length--;
    /* enable interrupt */
    portENABLE_INTERRUPTS();
  }
  return size - length;
}
/*判断是否进入在中断中*/
#ifndef IS_IRQ()
extern __asm uint32_t vPortGetIPSR(void); //调用FreeRTOS API
__inline bool IS_IRQ(void) //使用内联函数提高速度
{
  if (vPortGetIPSR()) 
  {
    return TRUE;
  }
  return FALSE;
}
#endif // MACRO

3.修改porttimer_m.c文件,内容如下,移除掉rt_threed内容

/* ----------------------- Platform includes --------------------------------*/
#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbport.h"
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/* ----------------------- Variables ----------------------------------------*/
static USHORT usT35TimeOut50us;
static TimerHandle_t timer = NULL;
static void prvvTIMERExpiredISR(void);
static void timer_timeout_ind(TimerHandle_t xTimer);
static BaseType_t  pxHigherPriorityTaskWoken;
/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR(void);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us) 
{
  /* backup T35 ticks */
  usT35TimeOut50us = usTimeOut50us;
  timer = xTimerCreate("Master timer",
					(50 * usT35TimeOut50us) / (1000 * 1000 / configTICK_RATE_HZ) + 1, pdFALSE,
					(void *)1, timer_timeout_ind);
  if (timer != NULL) 
  {
    Debugprintf("Create Master Timer Success!\r\n");
    return TRUE;
  } 
  else 
  {
    Debugprintf("Create Master Timer Faild!\r\n");
    return FALSE;
  }
 
}

void vMBMasterPortTimersT35Enable()
{
//	Debugprintf("Start master timer!\r\n");
	uint32_t timer_tick =(50 * usT35TimeOut50us) / (1000 * 1000 / configTICK_RATE_HZ) + 1;
  /* Set current timer mode, don't change it.*/
  	vMBMasterSetCurTimerMode(MB_TMODE_T35);
 	 if (IS_IRQ())
 	 {
//		xTimerStopFromISR(timer, 0);
   		 xTimerChangePeriodFromISR((TimerHandle_t)timer, timer_tick, &pxHigherPriorityTaskWoken);
//		xTimerStartFromISR(timer, 0);
	} 
	else 
	{
//		xTimerStop(timer, 0);
    	xTimerChangePeriod((TimerHandle_t)timer, timer_tick, 0);
//		xTimerStart(timer, 0);
 	}
}

void vMBMasterPortTimersConvertDelayEnable() 
{
   uint32_t timer_tick = MB_MASTER_DELAY_MS_CONVERT * configTICK_RATE_HZ / 1000;
  /* Set current timer mode, don't change it.*/
  vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY);
//	xTimerStop(timer, 0);
	if (IS_IRQ()) 
	{
  	  xTimerChangePeriodFromISR((TimerHandle_t)timer, timer_tick, &pxHigherPriorityTaskWoken);
 	} 
    else 
    {
    	xTimerChangePeriod((TimerHandle_t)timer, timer_tick, 0);
    }
}

void vMBMasterPortTimersRespondTimeoutEnable() 
{
   uint32_t timer_tick = MB_MASTER_TIMEOUT_MS_RESPOND * configTICK_RATE_HZ / 1000;
  /* Set current timer mode, don't change it.*/
  vMBMasterSetCurTimerMode(MB_TMODE_RESPOND_TIMEOUT);
   if (IS_IRQ()) 
   {
//		xTimerStopFromISR(timer, 0);
    xTimerChangePeriodFromISR((TimerHandle_t)timer, timer_tick, &pxHigherPriorityTaskWoken);
//		xTimerStartFromISR(timer, 0);
	} 
	else 
	{
//		xTimerStop(timer, 0);
   	 xTimerChangePeriod((TimerHandle_t)timer, timer_tick, 0);
//		xTimerStart(timer, 0);
    }
}

void vMBMasterPortTimersDisable() 
{
  // Debugprintf("Stop master timer!\r\n");
  if (IS_IRQ()) 
  {
   	xTimerStopFromISR((TimerHandle_t)timer, 0);
  } 
  else 
  {
    xTimerStop((TimerHandle_t)timer, 0);
  }
}

void prvvTIMERExpiredISR(void)
{ 
	(void)pxMBMasterPortCBTimerExpired(); 
}
static void timer_timeout_ind(xTimerHandle xTimer) 
{
  // Debugprintf(" Master Timer callback!\r\n");
 	prvvTIMERExpiredISR();
}
#endif

4.修改portevent_m.c文件。

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mb_m.h"
#include "mbport.h"
#include "port.h"
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/* ----------------------- Defines ------------------------------------------*/
/* ----------------------- Variables ----------------------------------------*/
static SemaphoreHandle_t xMasterRunRes;
static EventGroupHandle_t xMasterOsEvent;
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortEventInit(void)
{
  xMasterOsEvent = xEventGroupCreate(); /*创建事件标志组*/
  if (xMasterOsEvent != NULL) 
  {
    Debugprintf("xMBMasterPortEventInit Success!\r\n");
  } 
  else 
  {
    Debugprintf("xMBMasterPortEventInit Faild\r\n");
    return FALSE;
  }
  return TRUE;
}

BOOL xMBMasterPortEventPost(eMBMasterEventType eEvent) 
{
  BaseType_t flag;
  Debugprintf("m_post Event=%d\r\n", eEvent);
  if (xMasterOsEvent != NULL) 
  {
    if (IS_IRQ()) 
    {
      xEventGroupSetBitsFromISR(xMasterOsEvent, eEvent, &flag);
    } 
    else 
    {
      xEventGroupSetBits(xMasterOsEvent, eEvent);
    }
  }
  return TRUE;
}

BOOL xMBMasterPortEventGet(eMBMasterEventType *eEvent) 
{
  uint32_t recvedEvent;
  /* waiting forever OS event */
  recvedEvent = xEventGroupWaitBits(xMasterOsEvent, /* 事件对象句柄 */
                          EV_MASTER_READY | EV_MASTER_FRAME_RECEIVED |
                          EV_MASTER_EXECUTE | EV_MASTER_FRAME_SENT |
                          EV_MASTER_ERROR_PROCESS, /* 接收任务感兴趣的事件*/
                          pdTRUE,         /* 退出时清除事件标志 */
                          pdFALSE,        /* 满足其中一个事件就退出*/
                          portMAX_DELAY); /* 指定超时事件,无限等待 */
  /* the enum type couldn't convert to int type */
  switch (recvedEvent) 
  {
	  case EV_MASTER_READY:
	    *eEvent = EV_MASTER_READY;
	    break;
	  case EV_MASTER_FRAME_RECEIVED:
	    *eEvent = EV_MASTER_FRAME_RECEIVED;
	    break;
	  case EV_MASTER_EXECUTE:
	    *eEvent = EV_MASTER_EXECUTE;
	    break;
	  case EV_MASTER_FRAME_SENT:
	    *eEvent = EV_MASTER_FRAME_SENT;
	    break;
	  case EV_MASTER_ERROR_PROCESS:
	    *eEvent = EV_MASTER_ERROR_PROCESS;
	    break;
  }
  return TRUE;
}
/**
 * This function is initialize the OS resource for modbus master.
 * Note:The resource is define by OS.If you not use OS this function can be
 * empty.
 *
 */
void vMBMasterOsResInit(void) 
{
  // rt_sem_init(&xMasterRunRes, "master res", 0x01, RT_IPC_FLAG_PRIO);
  xMasterRunRes = xSemaphoreCreateBinary();	/*创建二值信号量,刚创建为空,获取不到*/
//	xMasterRunRes = xSemaphoreCreateMutex();
//	if(xMasterRunRes)
//	{
//		xSemaphoreGive(xMasterRunRes);
//	}
}

/**
 * This function is take Mobus Master running resource.
 * Note:The resource is define by Operating System.If you not use OS this
 * function can be just return TRUE.
 *
 * @param lTimeOut the waiting time.
 *
 * @return resource taked result
 */
BOOL xMBMasterRunResTake(LONG lTimeOut)
 {
  /*If waiting time is -1 .It will wait forever */
  // return rt_sem_take(&xMasterRunRes, lTimeOut) ? FALSE : TRUE;
  if (lTimeOut == -1) 
  {
    return xSemaphoreTake(xMasterRunRes, portMAX_DELAY); /*获取二值信号量*/
  }
  return xSemaphoreTake(xMasterRunRes, lTimeOut);
}

/**
 * This function is release Mobus Master running resource.
 * Note:The resource is define by Operating System.If you not use OS this
 * function can be empty.
 *
 */
void vMBMasterRunResRelease(void) 
{
  /* release resource */
  // rt_sem_release(&xMasterRunRes);
	/*释放二值信号量*/
  if(xSemaphoreGive(xMasterRunRes) != pdPASS)
	{
		Debugprintf("SemaphoreGive false\r\n");
	}
}

/**
 * This is modbus master respond timeout error process callback function.
 * @note There functions will block modbus master poll while execute OS waiting.
 * So,for real-time of system.Do not execute too much waiting process.
 *
 * @param ucDestAddress destination salve address
 * @param pucPDUData PDU buffer data
 * @param ucPDULength PDU buffer length
 *
 */
void vMBMasterErrorCBRespondTimeout(UCHAR ucDestAddress,
                                    const UCHAR *pucPDUData,
                                    USHORT ucPDULength)
{
  /**
   * @note This code is use OS's event mechanism for modbus master protocol
   * stack. If you don't use OS, you can change it.
   */
  xEventGroupSetBits(xMasterOsEvent, EV_MASTER_ERROR_RESPOND_TIMEOUT);
  /* You can add your code under here. */
}

/**
 * This is modbus master receive data error process callback function.
 * @note There functions will block modbus master poll while execute OS waiting.
 * So,for real-time of system.Do not execute too much waiting process.
 *
 * @param ucDestAddress destination salve address
 * @param pucPDUData PDU buffer data
 * @param ucPDULength PDU buffer length
 *
 */
void vMBMasterErrorCBReceiveData(UCHAR ucDestAddress, const UCHAR *pucPDUData,
                                 USHORT ucPDULength) 
{
  /**
   * @note This code is use OS's event mechanism for modbus master protocol
   * stack. If you don't use OS, you can change it.
   */
  // rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_RECEIVE_DATA);
  xEventGroupSetBits(xMasterOsEvent, EV_MASTER_ERROR_RECEIVE_DATA);
  /* You can add your code under here. */
}

/**
 * This is modbus master execute function error process callback function.
 * @note There functions will block modbus master poll while execute OS waiting.
 * So,for real-time of system.Do not execute too much waiting process.
 *
 * @param ucDestAddress destination salve address
 * @param pucPDUData PDU buffer data
 * @param ucPDULength PDU buffer length
 *
 */
void vMBMasterErrorCBExecuteFunction(UCHAR ucDestAddress,
                                     const UCHAR *pucPDUData,
                                     USHORT ucPDULength) 
{
  /**
   * @note This code is use OS's event mechanism for modbus master protocol
   * stack. If you don't use OS, you can change it.
   */
  // rt_event_send(&xMasterOsEvent, EV_MASTER_ERROR_EXECUTE_FUNCTION);
  xEventGroupSetBits(xMasterOsEvent, EV_MASTER_ERROR_EXECUTE_FUNCTION);
  /* You can add your code under here. */
}

/**
 * This is modbus master request process success callback function.
 * @note There functions will block modbus master poll while execute OS waiting.
 * So,for real-time of system.Do not execute too much waiting process.
 *
 */
void vMBMasterCBRequestScuuess(void) 
{
  /**
   * @note This code is use OS's event mechanism for modbus master protocol
   * stack. If you don't use OS, you can change it.
   */
  // rt_event_send(&xMasterOsEvent, EV_MASTER_PROCESS_SUCESS);
  xEventGroupSetBits(xMasterOsEvent, EV_MASTER_PROCESS_SUCESS);
  /* You can add your code under here. */
}

/**
 * This function is wait for modbus master request finish and return result.
 * Waiting result include request process success, request respond timeout,
 * receive data error and execute function error.You can use the above callback
 * function.
 * @note If you are use OS, you can use OS's event mechanism. Otherwise you have
 * to run much user custom delay for waiting.
 *
 * @return request error code
 */
eMBMasterReqErrCode eMBMasterWaitRequestFinish(void) 
{
  eMBMasterReqErrCode eErrStatus = MB_MRE_NO_ERR;
  uint32_t recvedEvent;
  /* waiting for OS event */
  recvedEvent = xEventGroupWaitBits(xMasterOsEvent, /* 事件对象句柄 */
			      EV_MASTER_PROCESS_SUCESS | EV_MASTER_ERROR_RESPOND_TIMEOUT |
			      EV_MASTER_ERROR_RECEIVE_DATA |
			      EV_MASTER_ERROR_EXECUTE_FUNCTION, /* 接收任务感兴趣的事件*/
			      pdTRUE,                               /* 退出时清除事件*/
			      pdFALSE,        /* 满足任一事件 */
			      portMAX_DELAY); /* 指定超时事件,无限等待 */
  /* the enum type couldn't convert to int type */
  switch (recvedEvent) 
  {
	  case EV_MASTER_PROCESS_SUCESS:
	    break;
	  case EV_MASTER_ERROR_RESPOND_TIMEOUT: 
	  {
	    eErrStatus = MB_MRE_TIMEDOUT;
	    break;
	  }
	  case EV_MASTER_ERROR_RECEIVE_DATA: 
	  {
	    eErrStatus = MB_MRE_REV_DATA;
	    break;
	  }
	  case EV_MASTER_ERROR_EXECUTE_FUNCTION:
	  {
	    eErrStatus = MB_MRE_EXE_FUN;
	    break;
	  }
  }
  return eErrStatus;
}
#endif

5.修改portserail_m.c文件:


#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"

#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/* ----------------------- Static variables ---------------------------------*/
static volatile uint8_t rx_buff[FIFO_SIZE_MAX];
static Serial_fifo Master_serial_rx_fifo;
/* software simulation serial transmit IRQ handler thread stack */
/* software simulation serial transmit IRQ handler thread */
static TaskHandle_t thread_serial_soft_trans_irq = NULL; /* 创建任务句柄 */
/* serial event */
static EventGroupHandle_t event_serial = NULL;
/* modbus master serial device */
static UART_HandleTypeDef *serial;

/* ----------------------- Defines ------------------------------------------*/
/* serial transmit event */
#define EVENT_SERIAL_TRANS_START (1 << 0)

/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void);
static void prvvUARTRxISR(void);
static void serial_soft_trans_irq(void *parameter);
static void Master_TxCpltCallback(struct __UART_HandleTypeDef *huart);
static void Master_RxCpltCallback(struct __UART_HandleTypeDef *huart);
static int stm32_getc(void);
static int stm32_putc(CHAR c);
/* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,eMBParity eParity)
{
  /**
   * set 485 mode receive and transmit control IO
   * @note MODBUS_MASTER_RT_CONTROL_PIN_INDEX need be defined by user
   */

  /* set serial name */
  if (ucPORT == 1) 
  {
#if defined(USING_UART1)
    extern UART_HandleTypeDef huart1;
    serial = &huart1;
    Debugprintf("Master using uart1!\r\n");
#endif
  } 
  else if (ucPORT == 2) 
  {
#if defined(USING_UART2)
    extern UART_HandleTypeDef huart2;
    serial = &huart2;
    Debugprintf("Master using uart2!\r\n");

#endif
  }
   else if (ucPORT == 3) 
   {
#if defined(USING_UART3)
    extern UART_HandleTypeDef huart3;
    serial = &huart3;
    Debugprintf("Master using uart3!\r\n");
#endif
  }
  /* set serial configure parameter */
  /* set serial configure */
  serial->Init.BaudRate = ulBaudRate;
  serial->Init.StopBits = UART_STOPBITS_1;
  switch (eParity) 
  {
	  case MB_PAR_NONE: 
	  {
	    serial->Init.WordLength = UART_WORDLENGTH_8B;
	    serial->Init.Parity = UART_PARITY_NONE;
	    break;
	  }
	  case MB_PAR_ODD: 
	  {
	    serial->Init.WordLength = UART_WORDLENGTH_9B;
	    serial->Init.Parity = UART_PARITY_ODD;
	    break;
	  }
	  case MB_PAR_EVEN: 
	  {
	    serial->Init.WordLength = UART_WORDLENGTH_9B;
	    serial->Init.Parity = UART_PARITY_EVEN;
	    break;
	  }
  }
  if (HAL_UART_Init(serial) != HAL_OK) 
  {
    Error_Handler();
  }
  __HAL_UART_DISABLE_IT(serial, UART_IT_RXNE);
  __HAL_UART_DISABLE_IT(serial, UART_IT_TC);
  /*registe recieve callback*/
  HAL_UART_RegisterCallback(serial, HAL_UART_RX_COMPLETE_CB_ID, Master_RxCpltCallback);
  /* software initialize */
  Master_serial_rx_fifo.buffer = rx_buff;
  Master_serial_rx_fifo.get_index = 0;
  Master_serial_rx_fifo.put_index = 0;
  /* software initialize */

  /* 创建主站发送任务 */
  event_serial = xEventGroupCreate();
  if (NULL != event_serial)
  {
    Debugprintf("Master create event_serial success! event_serial=%d\r\n",event_serial);
  }
  else 
  {
    Debugprintf("Master create event_serial Failed!\r\n");
  }
  BaseType_t xReturn = pdPASS;
  xReturn = xTaskCreate((TaskFunction_t)serial_soft_trans_irq, /* 任务入口函数 */
                  (const char *)"master trans",          /* 任务名字 */
                  (uint16_t)128,                         /* 任务栈大�?? */
                  (void *)NULL,    /* 任务入口函数参数 */
                  (UBaseType_t)8, /* 任务的优先级 */
                  NULL);           /*任务控制块*/
  if (xReturn == pdPASS) 
  {
    Debugprintf("xTaskCreate Master trans success\r\n");
  }
  else 
  {
    Debugprintf("xTaskCreate Master trans faild!\r\n");
    return FALSE;
  }
  return TRUE;
}

void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
  /*这一步不能省略,需要提前清理掉标志位,否则接收会有问题*/
  __HAL_UART_CLEAR_FLAG(serial,UART_FLAG_RXNE);
   __HAL_UART_CLEAR_FLAG(serial,UART_FLAG_TC);
  if (xRxEnable == pdTRUE) 
  {
    /* enable RX interrupt */
    __HAL_UART_ENABLE_IT(serial, UART_IT_RXNE);
  } 
  else 
  {
    /* disable RX interrupt */
    __HAL_UART_DISABLE_IT(serial, UART_IT_RXNE);
  }
  if (xTxEnable == pdTRUE)
  {
    /* start serial transmit */
    xEventGroupSetBits(event_serial, EVENT_SERIAL_TRANS_START);
  }
  else
  {
    xEventGroupClearBits(event_serial, EVENT_SERIAL_TRANS_START);
  }
}

void vMBMasterPortClose(void) 
{
  __HAL_UART_DISABLE(serial);
}

BOOL xMBMasterPortSerialPutByte(CHAR ucByte) 
{
  stm32_putc(ucByte);
  return TRUE;
}

BOOL xMBMasterPortSerialGetByte(CHAR *pucByte) 
{
  Get_from_fifo(&Master_serial_rx_fifo, (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) 
{ 
	pxMBMasterFrameCBTransmitterEmpty(); 
}

/*
 * 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) 
{ 
	pxMBMasterFrameCBByteReceived(); 
}

/**
 * Software simulation serial transmit IRQ handler.
 *
 * @param parameter parameter
 */
static void serial_soft_trans_irq(void *parameter) 
{
  while (1) 
  {
    /* waiting for serial transmit start */
    xEventGroupWaitBits(event_serial,             /* 事件对象句柄 */
                        EVENT_SERIAL_TRANS_START, /* 接收任务感兴趣的事件 */
                        pdFALSE,        /* 退出时清除事件标志*/
                        pdFALSE,        /* 满足感兴趣的任一事件 */
                        portMAX_DELAY); /* 指定超时事件,无限等待 */
    /* execute modbus callback */
    prvvUARTTxReadyISR();
  }
}

/**
 * @brief  Rx Transfer completed callbacks.
 * @param  huart  Pointer to a UART_HandleTypeDef structure that contains
 *                the configuration information for the specified UART module.
 * @retval None
 */
static void Master_RxCpltCallback(struct __UART_HandleTypeDef *huart) 
{
  int ch = -1;
  /*UART RX非空中断调用,并获取一帧数据*/
  while (1) 
  {
    ch = stm32_getc();
    if (ch == -1)
    {
      break;
    }
    Put_in_fifo(&Master_serial_rx_fifo, (uint8_t *)&ch, 1);
  }
  prvvUARTRxISR();
}
/*UART发送一个数据*/
static int stm32_putc(CHAR c) 
{
  serial->Instance->DR = c;
  while (!(serial->Instance->SR & UART_FLAG_TC));
  return TRUE;
}
/*UART接收一个数据*/
static int stm32_getc(void) 
{
  int ch;
  ch = -1;
  if (serial->Instance->SR & UART_FLAG_RXNE) 
  {
    ch = serial->Instance->DR & 0xff;
  }
  return ch;
}
#endif

至此移植基本结束下面是freertos创建文件。

#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

#include "user_mb_app.h"
#include "tim.h"

/*主机任务*/
osThreadId_t MasterTaskHandle;
const osThreadAttr_t MasterTask_attributes = {
    .name = "MasterTask",
    .priority = 2,
    .stack_size = 128 * 4};

/*从机任务*/
osThreadId_t SlaveTaskHandle;
const osThreadAttr_t SlaveTask_attributes = {
    .name = "SlaveTask",
    .priority = 2,
    .stack_size = 128 * 4};

/*写任务*/
osThreadId_t WriteTaskHandle;
const osThreadAttr_t Write_TASK = {
    .name = "Write_Task",
    .priority = 2,
    .stack_size = 128 * 8};

/*读任务*/
osThreadId_t ReadTaskHandle;
const osThreadAttr_t Read_Task = {
    .name = "Read_Task",
    .priority = 2,
    .stack_size = 128 * 8};

void MasterTask(void *argument);
void SlaveTask(void *argument);
void StartWriteTask(void *argument);
void StartReadTask(void *argument);
		
void MX_FREERTOS_Init(void);

void MX_FREERTOS_Init(void)
{
  HAL_TIM_Base_Start(&htim6); //开启帧率测试
  eMBMasterInit(MB_RTU, 2, 38400, MB_PAR_NONE); /*主机初始化*/
  eMBMasterEnable();	/*主机使能*/
//  eMBInit(MB_RTU, 0x01, 3, 38400, MB_PAR_NONE); /*从机初始化*/
//  eMBEnable();	/*从机使能*/
	/*创建写任务*/
  WriteTaskHandle = osThreadNew(StartWriteTask, NULL, &Write_TASK);
	/*创建主机任务*/
  MasterTaskHandle = osThreadNew(MasterTask, NULL, &MasterTask_attributes);
	/*创建读任务*/
	ReadTaskHandle = osThreadNew(StartReadTask, NULL, &Read_Task);
	/*创建从机任务*/
// SlaveTaskHandle = osThreadNew(SlaveTask, NULL, &SlaveTask_attributes);

}

void StartWriteTask(void *argument)
{
	vTaskSuspend(ReadTaskHandle);
	eMBMasterReqErrCode ret;
//  uint16_t data[] = {0,1,1,1};
	uint16_t data[10] = {6,2,3,4,5,8,2,50,10,11};
	unsigned long H_value;

  for (;;)
  {
		H_value = uxTaskGetStackHighWaterMark(WriteTaskHandle);
		Debugprintf("H_value:%d\r\n", H_value);
		/*写单个寄存器*/
//		ret = eMBMasterReqWriteHoldingRegister(1, 1, data[0], 100);
		/*写多个寄存器*/
		ret = eMBMasterReqWriteMultipleHoldingRegister(1, 0, 10, data, 100);
		Debugprintf("ret values :%d ", ret);
   		 for(uint8_t i=0;i<sizeof(data)/sizeof(uint16_t);i++)
		{
     		 data[i]++;
		}
		osDelay(500);
		vTaskResume(ReadTaskHandle);
		vTaskSuspend(WriteTaskHandle);
		vTaskDelete(NULL);
  }
}

void StartReadTask(void *argument)
{
//	vTaskSuspend(WriteTaskHandle);
	extern USHORT usMRegHoldBuf[MB_MASTER_TOTAL_SLAVE_NUM][M_REG_HOLDING_NREGS];
	eMBMasterReqErrCode ret;
	uint8_t slaveid;
	uint8_t regaddr;
	uint8_t regnums;
	uint8_t i;
	for (;;)
 	{
		slaveid = 1;
		regaddr = 0;
		regnums = 10;
		/*读多个寄存器*/
		ret = eMBMasterReqReadHoldingRegister(slaveid, regaddr, regnums, 100);		
		if(ret == MB_MRE_NO_ERR)
		{
			Debugprintf("===eMBMasterReqReadHoldingRegister successful! values : ");
			for(i = 0; i < regnums; i++)
			{
				Debugprintf("%#x ", usMRegHoldBuf[slaveid-1][regaddr+i]);
			}
			Debugprintf("\r\n");
		} 
		else
		{
			Debugprintf("===eMBMasterReqReadHoldingRegister failed!\r\n");
		}
		osDelay(500);
//		vTaskResume(WriteTaskHandle);
//		vTaskSuspend(ReadTaskHandle);
//		vTaskDelete(ReadTaskHandle);
	}
}

void MasterTask(void *argument)
{
  for (;;)
  {
    eMBMasterPoll();		/*主机轮询*/
	osDelay(500);
  }
}

void SlaveTask(void *argument)
{
  for (;;)
  {
    eMBPoll();		/*从机轮询*/
    osDelay(500);
  }
}

6.stm32xxxit.c文件修改串口中断函数以及main.c文件修改定时器回调函数

void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART2_IRQn 0 */
  if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE))
  {
    huart2.RxCpltCallback(&huart2);
    __HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_RXNE);
  }
  if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_ORE))
  {
    uint16_t pucByte = (uint16_t)((&huart2)->Instance->DR & (uint16_t)0x01FF);
    __HAL_UART_CLEAR_OREFLAG(&huart2);
  }
  if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TC))
  {
    __HAL_UART_CLEAR_FLAG(&huart2, UART_FLAG_TC);
  }
  /* USER CODE END USART2_IRQn 0 */
  /* USER CODE BEGIN USART2_IRQn 1 */

  /* USER CODE END USART2_IRQn 1 */
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM7) {
    HAL_IncTick();
  }
	if(htim->Instance == htim6.Instance)
	{
#if MB_MASTER_RTU_ENABLED > 0			
		pxMBMasterPortCBTimerExpired();
#else		
		pxMBPortCBTimerExpired();
#endif	
	}
  /* USER CODE BEGIN Callback 1 */

  /* USER CODE END Callback 1 */
}

三、工具测试:

在这里插入图片描述
在这里插入图片描述
首先创建读写任务和主机轮询任务,进入写任务,先挂起读任务,然后写,写完之后恢复读任务,同时删除写任务,可以看到读写数据一致,主机移植成功。

  • 8
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 69
    评论
### 回答1: STM32是一款由ST(意法半导体)公司开发的高性能32位单片机系列。它集成了丰富的外设,如串口、定时器、PWM、ADC等,同时支持多种通信接口如SPI、I2C和CAN等。STM32 HAL(Hardware Abstraction Layer)是ST公司为STM32系列开发的一套硬件抽象层,它提供了一套统一的编程接口,简化了在不同STM32芯片之间的移植工作。 FreeRTOS是一个流行的实时操作系统(RTOS),它在STM32上得到广泛的应用。它提供了多任务调度、信号量、消息队列等功能,可以帮助开发者实现复杂的任务并行处理。在STM32中使用FreeRTOS,可以充分利用STM32的多核处理能力和丰富的外设资源。 MQTT是一种轻量的消息传输协议,广泛应用于物联网领域。它通过发布和订阅模式实现消息的传输,具有简单、开销小、可靠性高的特点。在STM32中使用MQTT,可以实现与各种设备的通信,如传感器、控制器等。 综上所述,STM32 HAL是ST公司为STM32系列开发的硬件抽象层,可以方便地在不同芯片之间移植FreeRTOS是一个实时操作系统,能够帮助开发者实现并行处理和任务调度。MQTT是一种轻量的消息传输协议,可以用于STM32与其他设备之间的通信。通过结合使用这三种技术,可以开发出高性能、可靠的物联网应用。 ### 回答2: STM32 HAL是ST公司提供的一套基于硬件抽象层的开发库,用于简化嵌入式系统的开发。HAL库提供了一系列功能丰富的函数接口,包括GPIO、UART、SPI、I2C等外设的控制接口,可以方便地对STM32单片机进行配置和控制。 FreeRTOS是一款广泛使用的开源实时操作系统(RTOS),适用于嵌入式系统的开发。FreeRTOS提供了任务管理、调度器、队列、信号量等功能,可以用于多任务的并发执行。它具有轻量、可移植、可靠等特点,广泛应用于各种嵌入式系统中。 MQTT(Message Queuing Telemetry Transport)是一种基于发布-订阅模式的轻量级通信协议,常用于物联网(IoT)应用中的设备间通信。MQTT协议使用简单、开销小,适用于带宽有限的场景。它通过客户端和代理服务器之间的消息传递实现通信,支持可靠传输和压缩技术,可以满足物联网应用对低功耗、低带宽的要求。 结合起来,使用STM32 HAL库FreeRTOS可以实现在STM32单片机上运行MQTT协议。HAL库提供了对待控制的硬件外设的支持,可以与MQTT库进行配合,实现对设备的配置和控制。FreeRTOS提供了任务管理和调度功能,可以用于处理MQTT消息的异步接收和处理,以及与其他任务的并行执行。通过这些组件的结合使用,可以开发出功能强大、稳定可靠的物联网设备。 ### 回答3: STM32 HAL是指STM32微控制器的硬件抽象层(Hardware Abstraction Layer)。它提供了一个统一的接口,以便开发人员能够简化对STM32微控制器的底层硬件操作。通过使用HAL,开发人员可以更方便地编写可移植且易于维护的代码。 FreeRTOS是一个开源的嵌入式实时操作系统(RTOS)。它提供了任务调度、时间管理、内存管理、通信和同步机制等功能,使开发人员能够更方便地编写多任务并发的嵌入式应用程序。在STM32项目中,FreeRTOS通常与STM32 HAL一起使用,以实现高效的任务调度和资源管理。 MQTT是一种基于发布/订阅模式的轻量级消息传输协议。它被广泛应用于物联网等场景中,以实现设备之间的消息通信。MQTT具有低延迟、低能耗和网络带宽占用小等特点,非常适合在资源有限的嵌入式系统中使用。在STM32 HAL和FreeRTOS的基础上,使用MQTT可以实现STM32微控制器与其他设备之间的可靠、高效的通信。 总结来说,STM32 HAL提供了对STM32微控制器硬件的抽象接口,简化了底层编程;FreeRTOS是一个实时操作系统,提供了任务调度和资源管理;而MQTT是一种轻量级的消息传输协议,用于在嵌入式系统中实现设备之间的通信。这三个技术共同使用可以实现高效、可靠的嵌入式应用程序开发。
评论 69
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值