STC32G12K128单片机的 moubus-rtu 从机测试工程

news2024/11/19 18:33:16

简介

STC32G12K128 是STC 推出的一款32位的 C251 的单片机。最近拿到一块官方申请的 屠龙刀-STC32G开发板,就用它的提供的库函数,查考安富莱提供的 modbus 例程移植了一个 modbus-rtu 从站的工程。

modbus-rtu slave 移植注意点

  1. modbus-rtu 功能配置
  • 配置 modbus-rtu 使能主机还是从机,亦或是全部使能
  • 配置主机或者从机使用的串口、波特率、从机地址、打印调试信息
    在这里插入图片描述
  1. 初始化 modbus-rtu 从站使用到的串口和定时器
  • modbus-rtu 没有开始和结束符,通过3.5个字符的时间间隔来断帧,所以此处初始化一个定时器4来计算3.5个字符的时间用于断帧。注意:此处使用定时器不要和对应串口波特率产生的定时器冲突
  • 初始化对应的串口4
void MODS_PeripheralInit(void)
{
    TIM_InitTypeDef		TIM_InitStructure = {0};
    GPIO_InitTypeDef	GPIO_InitStructure;		//结构定义
    COMx_InitDefine		COMx_InitStructure;					//结构定义

    /* 硬件定时器初始化 */
    /*
    	3.5个字符的时间间隔,只是用在RTU模式下面,因为RTU模式没有开始符和结束符,
    	两个数据包之间只能靠时间间隔来区分,Modbus定义在不同的波特率下,间隔时间是不一样的,
    	所以就是3.5个字符的时间,波特率高,这个时间间隔就小,波特率低,这个时间间隔相应就大

    	4800  = 7.297ms
    	9600  = 3.646ms
    	19200  = 1.771ms
    	38400  = 0.885ms
    */
    uint32_t timeout = 0;

    //timeout = 35000000 / MODBUS_SLAVE_BAUD;	/* 计算超时时间,单位us 35000000*/
    /* 此处直接将定时器的初始值赋值,具体计算的公式参考注释,此处默认使用9600的波特率/主频22.1184MHZ,且定时器使用12T模式 */
    uiTimerAutoLoadVal = 63558;//(65536UL - ((12000000*3646) / MAIN_Fosc));//3646=35000000 / 9600

    /* 使用硬件定时器4  如果有冲突,请改修此处定时器 */
    //	//定时器4做16位自动重装, 中断频率为50HZ,中断函数从P6.3取反输出25HZ方波信号.
    TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_12T;	//指定时钟源,     TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
    TIM_InitStructure.TIM_ClkOut    = DISABLE;					//是否输出高速脉冲, ENABLE或DISABLE
    TIM_InitStructure.TIM_Value     = uiTimerAutoLoadVal;		//初值 因为上面12分频了  所以是 12*1000000
    TIM_InitStructure.TIM_Run       = DISABLE;					//是否初始化后启动定时器, ENABLE或DISABLE
    Timer_Inilize(Timer4, &TIM_InitStructure);					//初始化Timer4	  Timer0,Timer1,Timer2,Timer3,Timer4
    NVIC_Timer4_Init(ENABLE, NULL);		//中断使能, ENABLE/DISABLE; 无优先级


    /* 初始化 MODBUS 从机使用的串口 P02-RXD P03-TXD */
    GPIO_InitStructure.Pin  = GPIO_Pin_2 | GPIO_Pin_3;		//指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
    GPIO_InitStructure.Mode = GPIO_PullUp;	                //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
    GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);	            //初始化

    COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;		//模式,   UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
    COMx_InitStructure.UART_BRT_Use   = BRT_Timer2;			//使用波特率,   BRT_Timer2, BRT_Timer4 (注意: 串口2固定使用BRT_Timer2)
    COMx_InitStructure.UART_BaudRate  = 9600ul;			    //波特率,     110 ~ 115200
    COMx_InitStructure.UART_RxEnable  = ENABLE;				//接收允许,   ENABLE或DISABLE
    UART_Configuration(UART4, &COMx_InitStructure);		    //初始化串口4 UART1,UART2,UART3,UART4
    NVIC_UART4_Init(ENABLE, Priority_1);		            //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3

    UART4_SW(UART4_SW_P02_P03);		                        //UART4_SW_P02_P03,UART4_SW_P52_P53

}
  1. 在定时器的中断函数中添加 modbus-rtu 从机 3.5 个字符超时处理函数
//========================================================================
// 函数: Timer4_ISR_Handler
// 描述: Timer4中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-23
//========================================================================
void Timer4_ISR_Handler (void) interrupt TMR4_VECTOR		//进中断时已经清除标志
{
#if ( MODBUS_CFG_SLAVE_EN == 1 )
    MODS_RxTimeOut();    /* Modbus从站超时处理 */
#endif
#if ( MODBUS_CFG_HOST_EN == 1 )
    MODH_RxTimeOut();    /* Modbus主站超时处理 */
#endif
	// TODO: 在此处添加用户代码
	//P63 = ~P63;
}
  1. 在串口的接口中断函数中添加 modbus-rtu 从机接收字节的处理函数
//========================================================================
// 函数: UART4_ISR_Handler
// 描述: UART4中断函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-23
//========================================================================
#ifdef UART4
void UART4_ISR_Handler(void) interrupt UART4_VECTOR
{
    if(S4RI)
    {
        CLR_RI4();
#if ( MODBUS_CFG_SLAVE_EN == 1 )
        MODS_ReciveNew(S4BUF);
#elif ( MODBUS_CFG_HOST_EN == 1 )
        MODH_ReciveNew(S4BUF);
#else
        if(COM4.RX_Cnt >= COM_RX4_Lenth)	COM4.RX_Cnt = 0;
        RX4_Buffer[COM4.RX_Cnt++] = S4BUF;
        COM4.RX_TimeOut = TimeOutSet4;
#endif
    }

    if(S4TI)
    {
        CLR_TI4();

#if(UART_QUEUE_MODE == 1)   //判断是否使用队列模式
        if(COM4.TX_send != COM4.TX_write)
        {
            S4BUF = TX4_Buffer[COM4.TX_send];
            if(++COM4.TX_send >= COM_TX4_Lenth)		COM4.TX_send = 0;
        }
        else	COM4.B_TX_busy = 0;
#else
        COM4.B_TX_busy = 0;     //使用阻塞方式发送直接清除繁忙标志
#endif
    }
}
  1. 在 main() 函数的大循环之前调用 MODS_PeripheralInit() 以初始化使用到的相关硬件;然后在死循环里一直调用 MODS_Poll() 解析 modbus-rtu 从机协议。
  2. 可以通过 modbus_slave.h 文件中的宏定义对 modbus-rtu 的功能进行裁剪,可以禁用不需要使用的功能,以解决空间。
//-----------------------------------------------------------------------------------------//
#define MODBUS_SLAVE_RTU_01H_FUNCTION DISABLE
#define MODBUS_SLAVE_RTU_02H_FUNCTION DISABLE
#define MODBUS_SLAVE_RTU_03H_FUNCTION ENABLE
#define MODBUS_SLAVE_RTU_04H_FUNCTION DISABLE
#define MODBUS_SLAVE_RTU_05H_FUNCTION DISABLE
#define MODBUS_SLAVE_RTU_06H_FUNCTION ENABLE
#define MODBUS_SLAVE_RTU_10H_FUNCTION ENABLE
/* 使能测试功能,实际使用可禁用 */
#define MODBUS_RTU_TEST ENABLE//DISABLE  ENABLE

工程源码

工程源码可以在此处下载(无需积分);如果觉得文章对你有帮忙,请关注点赞!

测试

  1. 先将工程源码编译生成后的hex烧录到开发板中
  2. 再使用 USB转TTL 连接 STC32G12K28 开发板的串口4(P02-RXD P03-TXD)
  3. 电脑端使用 modbus 主机的模拟软件(此处使用 modbuspoll )
  • 设置串口和波特率
    在这里插入图片描述

  • 根据工程源码里设置的保存寄存器的参数,设置 modbuspoll 软件里读取的地址

//-----------------------------------------------------------------------------------------//
#if (MODBUS_RTU_TEST == ENABLE)   //测试使用代码
/* 01H 读强制单线圈 */
/* 05H 写强制单线圈 */
#define REG_D01		0x0101
#define REG_D02		0x0102
#define REG_D03		0x0103
#define REG_D04		0x0104
#define REG_DXX 	REG_D04

/* 02H 读取输入状态 */
#define REG_T01		0x0201
#define REG_T02		0x0202
#define REG_T03		0x0203
#define REG_TXX		REG_T03

/* 03H 读保持寄存器 */
/* 06H 写保持寄存器 */
/* 10H 写多个保存寄存器 */
#define SLAVE_REG_P01		0x0301
#define SLAVE_REG_P02		0x0302

/* 04H 读取输入寄存器(模拟信号) */
#define REG_A01		0x0401
#define REG_AXX		REG_A01
typedef struct
{
	/* 03H 06H 读写保持寄存器 */
	uint16_t P01;
	uint16_t P02;

	/* 04H 读取模拟量寄存器 */
	uint16_t A01;

	/* 01H 05H 读写单个强制线圈 */
	uint16_t D01;
	uint16_t D02;
	uint16_t D03;
	uint16_t D04;

}SLAVE_VAR_T;
#endif

在这里插入图片描述

  • 单击对应保持寄存器的值,可以设置该寄存器的值
    在这里插入图片描述

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

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

相关文章

每日学术速递5.3

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV 1.Learning Locally Editable Virtual Humans 标题:学习本地可编辑虚拟人 作者:Hsuan-I Ho, Lixin Xue, Jie Song, Otmar Hilliges 文章链接:htt…

【分享】7-Zip解压缩软件的超详细使用攻略

常用的解压缩软件,除了WinRAR之外,7-Zip也是不错的选择。 7-Zip不仅是一款完全免费的开源解压软件,它的解压缩功能也很强大,可以支持视频、文档、文件夹、图片等文件进行压缩操作。 今天小编就来分享一下,7-Zip解压缩…

python一键登录srun校园网(以深圳技术大学为例)

全世界最(不)好的目录 一、需求分析二、实现过程2.1 分析api2.1.1 连接到校园网,自动弹出登录认证界面2.1.2 先输入错误的账号密码,按F12看会获取哪些信息2.1.3 api 2.2 分析加密2.3 流程总结 三.模拟登录3.1 编写配置文件3.2.功能…

【微软Bing王炸更新】无需等待,人人可用,答案图文并茂,太牛了

🚀 AI破局先行者 🚀 🌲 AI工具、AI绘图、AI专栏 🍀 🌲 如果你想学到最前沿、最火爆的技术,赶快加入吧✨ 🌲 作者简介:硕风和炜,CSDN-Java领域优质创作者🏆&am…

opencv实践项目-图像拼接

目录 1.简介2. 步骤2.1 特征检测与提取2.2 关键点检测2.3 关键点和描述符2.4 特征匹配2.5 比率测试2.6 估计单应性 3. 完整代码 1.简介 图像拼接是计算机视觉中最成功的应用之一。如今,很难找到不包含此功能的手机或图像处理API。在本 文中,我们将讨论如…

虹科分享 | 专为创意专业人士设计的Thunderbolt适配器

一、方案介绍 虹科HK-ATTO ThunderLink雷电™ 适配器可以适用于任何地方。 1.小。 2.便携式。 3.强大。 我们的10GBE Thunderbolt适配器的性能至少比内置或附加NIC(包括Mac)高20% , ATTO 360只需点击一个按钮即可优化以太网SAN,并可与Thunder…

xxl-job 使用示例

目录 介绍 下载源码地址 文档网站 源码导入就是这样目录 数据库建表sql 就这么几个表出来了 修改xxl-job-admin项目下的application.properties文件 完事启动就行了 页面 页面访问地址 账号密码 增加自己的定时任务 介绍 这篇写的是接入使用xxl-job 的一个简单流程…

win系统使用macOS系统

最近 win 系统和 ubuntu 系统用的久了,想用一下 MacOS 系统,于是去网上查了相关资料,发现用一款叫 NEXUS 的软件可以实现在 windows 系统体验效果,现把教程记录下来,供大家使用。 目录 一、下载NEXUS 二、 安装NEXU…

IMX6ULL裸机篇之串口实验说明一

一. 串口 本章我们就来学习如何驱动 I.MX6U 上的串口,并使用串口和电脑进行通信。 串行接口指的是数据一个一个的顺序传输,通信线路简单。 UART 作为串口的一种,其工作原理也是将数据一位一位的进行传输,发送和接收各用一 条…

win11本地安全机构保护已关闭怎么办?如何修复windows11本地安全机构保护已关闭?

win11本地安全机构保护已关闭怎么办? 如何修复windows11本地安全机构保护已关闭? 近日有windows11系统用户反映说遇到了这样一个问题:启动电脑后,发现windows右下角的安全中心图标上会显示一个黄色叹号,打开windows安…

操作系统笔记--进程与线程

1--进程 1-1--进程的定义 进程表示一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程; 1-2--进程的组成 一个进程由以下部分组成:① 程序的代码; ② 程序处理的数据;③ 程序计数器中的值,其指示下一条将…

PHP流行框架的报错页面,你见过那些?

在PHP开发过程中,使用框架能够帮助我们更快速、高效地完成项目开发。但是,即使使用了框架,我们还是难免会遇到各种报错。而当我们在开发阶段或调试过程中遇到报错时,框架提供的错误页面可以给我们带来很大的帮助。PHP常用的流行框…

网易一面:如何设计线程池?请手写一个简单线程池?

说在前面 在40岁老架构师 尼恩的读者社区(50)中,最近有小伙伴拿到了一线互联网企业如极兔、有赞、希音、百度、网易的面试资格,遇到了几个很重要的面试题: 如何设计线程池? 与之类似的、其他小伙伴遇到过的问题还有: …

Reinhart FoodService的EDI需求详解

Reinhart FoodService是一家成立于1972年的美国食品服务公司,隶属于上市公司Performance Food Group。Reinhart FoodService为餐馆、酒店、医院、学校等各类机构提供广泛的食品选择和相关服务,产品包括新鲜的肉类、禽类、海鲜、奶制品、烘焙用品、蔬菜和…

迪赛智慧数——柱状图(象形动态图):不同性别消费者点外卖频率

效果图 我国超4亿人叫外卖,你多久点一次外卖? 据数据显示,30.7%男性消费者每周点3-4次外卖,34.3%的女性每周点3-4次,明显女性比男性点外卖频率多。而每周点1-2次外卖中均超过80%。 数据源:静态数据 { "column&…

MIT开源协议,多端适用的租房小程序,带完整的管理员后台

一、开源项目简介 多端适用的租房小程序,带管理员后台。是一个完整的项目,可以直接使用。 二、开源协议 使用MIT开源协议 三、界面展示 部分截图 1. 前台截图 2. 后台截图 四、功能概述 1、使用Uniapp开发的前台,基于 Vue.js 开发所有…

2 种方式在流水线中集成 DAST,动态保护应用程序安全

💡 如何在流水线中集成与应用 DAST ? 近日,在「DevSecOps软件安全开发实践」课程上,极狐(GitLab) 前端工程师钱堃、极狐(GitLab) 高级后端工程师张林杰,展开了关于 DAST 的概念、必要性、优缺点的内容分享,…

如何完美实现数据可视化?

为什么要可视化数据? 在工作中,无论你在哪个场景,你都会接触到数据,需要表达出来。数据可视化的作用是通过结合图表和数据来更好地传达业务信息。目前,大多数公司正在逐步从传统的流程管理过渡到基于数据的管理。数据可视化可以…

明明花钱上了ERP,为什么还要我装个MES系统

目前, ERP系统依旧是很多制造企业的选择。据统计,ERP系统的应用已经达到70%以上,但是在车间的应用, MES系统的应用比例并不高。那么,为什么现在很多企业又都选择再上个MES呢? MES系统是一个面向…

高性能HMI 走向扁平化

个人计算机作为图形用户界面(GUI)在自动化中已经使用了30多年。在那段时间里,从技术、术语、功能到用于创建接口的标准和指南,发生了许多变化。 PC 技术的飞速发展,特别是图形显示,用户界面的技术发展导致了…