首页 > 其他分享 >FreeModbus RTU 从机Hal库裸机移植避坑指南

FreeModbus RTU 从机Hal库裸机移植避坑指南

时间:2024-11-13 18:07:39浏览次数:1  
标签:HAL __ usRegIndex UART 避坑 裸机 Hal BUF REG

首先说明 : FreeModbus 有很多个库!!!! 不同库的实现方法是略有不同的!!!
本次 FreeModbus RTU 移植 主要依据 这个网友分享的工程他人移植的库

你可能会在csdn看到他的文章, 但是完全跟着那个文章走很混乱 而且跟库的文件不一样. 故而 我重新整理了工程, 并写了一个详细的移植教程

1. 下载 FreeModbus RTU 库

FreeModbus RTU 库

2. STM32CubeMX 配置流程

我假设你已经学会使用stm32cubeMX点灯了;

2.1下载模式配置

下载模式配置

2.2 开启外部时钟

开启外部时钟

2.3 定时器配置

定时器配置

2.4 串口配置

串口配置

2.5 中断配置

开启定时器和串口的中断

2.6 配置中断函数(关闭自动生成)

中断函数关闭

2.7 配置时钟

时钟配置

3.库文件导入

3.1 .c文件汇总

_c文件汇总

3.2 .h文件汇总

_h文件索引汇总

3.3 demo文件选择

demo文件选择

4. 移植流程

ok 完成上述步骤后, 你就可以开始正式的移植工作了:

主要需要移植的地方为: portserial.c && porttimer.c && demo.c

4.1 portserial.c

vMBPortSerialEnable() 函数

这个函数要根据传入的参数进行串口接收和关闭中断使能

vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
	    if(xRxEnable)
    {

        __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);		
    }
    else
    {
        __HAL_UART_DISABLE_IT(&huart1, UART_IT_RXNE);
    }

    if(xTxEnable)
    {

		
        __HAL_UART_ENABLE_IT(&huart1, UART_IT_TXE);	
    }
    else
    {
        __HAL_UART_DISABLE_IT(&huart1, UART_IT_TXE);
    }
}

xMBPortSerialInit() 函数

这个函数主要初始化串口,因为我们已经使用stm32cubeMX配置好串口,所以直接调用就好了, 这样子可以实现配置统一,方便阅读和修改

xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
    MX_USART1_UART_Init();
		return TRUE;
}

xMBPortSerialPutByte () 函数

这个函数主要实现串口发送一个字节, 有点神奇的是我直接调用hal库的函数传输会有bug,通信失败. 具体原因我还没排查到.这里贴那个老哥是实现方法;

xMBPortSerialPutByte( CHAR ucByte )
{
    USART1->DR = ucByte;
    return TRUE;
}

xMBPortSerialGetByte() 函数

这个函数主要实现串口接收一个字节, 有点神奇的是我直接调用hal库的函数传输会有bug,通信失败. 具体原因我还没排查到.这里贴那个老哥的实现方法;

xMBPortSerialGetByte( CHAR * pucByte )
{
    *pucByte = (USART1->DR & (uint16_t)0x00FF);
    return TRUE;
}

手搓串口1中断函数USART1_IRQHandler()

这个中断函数要在portserial.c中手动添加, 主要是因为它调用了static void prvvUARTTxReadyISR( void ) 和 static void prvvUARTRxISR( void ); 再其他文件调用不了. 所以才要关闭hal库自动生成中断函数在这里手动添加;

void USART1_IRQHandler(void)
{
    if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))
    {
        __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);	
        prvvUARTRxISR();	
    }

    if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE))				
    {
        __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);			
        prvvUARTTxReadyISR();
    }
}

4.2 porttimer.c

xMBPortTimersInit() 函数

这个函数主要初始化定时器, 因为我使用的是stm32cubeMX配置好定时器, 所以直接调用就好了, 这样子可以实现配置统一,方便阅读和修改

xMBPortTimersInit( USHORT usTim1Timerout50us )
{
	MX_TIM4_Init();
	__HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);      
    __HAL_TIM_ENABLE_IT(&htim4, TIM_IT_UPDATE);					
    return TRUE;
}

vMBPortTimersEnable() 函数

使能定时器 和情况计数器数值

vMBPortTimersEnable(  )
{
   __HAL_TIM_SET_COUNTER(&htim4, 0);
   __HAL_TIM_ENABLE(&htim4);
}

vMBPortTimersDisable() 函数

关闭定时器

vMBPortTimersDisable(  )
{
   __HAL_TIM_DISABLE(&htim4);
}

手搓定时器4中断函数TIM4_IRQHandler()

这个中断函数要在porttimer.c中手动添加, 主要是因为它调用了static void prvvTIMERExpiredISR( void ); 再其他文件调用不了. 所以才要关闭hal库自动生成中断函数在这里手动添加;

void TIM4_IRQHandler(void)
{
    if(__HAL_TIM_GET_FLAG(&htim4, TIM_FLAG_UPDATE))
    {
        __HAL_TIM_CLEAR_FLAG(&htim4, TIM_FLAG_UPDATE);
        prvvTIMERExpiredISR();
    }
}

4.3. demo.c

这个文件就是FreeModbus移植的关键位置了, 其通讯都是在调用这些信息;
以下直接贴验证的好代码, 想要自定义就修改前面那四个寄存器就可以;

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


// 十路输入寄存器
#define REG_INPUT_SIZE  10
uint16_t REG_INPUT_BUF[REG_INPUT_SIZE];


// 十路保持寄存器
#define REG_HOLD_SIZE   10
uint16_t REG_HOLD_BUF[REG_HOLD_SIZE];


// 十路线圈
#define REG_COILS_SIZE 10
uint8_t REG_COILS_BUF[REG_COILS_SIZE] = {1, 1, 1, 1, 0, 0, 0, 0, 1, 1};


// 十路离散量
#define REG_DISC_SIZE  10
uint8_t REG_DISC_BUF[REG_DISC_SIZE] = {1,1,1,1,0,0,0,0,1,1};


/// CMD4命令处理回调函数
eMBErrorCode eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    USHORT usRegIndex = usAddress - 1;

    // 非法检测
    if((usRegIndex + usNRegs) > REG_INPUT_SIZE)
    {
        return MB_ENOREG;
    }

    // 循环读取
    while( usNRegs > 0 )
    {
        *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] >> 8 );
        *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUF[usRegIndex] & 0xFF );
        usRegIndex++;
        usNRegs--;
    }

    // 模拟输入寄存器被改变
    for(usRegIndex = 0; usRegIndex < REG_INPUT_SIZE; usRegIndex++)
    {
        REG_INPUT_BUF[usRegIndex]++;
    }

    return MB_ENOERR;
}

/// CMD6、3、16命令处理回调函数
eMBErrorCode eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{
    USHORT usRegIndex = usAddress - 1;

    // 非法检测
    if((usRegIndex + usNRegs) > REG_HOLD_SIZE)
    {
        return MB_ENOREG;
    }

    // 写寄存器
    if(eMode == MB_REG_WRITE)
    {
        while( usNRegs > 0 )
        {
            REG_HOLD_BUF[usRegIndex] = (pucRegBuffer[0] << 8) | pucRegBuffer[1];
            pucRegBuffer += 2;
            usRegIndex++;
            usNRegs--;
        }
    }

    // 读寄存器
    else
    {
        while( usNRegs > 0 )
        {
            *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] >> 8 );
            *pucRegBuffer++ = ( unsigned char )( REG_HOLD_BUF[usRegIndex] & 0xFF );
            usRegIndex++;
            usNRegs--;
        }
    }

    return MB_ENOERR;
}

/// CMD1、5、15命令处理回调函数
eMBErrorCode eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
    USHORT usRegIndex   = usAddress - 1;
    UCHAR  ucBits       = 0;
    UCHAR  ucState      = 0;
    UCHAR  ucLoops      = 0;

    // 非法检测
    if((usRegIndex + usNCoils) > REG_COILS_SIZE)
    {
        return MB_ENOREG;
    }

    if(eMode == MB_REG_WRITE)
    {
        ucLoops = (usNCoils - 1) / 8 + 1;
        while(ucLoops != 0)
        {
            ucState = *pucRegBuffer++;
            ucBits  = 0;
            while(usNCoils != 0 && ucBits < 8)
            {
                REG_COILS_BUF[usRegIndex++] = (ucState >> ucBits) & 0X01;
                usNCoils--;
                ucBits++;
            }
            ucLoops--;
        }
    }
    else
    {
        ucLoops = (usNCoils - 1) / 8 + 1;
        while(ucLoops != 0)
        {
            ucState = 0;
            ucBits  = 0;
            while(usNCoils != 0 && ucBits < 8)
            {
                if(REG_COILS_BUF[usRegIndex])
                {
                    ucState |= (1 << ucBits);
                }
                usNCoils--;
                usRegIndex++;
                ucBits++;
            }
            *pucRegBuffer++ = ucState;
            ucLoops--;
        }
    }

    return MB_ENOERR;
}

/// CMD2命令处理回调函数
eMBErrorCode eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    USHORT usRegIndex   = usAddress - 1;
    UCHAR  ucBits       = 0;
    UCHAR  ucState      = 0;
    UCHAR  ucLoops      = 0;

    // 非法检测
    if((usRegIndex + usNDiscrete) > REG_DISC_SIZE)
    {
        return MB_ENOREG;
    }

    ucLoops = (usNDiscrete - 1) / 8 + 1;
    while(ucLoops != 0)
    {
        ucState = 0;
        ucBits  = 0;
        while(usNDiscrete != 0 && ucBits < 8)
        {
            if(REG_DISC_BUF[usRegIndex])
            {
                ucState |= (1 << ucBits);
            }
            usNDiscrete--;
            usRegIndex++;
            ucBits++;
        }
        *pucRegBuffer++ = ucState;
        ucLoops--;
    }

    // 模拟离散量输入被改变
    for(usRegIndex = 0; usRegIndex < REG_DISC_SIZE; usRegIndex++)
    {
        REG_DISC_BUF[usRegIndex] = !REG_DISC_BUF[usRegIndex];
    }

    return MB_ENOERR;
}

5.移植最后一步 main.c 编写

ok 至此你已经完成90%的移植工作了;
现在只需要调用 对应初始化的函数 还有那四个数组就可以了;
贴一个简单版的main.c关键部分

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

void SystemClock_Config(void);
extern uint16_t REG_HOLD_BUF[10];

int main(void)
{
  HAL_Init();
	eMBInit(MB_RTU, 0x01, 0, 115200, MB_PAR_NONE); 
	eMBEnable();

  SystemClock_Config();

  REG_HOLD_BUF[0] = 0Xff00;
  MX_GPIO_Init();
  MX_TIM4_Init();
  MX_USART1_UART_Init();

  while (1)
  {
		eMBPoll();	
  }
}

6.剩下10%的坑

如果你操作完上面的步骤发现还没能使用, 恭喜你 还有几个坑得改一改:

  1. 使用 MicroLIB 库 且 编译优化等级选择 Level 3(-O3) 重编译;
    如下:

  2. 把你的modbus助手(如 QModBus) 关闭再开启 然后就可以使用了

标签:HAL,__,usRegIndex,UART,避坑,裸机,Hal,BUF,REG
From: https://www.cnblogs.com/chentuze/p/18544499

相关文章

  • AT_agc011_d [AGC011D] Half Reflector 题解
    用\(1\)表示A,\(0\)表示B,观察进行一次操作后字符串会发生什么变化。首先当第一个数为\(1\)时,只会将第一个数变为\(0\)。对于剩下的情况,手玩一下可以发现会将第一个数移到末尾,然后将所有数异或\(1\)。先考虑暴力怎么做,可以记一个指针\(i\)和当前应该给全体数异或的值\(......
  • Halcon教程:多方法提取轮廓坐标
    欢迎来到广州研为官方频道!我们将在频道中不断更新运动控制案例讲解、小型项目代码讲解、运动控制知识科普、机器视觉知识科普等内容,只为与您一起交流分享运动控制的那些事。目录1轮廓加工ContourProcessing2edges_sub_pix提取图像轮廓3轮廓获取轮廓坐标3.1获取轮廓......
  • hal库
    HAL库学习解疑网站参考视频一些小细节!alt+/触发自动补全定时器初始化函数MX_TIM2_Init在进行初始化的时候会把中断标志位至1,导致每次启动时钟都会调用一次中断回调函数!如果影响了程序的正确运行则需要在初始化后立马将标志位至0相较于TI1和TI2组成的输入捕获通道......
  • 使用halcon完成一维码、二维码的识别
    图片素材 通过网盘分享的文件:图片5链接:https://pan.baidu.com/s/1r9SG4lZ3ZQ5S-NGVsFx70w?pwd=BFDJ提取码:BFDJ读码一维码创建读码句柄create_bar_code_model([],[],BarCodeHandle)参数一:输入通用参数可以调整条形码模型的名称。参数二:通用参数可以调整条形码......
  • Halcon 灰度形态学及太阳能电池片缺陷检测应用
    一、基本概念        Halcon灰度形态学是图像处理领域中的一种重要技术,它允许对图像中的灰度值进行非线性操作,这些操作取决于像素的邻域。        灰度形态学是形态学的一种推广,与二值形态学相比,它不仅在图像本身的空间尺寸上有所变化,而且图像本身的灰度值也......
  • stm32 HAL 添加 FREERTOS系统(使用stm32cubemx)
    #学习笔记,留存#1.ClockConfiguration(时钟配置)​​​​​​​HSE,LSE选择外部晶振系统时钟选择TIM6,systick(滴答时钟)给FREERTOS用根据自己的芯片配置时钟(我用的是stm32f103zet6)AHB总线72MHZAPB1总线36MHZ APB2总线72MHZ2.ADDFREERTOS(添加实时系统)在Pinout&Co......
  • MAC下使用Clion软件进行STM32的HAL库的开发
    1、准备的软件(1)clion:链接:https://www.jetbrains.com.cn/clion/破解:方法可在某宝上去找。(2)STM32CubeMX与ST_Link:链接:https://www.st.com.cn/content/st_com/zh/stm32cubemx.htmlmac电脑在安装的时候会出现上面的界面,依次安装即可。(3)macOS的包管理器‌brew:打开终端......
  • halcon中将xld轮廓或者region区域绘制在图像上并保存
    1)单通道图像的绘制draw_circle(WindowHandle,Row,Column,Radius)gen_circle(Circle,Row,Column,Radius)paint_region(Circle,Image,ImageR,0,'fill')paint_region(Circle,Image,ImageG,255,'fill')paint_region(Circle,Image,ImageB,......
  • STM32(hal库)中的定时器从模式TIM_SlaveConfigTypeDef结构体中的含义,以及可选参数的含义
            在STM32的HAL库中,定时器从模式配置结构体TIM_SlaveConfigTypeDef用于配置定时器作为从定时器时的相关参数。该结构体及其可选参数的含义对于理解和配置STM32定时器的从模式至关重要。以下是对该结构体及其参数的详细解释:TIM_SlaveConfigTypeDef结构体该结构......
  • 【人脸伪造检测】Spatial-Phase Shallow Learning: Rethinking Face Forgery Detectio
    一、研究动机[!note]创新点:利用相位谱实现伪造检测,并且证明了卷积模型可以提取隐性特征。由于上采样是伪造模型的关键步骤,这篇论文通过相位信息检测上采样的伪影。对比之前的频率模型:F3-Net:通过离散余弦变换后的统计特征实现伪造检测二、检测模型可学习的知识点......