stm32裸机移植FreeModbus

发布者:代码漫游者最新更新时间:2022-07-14 来源: csdn关键字:stm32  FreeModbus 手机看文章 扫描二维码
随时随地手机看文章

简单记录一下步骤。


官方下载freemodbus-v1.6.zip源码,然后把源码中的modbus文件夹、demoBAREport文件夹导入工程。


先是一波无脑导,把文件夹里所有文件导入。


存储区配置,单片机上定义的起始地址要比实际通信过程中读写的地址+1。


#include "mb.h"

#include "mbport.h"

#include "mbutils.h"

//输入寄存器

#define REG_INPUT_START 1001

#define REG_INPUT_NREGS 2


static USHORT   usRegInputStart = REG_INPUT_START;

static USHORT   usRegInputBuf[REG_INPUT_NREGS];


//保持寄存器

#define REG_HOLDING_START 2001

#define REG_HOLDING_NREGS 1


static USHORT   usRegHoldingStart = REG_HOLDING_START;

static USHORT   usRegHoldingBuf[REG_HOLDING_NREGS];


//输出线圈点

#define REG_COILS_START 3001

#define REG_COILS_SIZE 4


static USHORT   usRegCoilsStart = REG_COILS_START;

static UCHAR    ucRegCoilsBuf[REG_COILS_SIZE/8+(REG_COILS_SIZE%8?1:0)];


//离散输入点

#define REG_DISCRETE_START 4001

#define REG_DISCRETE_SIZE 8


static USHORT   usRegDiscreteStart = REG_DISCRETE_START;

static UCHAR    ucRegDiscreteBuf[REG_DISCRETE_SIZE/8+(REG_DISCRETE_SIZE%8?1:0)];


主程序就是标准的运行三连+IO读写。


eStatus = eMBInit( MB_RTU, addr, 0, 9600, MB_PAR_EVEN );


    /* Enable the Modbus Protocol Stack. */

    eStatus = eMBEnable(  );


    for( ;; )

    {

        ( void )eMBPoll(  );

        usRegInputBuf[0]=Get_Adc_Average(8,10);

        usRegInputBuf[1]=Get_Adc_Average(9,10);

        ucRegDiscreteBuf[0]=(GPIOB->IDR&0xFFFFFF00)>>8;

        GPIOB->ODR=GPIOB->ODR&0xFFFFFF0F;

        GPIOB->ODR=GPIOB->ODR|ucRegCoilsBuf[0]<<4;

    }


支持的4种读写function扔在主函数后面就行了。


/**

* @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;

                usBitOffset += 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;

}


portserial.c就是和stm32相关的硬件实现接口,初始化那里可以直接调用RS485_Init(9600);


/*

 * FreeModbus Libary: BARE Port

 * Copyright (C) 2006 Christian Walter

 *

 * This library is free software; you can redistribute it and/or

 * modify it under the terms of the GNU Lesser General Public

[1] [2]
关键字:stm32  FreeModbus 引用地址:stm32裸机移植FreeModbus

上一篇:F1和F4对GPIO的操作区别
下一篇:MAX6675 K型热电偶读温度

推荐阅读最新更新时间:2024-11-17 11:59

如何利用STM32单片机串口发送字符串
最近由于要调试一个SMS发送短信的模块,该模块需要发送一系列AT指令,且需要字符串发送,但是STM32官方给的usart.c中并没有直接发送字符串的函数,因此写了一个发送字符串的函数。 其实发送字符串的本质还是发送一个个字符,所以只需在字符串结束标志之前,循环发送字符即可。不罗嗦,上程序。 //程序功能:利用串口发送一个字符串 // 参数:USARTx USART编号 可取 USART1、USART2、USART3、USART4、 USART5(STM32F103ZET6) str 需要发送的字符串 #include “stm32f10x.h” void Usart_SendString(USART_TypeDef* US
[单片机]
基于STM32单片机的控制步进电机实验
一、实验原理(以28BYJ48步进电机为例)和51控制步进电机原理一致 1、五线四相步进电机,不同线圈得电会让步进电机的转子转动一个角度,按一定规律给不同的线圈通电,就可以让步进电机连续转动,下表就是步进电机和拆解后的图片,以及四根线通电的顺序。 注:总共五条线,一个是VCC,剩下四条分别接上ABCD相。 2、每走一个位置,都要给一定的延时,不然还没等转子到位,下一个脉冲就进来了,肯定会引起错误,导致电机堵转、异常震动。 3、通过改变延时的时间,就可以控制电机的转速,不能太慢,也不要太快,不断调试到合理范围就行,转向用了一个枚举类型,控制转向。 4、单片机IO口和电机四条线连接时,一定不能错误,要按照顺序相连接。 5、调换
[单片机]
基于<font color='red'>STM32</font>单片机的控制步进电机实验
Ubuntu下安装Stm32的Eclipse的开发环境(1)
在最起初的时候,我刚刚接触linux上单片机的开发,最喜欢的就是 eclipse + arm-plug-in + arm-none-eabi 的开发环境,因为这是在Linux上最接近于windows下keil、IAR等IDE的开发方式,然而那是由于对eclipse亦或是makefile等编译过程中的工具的不甚了解,很多时候会遇到一些莫名的错误,也导致了那是觉得这样的环境很鬼畜,现在看来多是一些很浅显的问题,直到最近我再一次的尝试了eclipse开发环境的搭建和使用,我才很顺利的完成了程序的配置。现在也把这个方法推荐给大家,不过在使用这个方式前,还是建议大家先把之前的文章内容看懂了,否则很多时候遇到问题都会不知道怎么解决。 安装
[单片机]
stm32专题二十四:ADC简介
ADC简介: ADC :Analog to Digital,模拟数字转换器 三个独立的ADC 1 / 2 / 3; 分辨率为12位; 每个ADC具有18个通道,其中外部通道16个; ADC结构框图,主要分成7个部分: 电压输入范围、输入通道、转换顺序、触发源、转换时间、数据寄存器、中断。 (1)输入电压范围: ADC 输入范围为:VREF- ≤ VIN ≤ VREF+。由VREF-、VREF+ 、VDDA 、VSSA、这四个外部引脚决定。 在设计原理图的时候一般把VSSA 和VREF-接地,把VREF+和VDDA 接3V3,得到ADC 的输入电压范围为:0~3.3V。 如输入电压超过3.3v,如希望测量
[单片机]
<font color='red'>stm32</font>专题二十四:ADC简介
keil软件的安装和破解(STM32和C51都可使用)
教大家学会安装keil软件和破解(本篇以keil4软件为例) 第一步:运行mdk.exe软件,一直点默认即可 此处可以修改路径 第二步:点击next后,出现此框图,first name 和E-mail栏随便输入数字即可 第三步:等待安装完即可 第四步:安装完,点击next即可,最后点击finish,(出现黑框,点击关闭即可) 破解步骤: 第一步:运行keil软件 第二步:点击file,找到licence.. 选项,点开 复制CID选项下的内容 第三步:打开破解软件,即KEIL_Lic.exe软件 将所复制的CID码粘贴到CID处,同时选择Target为ARM模式 (注:STM32所用破解Target为A
[单片机]
keil软件的安装和破解(<font color='red'>STM32</font>和C51都可使用)
一种基于STM32的多路电压测量设计方案及实现
引言 近年来,数据采集及其应用受到了人们越来越广泛的关注,数据采集系统也有了迅速的发展,它可以广泛的应用于各种领域。 数据采集技术是信息科学的重要分支之一,数据采集也是从一个或多个信号获取对象信息的过程。数据采集是工业控制等系统中的重要环节,通常采用一些功能相对独立的单片机系统来实现,作为测控系统不可缺少的部分,数据采集的性能特点直接影响到整个系统。 电压的测量最为普遍性,研究设计并提高电压测量精度的方法及仪器具有十分重要的意义。在电压测量设计中,单片机作为控制器,是整个设计的核心。除此之外,设计中还必须有模数转换器(ADC)。ADC用于直接采集模拟电压并将模拟信号转换成数字信号,它直接影响着数据采集的精度和速度。
[单片机]
一种基于<font color='red'>STM32</font>的多路电压测量设计方案及实现
STM32-嵌入式学习笔记02-中断应用概述
本节目标: 通过DMA,无需中断,接收不定时长的串口数据 描述: 当在串口多数据传输下,CPU会产生多次中断来接收串口数据,这样会大大地降低CPU效率,同时又需要CPU去做其它更重要的事情,我们应该如何来优化? 比如四轴飞行器,当在不停地获取姿态控制方向时,又要去接收串口数据. 答:使用DMA,无需CPU中断便能实现接收串口数据 1.DMA介绍 DMA,全称为: Direct Memory Access,即直接存储器访问, DMA 传输方式无需 CPU 直接 控制传输,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。 2在main()中调用串口配置函数,初始化串口后,然后使能U
[单片机]
STM32-嵌入式学习笔记02-中断应用概述
【从智能锁谈STM32安全技术】之 - 安全固件安装
在第六季内容中,将介绍安全固件安装 SFI (Secure Firmware Installation)的原理及解决方案。 安全固件安装的本质是,我们是否能相信工厂的制造过程是安全的过程。如果我们相信工厂是可靠的,相信它总是按照我们的指示,例如,我们希望它不要泄露固件代码,我们希望它不要过生产,他们都能一一办到,那么安全固件安装是没有用武之地。 然而,总有一些工厂,或者工厂里的某些员工 ,他们为了一时利益,可能会将研发设计公司辛苦开发的源代码(通常是厂商的二进制固件代码),直接泄露给其他第三方。同时他们也有可能将委托生产的产品过生产。即,如果我们希望他试着生产的 1000 台 ,结果他们也许会生产 2000 台。1000
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved