github地址
本项目地址
设置快捷键
ctrl+shift+l变为find in file,原ctrl+shift+f与win10输入法冲突会切换繁体输入
对应实现
开关临界区
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文件修改修改名称即可,问题不大