STM32 裸机 标准库 移植 Freemodbus RTU

STM32 裸机 标准库 移植 Freemodbus RTU

https://download.csdn.net/download/weixin_41736398/19930460?spm=1001.2014.3001.5503
包含了源码,移植成功的代码,测试用的上位机

1、官网下载源码,解压得到文件夹如下

-rw-r--r-- 1 EDZ 197121  1436 十二月  8  2006 bsd.txt
-rw-r--r-- 1 EDZ 197121 14448 六月    5  2010 Changelog.txt
drwxr-xr-x 1 EDZ 197121     0 六月    6  2010 demo/
drwxr-xr-x 1 EDZ 197121     0 六月    6  2010 doc/
-rw-r--r-- 1 EDZ 197121 18351 二月   19  2006 gpl.txt
-rw-r--r-- 1 EDZ 197121 26936 二月   19  2006 lgpl.txt
drwxr-xr-x 1 EDZ 197121     0 六月    6  2010 modbus/
drwxr-xr-x 1 EDZ 197121     0 六月    6  2010 tools/

文件夹demo是官方针对不同平台移植的测试代码

文件夹doc是一些说明文档

文件夹modbus是实现功能的源码

文件夹tool是上位机

2、文件夹复制

新建STM32 工程

mobus文件夹:

drwxr-xr-x 1 EDZ 197121     0 六月    6  2010 ascii/
drwxr-xr-x 1 EDZ 197121     0 六月    6  2010 functions/
drwxr-xr-x 1 EDZ 197121     0 六月    6  2010 include/
-rw-r--r-- 1 EDZ 197121 12908 六月    6  2010 mb.c
drwxr-xr-x 1 EDZ 197121     0 六月    6  2010 rtu/
drwxr-xr-x 1 EDZ 197121     0 六月    6  2010 tcp/

demo文件夹:

|-- Makefile
|-- demo.c
`-- port
    |-- port.h
    |-- portevent.c
    |-- portserial.c
    `-- porttimer.c

需要复制modbus文件夹,和demo中的port文件夹。

3、修改代码

3.1 修改portserial.c

这个文件是用来移植串口的,不管是ASCII模式还是RTU模式都需要串口的支持。

3.1.1 修改void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )

void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
    /* If xRXEnable enable serial receive interrupts. If xTxENable enable
     * transmitter empty interrupts.
     */
/*
对下面要用到的宏定义进行解释
	#define RSUP_EN		PAout(0)
	#define RSDOWN_EN	PAout(1)
	#define DEF_UP_UART    USART3
	#define DEF_DOWN_UART   USART2
	typedef enum {RS_RECV = 0,RS_SEND = !RS_RECV} RS485_Status;
*/
	ENTER_CRITICAL_SECTION();
    if(xRxEnable)
    {
        RSUP_EN = RS_RECV; //  接收
        USART_ITConfig(DEF_UP_UART,USART_IT_RXNE,ENABLE);
    }
    else
    {
        RSUP_EN = RS_SEND; // 发送
        USART_ITConfig(DEF_UP_UART,USART_IT_RXNE,DISABLE);
    }

    if(xTxEnable)
    {
        RSUP_EN = RS_SEND; // 发送
        USART_ITConfig(DEF_UP_UART,USART_IT_TXE,ENABLE);
    }
    else
    {
        RSUP_EN = RS_RECV; // 接收
        USART_ITConfig(DEF_UP_UART,USART_IT_TXE,DISABLE);
    }
    EXIT_CRITICAL_SECTION();
    
}

3.1.2 修改BOOL xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )

BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
    (void) ucPORT;
    (void) ucDataBits;
    (void) eParity;

    UP_USART_Config(ulBaudRate); // 常规串口初始化

    return TRUE;
}

3.1.3 修改BOOL xMBPortSerialPutByte( CHAR ucByte )

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_SendData(RSUP_USART,ucByte);
	while (USART_GetFlagStatus(RSUP_USART, USART_FLAG_TC) == RESET);
    return TRUE;
}

3.1.4 修改BOOL xMBPortSerialGetByte( CHAR * pucByte )

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_ReceiveData(RSUP_USART);
    return TRUE;
}

3.1.5 添加 UART4_IRQHandler(void)

void UART4_IRQHandler(void)
{
    if(USART_GetITStatus(RSUP_USART,USART_IT_RXNE) == SET)
    {
        prvvUARTRxISR();
        USART_ClearFlag(RSUP_USART,USART_IT_RXNE);
    }
	if(USART_GetITStatus(RSUP_USART,USART_IT_TXE) == SET)
    {
        prvvUARTTxReadyISR();
        USART_ClearFlag(RSUP_USART,USART_IT_TXE);
    }
}

3.2 修改porttimer.c文件

3.2.1 修改BOOL xMBPortTimersInit( USHORT usTim1Timerout50us )

BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
	
	
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    TIM_TimeBaseStructure.TIM_Period = (uint16_t) usTim1Timerout50us;
    TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (72000000 / 20000) - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
    TIM_ARRPreloadConfig(TIM4,ENABLE);
     
	
    NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
     
    TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
    TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE);
    TIM_Cmd(TIM4,DISABLE);
    return TRUE;
}

3.2.2 修改inline void vMBPortTimersEnable( )

void
vMBPortTimersEnable(  )
{
    /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
    /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
    TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
    TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
    TIM_SetCounter(TIM4,0x0000);
    TIM_Cmd(TIM4,ENABLE);
}

3.2.3 修改inline void vMBPortTimersDisable( )

void
vMBPortTimersDisable(  )
{
    /* Disable any pending timers. */
    TIM_Cmd(TIM4, DISABLE);
    TIM_SetCounter(TIM4,0x0000); 
    TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE);
    TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
}

3.2.4 修改void TIM4_IQRHandler(void)

void TIM4_IRQHandler(void)
{
	if ( TIM_GetITStatus( TIM4, TIM_IT_Update) != RESET ) 
	{	
		prvvTIMERExpiredISR();
		TIM_ClearITPendingBit(TIM4 , TIM_FLAG_Update);  		 
	}	
}

3.3 添加port.c文件

#include "port.h"

#include "mb.h"
#include "mbport.h"
#include "mbutils.h"

uint16_t usRegInputBuf[REG_INPUT_NREGS] = {0x8001,0x7002,0x6003,0x5004,0x4005,0x3006,0x2007,0x1008};
uint16_t usRegHoldingBuf[REG_HOLDING_NREGS]={0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,0x0008};
uint8_t ucRegCoilsBuf[REG_COILS_SIZE]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
uint8_t ucRegDiscreteBuf[REG_DISCRETE_SIZE]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};

void EnterCriticalSection(void)
{
    __disable_irq();
}
void ExitCriticalSection(void)
{
    __enable_irq();
}

eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    int             iRegIndex;
 
    if( ( usAddress >= REG_INPUT_START )
        && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - REG_INPUT_START );
        while( usNRegs > 0 )
        {
            *pucRegBuffer++ =
                ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
            *pucRegBuffer++ =
                ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
            iRegIndex++;
            usNRegs--;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
 
    return eStatus;
}

eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
                 eMBRegisterMode eMode )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    int             iRegIndex;
 
    if( ( (int16_t)usAddress >= REG_HOLDING_START ) && ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - REG_HOLDING_START );
        switch ( eMode )
        {
        case MB_REG_READ:
            while( usNRegs > 0 )
            {
                *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] >> 8 );
                *pucRegBuffer++ = ( unsigned char )( usRegHoldingBuf[iRegIndex] & 0xFF );
                iRegIndex++;
                usNRegs--;
            }
            break;
 
        case MB_REG_WRITE:
            while( usNRegs > 0 )
            {
                usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
                usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
                iRegIndex++;
                usNRegs--;
            }
            break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
               eMBRegisterMode eMode )
{
    eMBErrorCode eStatus = MB_ENOERR;
    
    int16_t iNCoils = ( int16_t )usNCoils;
    
    int16_t usBitOffset;
     
     
    if( ( (int16_t)usAddress >= REG_COILS_START ) &&
    ( usAddress + usNCoils <= REG_COILS_START + REG_COILS_SIZE ) )
    {
        
        usBitOffset = ( int16_t )( usAddress - REG_COILS_START );
        switch ( eMode )
        {
            
            case MB_REG_READ:
            while( iNCoils > 0 )
            {
                *pucRegBuffer++ = xMBUtilGetBits( ucRegCoilsBuf, usBitOffset,
                ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ) );
                iNCoils -= 8;
                usBitOffset += 8;
            }
            break;
            
            
            case MB_REG_WRITE:
            while( iNCoils > 0 )
            {
                xMBUtilSetBits( ucRegCoilsBuf, usBitOffset,
                ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ),
                *pucRegBuffer++ );
                iNCoils -= 8;
            }
            break;
        }
     
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    eMBErrorCode eStatus = MB_ENOERR;
    
    int16_t iNDiscrete = ( int16_t )usNDiscrete;
    
    uint16_t usBitOffset;
     
    if( ( (int16_t)usAddress >= REG_DISCRETE_START ) &&
    ( usAddress + usNDiscrete <= REG_DISCRETE_START + REG_DISCRETE_SIZE ) )
    {
        usBitOffset = ( uint16_t )( usAddress - REG_DISCRETE_START );
        
        while( iNDiscrete > 0 )
        {
            *pucRegBuffer++ = xMBUtilGetBits( ucRegDiscreteBuf, usBitOffset,
            ( uint8_t)( iNDiscrete > 8 ? 8 : iNDiscrete ) );
            iNDiscrete -= 8;
            usBitOffset += 8;
        }
        
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;  
}

3.4 修改port.h

#include "stm32f10x.h"

#define REG_INPUT_START 0
#define REG_INPUT_NREGS 8
#define REG_HOLDING_START   0
#define REG_HOLDING_NREGS   8
#define REG_COILS_START     0
#define REG_COILS_SIZE      8
#define REG_DISCRETE_START  0
#define REG_DISCRETE_SIZE   8

extern uint16_t usRegInputBuf[REG_INPUT_NREGS];
extern uint16_t usRegHoldingBuf[REG_HOLDING_NREGS];
extern uint8_t ucRegCoilsBuf[REG_COILS_SIZE];
extern uint8_t ucRegDiscreteBuf[REG_DISCRETE_SIZE];

void EnterCriticalSection(void);
void ExitCriticalSection(void);

4、调试bug记录

正常进行一次通讯后(从机接收完成并返回),不能再正常进入到中断。
仿真查询后发现485使能引脚状态转为发送状态。
仿真时现象:
一次正常通讯后,完成485使能引脚转换,没有立刻退出vMBPortSerialEnable函数,而是再次进入到 xTxEnable = TURE判断中,将引脚使能为发送。

if(xTxEnable)
{
    RSUP_EN = RS_SEND; // 发送
    USART_ITConfig(DEF_UP_UART,USART_IT_TXE,ENABLE);
}

解决办法:
先对引脚状态进行改变,再对串口标志位进行使能/失能。
bug时代码为:

void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
    /* If xRXEnable enable serial receive interrupts. If xTxENable enable
     * transmitter empty interrupts.
     */
	ENTER_CRITICAL_SECTION();
    if(xRxEnable)
    {
        USART_ITConfig(DEF_UP_UART,USART_IT_RXNE,ENABLE);
        RSUP_EN = RS_RECV; //  接收
    }
    else
    {
        USART_ITConfig(DEF_UP_UART,USART_IT_RXNE,DISABLE);
        RSUP_EN = RS_SEND; // 恢复发送
    }

    if(xTxEnable)
    {
        USART_ITConfig(DEF_UP_UART,USART_IT_TXE,ENABLE);
        RSUP_EN = RS_SEND; // 发送
    }
    else
    {
        USART_ITConfig(DEF_UP_UART,USART_IT_TXE,DISABLE);
        RSUP_EN = RS_RECV; // 接收
    }
    EXIT_CRITICAL_SECTION();
    
}

解决bug后的代码为:

void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
    /* If xRXEnable enable serial receive interrupts. If xTxENable enable
     * transmitter empty interrupts.
     */
	ENTER_CRITICAL_SECTION();
    if(xRxEnable)
    {
        RSUP_EN = RS_RECV; //  接收
        USART_ITConfig(DEF_UP_UART,USART_IT_RXNE,ENABLE);
    }
    else
    {
        RSUP_EN = RS_SEND; // 恢复发送
        USART_ITConfig(DEF_UP_UART,USART_IT_RXNE,DISABLE);
    }

    if(xTxEnable)
    {
        RSUP_EN = RS_SEND; // 发送
        USART_ITConfig(DEF_UP_UART,USART_IT_TXE,ENABLE);
    }
    else
    {
        RSUP_EN = RS_RECV; // 接收
        USART_ITConfig(DEF_UP_UART,USART_IT_TXE,DISABLE);
    }
    EXIT_CRITICAL_SECTION();
    
}

https://gitee.com/lyj1940696668/stm32-f10x_-std-periph_-lib_bare_metal_-freemodbus_-rtu

你可能感兴趣的:(stm32,单片机,modbus)