FreeModBusRtu移植 --stm32L431RCT6(小熊派)

news2024/9/19 5:27:41

文章目录

  • 前言
  • 一、移植前需要的工作
  • 二、修改点讲解
    • 1.串口中断
    • 2.定时器
    • 3.保持寄存器
    • 4.测试
  • 总结


前言

最近需要做一个modbus485的传感器,主要是用来做从机。之前做过主机的是stm标准库,那这次做一个HAL的从机协议栈,方便大家直接获取数据。
移植成功的代码仓库如下:Freemodbus从机仓库代码


一、移植前需要的工作

1.了解modbus485协议(协议帧内容含义等等)
2.选一块stm32的开发板(随便选,能用stm32cubemx就行)
3.移植这个协议,主要关注3点,串口、定时器以及数据存储的寄存器缓冲区

二、修改点讲解

1.串口中断

portserial.c :


extern UART_HandleTypeDef huart1;


/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits,
                       eMBParity eParity)
{
    //这个是用stm32cubemx生成的函数名称,我增加了参数
	MX_USART1_UART_Init(ulBaudRate);
    return TRUE;
}

void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable)
{
   ENTER_CRITICAL_SECTION();
		  
  if (xRxEnable)
  {
  	  //使能串口接收中断
	 __HAL_UART_ENABLE_IT(&huart1, USART_IT_RXNE);
  }
  else
  {
     //关闭串口接收中断
	 __HAL_UART_DISABLE_IT(&huart1, USART_IT_RXNE);
  }


  if (xTxEnable)
  {
     //使能串口发送中断
	 __HAL_UART_ENABLE_IT(&huart1, USART_IT_TXE);
  }
  else
  {
 	 //关闭串口发送中断
	 __HAL_UART_DISABLE_IT(&huart1, USART_IT_TXE);
  }
	  
  EXIT_CRITICAL_SECTION();

}

void vMBPortClose(void)
{
	//不做函数处理
}

BOOL xMBPortSerialPutByte(CHAR ucByte)
{ 
	// 发送串口数据 一次发送一个数据
	HAL_UART_Transmit(&huart1, &ucByte,1,5);
    return TRUE;
}

BOOL xMBPortSerialGetByte(CHAR *pucByte)
{
	// 获取串口数据 一次拿一个数据
	HAL_UART_Receive(&huart1,pucByte,1, 0);	
    return TRUE;
}
void prvvUARTTxReadyISR(void)
{
    pxMBFrameCBTransmitterEmpty();
}

void prvvUARTRxISR(void)
{
    pxMBFrameCBByteReceived();

}

void USART1_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart1);
  if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET)
  {    //获取接收RXNE标志位是否被置位
	 prvvUARTRxISR();
	 __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
	
  } 
  
  if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE) == SET)
  {
	prvvUARTTxReadyISR();
	__HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_TXE);
  }
 

}

2.定时器

代码如下:

BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
{
	//这个是用stm32cubemx生成的函数名称,我增加了参数
	MX_TIM2_Init(usTim1Timerout50us);
    return TRUE;
}

void vMBPortTimersEnable()
{
    // 开启定时器,计算是否超时
	__HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE);  // 清除中断标志位
    __HAL_TIM_ENABLE_IT(&htim2, TIM_IT_UPDATE); //开启定时器自动更新中断
	__HAL_TIM_SET_COUNTER(&htim2, 0x0000);  // 设置计数器的值为0
	__HAL_TIM_ENABLE(&htim2);   // 开启定时器中断
}

void vMBPortTimersDisable()
{   
	__HAL_TIM_DISABLE(&htim2);    // 关闭定时器中断
	__HAL_TIM_SET_COUNTER(&htim2, 0x0000);  // 设置计数器的值为0
	__HAL_TIM_DISABLE_IT(&htim2, TIM_IT_UPDATE); //关闭定时器自动更新中断
	__HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE);  // 清除中断标志位
}

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

void TIM2_IRQHandler(void)
{
  HAL_TIM_IRQHandler(&htim2);
  if(__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET)
  {
    prvvTIMERExpiredISR();
  	__HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_UPDATE);  // 清除中断标志位
  }
}

3.保持寄存器

在寄存器中,我们需要划分我们自己的寄存器的含义,从而达到数据传输的含义

#define S_REG_HOLDING_START           0
#这是一个倾角传感器的保持寄存器数据划分
/*----------------------------------------
*         划分保持寄存器的类型区域            
*========================================
* 0 |从机地址
*-----------------------------------------
* 1 |X轴角度 
*-----------------------------------------
* 2 |Y轴角度
*-----------------------------------------
* 3 |Z轴角度
*-----------------------------------------
*/
#define S_SLAVEID_REG_START S_REG_HOLDING_START
#define S_SLAVEID_REG_NUM  1
#define S_SLAVEID_REG_END S_SLAVEID_REG_START+S_SLAVEID_REG_NUM

#define S_XANGLE_REG_START S_SLAVEID_REG_END
#define S_XANGLE_REG_NUM 1
#define S_XANGLE_REG_END S_XANGLE_REG_START+S_XANGLE_REG_NUM

#define S_YANGLE_REG_START S_XANGLE_REG_END
#define S_YANGLE_REG_NUM 1
#define S_YANGLE_REG_END S_YANGLE_REG_START+S_YANGLE_REG_NUM

#define S_ZANGLE_REG_START S_YANGLE_REG_END
#define S_ZANGLE_REG_NUM 1
#define S_ZANGLE_REG_END S_ZANGLE_REG_START+S_ZANGLE_REG_NUM


//当你发送指令过来时,最终的解析在这里。这是一个关键的函数,要想理解这个函数,你要多参考前面的接口。
//usAddress 要查询的寄存器地址 usNRegs 寄存器数量  eMode 模式  pucRegBuffer 缓冲区
//这个函数就是根据usAddress ,从你的保持寄存器usSRegHoldBuf中读出想要的数据返回给主机。
eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
        USHORT usNRegs, eMBRegisterMode eMode)
{
    eMBErrorCode    eStatus = MB_ENOERR;
    USHORT          iRegIndex;
    USHORT 			*pusRegHoldingBuf;
    USHORT          reg_holding_start;
    USHORT          reg_holding_nregs;
    USHORT          usRegHoldStart;

    pusRegHoldingBuf = usSRegHoldBuf;
    reg_holding_start = S_REG_HOLDING_START;
    reg_holding_nregs = S_REG_HOLDING_NREGS;
    usRegHoldStart = usSRegHoldStart;

    /* it already plus one in modbus function method. */
    usAddress--;

    if ((usAddress >= reg_holding_start)
            && (usAddress + usNRegs <= reg_holding_start + reg_holding_nregs))
    {
        iRegIndex = usAddress - usRegHoldStart;
        switch (eMode)
        {
        /* read current register values from the protocol stack. */
        case MB_REG_READ:
            while (usNRegs > 0)
            {
                *pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] >> 8);
                *pucRegBuffer++ = (UCHAR) (pusRegHoldingBuf[iRegIndex] & 0xFF);
                iRegIndex++;
                usNRegs--;
            }
            break;

        /* write current register values with new values from the protocol stack. */
        case MB_REG_WRITE:
            while (usNRegs > 0)
            {
                pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
                pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
                iRegIndex++;
                usNRegs--;
            }
            break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

4.测试

在这里插入图片描述
在这里插入图片描述

注意烧写的时候要擦除整片芯片

在这里插入图片描述


总结

多多指教

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1795006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

迈入智能新纪元:智慧机房运维系统引领行业变革

在数字化飞速发展的今天&#xff0c;机房作为信息时代的“心脏”&#xff0c;其稳定运行对于企业的业务连续性至关重要。然而&#xff0c;传统的机房运维模式面临着诸多挑战&#xff0c;如响应速度慢、故障定位难、资源浪费大等问题。智慧机房运维系统&#xff0c;它将以智能化…

裁判文书:司法公正的“名片”

在法治社会的建设中&#xff0c;裁判文书不仅是法院裁判活动的产物&#xff0c;更是司法公正的重要体现。今天&#xff0c;我们就来聊聊裁判文书上的那些知识&#xff0c;带大家走进这个充满法律智慧的领域。 一、什么是裁判文书&#xff1f; 裁判文书&#xff0c;是人民法院…

【乐吾乐2D可视化组态编辑器】在线使用,快速入门

一、在线使用 乐吾乐2D可视化组态编辑器地址&#xff1a;https://2d.le5le.com/ 二、步骤 本教程将带领你快速体验2D可视化编辑器的全流程开发。 1.创建图纸 进入2d编辑器主界面后&#xff0c;主界面最中心为图纸面板&#xff0c;默认为空图纸&#xff0c;在界面左侧为组…

Paperless-Ngx文档管理系统结合内网穿透实现随时远程搜索查阅文本

文章目录 前言1. 部署Paperless-ngx2. 本地访问Paperless-ngx3. Linux安装Cpolar4. 配置公网地址5. 远程访问6. 固定Cpolar公网地址7. 固定地址访问 前言 Paperless-ngx是一个开源的文档管理系统&#xff0c;可以将物理文档转换成可搜索的在线档案&#xff0c;从而减少纸张的使…

工业级物联网边缘网关解决方案-天拓四方

随着工业4.0时代的到来&#xff0c;越来越多的企业开始寻求智能化升级&#xff0c;以提高生产效率、降低运营成本并增强市场竞争力。然而&#xff0c;在实际的转型升级过程中&#xff0c;许多企业面临着数据孤岛、设备兼容性差、网络安全风险高等问题&#xff0c;这些问题严重制…

Google Guice超轻量级依赖注入容器

Google Guice是Goolge开源的一款超轻量级依赖注入容器&#xff0c;超轻量的特点主要体现在&#xff1a;可与其它依赖注入容器混合使用&#xff0c;例如和Spring/Spring Boot的IOC容器混合使用&#xff1b;不需要任何配置信息&#xff0c;只需要引入几个有限的依赖包即可以使用&…

容器化实践:DevOps环境下的容器交付流程

DevOps的兴起是为了应对市场和消费者对技术应用的不断增长的需求。它的目标是构建一个更快的开发环境&#xff0c;同时保持软件的高质量标准。DevOps还致力于在敏捷开发周期中提升软件的整体品质。这一目标的实现依赖于多种技术、平台和工具的综合运用。 结合容器化技术与DevO…

echarts学习: 在图表中添加多条y轴会怎么样?

前言 在撰写如何绘制双y轴图表文章时&#xff0c;我突然萌生出了一个想法&#xff0c;如果给图表添加两个以上的y轴会怎么样呢? 带着这个问题我开始了自己的探索之旅。 我找到了一篇优秀的文章作为参考&#xff0c;虽然它需要付费&#xff0c;但是不要紧&#xff0c;文中免费…

达摩院重大“遗产”!fluxonium量子比特初始化300纳秒且保真度超过99%

通用量子计算机开发的主要挑战之一是制备量子比特。十多年来&#xff0c;研究人员在构建量子计算机的过程中主要使用了transmon量子比特&#xff0c;这也是迄今为止商业上最成功的超导量子比特。 但与业界多数选择transmon量子比特不同&#xff0c;&#xff08;前&#xff09;…

关于浔川python社在全网博主原力月度排名泸州地区排名第三名的调查——浔川总社部

6月6日&#xff0c;浔川python社在全网博主原力月度排名泸州地区排名第三名。 引起了广大python爱好者等的不满&#xff0c;为什么浔川python社这么一个大的python社排名第三&#xff1f; 2024-06-04 21:59:52 浔川python社在全网博主原力月度排名泸州地区排名第一名。 2024-…

基于Vue3的Uniapp实训项目|一家鲜花店

基于Vue的Uniapp实训指导项目 项目预览&#xff1a; 在这里插入图片描述 pages.json {"pages": [ //pages数组中第一项表示应用启动页&#xff0c;参考&#xff1a;https://uniapp.dcloud.io/collocation/pages{"path": "pages/index/index",&…

static的用法

static一般用于修饰局部变量&#xff0c;全局变量&#xff0c;函数 1 static修饰局部变量 是因为改为static int a1;后&#xff0c;出了作用域&#xff0c;不会销毁a的值&#xff0c;想要理解其本质&#xff0c;首先先看一下这个图&#xff1a; static修饰局部变量时&#xf…

每天一道大厂SQL题【Day32】按消息量给广东省qq打标记

文章目录 每天一道大厂SQL题【Day32】按消息量给广东省qq打标记每日语录第32题 需求三&#xff1a;按消息量给广东省qq打标记思路分析附表 答案获取加技术群讨论文末SQL小技巧 后记 每天一道大厂SQL题【Day32】按消息量给广东省qq打标记 大家好&#xff0c;我是Maynor。相信大…

RabbitMQ系列-rabbitmq无法重新加入集群,启动失败的问题

当前存在3个节点&#xff1a;rabbitmq5672、rabbitmq5673、rabbitmq5674 当rabbitmq5673节点掉线之后&#xff0c;重启失败 重启的时候5672节点报错如下&#xff1a; 解决方案 在集群中取消失败节点 rabbitmqctl forget_cluster_node rabbitrabbitmq5673删除失败节点5673的…

工欲善其事必先利其器——IntelliJ IDEA神器使用技巧

1.IntelliJ IDEA神器使用技巧【时长2小时20分】 程序员每日都会花费数小时使用ide编写和调试代码&#xff0c;其中很多操作都是机械重复且频率非常高&#xff0c;本着"工欲善其事必先利其器"的精神&#xff0c;闷头写代码之外花点时间研究一下自己用的ide&#xff0…

zookeeper启动(一)

1.zookeeper启动入口 在zkServer.sh的启动命令中,我们可以找到zookeeper启动的关键类org.apache.zookeeper.server.quorum.QuorumPeerMain QuorumPeerMain#main 我们可以直接看org.apache.zookeeper.server.quorum.QuorumPeerMain中的main方法,从下面的main方法中,我们可以…

JavaSE基础语法合集

随着不断学习&#xff0c;我们已经走完了JavaSE基础语法的所有内容&#xff0c;博主的单独语法篇共十二篇&#xff0c;感兴趣的也可以去看看&#xff0c;内容基本一致&#xff0c;目录是重新排布的&#xff0c;数组和方法都在初识Java章节。 适合&#xff1a;老手复习和新手从零…

Ubuntu系统升级k8s节点的node节点遇到的问题

从1.23版本升级到1.28版本 node节点的是Ubuntu系统20.04的版本 Q1 node节点版本1.23升级1.28失败 解决办法&#xff1a; # 改为阿里云镜像 vim /etc/apt/sources.list.d/kubernetes.list# 新增 deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main# 执…

pdf处理命令合集

安装weasyprint用于生成pdf 单个文件合成多个pdf linux - Merge / convert multiple PDF files into one PDF - Stack Overflow

深入解析Java中volatile关键字

前言 我们都听说过volatile关键字&#xff0c;也许大家都知道它在Java多线程编程编程中可以减少很多的线程安全问题&#xff0c;但是会用或者用好volatile关键字的开发者可能少之又少&#xff0c;包括我自己。通常在遇到同步问题时&#xff0c;首先想到的一定是加锁&#xff0…