当前位置: 首页 > 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.lryc.cn/news/592228.html

相关文章:

  • 《Python Web 框架深度剖析:Django、Flask 与 FastAPI 的选择之道》
  • 数据库防止数组字符串序列化
  • Python暑期学习笔记5
  • C++编程学习(第10天)
  • 近期遇到的问题汇总
  • 微信小程序商品结算功能
  • 【嵌入式硬件实例】-555定时器实现LED追逐效果
  • 后端参数校验
  • LP-MSPM0G3507学习--05管脚中断
  • 网络基础12--可靠性概述及要求
  • postman接口测试,1个参数有好几个值的时候如何测试比较简单快速?
  • Leetcode 04 java
  • 今日行情明日机会——20250718
  • 【Spring WebFlux】什么是响应式编程
  • Linux入门篇学习——借助 U 盘或 TF 卡拷贝程序到开发板上
  • 证券行业 SCRM 落地:企业微信与系统协同的合规技术方案
  • 二进制写入与文本写入的本质区别:系统视角下的文件操作
  • 数据结构:顺序表和链表
  • 【PTA数据结构 | C语言版】我爱背单词
  • 【PTA数据结构 | C语言版】二叉堆的朴素建堆操作
  • HTML 页面禁止缩放功能
  • 深入解析文本分类技术全景:从特征提取到深度学习架构
  • 数据库的基础概操作
  • 计算机视觉与机器视觉
  • 基于物联网的智能农情监测预警系统
  • 深入解析PyQt5信号与槽的高级玩法:解锁GUI开发新姿势
  • Maven学习总结(62)—— Maven 打包瘦身和提速解决方案
  • 电网驱鸟黑科技:鸟类AI识别算法+无人机实现“智慧护线“
  • 在ajax中什么时候需要将返回值类型做转换
  • 【教程】基于无人机的大豆光合效率研究