FreeMODBUS库 实现串口的选择切换
日期 | 作者 | 版本 | 说明 |
---|---|---|---|
2020.12.16 | Hxj | V1.0 | 完成主体 |
2021.01.08 | Hxj | V1.0 | 精简后的版本 |
介绍
在FreeMODBUS 库中是不支持串口在运行的时候进行切换,同时也不支持多串口同时运行,必须得从新的配置才能进行串口的输出的选择。这样就使得程序有他的局限性。下文将会着重介绍如何进行选择性配置串口的输出。
一、FreeMODEBUS的串口配置
源码
头文件
/*
* mb_user.h
*
* Created on: May 24, 2020
* Author: 81001
*/
#ifndef FREEMODBUS_USER_MB_USER_H_
#define FREEMODBUS_USER_MB_USER_H_
#include "mb_user.h"
#include "mb.h"
#include "mbplatform.h"
#include "mb_coilsreg.h"
#include "mb_discretereg.h"
#include "mb_inputreg.h"
#include "mb_holdingreg.h"
#include "gpio_ext.h"
//是否启用FreeModbus模块
#define FREEMODBUS_ENABLE 1
//选择PORT类型是否为RS485模块
#define FREEMODBUS_PORT_INTERFACE_RS485
//#define FREEMODBUS_PORT_INTERFACE_RS232
//设置FreeModbus从机的地址
#define FREEMODBUS_DEV_ADDR 0x01
#define RS485_T_CTRL GPIOE_OUT(15)
#define FREEMODBUS_TIMER 2
extern uint8_t FreeModbus_PortNum;
extern USART_TypeDef *USART_Modbus;
extern uint32_t FreeModbus_PortBaudrate;
extern eMBParity Freemodbus_PortParity;
extern uint8_t DipValue;
extern uint8_t PORT_Switch;
void User_MB_InitPortParam(uint8_t portNum, uint32_t baudRate, eMBParity parity);
void User_MB_Config();
void User_MB_ConfigNVIC();
void User_MB_InitRegs();
void User_MB_RefreshInputRegister();
void User_MB_RefreshCoilsRegister();
void User_MB_RefreshDiscreteRegister();
void User_MB_RefreshHoldingRegister();
#endif /* FREEMODBUS_USER_MB_USER_H_ */
源文件
/*
* mb_user.c
*
* Created on: May 24, 2020
* Author: 81001
*/
#include "mb_user.h"
#include "sensor.h"
#include "user.h"
#include "tc.h"
#include "globalVariate.h"
#include "usart_ext.h"
#include "bldcmotor.h"
uint8_t FreeModbus_PortNum = 3;
USART_TypeDef *USART_Modbus = USART3;
uint32_t FreeModbus_PortBaudrate = 115200;
eMBParity Freemodbus_PortParity = MB_PAR_NONE;
uint8_t PORT_Switch = 0;
void User_MB_Config()
{
switch (BitData_PortCtrl.ByteData)
{
//Bit0 = 0, configure DB-9 port
case 0:
//配置Modbus通讯串口的全局参数
User_MB_InitPortParam(USART_DB9_NUM, 115200, MB_PAR_NONE);
//配置GPIO
USART_ConfigGPIO(USART_DB9_TXD_PORT, USART_DB9_TXD_PIN, USART_DB9_RXD_PORT, USART_DB9_RXD_PIN);
//配置NVIC
User_MB_ConfigNVIC();
break;
//Bit0 = 1, configure LCD port
case 1:
//配置Modbus通讯串口的全局参数
User_MB_InitPortParam(USART_LCD_NUM, 115200, MB_PAR_NONE);
//配置GPIO
USART_ConfigGPIO(USART_LCD_TXD_PORT, USART_LCD_TXD_PIN, USART_LCD_RXD_PORT, USART_LCD_RXD_PIN);
//配置NVIC
User_MB_ConfigNVIC();
break;
//Bit0 = 0 & Bit1 = 1, configure RS485 port
case 2:
//Bit0 = 1 & Bit1 = 1, configure RS485 port
case 3:
//配置Modbus通讯串口的全局参数
User_MB_InitPortParam(USART_485_NUM, 115200, MB_PAR_NONE);
//配置GPIO
USART_ConfigGPIO(USART_485_TXD_PORT, USART_485_TXD_PIN, USART_485_RXD_PORT, USART_485_RXD_PIN);
//配置NVIC
User_MB_ConfigNVIC();
break;
default:
break;
}
//初始化Modbus四种寄存器
User_MB_InitRegs();
//初始化Modbus
eMBInit(MB_RTU, FREEMODBUS_DEV_ADDR, FreeModbus_PortNum,
FreeModbus_PortBaudrate, Freemodbus_PortParity);
//使能Modbus功能
eMBEnable();
}
void User_MB_RefreshCoilsRegister()
{
//设置缓冲数组,提高轮询效率,只有缓冲数组中的数据发生变化的时候,才会实际寄存器的读写操作
static uint8_t coilsReg_buffer[32] =
{
2 };
(void) coilsReg_buffer;
//开启串口切换
if (coilsReg_buffer[24] != CoilsReg_GetBit(24))
{
coilsReg_buffer[24] = CoilsReg_GetBit(24);
BitData_PortCtrl.BitData.bit1 = coilsReg_buffer[24];
}
}
1.串口的选择配置函数 void User_MB_Config()
解析
BitData_PortCtrl.ByteData
与BitData_PortCtrl.BitData
共用一块内存 所以可以直接用BitData_PortCtrl.ByteData
进行判断。
/**
* @brief 提供了一个快速配置并启动Modbus功能的模板(采用默认配置)
* 需要注意的是为了使此函数尽可能的简洁易用,并未设置函数参数。
* 用户需要根据自己项目的实际情况修改函数中的各个配置参数。
*/
void User_MB_Config()
{
switch (BitData_PortCtrl.ByteData)
{
//Bit0 = 0, configure DB-9 port
case 0:
//配置Modbus通讯串口的全局参数
User_MB_InitPortParam(USART_DB9_NUM, 115200, MB_PAR_NONE);
//配置GPIO
USART_ConfigGPIO(USART_DB9_TXD_PORT, USART_DB9_TXD_PIN, USART_DB9_RXD_PORT, USART_DB9_RXD_PIN);
//配置NVIC
User_MB_ConfigNVIC();
break;
//Bit0 = 1, configure LCD port
case 1:
//配置Modbus通讯串口的全局参数
User_MB_InitPortParam(USART_LCD_NUM, 115200, MB_PAR_NONE);
//配置GPIO
USART_ConfigGPIO(USART_LCD_TXD_PORT, USART_LCD_TXD_PIN, USART_LCD_RXD_PORT, USART_LCD_RXD_PIN);
//配置NVIC
User_MB_ConfigNVIC();
break;
//Bit0 = 0 & Bit1 = 1, configure RS485 port
case 2:
//Bit0 = 1 & Bit1 = 1, configure RS485 port
case 3:
//配置Modbus通讯串口的全局参数
User_MB_InitPortParam(USART_485_NUM, 115200, MB_PAR_NONE);
//配置GPIO
USART_ConfigGPIO(USART_485_TXD_PORT, USART_485_TXD_PIN, USART_485_RXD_PORT, USART_485_RXD_PIN);
//配置NVIC
User_MB_ConfigNVIC();
break;
default:
break;
}
//初始化Modbus四种寄存器
User_MB_InitRegs();
//初始化Modbus
eMBInit(MB_RTU, FREEMODBUS_DEV_ADDR, FreeModbus_PortNum,
FreeModbus_PortBaudrate, Freemodbus_PortParity);
//使能Modbus功能
eMBEnable();
}
二.使用指南
思路说明:
本文实现的是通过使用硬件(拨码开关)来实现主串口的选择(DB9 或 LCD),主次串口的切换是通过一位线圈寄存器控制通过 写入0 1进行主次串口的切换。
串口的配置通过调用 void User_MB_Config()
;
使用步骤
1.在程序初始化阶段 通过一个位域操作 创建一个类似位操作的共用体,通过最小的空间来进行最多的操作。
typedef struct
{
uint8_t bit0:1;
uint8_t bit1:1;
uint8_t bit2:1;
uint8_t bit3:1;
uint8_t bit4:1;
uint8_t bit5:1;
uint8_t bit6:1;
uint8_t bit7:1;
} BitDataStruct;
typedef union
{
BitDataStruct BitData;
uint8_t ByteData;
} BitDataUnion;
2.在进入任务前 获取拨码开关的值将其保存在BitData_PortCtrl.BitData.bit0
DipValue = User_GetDipSwitchValue();//读取拨码开关的值
BitData_PortCtrl.BitData.bit0 = (DipValue & 0x01);//将其保存
//OFF==0 ON ==1
uint8_t User_GetDipSwitchValue()
{
uint8_t value = 0x00;
uint8_t dipSwitchBit1 = (~(*DIP_SWITCH_BIT_1)) & 0x01;
uint8_t dipSwitchBit2 = (~(*DIP_SWITCH_BIT_2)) & 0x01;
uint8_t dipSwitchBit3 = (~(*DIP_SWITCH_BIT_3)) & 0x01;
uint8_t dipSwitchBit4 = (~(*DIP_SWITCH_BIT_4)) & 0x01;
value = ((dipSwitchBit1 << 0) | (dipSwitchBit2 << 1) | (dipSwitchBit3 << 2) | (dipSwitchBit4 << 3)) & 0x0F;
return value;
}
3.在FreeRTOS系统中创建一个任务进行串口的选择配置并进行轮询Modbus。
void ModbusPoll_task(void *pvParameters)
{
User_MB_Config();//串口的初始化配置
TickType_t ticks = xTaskGetTickCount();
while (1)
{
eMBPoll();// modebus 的轮询
//1ms 一个处理周期
vTaskDelayUntil( &ticks, 1 );
}
}
4.在刷新线圈寄存器中 轮询串口切换控制位是否发生改变。改变后将值赋值给BitData_PortCtrl.BitData.bit1
/**
* @brief 刷新线圈寄存器,根据线圈寄存器的值执行对应动作
* @param none
* @retval none
*/
void User_MB_RefreshCoilsRegister()
{
//设置缓冲数组,提高轮询效率,只有缓冲数组中的数据发生变化的时候,才会实际寄存器的读写操作
static uint8_t coilsReg_buffer[32] =
{
2 };
(void) coilsReg_buffer;
//开启串口切换
if (coilsReg_buffer[24] != CoilsReg_GetBit(24))
{
coilsReg_buffer[24] = CoilsReg_GetBit(24);
BitData_PortCtrl.BitData.bit1 = coilsReg_buffer[24];
}
}
5.在FreeRTOS系统中创建一个串口切换任务。轮询BitData_PortCtrl.BitData.bit1
是否发生变化。改变后先将void ModbusPoll_task(void *pvParameters)
任务删除 之后再进行创建新的void ModbusPoll_task(void *pvParameters)
任务这样配置函数 void User_MB_Config()
将进行重新的选择。
void PortSwitch_task(void *pvParameters)
{
static uint8_t Port=0;
TickType_t ticks = xTaskGetTickCount();
while(1)
{
if(Port != BitData_PortCtrl.BitData.bit1)
{
Port = BitData_PortCtrl.BitData.bit1;
taskENTER_CRITICAL(); //进入临界区
eMBDisable();
vTaskDelete(ModbusPollTask_Handler); //删除ModbusPollTask_Handler任务
xTaskCreate((TaskFunction_t )ModbusPoll_task,
(const char* )"ModbusPoll_task",
(uint16_t )MODBUS_POLL_STK_SIZE,
(void* )NULL,
(UBaseType_t )MODBUS_POLL_TASK_PRIO,
(TaskHandle_t* )&ModbusPollTask_Handler);
taskEXIT_CRITICAL(); //退出临界区
}
vTaskDelayUntil( &ticks, 500);
}
}