STM32F429用freemodbus与电脑通信 显示写通讯错误

2019-03-23 14:43发布

#include "stm32f4xx.h"
#include "./usart/bsp_rs232_usart.h"
#include "./modbus/include/mb.h"
#include "./modbus/include/mbutils.h"
#include "./modbus/include/mbport.h"
#include "./usart/bsp_rs232_usart.h"
/* ----------------------- Defines ------------------------------------------*/
/*线圈状态寄存器*/
#define REG_COILS_START 0x0000
#define REG_COILS_SIZE 8

/*线圈状态输入寄存器*/
#define REG_DISCRETE_START 0x0000
#define REG_DISCRETE_SIZE 8

/*保持寄存器*/
#define REG_HOLDING_START 0x0000
#define REG_HOLDING_NREGS 8

/*输入寄存器*/
#define REG_INPUT_START 0x0000
#define REG_INPUT_NREGS 1

/* USER CODE END PV */

/* Private function prototypes ------------------------------------------*/
void SystemClock_Config(void);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/*定义线圈状态寄存器的地址起始值和存储数组*/
uint8_t   ucRegCoilsStart = REG_HOLDING_START;
uint8_t   ucRegCoilsBuf[REG_COILS_SIZE / 8];

/*定义线圈输入状态寄存器的地址起始值和存储数组*/
uint8_t   ucRegDiscreteStart = REG_HOLDING_START;
uint8_t   ucRegDiscreteBuf[REG_DISCRETE_SIZE / 8];

/*定义输入寄存器的地址起始值和存储数组*/
uint16_t   usRegInputStart = REG_INPUT_START;
uint16_t   usRegInputBuf[REG_INPUT_NREGS];

//保持寄存器起始地址
#define REG_HOLDING_START 0x0000
//保持寄存器数量
#define REG_HOLDING_NREGS 8
//保持寄存器内容
uint16_t usRegHoldingBuf[REG_HOLDING_NREGS]
= {0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0x4055,0x147b,0x408e};

uint8_t Rxflag=0;
uint8_t ucTemp;
/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
        
int main(void)
{
  eMBErrorCode    eStatus;
  eStatus = eMBInit( MB_RTU, 0x01, 0X01, 115200, MB_PAR_NONE );
  eMBInit( MB_RTU, 0x01,1, 115200, MB_PAR_NONE );
    /* Enable the Modbus Protocol Stack. */
  //eStatus = eMBEnable(  );
        eMBEnable(  );
                while(1)
    {
        eMBPoll(  );
    }
}


/**
* @brief 输入寄存器处理函数,输入寄存器可读,但不可写。
* @param pucRegBuffer 返回数据指针
* usAddress 寄存器起始地址
* usNRegs 寄存器长度
* @retval eStatus 寄存器状态
*/
eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
int16_t iRegIndex;

//查询是否在寄存器范围内
//为了避免警告,修改为有符号整数
if( ( (int16_t)usAddress >= REG_INPUT_START )
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
{
//获得操作偏移量,本次操作起始地址-输入寄存器的初始地址
iRegIndex = ( int16_t )( usAddress - REG_INPUT_START );
//逐个赋值
while( usNRegs > 0 )
{
//赋值高字节
*pucRegBuffer++ = ( uint8_t )( usRegInputBuf[iRegIndex] >> 8 );
//赋值低字节
*pucRegBuffer++ = ( uint8_t )( usRegInputBuf[iRegIndex] & 0xFF );
//偏移量增加
iRegIndex++;
//被操作寄存器数量递减
usNRegs--;
}
}
else
{
//返回错误状态,无寄存器
eStatus = MB_ENOREG;
}

return eStatus;
}

/**
* @brief 保持寄存器处理函数,保持寄存器可读,可读可写
* @param pucRegBuffer 读操作时--返回数据指针,写操作时--输入数据指针
* usAddress 寄存器起始地址
* usNRegs 寄存器长度
* eMode 操作方式,读或者写
* @retval eStatus 寄存器状态
*/
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
eMBRegisterMode eMode )
{
                //错误状态
                eMBErrorCode eStatus = MB_ENOERR;
                //偏移量
                int16_t iRegIndex;

                //判断寄存器是不是在范围内
                if( ( (int16_t)usAddress >= REG_HOLDING_START )
                && ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
                                {
                                //计算偏移量
                                iRegIndex = ( int16_t )( usAddress - REG_HOLDING_START );

                                switch ( eMode )
                                {
                                //读处理函数
                                case MB_REG_READ:
                                while( usNRegs > 0 )
                                {
                                *pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] >> 8 );
                                *pucRegBuffer++ = ( uint8_t )( 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;
}

/**
* @brief 线圈寄存器处理函数,线圈寄存器可读,可读可写
* @param pucRegBuffer 读操作---返回数据指针,写操作--返回数据指针
* usAddress 寄存器起始地址
* usNRegs 寄存器长度
* eMode 操作方式,读或者写
* @retval 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;
}

/**
* @brief 开关输入寄存器处理函数,开关输入寄存器,可读
* @param pucRegBuffer 读操作---返回数据指针,写操作--返回数据指针
* usAddress 寄存器起始地址
* usNRegs 寄存器长度
* eMode 操作方式,读或者写
* @retval 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;
}

/* USER CODE END 4 */

#ifdef USE_FULL_ASSERT

/**
   * @brief Reports the name of the source file and the source line number
   * where the assert_param error has occurred.
   * @param file: pointer to the source file name
   * @param line: assert_param error line source number
   * @retval None
   */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d ", file, line) */
  /* USER CODE END 6 */

}



下面是port timer.c

/* ----------------------- Platform includes --------------------------------*/
#include "./modbus/port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "./modbus/include/mb.h"
#include "./modbus/include/mbport.h"
#include "stm32f4xx.h"

/* ----------------------- static functions ---------------------------------*/
void prvvTIMERExpiredISR( void );

/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{                //使用TIM4     180MHz
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
  //
  uint16_t PrescalerValue = 0;
  //使能定时器4时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

/*
        3.5个字符时间区分不同的帧,即接收到的两个字符之间时间间隔小于3.5个字符
        时间时认为是同一个帧的,如果间隔大于3.5个字符时间则认为是不同帧的
        在一般的串口通信中,发送1个字符需要:1位起始位,8位数据位,1位校验位(可无),
        1位停止位,总共 1+8+1+1 = 11位,3.5个字符时间就是 3.5 * 11 = 38.5位,
        假如波特率是9600,那么传输1位的时间是1000/9600 = 0.10416667(ms) ,
        这样,3.5个字符时间就大约是 4 ms ,即定时器需要的中断时间
        */
  // 这个就是预分频系数9000/180M = 0.00005,即每50us计数值加1
  //50us x 100 = 5ms,即5ms中断一次        
  TIM_TimeBaseStructure.TIM_Period = (uint16_t) usTim1Timerout50us-1;
  TIM_TimeBaseStructure.TIM_Prescaler =(9000 - 1);
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
  //预装载使能
  TIM_ARRPreloadConfig(TIM4, ENABLE);

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  //定时器4中断优先级
  NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  //清除溢出中断标志位
  TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
  //定时器4溢出中断关闭
  TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE);
  //定时器4禁能
  TIM_Cmd(TIM4,  DISABLE);
  return TRUE;
}


void vMBPortTimersEnable(  )
{
    /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
        TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
  //设定定时器4的初始值
  TIM_SetCounter(TIM4,0);
  //定时器4启动
  TIM_Cmd(TIM4, ENABLE);
}

void vMBPortTimersDisable(  )
{
    /* Disable any pending timers. */        

        TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
  TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE);
  TIM_SetCounter(TIM4,0);
  //关闭定时器4
  TIM_Cmd(TIM4, DISABLE);
}

/* 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.
*/
void prvvTIMERExpiredISR( void )
{
    ( void )pxMBPortCBTimerExpired(  );
}




下面是portserial.c

#include "./modbus/port.h"
#include "./usart/bsp_rs232_usart.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "./modbus/include/mb.h"
#include "./modbus/include/mbport.h"

/* ----------------------- static functions ---------------------------------*/
void prvvUARTTxReadyISR( void );
void prvvUARTRxISR( void );
/* ----------------------- Start implementation -----------------------------*/
/**
* @brief 串口初始化
* @param ucPORT 串口号
* ulBaudRate 波特率
* ucDataBits 数据位
* eParity 校验位
* @retval None
*/
BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{               
        GPIO_InitTypeDef                 GPIO_InitStructure;
        USART_InitTypeDef                 USART_InitStructure;
        NVIC_InitTypeDef                  NVIC_InitStructure;
        
        (void)ucPORT; //不修改串口
        (void)ucDataBits; //不修改数据位长度
        (void)eParity; //不修改校验格式
        
  /* 使能 UART 时钟 */
  RCC_APB1PeriphClockCmd(RS232_USART_CLK, ENABLE);

  /* 连接 PXx 到 USARTx_Tx*/
  GPIO_PinAFConfig(RS232_USART_RX_GPIO_PORT,RS232_USART_RX_SOURCE, RS232_USART_RX_AF);

  /*  连接 PXx 到 USARTx__Rx*/
  GPIO_PinAFConfig(RS232_USART_TX_GPIO_PORT,RS232_USART_TX_SOURCE,RS232_USART_TX_AF);

  /* 配置Tx引脚为复用功能  */
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = RS232_USART_TX_PIN  ;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(RS232_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  /* 配置Rx引脚为复用功能 */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = RS232_USART_RX_PIN;
  GPIO_Init(RS232_USART_RX_GPIO_PORT, &GPIO_InitStructure);
                        
  /* 配置串口RS232_USART 模式 */
  USART_InitStructure.USART_BaudRate = RS232_USART_BAUDRATE;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No ;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(RS232_USART, &USART_InitStructure);

        USART_Init(RS232_USART, &USART_InitStructure);        
        USART_Cmd(RS232_USART, ENABLE);                                                                                        //使能USART2
        USART_ITConfig(RS232_USART,USART_IT_RXNE, ENABLE);        /*配置串口接收中断*/         


        //=====================中断初始化======================================
        //设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
        NVIC_InitStructure.NVIC_IRQChannel = RS232_USART_IRQ;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
    return TRUE;
}

/**
* @brief 控制接收和发送状态
* @param xRxEnable 接收使能、
* xTxEnable 发送使能
* @retval None
*/
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{               
                if(xRxEnable)
                {
                //使能接收和接收中断
                USART_ITConfig(RS232_USART, USART_IT_RXNE, ENABLE);;
                }
                else
                {
                USART_ITConfig(RS232_USART, USART_IT_RXNE, DISABLE);
                }
                if(xTxEnable)
                {
                //使能发送完成中断
                USART_ITConfig(RS232_USART, USART_IT_TXE, ENABLE);
                }
                else
                {
                //禁止发送完成中断
                USART_ITConfig(RS232_USART, USART_IT_TXE, DISABLE);
                }
    /* If xRXEnable enable serial receive interrupts.
                         If xTxENable enable transmitter empty interrupts.
                                如果XRX启用启用串行接收中断。
                                如果XTX启用使发射器空中断。
     */
}


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.
                        在UART传输缓冲区中放置一个字节。
                        如果调用了pxMBFrameCBTransmitterEmpty(),则协议栈调用此函数*/
        
        
        //发送数据
                        USART_SendData(RS232_USART, 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.
                 *返回UART接收缓冲区中的字节。此函数在调用pxMBFrameCBByteRecei.()之后由协议栈调用。
     */
                *pucByte = USART_ReceiveData(RS232_USART);
    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.
*为目标处理器的传输缓冲区空中断(或等效中断)创建一个中断处理程序。
*然后这个函数应该调用pxMBFrameCBTransmitterEmpty(),
*它告诉协议栈可以发送一个新字符。
*然后,协议栈将调用XMbPosialPutPoType()来发送字符。
*/
void prvvUARTTxReadyISR( void )
{
        //mb.c eMBInit函数中
        //pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM
        //发送状态机
    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.
*/
/*FreeModbus协议栈通过串口中断接收一帧数据,用户需在串口接收中断中回调prvvUARTRxISR()函数;
prvvUARTRxISR()函数:*/
void prvvUARTRxISR( void )
{
                //mb.c eMBInit函数中
                //pxMBFrameCBByteReceived = xMBRTUReceiveFSM
                //接收状态机
    pxMBFrameCBByteReceived(  );
}

void USART1_IRQHandler(void)
{
//发生接收中断
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
prvvUARTRxISR();
//清除中断标志位
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}

//发生完成中断
if(USART_GetITStatus(USART1, USART_IT_TC) == SET)
{
prvvUARTTxReadyISR();
//清除中断标志
USART_ClearITPendingBit(USART1, USART_IT_TC);
}
}



freemodbus我是官网下载的       别的文件没有动      请问错误出在哪里了     感谢各位大佬给解答    

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
10条回答
chunyang
1楼-- · 2019-03-23 17:45
 精彩回答 2  元偷偷看……
Xmc10086
2楼-- · 2019-03-23 18:08
在调试模式下    发现mbrtu.c中的eMBRTUReceive()函数  在判断报文长度和CRC检验的时候出现了错误    不进行检验 直接else了     目前还是在找问题出在哪里     
Xmc10086
3楼-- · 2019-03-23 20:30


建议用串口监视软件看看实际发送的数据,再按协议规范检查哪里不对,进而去查找相关代码的错误。
关于一言 ...


好的      第一次发这种帖子

Xmc10086
4楼-- · 2019-03-23 22:05
 精彩回答 2  元偷偷看……
Xmc10086
5楼-- · 2019-03-23 22:16


建议用串口监视软件看看实际发送的数据,再按协议规范检查哪里不对,进而去查找相关代码的错误。
关于一言 ...


大佬您好 在mbrtu.c文件中eMBRTUReceive() 现在是能检测到帧但是usRcvBufferPos没值是怎么回事 是我哪里配置错误了

chunyang
6楼-- · 2019-03-24 03:22


大佬您好 在mbrtu.c文件中eMBRTUReceive() 现在是能检测到帧但是usRcvBufferPos没值是怎么回事 是我哪 ...


不知道,这个只能靠你自己检查。

一周热门 更多>

相关问题

相关文章