1、【增加】基于RTT自带设备及定时器框架的主机,降低软件的移植难度。;

2、【优化】RTT串口驱动,解决了系统启动前,串口输入导致系统停止的bug。

Signed-off-by: armink <armink.ztl@gmail.com>
This commit is contained in:
armink 2014-12-05 10:27:31 +08:00
parent 334f97f211
commit 092cee82c4
6 changed files with 179 additions and 186 deletions

View File

@ -48,6 +48,7 @@
/* RT_USING_UART */ /* RT_USING_UART */
#define RT_USING_UART3 #define RT_USING_UART3
#define RT_USING_UART2
#define RT_USING_UART1 #define RT_USING_UART1
#define RT_UART_RX_BUFFER_SIZE 64 #define RT_UART_RX_BUFFER_SIZE 64

View File

@ -86,8 +86,6 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c
/* Enable USART */ /* Enable USART */
USART_Cmd(uart->uart_device, ENABLE); USART_Cmd(uart->uart_device, ENABLE);
/* enable interrupt */
USART_ITConfig(uart->uart_device, USART_IT_RXNE, ENABLE);
return RT_EOK; return RT_EOK;
} }

View File

@ -123,8 +123,6 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
rt_thread_startup(&thread_serial_soft_trans_irq); rt_thread_startup(&thread_serial_soft_trans_irq);
rt_event_init(&event_serial, "slave event", RT_IPC_FLAG_PRIO); rt_event_init(&event_serial, "slave event", RT_IPC_FLAG_PRIO);
return TRUE; return TRUE;
} }

View File

@ -24,124 +24,162 @@
/* ----------------------- Modbus includes ----------------------------------*/ /* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h" #include "mb.h"
#include "mbport.h" #include "mbport.h"
#include "rtdevice.h"
#include "bsp.h"
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0 #if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/* ----------------------- Static variables ---------------------------------*/
ALIGN(RT_ALIGN_SIZE)
/* software simulation serial transmit IRQ handler thread stack */
static rt_uint8_t serial_soft_trans_irq_stack[512];
/* software simulation serial transmit IRQ handler thread */
static struct rt_thread thread_serial_soft_trans_irq;
/* serial event */
static struct rt_event event_serial;
/* modbus slave serial device */
static rt_serial_t *serial;
/* ----------------------- Defines ------------------------------------------*/
/* serial transmit event */
#define EVENT_SERIAL_TRANS_START (1<<0)
/* ----------------------- static functions ---------------------------------*/ /* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR(void); static void prvvUARTTxReadyISR(void);
static void prvvUARTRxISR(void); static void prvvUARTRxISR(void);
static rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size);
static void serial_soft_trans_irq(void* parameter);
/* ----------------------- Start implementation -----------------------------*/ /* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
eMBParity eParity)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* set 485 model receive and transmit control IO */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* set serial name */
if (ucPORT == 1) {
#if defined(RT_USING_UART1) || defined(RT_USING_REMAP_UART1)
extern struct rt_serial_device serial1;
serial = &serial1;
#endif
} else if (ucPORT == 2) {
#if defined(RT_USING_UART2)
extern struct rt_serial_device serial2;
serial = &serial2;
#endif
} else if (ucPORT == 3) {
#if defined(RT_USING_UART3)
extern struct rt_serial_device serial3;
serial = &serial3;
#endif
}
/* set serial configure parameter */
serial->config.baud_rate = ulBaudRate;
serial->config.stop_bits = STOP_BITS_1;
switch(eParity){
case MB_PAR_NONE: {
serial->config.data_bits = DATA_BITS_8;
serial->config.parity = PARITY_NONE;
break;
}
case MB_PAR_ODD: {
serial->config.data_bits = DATA_BITS_9;
serial->config.parity = PARITY_ODD;
break;
}
case MB_PAR_EVEN: {
serial->config.data_bits = DATA_BITS_9;
serial->config.parity = PARITY_EVEN;
break;
}
}
/* disable all interrupt */
ENTER_CRITICAL_SECTION();
/* set serial configure */
serial->ops->configure(serial, &(serial->config));
/* resume all interrupt */
EXIT_CRITICAL_SECTION();
/* open serial device */
if (!serial->parent.open(&serial->parent,
RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX )) {
serial->parent.rx_indicate = serial_rx_ind;
} else {
return FALSE;
}
/* software initialize */
rt_thread_init(&thread_serial_soft_trans_irq,
"slave trans",
serial_soft_trans_irq,
RT_NULL,
serial_soft_trans_irq_stack,
sizeof(serial_soft_trans_irq_stack),
10, 5);
rt_thread_startup(&thread_serial_soft_trans_irq);
rt_event_init(&event_serial, "slave event", RT_IPC_FLAG_PRIO);
return TRUE;
}
void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable) void vMBMasterPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{ {
rt_uint32_t recved_event;
if (xRxEnable) if (xRxEnable)
{ {
/* 485通信时等待串口移位寄存器中的数据发送完成后再去使能485的接收、失能485的发送*/ /* waiting for last transmit complete */
while (!USART_GetFlagStatus(USART2,USART_FLAG_TC)); while (1)
MASTER_RS485_RECEIVE_MODE; {
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); if (serial->ops->control(serial, RT_DEVICE_CTRL_GET_FLAG, (void *)RT_DEVICE_FLAG_INT_TX))
{
break;
}
}
/* enable RX interrupt */
serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX);
/* switch 485 to receive mode */
SLAVE_RS485_RECEIVE_MODE;
} }
else else
{ {
MASTER_RS485_TRANS_MODE; /* switch 485 to transmit mode */
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE); SLAVE_RS485_TRANS_MODE;
/* disable RX interrupt */
serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *)RT_DEVICE_FLAG_INT_RX);
} }
if (xTxEnable) if (xTxEnable)
{ {
USART_ITConfig(USART2, USART_IT_TXE, ENABLE); /* start serial transmit */
rt_event_send(&event_serial, EVENT_SERIAL_TRANS_START);
} }
else else
{ {
USART_ITConfig(USART2, USART_IT_TXE, DISABLE); /* stop serial transmit */
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0,
&recved_event);
} }
} }
void vMBMasterPortClose(void) void vMBMasterPortClose(void)
{ {
USART_ITConfig(USART2, USART_IT_TXE | USART_IT_RXNE, DISABLE); serial->parent.close(&(serial->parent));
USART_Cmd(USART2, DISABLE);
}
//默认一个主机 串口2 波特率可设置 奇偶检验可设置
BOOL xMBMasterPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
eMBParity eParity)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//======================时钟初始化=======================================
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//======================IO初始化=======================================
//USART2_TX
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART2_RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置485发送和接收模式
// TODO 暂时先写B13 等之后组网测试时再修改
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//======================串口初始化=======================================
USART_InitStructure.USART_BaudRate = ulBaudRate;
//设置校验模式
switch (eParity)
{
case MB_PAR_NONE: //无校验
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
break;
case MB_PAR_ODD: //奇校验
USART_InitStructure.USART_Parity = USART_Parity_Odd;
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
break;
case MB_PAR_EVEN: //偶校验
USART_InitStructure.USART_Parity = USART_Parity_Even;
USART_InitStructure.USART_WordLength = USART_WordLength_9b;
break;
default:
return FALSE;
}
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
if (ucPORT != 2)
return FALSE;
ENTER_CRITICAL_SECTION(); //关全局中断
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_Cmd(USART2, ENABLE);
//=====================中断初始化======================================
//设置NVIC优先级分组为Group20-3抢占式优先级0-3的响应式优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
EXIT_CRITICAL_SECTION(); //开全局中断
return TRUE;
} }
BOOL xMBMasterPortSerialPutByte(CHAR ucByte) BOOL xMBMasterPortSerialPutByte(CHAR ucByte)
{ {
USART_SendData(USART2, ucByte); serial->parent.write(&(serial->parent), 0, &ucByte, 1);
return TRUE; return TRUE;
} }
BOOL xMBMasterPortSerialGetByte(CHAR * pucByte) BOOL xMBMasterPortSerialGetByte(CHAR * pucByte)
{ {
*pucByte = USART_ReceiveData(USART2); serial->parent.read(&(serial->parent), 0, pucByte, 1);
return TRUE; return TRUE;
} }
@ -167,33 +205,35 @@ void prvvUARTRxISR(void)
{ {
pxMBMasterFrameCBByteReceived(); pxMBMasterFrameCBByteReceived();
} }
/*******************************************************************************
* Function Name : USART2_IRQHandler /**
* Description : This function handles USART2 global interrupt request. * Software simulation serial transmit IRQ handler.
* Input : None *
* Output : None * @param parameter parameter
* Return : None */
*******************************************************************************/ static void serial_soft_trans_irq(void* parameter) {
void USART2_IRQHandler(void) rt_uint32_t recved_event;
{ while (1)
rt_interrupt_enter();
//溢出错误
if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) == SET)
{
prvvUARTRxISR();
}
//接收中断
if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
prvvUARTRxISR();
}
//发送中断
if (USART_GetITStatus(USART2, USART_IT_TXE) == SET)
{ {
/* waiting for serial transmit start */
rt_event_recv(&event_serial, EVENT_SERIAL_TRANS_START, RT_EVENT_FLAG_OR,
RT_WAITING_FOREVER, &recved_event);
/* execute modbus callback */
prvvUARTTxReadyISR(); prvvUARTTxReadyISR();
} }
rt_interrupt_leave(); }
/**
* 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 rt_err_t serial_rx_ind(rt_device_t dev, rt_size_t size) {
prvvUARTRxISR();
return RT_EOK;
} }
#endif #endif

View File

@ -56,6 +56,7 @@ void prvvTIMERExpiredISR(void)
{ {
(void) pxMBPortCBTimerExpired(); (void) pxMBPortCBTimerExpired();
} }
/** /**
* This function is PLC uart receive timer callback function * This function is PLC uart receive timer callback function
* *

View File

@ -30,7 +30,9 @@
#if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0 #if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
/* ----------------------- Variables ----------------------------------------*/ /* ----------------------- Variables ----------------------------------------*/
static USHORT usT35TimeOut50us; static USHORT usT35TimeOut50us;
static USHORT usPrescalerValue = 0; static struct rt_timer timer;
static void prvvTIMERExpiredISR(void);
static void timer_timeout_ind(void* parameter);
/* ----------------------- static functions ---------------------------------*/ /* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR(void); static void prvvTIMERExpiredISR(void);
@ -38,102 +40,58 @@ static void prvvTIMERExpiredISR(void);
/* ----------------------- Start implementation -----------------------------*/ /* ----------------------- Start implementation -----------------------------*/
BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us) BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
{ {
NVIC_InitTypeDef NVIC_InitStructure; /* backup T35 ticks */
//====================================时钟初始化===========================
//使能定时器2时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
//====================================定时器初始化===========================
//定时器时间基配置说明
//HCLK为72MHzAPB1经过2分频为36MHz
//TIM2的时钟倍频后为72MHz硬件自动倍频,达到最大)
//TIM2的分频系数为3599时间基频率为72 / (1 + Prescaler) = 20KHz,基准为50us
//TIM最大计数值为usTim1Timerout50u
usPrescalerValue = (uint16_t) (SystemCoreClock / 20000) - 1;
//保存T35定时器计数值
usT35TimeOut50us = usTimeOut50us; usT35TimeOut50us = usTimeOut50us;
//预装载使能 rt_timer_init(&timer, "plc_recv_timer",
TIM_ARRPreloadConfig(TIM2, ENABLE); timer_timeout_ind, /* bind timeout callback function */
//====================================中断初始化=========================== RT_NULL,
//设置NVIC优先级分组为Group20-3抢占式优先级0-3的响应式优先级 (50 * usT35TimeOut50us) / (1000 * 1000 / RT_TICK_PER_SECOND),
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); RT_TIMER_FLAG_ONE_SHOT); /* one shot */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//清除溢出中断标志位
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
//定时器3溢出中断关闭
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
//定时器3禁能
TIM_Cmd(TIM2, DISABLE);
return TRUE; return TRUE;
} }
void vMBMasterPortTimersT35Enable() void vMBMasterPortTimersT35Enable()
{ {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; rt_tick_t timer_tick = (50 * usT35TimeOut50us)
/ (1000 * 1000 / RT_TICK_PER_SECOND);
/* Set current timer mode,don't change it.*/ /* Set current timer mode,don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_T35); vMBMasterSetCurTimerMode(MB_TMODE_T35);
TIM_TimeBaseStructure.TIM_Prescaler = usPrescalerValue; rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = (uint16_t) usT35TimeOut50us;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); rt_timer_start(&timer);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, ENABLE);
} }
void vMBMasterPortTimersConvertDelayEnable() void vMBMasterPortTimersConvertDelayEnable()
{ {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; rt_tick_t timer_tick = MB_MASTER_DELAY_MS_CONVERT * RT_TICK_PER_SECOND / 1000;
/* Set current timer mode,don't change it.*/ /* Set current timer mode,don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY); vMBMasterSetCurTimerMode(MB_TMODE_CONVERT_DELAY);
TIM_TimeBaseStructure.TIM_Prescaler = usPrescalerValue; rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = (uint16_t)(MB_MASTER_DELAY_MS_CONVERT * 1000 / 50);
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); rt_timer_start(&timer);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, ENABLE);
} }
void vMBMasterPortTimersRespondTimeoutEnable() void vMBMasterPortTimersRespondTimeoutEnable()
{ {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; rt_tick_t timer_tick = MB_MASTER_TIMEOUT_MS_RESPOND * RT_TICK_PER_SECOND / 1000;
/* Set current timer mode,don't change it.*/ /* Set current timer mode,don't change it.*/
vMBMasterSetCurTimerMode(MB_TMODE_RESPOND_TIMEOUT); vMBMasterSetCurTimerMode(MB_TMODE_RESPOND_TIMEOUT);
TIM_TimeBaseStructure.TIM_Prescaler = usPrescalerValue; rt_timer_control(&timer, RT_TIMER_CTRL_SET_TIME, &timer_tick);
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = (uint16_t)(MB_MASTER_TIMEOUT_MS_RESPOND * 1000 / 50);
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); rt_timer_start(&timer);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, ENABLE);
} }
void vMBMasterPortTimersDisable() void vMBMasterPortTimersDisable()
{ {
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); rt_timer_stop(&timer);
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, DISABLE);
} }
void prvvTIMERExpiredISR(void) void prvvTIMERExpiredISR(void)
@ -141,17 +99,14 @@ void prvvTIMERExpiredISR(void)
(void) pxMBMasterPortCBTimerExpired(); (void) pxMBMasterPortCBTimerExpired();
} }
void TIM2_IRQHandler(void) /**
* This function is PLC uart receive timer callback function
*
* @param parameter null
*/
static void timer_timeout_ind(void* parameter)
{ {
rt_interrupt_enter(); prvvTIMERExpiredISR();
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearFlag(TIM2, TIM_FLAG_Update); //清中断标记
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除定时器TIM2溢出中断标志位
prvvTIMERExpiredISR();
}
rt_interrupt_leave();
} }
#endif #endif