当前位置: 首页 > news >正文

[AI8051U入门第五步]modbus_RTU主机


前言

学习目标
1、学习Modbus rtu 主机程序编写
2、学习Modbus slave软件使用
完整程序可在博主下载资源进行下载

Modbus rtu介绍可以看添加链接描述[AI8051U入门第四步]modbus_RTU从机了解

一、Modbus slave软件使用

STEP1:打开Modbus slave软件
在这里插入图片描述
STEP2:点击connect
在这里插入图片描述
STEP3:按照下面进行配置,串口号根据自己的配置
在这里插入图片描述
STEP4:按照下面进行配置
在这里插入图片描述
STEP5:按照下面进行配置
在这里插入图片描述

二、部分程序展示

以下是Modbus 发送函数,

/********************************** 
*函数名:发送数据给从机 0x03
*形参:形参:unsigned char Device,  //从机地址
*unsigned char Function  //功能码
*unsigned short Frist_addr, //读取的寄存器起始地址
*unsigned short number,   //读取的寄存器个数
*时间:2025/7/18
*作者:单片有机机
**********************************/
void Modbus_Rtu_Pull_Write(unsigned char Device,unsigned char Function,unsigned short Frist_addr,unsigned short number){unsigned char buff[8];unsigned short crc16=0;buff[0]=Device; //从机地址buff[1]=Function;    //功能码buff[2]=Frist_addr>>8;    //寄存器地址高位    buff[3]=Frist_addr;    //寄存器地址低位buff[4]=number>>8;    //读取寄存器个数高位    buff[5]=number;    //读取寄存器个数低位  crc16=GetCRC16(buff,6);buff[6]=crc16>>8;    //读取寄存器个数高位    buff[7]=crc16;    //读取寄存器个数低位      //发送指令Uart1_Putc_Num(buff,sizeof(buff));
}

解析数据帧,按下P33控制P2LED电亮

/********************************** 
*函数名:解析从机发送来的数据 
*形参:形参:无
*时间:2025/7/18
*作者:单片有机机
**********************************/
unsigned char Modbus_Rtu_Pull_Parsing(void){int j=0;unsigned short crc=0;unsigned short crc2=0;unsigned short sum=0;   unsigned short addr=0; unsigned short dat=0;unsigned short return_dat=0;if(UAR1.timeOut==1){UAR1.timeOut=0;if(UAR1.rx1_len >=5){crc =GetCRC16((unsigned char*)UAR1.buff1,UAR1.rx1_len-2);//计算接收数据的CRC16校验crc2=((UAR1.buff1[UAR1.rx1_len-2]<<8)+UAR1.buff1[UAR1.rx1_len-1]);//读取串口接收的数据的CRC校验位                    if(crc == crc2){ //判断CRC16校验位是否正确if(UAR1.buff1[0]==Modbus_Slave_Device) //判断modebus从机地址{   if(UAR1.buff1[1] ==Modbus_PULL_Keep_Read){//判断是0x03         sum = UAR1.buff1[2]/2; //读取从机上传数量                             for(j=0;j<sum;j++){ //将数据提取出来info.datas[j]= (UAR1.buff1[3+2 * j] << 8) | UAR1.buff1[3+2 * j + 1];                               }return_dat =1;}else if(UAR1.buff1[1] ==Modbus_PULL_Write){addr = UAR1.buff1[2]<<8|UAR1.buff1[3];if(addr == Modbus_PULL_Write_addr){ //读取地址dat = UAR1.buff1[4]<<8|UAR1.buff1[5];                                    if(dat == 0x0000){P27=1;                                          P21=0;}                                      if(dat == 0x0001){P21=1;                                          P22=0;}if(dat == 0x0002){P22=1;                                          P23=0;}if(dat == 0x0003){P23=1;                                          P24=0;}if(dat == 0x0004){P24=1;                                          P25=0;} if(dat == 0x0005){P25=1;                                          P26=0;} if(dat == 0x0006){P26=1;                                          P27=0;}  return_dat =2;                                     }}                                }}UAR1.rx1_len =0;                       }}                   return return_dat;      
}

运行函数

void Modbus_Rtu_Pull_loop(void){//循环发送数据给从机if(Modbus_cnt>=Modbus_Read_Time){Modbus_Rtu_Pull_Write(Modbus_Slave_Device,Modbus_PULL_Keep_Read,0x0000,0x0001); //读从机地址为0x01,起始地址0x0000,读取数量1个 Modbus_cnt =0;//从新计数       }if((Modbus_cnt >= 50 && Modbus_cnt <= Modbus_Read_Time-50) &&wait_Send_flag ==1){ //避免粘包wait_Send_flag =0;Modbus_Rtu_Pull_Write(Modbus_Slave_Device,Modbus_PULL_Write,Modbus_PULL_Write_addr,tast);}        if(KEY ==0){delay_ms(5);if(KEY ==0){                       wait_Send_flag =1;tast++;            if(tast >6){tast=0;}}    while(KEY ==0);  }//解析从机发送来的数据Modbus_Rtu_Pull_Parsing();if(rc->CtrlBits.LED_P20 ==1){P20=0; }else if(rc->CtrlBits.LED_P20 ==0){P20=1;}}

三、完整程序展示

Modbus_RTU_P.c

#include "Modbus_RTU_P.h"
#include "crc16.h"
#include "uart.h"
#include "string.h"
#include "system.h"#define Modbus_Read_Time   200   //每100ms发送一次0x03寄存器数据
#define Modbus_Slave_Device 0x01 //从机地址
#define Modbus_PULL_Write 0x06 
#define Modbus_PULL_Keep_Read  0x03#define Modbus_PULL_Write_addr 0x0001#define KEY  P33struct tagINFO info;unsigned long  Modbus_cnt=0;unsigned short tast=0;
unsigned short wait_Send_flag=0;void Modbus_Rtu_Pull_loop(void){//循环发送数据给从机if(Modbus_cnt>=Modbus_Read_Time){Modbus_Rtu_Pull_Write(Modbus_Slave_Device,Modbus_PULL_Keep_Read,0x0000,0x0001); //读从机地址为0x01,起始地址0x0000,读取数量1个 Modbus_cnt =0;//从新计数       }if((Modbus_cnt >= 50 && Modbus_cnt <= Modbus_Read_Time-50) &&wait_Send_flag ==1){ //避免粘包wait_Send_flag =0;Modbus_Rtu_Pull_Write(Modbus_Slave_Device,Modbus_PULL_Write,Modbus_PULL_Write_addr,tast);}        if(KEY ==0){delay_ms(5);if(KEY ==0){                       wait_Send_flag =1;tast++;            if(tast >6){tast=0;}}    while(KEY ==0);  }//解析从机发送来的数据Modbus_Rtu_Pull_Parsing();if(rc->CtrlBits.LED_P20 ==1){P20=0; }else if(rc->CtrlBits.LED_P20 ==0){P20=1;}}/********************************** 
*函数名:发送数据给从机 0x03
*形参:形参:unsigned char Device,  //从机地址
*unsigned char Function  //功能码
*unsigned short Frist_addr, //读取的寄存器起始地址
*unsigned short number,   //读取的寄存器个数
*时间:2025/7/18
*作者:单片有机机
**********************************/
void Modbus_Rtu_Pull_Write(unsigned char Device,unsigned char Function,unsigned short Frist_addr,unsigned short number){unsigned char buff[8];unsigned short crc16=0;buff[0]=Device; //从机地址buff[1]=Function;    //功能码buff[2]=Frist_addr>>8;    //寄存器地址高位    buff[3]=Frist_addr;    //寄存器地址低位buff[4]=number>>8;    //读取寄存器个数高位    buff[5]=number;    //读取寄存器个数低位  crc16=GetCRC16(buff,6);buff[6]=crc16>>8;    //读取寄存器个数高位    buff[7]=crc16;    //读取寄存器个数低位      //发送指令Uart1_Putc_Num(buff,sizeof(buff));
}/********************************** 
*函数名:解析从机发送来的数据 
*形参:形参:无
*时间:2025/7/18
*作者:单片有机机
**********************************/
unsigned char Modbus_Rtu_Pull_Parsing(void){int j=0;unsigned short crc=0;unsigned short crc2=0;unsigned short sum=0;   unsigned short addr=0; unsigned short dat=0;unsigned short return_dat=0;if(UAR1.timeOut==1){UAR1.timeOut=0;if(UAR1.rx1_len >=5){crc =GetCRC16((unsigned char*)UAR1.buff1,UAR1.rx1_len-2);//计算接收数据的CRC16校验crc2=((UAR1.buff1[UAR1.rx1_len-2]<<8)+UAR1.buff1[UAR1.rx1_len-1]);//读取串口接收的数据的CRC校验位                    if(crc == crc2){ //判断CRC16校验位是否正确if(UAR1.buff1[0]==Modbus_Slave_Device) //判断modebus从机地址{   if(UAR1.buff1[1] ==Modbus_PULL_Keep_Read){//判断是0x03         sum = UAR1.buff1[2]/2; //读取从机上传数量                             for(j=0;j<sum;j++){ //将数据提取出来info.datas[j]= (UAR1.buff1[3+2 * j] << 8) | UAR1.buff1[3+2 * j + 1];                               }return_dat =1;}else if(UAR1.buff1[1] ==Modbus_PULL_Write){addr = UAR1.buff1[2]<<8|UAR1.buff1[3];if(addr == Modbus_PULL_Write_addr){ //读取地址dat = UAR1.buff1[4]<<8|UAR1.buff1[5];                                    if(dat == 0x0000){P27=1;                                          P21=0;}                                      if(dat == 0x0001){P21=1;                                          P22=0;}if(dat == 0x0002){P22=1;                                          P23=0;}if(dat == 0x0003){P23=1;                                          P24=0;}if(dat == 0x0004){P24=1;                                          P25=0;} if(dat == 0x0005){P25=1;                                          P26=0;} if(dat == 0x0006){P26=1;                                          P27=0;}  return_dat =2;                                     }}                                }}UAR1.rx1_len =0;                       }}                   return return_dat;      
}

Modbus_RTU_P.h

#ifndef __Modbus_Rtu_P
#define __Modbus_Rtu_P
#include <AI8051U.H>typedef struct tagINFO
{unsigned short 			datas[4];	
}*pINFO;
typedef struct 
{struct{unsigned  LED_P20			:1;		//0unsigned  LED_P21			:1;unsigned  LED_P22		:1;unsigned  LED_P23		:1;unsigned  LED_P24		:1;unsigned  LED_P25			:1;		//5unsigned  LED_P26		:1;unsigned  LED_P27	:1;unsigned  NULL8		:1;unsigned  NULL9		:1;unsigned  NULL10				:1;		//10unsigned  NULL11				:1;unsigned  NULL12			:1;unsigned  NULL13			:1;unsigned  NULL14	:1;unsigned  NULL15		:1;		//15}CtrlBits;unsigned short 					PTC100_N0_AD;
}RegCtrl;
extern struct tagINFO 				info;
#define rc                			((RegCtrl *) 		info.datas)extern unsigned long  Modbus_cnt;void Modbus_Rtu_Pull_loop(void);
void Modbus_Rtu_Pull_Write(unsigned char Device,unsigned char Function,unsigned short Frist_addr,unsigned short number);
unsigned char Modbus_Rtu_Pull_Parsing(void);
#endif

Timer定时器
timer.c

#include "timer.h"
#include "uart.h"
#include "Modbus_RTU_P.h"#define LED  P20
unsigned long timer3_cnt=0;/********************************** 
*功能:定时器3初始化
*形参:无
*时间:2025/7/14
*作者:单片有机机
**********************************/
void Timer3Init(void)		//@33.1776Mhz    定时1ms
{T4T3M &= 0xFD;		 T3L = 0x33;		 T3H = 0xF5;		 ET3 =1;    EA = 1;T4T3M |= 0x08;        //开始计时 
}/********************************** 
*功能:定时器3中断处理函数
*形参:无
*时间:2025/7/14
*作者:单片有机机
**********************************/
void t3int() interrupt 19           
{  timer3_cnt++;if(timer3_cnt>=1){if(UAR1.timeOut>1)UAR1.timeOut--;if(UAR1.timeOut>1)UAR1.timeOut--;if(UAR1.timeOut>1)UAR1.timeOut--;timer3_cnt=0;}Modbus_cnt ++;     
}

timer.h

#ifndef __timer_H
#define __timer_H
#include <AI8051U.H>
void Timer3Init(void);#endif

main.c

/********************************** (C) COPYRIGHT ******************************** File Name          : Main.c* Author             : 单片有机机* Version            : V1.0* Date               : 2025/07/15* Description        : modbus Rtu从机程序* Hardware           : RX     P30TX     P31 * Frequency          : 33.1776Mhz
*******************************************************************************/
#include <AI8051U.H>
#include "system.h"
#include "uart.h"
#include "timer.h"
#include "crc16.h"
#include "Modbus_RTU_P.h"
#include "modbus_rtu_s.h"#define Modbus_Slave_Mode 0
#define Modbus_PULL_Mode 1void main(void){GPIO_Init();Timer3Init();     Uart1_Init(115200);   printf("hello,AI8051U、单片有机机\r\n");while(1){#if Modbus_PULL_ModeModbus_Rtu_Pull_loop();             #endif#if Modbus_Slave_ModeModbus_Rtu_Slave_loop();#endif}
}

总结

这就是Modbus RTU PULL程序

http://www.xdnf.cn/news/1143991.html

相关文章:

  • stack and queue 之牛刀小试
  • Excel批量生成SQL语句 Excel批量生成SQL脚本 Excel拼接sql
  • 大型市政污水处理厂“智变”记:天拓四方IOT平台让磁悬浮鼓风机“活”起来
  • React 实现人员列表多选、全选与取消全选功能
  • MC0457符咒封印
  • Ansible + Shell 服务器巡检脚本
  • mysql not in 查询引发的bug问题记录
  • pycharm结构查看器
  • 2.3 前端-ts的接口以及自定义类型
  • 哪个厂家生产的戒烟药好:从机制到体验的差异化博弈
  • MySQL 插入时间 更新时间
  • 推荐 1 款 4.5k stars 的AI 大模型驱动的开源知识库搭建系统
  • 跨域问题及解决方案
  • AI(day10)模块化编程概念(模块、包、导入)及常见系统模块总结和第三方模块管理
  • Java Web项目Dump文件分析指南
  • LLM(Large Language Model)大规模语言模型浅析
  • 在 Jenkins 中使用 SSH 部署密钥
  • 游戏盾能否保护业务免受DDoS攻击吗?
  • C语言基础:数组练习题
  • 服务器内存满了怎么清理缓存?
  • 【C++】——类和对象(中)——默认成员函数
  • 前端基础——B/S工作原理、服务器与前端三大件
  • 【Docker】在Linux环境下使用Dockerfile打包镜像(图文示例)
  • 完整的 Meteor NPM 集成
  • 6 种无线传输照片从安卓到 Mac 的方法
  • UDP 协议下一发一收通信程序的实现与解析
  • 防爆手机是什么?能用普通手机改装吗?
  • 免费PDF文件格式转换工具
  • FastAdmin框架超级管理员密码重置与常规admin安全机制解析-卓伊凡|大东家
  • python学智能算法(二十三)|SVM-几何距离