OpenVINOTM,给你看得见的未来!>>
电子产品世界 » 论坛首页 » 高校专区 » 坤创E-Geek/天科大新电社 » 【原创】手把手教你移植FreeModbus到STM32(三)

共6条 1/1 1 跳转至

【原创】手把手教你移植FreeModbus到STM32(三)

高工
2020-04-22 02:15:48    评分

------------------紧接上一帖----------------

4.freemodbusstm32平台测试与调试

一个不会打仗的士兵不是好士兵,整天在兵营里吹牛x,偶尔还放空枪,这样的还放下狠话,要灭人家一个师,就没见过这么厚脸皮的。我们要学习独立团团长李云龙,别扯那多没有用的,有真本事“亮剑”见识一下。So,我们今天就来试一试移植的效果,一起调一调主函数。

先来分析一下,想要能请得动FreeModbus这位大佬,要想让它为我们服务,首先需要给它伺候舒服了,也就是需要先对FreeModbus进行初始化。初始化的步骤其实就是调用eMBInit函数和eMBEnable函数,温馨补充一下照顾一下腼腆的孩子们:eMBInit函数函数是设置硬件的,有五个参数,分别是:

参数1.Modbus的模式:这里可以选择RTU、ASCII、TCP,这里我们选择RTU模式(MB_RTU);

参数2.设备的地址:这里可以直接写死(0x01),也可以通过拨码开关来设置;

参数3.Modbus选择的串口号:这里默认是串口2(0x02);

参数4.波特率:默认写115200,我们这里配置为9600;

参数5.校验位:默认不效验(MB_PAR_NONE)。

然后在主循环中调用eMBPoll函数不断查询。int main()函数具体代码如下:

int main(void)
{ 
  delay_init();     //延时函数初始化     
  //初始化 RTU模式 从机地址为1 USART2 9600 无效验
  eMBInit(MB_RTU, 0x01, 0x02, 9600, MB_PAR_NONE);
  //启动FreeModbus 
  eMBEnable();
  while(1)
  {  
   //FreeMODBUS不断查询
   eMBPoll(); 
  }
}



01.当然,仅仅拿个main函数出来,是不能够证明FreeModbus就跑起来了,我们再来添加点测试部分代码,以观其效吧!测试代码部分,主要添加输入寄存器、保持寄存器、线圈的起始地址和定义的内容,以及输入寄存器、保持寄存器、线圈的处理函数,具体如下:

/* ----------------------- Defines ------------------------------------------*/
//添加输入寄存器、保持寄存器、线圈的起始地址和定义的内容
//保持寄存器起始地址
#define REG_HOLDING_START 0x0001
//保持寄存器数量
#define REG_HOLDING_NREGS 8
//保持寄存器内容
uint16_t usRegHoldingBuf[REG_HOLDING_NREGS] ={0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0x4055,0x147b,0x408e};
 
//输入寄存器起始地址
#define REG_INPUT_START 0x0001
//输入寄存器数量
#define REG_INPUT_NREGS 8
//输入寄存器内容
uint16_t usRegInputBuf[REG_INPUT_NREGS] ={0x1111,0x2222,0x3333,0x4444,0x5555,0x6666,0x7777,0x8888};
 
//线圈寄存器起始地址
#define REG_COILS_START 0x0001
//线圈寄存器数量
#define REG_COILS_SIZE 16
//线圈寄存器内容
uint8_t ucRegCoilsBuf[REG_COILS_SIZE/8] = {0x00,0xFF};
/***********************************************************************/
输入寄存器、保持寄存器、线圈的处理函数
// 保持寄存器的读写函数 支持的命令为读 0x03 和写0x06 可读可写  
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;
}
 
//读输入寄存器函数 支持的命令为读 0x04 
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;
}
 
//线圈处理函数 可读可写 支持的命令为读 0x01 0x05
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; 
 return MB_ENOREG;
}



02.好了,测试代码准备就绪,下面就是见证奇迹的时刻?我们使用ModbusPoll软件测试版来完成对移植FreeModbus rtu的测试,如下图,该代码能够成功的读出输入寄存器、保持寄存器、线圈的数据。

图片10.png

03. 通信正常,则可以看到USB转串口工具的TX和RX指示灯不停闪烁着。想象一下突然有一天,人类的眼睛可以分辨出100MHz以上的闪烁频率时,我们的世界将会如何?emmmm....这个脑洞可能开的有点大,留给大家去发挥想象力吧。如果我们能够分辨更高的频率,那么我们的电脑手机显示器的144Hz的刷新率,就再也不香了吧,哈哈~!

图片11.png


综上可以看出,本次对FreeModbus的移植工作已经完成了,该平台虽然是基于STM32F1xx,但是使用其他STM32的芯片也非常的方便,过程大致相同,简单改一下就好了。从通过ModbusPoll工具进行测试的结果看来,整个工程基本能够达到预期效果,当然本人技术有限,还请各位大佬们不吝赐教。最后贴上main测试完整代码供大家参考。

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
 
#include "mb.h"
#include "mbport.h"
 
/* ----------------------- Defines ------------------------------------------*/
//保持寄存器起始地址
#define REG_HOLDING_START 0x0001
//保持寄存器数量
#define REG_HOLDING_NREGS 8
//保持寄存器内容
uint16_t usRegHoldingBuf[REG_HOLDING_NREGS] ={0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0x4055,0x147b,0x408e};
 
//输入寄存器起始地址
#define REG_INPUT_START 0x0001
//输入寄存器数量
#define REG_INPUT_NREGS 8
//输入寄存器内容
uint16_t usRegInputBuf[REG_INPUT_NREGS] ={0x1111,0x2222,0x3333,0x4444,0x5555,0x6666,0x7777,0x8888};
 
//线圈寄存器起始地址
#define REG_COILS_START 0x0001
//线圈寄存器数量
#define REG_COILS_SIZE 16
//线圈寄存器内容
uint8_t ucRegCoilsBuf[REG_COILS_SIZE/8] = {0x00,0xFF};
 
 int main(void)
 { 
delay_init();     //延时函数初始化    
//初始化 RTU模式 从机地址为1 USART2 9600 无效验
eMBInit(MB_RTU, 0x01, 0x02, 9600, MB_PAR_NONE);
//启动FreeModbus 
eMBEnable();
while(1)
{  
 //FreeMODBUS不断查询
    eMBPoll(); 
}
}
 
// 保持寄存器的读写函数 支持的命令为读 0x03 和写0x06 可读可写  
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;
}
 
//读输入寄存器函数 支持的命令为读 0x04 
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;
}
 
//线圈处理函数 可读可写 支持的命令为读 0x01 0x05
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; 
 return MB_ENOREG;
}
 
 
//开关输入寄存器处理函数 可读 支持的命令为读 0x02
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    return MB_ENOREG;
}
 
//针对 assert错误添加的函数
#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 can add his own implementation to report the file name and line number, 
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */  
   
  /* Infinite loop */  
  while (1)  
  {  
  }  
}
#else
void __aeabi_assert(const char * x1, const char * x2, int x3)
{
}
#endif


 

本系列到此就全部结束了,大家好,我是大Z,感谢大家支持~





关键词: FreeModbus     移植     STM32     手把手         

工程师
2020-04-22 09:27:21    评分
2楼

手动撒花


专家
2020-04-22 10:21:51    评分
3楼

楼主辛苦了

FreeModbus还是非常实用的。


专家
2020-04-22 14:26:57    评分
4楼

主机模式自己写啊!

可简单,可随意,可严谨


管理员
2020-04-22 14:45:33    评分
5楼

完结撒花


专家
2020-04-26 21:52:15    评分
6楼

给祝老师点赞


共6条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]