【freeModbus】STM32之HAL库移植笔记

这篇具有很好参考价值的文章主要介绍了【freeModbus】STM32之HAL库移植笔记。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        工作主要是传感器相关,常与之打交道的协议,莫过于MODBUS了。之前一直都是手撸相关功能码,所以也就没了解过类似freeModbus之类的,现在需要使用HAL库开发,且配置Modbus从机协议为全栈,最近趁着空余时间,学习一番。

(网上说好的移植简单快捷,结果照着各种教程配置,磕磕碰碰了小一周才搞定,在此记录下详细教程)

一、下载压缩包

官网下载地址:About - Embedded Experts (embedded-experts.at)

注:下拉页面,然后点击右下角的Downloads,然后点击红框选中,下载;

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

 二、移植准备

        解压后,我们会看到几个文件夹,但是对我们当前移植来说,有用的是modbus,以及demo下的BARE,我们新建一个工程文件夹,并在该工程目录下新建文件夹freemodbus,将上面所说的两个文件夹复制到这里,如下图:

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

                                                图2 freemodbus解压缩后目录

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcufreemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu 

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

                                图3 新建工程内的freemodbus文件内容

注:modbus与port文件没有进行内容增删,usModbus文件夹放置的是BARE文件夹下的demo.c,将其改名,并新增usModbus.h文件(为了后期其他项目方便移植使用);

三、新建工程

        Modbus协议,我们需要知道的一个关键点是:超时时间;所以,我们需要为其配置一个定时器TIM,以及一个串口USART

定时器配置

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

 定时器的配置是比较关键的,freeModbus中,计时步长为50us,且当波特率大于19200时,固定超时时间为1750us(35*50us),19200及其以下的波特率则还按照波特率计算3.5字节的超时时间,我使用的定时器的时钟为84M,串口波特率为115200,所以配置如上;

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

                                                图 超时时间设置来源

串口配置:

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

串口配置无须多言,选择Asynchronous后,因为使用115200波特率,所以其他的使用默认即可,不需要多余配置;

重点!重点!!重点!!!

不要开启选择的定时器以及串口中断啊,纯纯的都是血泪史,之前就是看教程没有这一步,浪费了好多时间;

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

 到此为此,我们已经完成了工程配置,然后生成工程即可;

四、文件添加

(1)点击魔术棒右边的品字图形,打开Manage Project items,然后添加三个组,FreeModbus,modbus_port,usModbus,三个组下的文件分别来源于工程文件下freemodbus内的modbus,port,usmodbus

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

 添加文件如上,其中usmodbus.c是由demo.c改名而来;

(2)点击魔术棒,然后在C/C++中,将包含了.h文件的路径都包含进去;

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

五、内容修改

战前准备:【main.h】

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

方便我们后面修改内容时调用;

1.首先我们修改的是串口配置文件[portserial.c]

这其中只有六个函数,如下:

/* 串口中断使能函数 */
void vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable );

/* 串口初始化函数 */
BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity );

/* 发送函数:将一个数据推至串口发送缓存 */
BOOL   
xMBPortSerialPutByte( CHAR ucByte );

/* 接收函数 */
BOOL
xMBPortSerialGetByte( CHAR * pucByte );

/* 串口中断发送处理函数 */
void prvvUARTTxReadyISR( void );

/* 串口中断接收函数 */
void prvvUARTRxISR( void );

我们首先在开头添加头文件[main.h]

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

#include "main.h"       /* 添加,方便调用usart函数以及句柄 */

1.1 【vMBPortSerialEnable(BOOL , BOOL)】

        这个函数主要是用于使能接收/发送中断,根据形参BOOL可知,仅由TRUE与FALSE两值;

在这里有个关键点,在于发送标志用的是UART_IT_TXE还是UART_IT_TC,特别是Modbus协议是通过RS485去通讯的;

UART_IT_TC:发送数据完成;

UART_IT_TXE:发送寄存器空,但是不代表已经将数据发送出去,所以将RS485的发送/接收使能引脚跳变为接收前,需要添加一个小延迟,否则会导致个别数据包丢失最后一个字节;

void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
    /* If xRXEnable enable serial receive interrupts. If xTxENable enable
     * transmitter empty interrupts.
     */
	if(xRxEnable)
	{
        RS485_Receive_ENABLE();
		__HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);
	}
	else
	{
		__HAL_UART_DISABLE_IT(&huart1,UART_IT_RXNE);
	}
	
	
	if(xTxEnable)
	{
        RS485_Transmit_ENABLE();
		__HAL_UART_ENABLE_IT(&huart1,UART_IT_TC);
	}
	else
	{
		__HAL_UART_DISABLE_IT(&huart1,UART_IT_TC);
	}
}

1.2【xMBPortSerialInit】

        串口初始化函数,因为我们在cubeMX中配置好工程后,已经自动进行了串口引脚及参数的配置,所以在这里我们不需要多余配置,只需要把NVIC打开即可(很重要)

BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
    /**
      *  \note    我们在配置时关闭了中断,是因为我们需要手动的去开始关闭
      ***/
	HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
	
	__HAL_UART_DISABLE_IT(&huart1,UART_IT_RXNE);
	__HAL_UART_DISABLE_IT(&huart1,UART_IT_TC);
	
    return TRUE;
}

1.3【xMBPortSerialPutByte】

        将一个字节推至串口发送缓冲中

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. */
	
		USART1->DR = ucByte;
		return TRUE;
}

1.4【xMBPortSerialGetByte】

        从串口接收缓冲中读出一个字节

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 = (USART1->DR & (uint16_t)0x00ff);
    return TRUE;
}

1.5 接收/发送中断处理函数

prvvUARTTxReadyISR(),prvvUARTRxISR()两个函数不需要改动,只需要将[static]关键字屏蔽即可;

/* 函数声明:在文件的开头,记得将static关键字屏蔽 */
void prvvUARTTxReadyISR( void );
void prvvUARTRxISR( void );



void prvvUARTTxReadyISR( void )
{
    pxMBFrameCBTransmitterEmpty(  );
}

void prvvUARTRxISR( void )
{
    pxMBFrameCBByteReceived(  );
}

然后将prvvUARTTxReadyISR(),prvvUARTRxISR()两个函数添加至main.h中;

1.6 中断调用

        freeModbus的接收和发送都是在中断中完成的,所以当我们配置好串口的各个函数后,也需要去完成串口中断函数,如下:

void USART1_IRQHandler(void)
{
	if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) != RESET)
	{
		prvvUARTRxISR();
		__HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_RXNE);
	}
	
	
	if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_TC) != RESET)
	{
		prvvUARTTxReadyISR();
		__HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_TC);
	}
}

2.接下来我们需要配置的是定时器,即【porttimer.c】文件

        熟悉的环节,我们需要了解这个文件中包含了哪些函数

/* 定时器初始化 */
BOOL xMBPortTimersInit( USHORT usTim1Timerout50us );

/* 定时器使能 */
void vMBPortTimersEnable(  );         //inline关键字屏蔽

/* 定时器失能 */
void vMBPortTimersDisable(  );        //inline关键字屏蔽

/* 超时处理函数 */
void prvvTIMERExpiredISR( void );

然后,在开头将[main.h]头文件包含进去

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

#include "main.h"

2.1定时器初始化【xMBPortTimersInit】

        定时器的初始化不需要多余的配置,只需要将中断打开即可,并且返回true。

  注:串口和定时器初始化中最重要的,就是配置并打开中断,否则程序将无法正常运行;

BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
	HAL_NVIC_SetPriority(TIM3_IRQn, 1, 0);
    HAL_NVIC_EnableIRQ(TIM3_IRQn);
		
	__HAL_TIM_CLEAR_IT(&htim3,TIM_IT_UPDATE);
	__HAL_TIM_ENABLE_IT(&htim3,TIM_IT_UPDATE);
	
    return TRUE;
}

2.2定时器使能/失能【vMBPortTimersEnable】

        接下来是配置定时器的使能/失能函数,配置完后,记得将inline关键字屏蔽;

/* 定时器使能 */
void
vMBPortTimersEnable(  )
{
    /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
	
		__HAL_TIM_CLEAR_IT(&htim3,TIM_IT_UPDATE);
		__HAL_TIM_ENABLE_IT(&htim3,TIM_IT_UPDATE);
		__HAL_TIM_SetCounter(&htim3,0);
		__HAL_TIM_ENABLE(&htim3);
	
}

/* 定时器失能 */
void
vMBPortTimersDisable(  )
{
    /* Disable any pending timers. */
		__HAL_TIM_ENABLE(&htim3);
		__HAL_TIM_SetCounter(&htim3,0);
		__HAL_TIM_CLEAR_IT(&htim3,TIM_IT_UPDATE);
		__HAL_TIM_DISABLE_IT(&htim3,TIM_IT_UPDATE);
}

2.3超时处理函数【prvvTIMERExpiredISR】

        超时处理函数是放置在定时器中断函数中,这个函数中我们不需要增删内容,只需要将static关键字屏蔽即可,方便我们后面在中断函数中调用,然后将该函数放置于main.h函数中;

/* 函数声明,放置在程序牵头 */
void prvvTIMERExpiredISR( void );

void prvvTIMERExpiredISR( void )
{
    ( void )pxMBPortCBTimerExpired(  );
}

至此,porttimer.c的修改就完成了,接下来就是定时器中断函数配置;

2.4中断调用

        在cubemx配置时,已经将定时器配置为1750us(35*50us)了,所以在定时器中断中,我们不需要再去计算时间,当TIM_FLAG_UPDATE标志置位时,我们直接调用prvvTIMERExpiredISR()即可;

void TIM3_IRQHandler(void)
{
	if(__HAL_TIM_GET_FLAG(&htim3,TIM_FLAG_UPDATE) != RESET)
	{
		
		prvvTIMERExpiredISR();
		
		__HAL_TIM_CLEAR_FLAG(&htim3,TIM_FLAG_UPDATE);
	}
}

3.从机地址修改

        freeModbus的函数中,对从机地址进行了一次usRegAddress++;在这里,我们不需要这个机制,所以,crtl+F,在find in files中搜索[usRegAddress++],然后全部屏蔽;

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

 freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

 4.Modbus ASCII

        这次我们只是需要移植RTU功能,不需要用到Modbus ascii功能,所以直接关闭即可,随便找一个文件,将头文件包含进去,即#include "mbconfig.h",然后鼠标右键跳转至该文件中,将line 49的MB_ASCII_ENABLED设置为0,

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

5.发送中断修复

        打开[mbrtu.c]文件,然后下拉到line 213,即eMBRTUSend()函数之中,然后插入图中红框内容,插入内容的作用是将一个带发送字节的数据推入串口数据寄存器中,触发串口的发送中断,实现从机对主机指令的响应;

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

6.

        点开魔术棒,勾选Use MicroLIB,很重要的一步!!!

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

7.[demo.c]

打开demo.c文件,删除该文件中的main函数,保留其他函数。小小修改以下方便测试,

起始地址为0x01;

寄存器数量为0x0004;

寄存器保存值为0x01,0x02,0x03,0x04

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

 8.[main.h]

        main.h中新增一个头文件

#include "mb.h"

六、测试

        至此,我们已经完成了freemodbus移植文件的所有修改,剩下的,即是初始化以及调用了;

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

我们进入main()函数,在while(1)之前调用freemodbus的初始化函数eMBInit()与使能函数eMBEnable();

/**
  * 第一个参数:(eMode)MB_RTU,表示freeModbus初始化模式为Modbus RTU
  * 第二个参数:(ucSlaveAddress)0x01,表示从机地址为0x01;
  * 第三个参数:(ucPort)0x01,使用串口1;
  * 第四个参数:(ulBaudRate)115200,表示波特率为115200;
  * 第五个参数:(eParity)MB_PAR_NONE,表示无校验码;
  **/
eMBInit(MB_RTU,0X01,0X01,115200,MB_PAR_NONE);
eMBEnable();    /* freeModbus 使能 */

 在while(1)中,然后使用eMBPoll()函数轮询;

使用Modbus Poll工具来测试,测试结果如下:

freemodbus stm32移植,freeModbus,stm32,笔记,单片机,mcu

 至此,freemodbus的移植以及测试已经完成;文章来源地址https://www.toymoban.com/news/detail-760965.html

到了这里,关于【freeModbus】STM32之HAL库移植笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 关于STM32F4和GD32F4以太网,LAN8720+lwip+freemodbus,实现modbus tcp

    关于STM32F4和GD32F4以太网,LAN8720+lwip+freemodbus 这里使用了大佬 小灰灰搞电子 的代码,文章看 STM32F407+LAN8720移植Lwip和freeModbus实现MODBUS TCP 代码看 STM32F407+LAN8720+LWIP移植freemodbus TCP.zip 他的代码是基于正点原子F407的板子开发的,如果是别的板子,需要修改引脚 小灰灰的代码里,没

    2024年02月14日
    浏览(26)
  • 【HAL库】STM32+ESP8266+Onenet+MQTT,极简工程,hal库移植。

    ESP8266通过MQTT协议连接Onenet。从标准库移到了HAL库,过程有点麻烦,整了一天。做完后整理了一下,这个极简的工程,方便以后开发,也希望能帮助到大家,节约时间。 代码工程: https://github.com/wyfroom/ESP8266-Onenet-MQTT 该份代码硬件配置: 板子:STM32F103C8T6最小系统板。 外设:

    2024年02月03日
    浏览(37)
  • 单片机移植Lua(STM32H743移植Lua-5.4.6)

    通常单片机都是使用C/C++来开发的,任何修改都需要重新编译固件然后下载运行。在一些需要灵活性更强的场合中可以内嵌Lua解释器实现动态更新应用程序的功能。这篇文章将对相关内容做个简单说明。 Lua本身就是纯C实现的,不管是移植到上位机程序还是单片机程序中本质上

    2024年02月21日
    浏览(31)
  • STM32 Cube MX 之hal库软件模拟IIC 可直接移植使用

    此为软件模拟IIC,可以直接移植到HAL库使用。.h文件需要自己做函数声明这里就不再放出,如有问题大家可以讨论。 使用的时候只需要更改SDA 和SCL引脚的宏定义就可以移植使用,当然IIC协议其实就是根据IIC的时序图编写代码,主要内容就是包括开始信号,停止信号以及发送数

    2024年02月15日
    浏览(44)
  • POWERLINK协议在stm32单片机+w5500移植成功经验分享

    连续折腾了多个晚上,又趁周末又花了一天时间,终于把powerlink协议移植成功到单片机上啦。本想放弃,但想了下不管我能不能用上,结个尾吧,分享给有需要的人。放弃并不难,但坚持一定很酷。为了移植测试这个协议花了不少血本。stm32开发板就买了两套,其中第一套板

    2024年02月09日
    浏览(45)
  • FreeRTOS_Stm32F103系列单片机标准库移植

    链接:FreeRTOS 下面的教程是基于从github下载压缩包进行的,最好下载这个或者直接看3.1,从我百度网盘下载。如果是别的下载源也问题不大,大同小异。 此时我们需要下载以下两个仓库, 点进去按下面的步骤下载就行了,另一个也是这样下。 链接: FreeRTOS官网 打开链接我们

    2024年01月22日
    浏览(38)
  • mpu6050六轴陀螺仪dmp姿态解算-C语言移植(stm32+hal)

    官方库源文件: 1 移植官方6个库文件 2 修改inv_mpu.h中结构体 3 修改inv_mpu.c 4 修改 inv_mpu_motion_driver.c 5 keil中增加宏定义 6 移植核心[修改inv_mpu.c|inv_mpu_motion_driver.c]

    2024年02月14日
    浏览(31)
  • MPU6050(读取原数据、移植DMP、stm32f4、HAL库、KEIL5)

    记录一下自己遇到的问题及解决方法,希望能帮助到一些人。 第一步,读取芯片的原始数据。需要注意两点:1、对HAL库提供的IIC读取写入函数进行再包装。(千万不要觉的这步多此一举,后面移植DMP时用得到) 2、芯片的地址(这里面有俩坑)第一就是,芯片的 I2C 设备地址

    2023年04月08日
    浏览(37)
  • STM32 -- 实现按键的长按与短按检测(其他单片机可移植)

    目录 资源获取 一 前言 二 思路  三 实现代码 1.主要代码 四 完整代码 Key.h Key.c 该改进版本(1ms太繁琐了,我改成了25ms检测一次)   1.定时器部分 2.按键检测部分  五、参考 欢迎关注微信公众号--星之援工作室 发送(长短按检测) 今天在逛博客的时候,偶然看到了一

    2024年02月12日
    浏览(26)
  • 基于stm32F407的hal库,移植FreeRTOS的具体步骤和遇到的问题(看正点原子的视频)

    因为板子是stm32F407的第二版的,所以开始下的资料是旧版本的,但是旧版本的FreeRTOS工程没有hal库的,都是标准库的,这里是下载stm32F407最新版的资料,进行移植。 资料可以在正点原子官网下载,如下: http://www.openedv.com/docs/boards/stm32/index.html 一定要下载最新的资料(开始用

    2024年02月06日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包