modbus主机源码下载
freemodbus主机源码下载地址 注:感谢armink提供的开源主机代码。
博主移植代码keil5+stm32l151+freertoskeil+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 */
}
三、工具测试:
首先创建读写任务和主机轮询任务,进入写任务,先挂起读任务,然后写,写完之后恢复读任务,同时删除写任务,可以看到读写数据一致,主机移植成功。