前言:
...
网址:FreeMODBUS Downloads - Embedded Experts
Modbus 文件
modbus是最核心的文件夹:
modbus文件夹下包含的文件夹:
function文件夹下:
demo文件夹:
Modbus 移植:
项目结构:
添加对应库文件路径:
初始化流程:
一个是对串口的初始化相关的初始化文件需要放到portserial.c文件中,一个是定时器相关的初始化和中断相关的代码放在porttimer.c这个文件中。
这些初始化函数是在mb.c里面的eMBRTInit()这个文件中调用的。
freemodbus初始化:
对应的是freemodbus移植1
串口方面的初始化:
如果使用TXE标志位的话,可能发送移位寄存器中的数据还没有完全发送出去就切换到接收模式了这个时候导致接收的数据部完全。
/*
* FreeModbus Libary: BARE Port
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id$
*/
#include "port.h"
#include "gd32f30x.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
typedef struct
{
uint32_t uartNo;
rcu_periph_enum rcuUart;
rcu_periph_enum rcuGpio;
uint32_t gpio;
uint32_t txPin;
uint32_t rxPin;
uint8_t irq;
} UartHwInfo_t;
static UartHwInfo_t g_uartHwInfo = {USART1, RCU_USART1, RCU_GPIOA, GPIOA, GPIO_PIN_2, GPIO_PIN_3, USART1_IRQn};
static void GpioInit(void)
{
rcu_periph_clock_enable(g_uartHwInfo.rcuGpio);
gpio_init(g_uartHwInfo.gpio, GPIO_MODE_AF_PP, GPIO_OSPEED_10MHZ, g_uartHwInfo.txPin);
gpio_init(g_uartHwInfo.gpio, GPIO_MODE_IPU, GPIO_OSPEED_10MHZ, g_uartHwInfo.rxPin);
}
static void UartInit(uint32_t baudRate)
{
/* 使能UART时钟;*/
rcu_periph_clock_enable(g_uartHwInfo.rcuUart);
/* 复位UART;*/
usart_deinit (g_uartHwInfo.uartNo);
/* 通过USART_CTL0寄存器的WL设置字长;*/
//usart_word_length_set(g_uartHwInfo.uartNo, USART_WL_8BIT);
/* 通过USART_CTL0寄存器的PCEN设置校验位;*/
//usart_parity_config(g_uartHwInfo.uartNo, USART_PM_NONE);
/* 在USART_CTL1寄存器中写STB[1:0]位来设置停止位的长度;*/
//usart_stop_bit_set(g_uartHwInfo.uartNo, USART_STB_1BIT);
/* 在USART_BAUD寄存器中设置波特率;*/
usart_baudrate_set(g_uartHwInfo.uartNo, baudRate);
/* 在USART_CTL0寄存器中设置TEN位,使能发送功能;*/
usart_transmit_config(g_uartHwInfo.uartNo, USART_TRANSMIT_ENABLE);
/* 在USART_CTL0寄存器中设置TEN位,使能接收功能;*/
usart_receive_config(g_uartHwInfo.uartNo, USART_RECEIVE_ENABLE);
/* 使能串口中断;*/
nvic_irq_enable(g_uartHwInfo.irq, 0, 0);
/* 在USART_CTL0寄存器中置位UEN位,使能UART;*/
usart_enable(g_uartHwInfo.uartNo);
}
static void SwitchInit(void)
{
rcu_periph_clock_enable(RCU_GPIOC); //使能GPIOG的时钟
gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5); //推挽输出
}
/* ----------------------- static functions ---------------------------------*/
static void prvvUARTTxReadyISR( void );
static void prvvUARTRxISR( void );
/* ----------------------- Start implementation -----------------------------*/
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
/* If xRXEnable enable serial receive interrupts. If xTxENable enable
* transmitter empty interrupts.
*/
if(TRUE == xRxEnable)
{
usart_interrupt_enable(g_uartHwInfo.uartNo, USART_INT_RBNE);//使能接收中断
gpio_bit_reset(GPIOC, GPIO_PIN_5);
}
else
{
usart_interrupt_disable(g_uartHwInfo.uartNo, USART_INT_RBNE);//失能接收中断
gpio_bit_set(GPIOC, GPIO_PIN_5);
}
if(TRUE == xTxEnable)
{
usart_interrupt_enable(g_uartHwInfo.uartNo, USART_INT_TC);//使能发送中断
gpio_bit_set(GPIOC, GPIO_PIN_5);
}
else
{
usart_interrupt_disable(g_uartHwInfo.uartNo, USART_INT_TC);//失能发送中断
gpio_bit_reset(GPIOC, GPIO_PIN_5);
}
}
BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
(void)ucPORT;
(void)ucDataBits;
(void)eParity;
SwitchInit();
GpioInit();
UartInit(ulBaudRate);
return TRUE;
}
BOOL
xMBPortSerialPutByte( CHAR ucByte )
{
/* Put a byte in the UARTs transmit buffer. This function is called
* by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
* called. */
usart_data_transmit(g_uartHwInfo.uartNo, ucByte);
return TRUE;
}
BOOL
xMBPortSerialGetByte( CHAR * pucByte )
{
/* Return the byte in the UARTs receive buffer. This function is called
* by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
*/
*pucByte = usart_data_receive(g_uartHwInfo.uartNo);
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.
*/
static 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.
*/
static void prvvUARTRxISR( void )
{
pxMBFrameCBByteReceived( );
}
void USART1_IRQHandler(void)
{
//判断接收还是发送中断
if (RESET != usart_interrupt_flag_get(g_uartHwInfo.uartNo, USART_INT_FLAG_RBNE))
{
//接收完成中断
prvvUARTRxISR();
usart_interrupt_flag_clear(g_uartHwInfo.uartNo, USART_INT_FLAG_RBNE_ORERR);
}
if(RESET != usart_interrupt_flag_get(g_uartHwInfo.uartNo, USART_INT_FLAG_TC))
{
//发送完成中断
prvvUARTTxReadyISR();
usart_interrupt_flag_clear(g_uartHwInfo.uartNo, USART_INT_FLAG_TC);
}
}
定时器方面的初始化:
/*
* FreeModbus Libary: BARE Port
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* File: $Id$
*/
/* ----------------------- Platform includes --------------------------------*/
#include "port.h"
#include "gd32f30x.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR( void );
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
/* 使能定时器时钟;*/
rcu_periph_clock_enable(RCU_TIMER3);
/* 复位定时器;*/
timer_deinit(TIMER3);
timer_parameter_struct timerInitPara;
timer_struct_para_init(&timerInitPara);
/* 设置预分频器值;*/
timerInitPara.prescaler = 5999; // 频率120MHZ / 6000 = 20khz,对应周期50us
/* 设置自动重装载值;*/
timerInitPara.period = usTim1Timerout50us - 1;
timer_init(TIMER3, &timerInitPara);
/* 使能定时器的计数更新中断;*/
timer_interrupt_enable(TIMER3, TIMER_INT_UP);
/* 使能定时器中断和优先级;*/
nvic_irq_enable(TIMER3_IRQn, 0, 0);
/* 使能定时器;*/
//timer_enable(TIMER3);
return TRUE;
}
inline void
vMBPortTimersEnable( )
{
/* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
timer_counter_value_config(TIMER3, 0);//清零定时器
timer_interrupt_flag_clear(TIMER3, TIMER_INT_UP);//清除定时器更新中断
timer_interrupt_enable(TIMER3, TIMER_INT_UP);//使能定时器更新中断
timer_enable(TIMER3);//使能定时器
}
inline void
vMBPortTimersDisable( )
{
/* Disable any pending timers. */
timer_counter_value_config(TIMER3,0);//清零定时器
timer_interrupt_flag_clear(TIMER3, TIMER_INT_UP);//清除定时器更新中断
timer_interrupt_disable(TIMER3, TIMER_INT_UP);//禁用定时器更新中断
timer_disable(TIMER3);//失能定时器
}
/* Create an ISR which is called whenever the timer has expired. This function
* must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
* the timer has expired.
*/
static void prvvTIMERExpiredISR( void )
{
( void )pxMBPortCBTimerExpired( );
}
void TIMER3_IRQHandler(void)
{
if (timer_interrupt_flag_get(TIMER3, TIMER_INT_FLAG_UP) == SET)
{
timer_interrupt_flag_clear(TIMER3, TIMER_INT_FLAG_UP);
timer_counter_value_config(TIMER3, 0);
prvvTIMERExpiredISR();
}
}
定时的时间是如何计算的:
这个前面有对这部分的知识有一个讲解,具体查看下面的这张图
这一段代码就是对上面图中计算公式的讲
图解:
freemodbus执行流程:
对应的是freeModbus移植2。
Modbus中自带的错误需要对源代码做一些修改在mbfuncholding.c这个文件中带 modify 都需要进行修改。
mbrtu.c
上电一次启动一次触发中断
串口portserial.c的代码实现