串口通信-Modbus-rtu协议例程(51实现)

/*务必通过ISP通讯,烧录时,选11.0592Mhz进行烧录,否则数据会乱码modbus-rtu 处理过程主机数据接收(超时机制,不定长接收)->数据校验码判断->
*/
#include <STC15F2K60S2.H>
#include "string.h"
typedef unsigned char uint8_t;
typedef unsigned int  uint16_t;bit busy=0;//0 表示不忙
bit rxend=0;
#define LENMAX 25 /*最大接收数据长度,根据实际需要而定,不宜过长,*本代码用于modbus-rtu,一般数据长度为8字节*/
uint8_t rxbuf[LENMAX];//用于存储接收数据
uint8_t rxcnt=0;//用于保存当前接收数据长度。最大值=LENMAX,
uint16_t rxcrc; //CRC16校验码//uint8_t err[]={""};
/*蓝桥杯51开发板开机LED和蜂鸣器上电需要初始化,否则会出现蜂鸣器乱响*/
void IOinit(void)
{P0=0xff;P2=P2&0X1F|0X80;P2=P2&0X1F;P0=0x00;P2=P2&0X1F|0XA0;P2=P2&0X1F;
}
/*初始化串口1,可以由STC-ISP软件生成(推荐)*/
void UartInit(void)		//9600bps@11.0592MHz
{SCON = 0x50;		//8位数据,可变波特率AUXR |= 0x01;		//串口1选择定时器2为波特率发生器AUXR |= 0x04;		//定时器2时钟为Fosc,即1TT2L = 0xE0;		//设定定时初值T2H = 0xFE;		//设定定时初值AUXR |= 0x10;		//启动定时器2ES=1;//允许串口中断
}/*初始化定时器1,可以由STC-ISP软件生成(推荐)*/
void Timer1Init(void)		//1毫秒@11.0592MHz
{AUXR |= 0x40;		//定时器时钟1T模式TMOD &= 0x0F;		//设置定时器模式TL1 = 0xCD;		//设置定时初值TH1 = 0xD4;		//设置定时初值TF1 = 0;		//清除TF1标志TR1 = 1;		//定时器1开始计时ET1 = 1;//开定时器1中断允许
}/*串口1单字符发送函数*/
void sendchar(uint8_t ch)
{/**由于此单片机中的串口收发是由同一个寄存器完成的,一次仅发送一个字符。*因此需要一个忙标志来防止字符还未发送完成就进行下一次发送了。*/while(busy);//忙?等待上一次发送完成,何时busy置零?在触发串口发送中断后busy=1;//设置为忙状态,即将发送数据SBUF = ch;//发送数据
}
/*串口1字符串发送函数*/
void sendstring(char *str)
{while(*str)//字符串结束?等价于while(*str!='\0'){sendchar(*str++);//发送当前字符}		
}//RS485通信CRC校验,buf待校验数组,n待校验长度
//返回success表示数据正常,返回error表示数据错误
uint16_t crc16(uint8_t *buf) {uint16_t tmp = 0xffff, ret1 = 0;uint8_t i = 0, j;for (j = 0; j <6; j++) {/*此处的n -- 要校验的位数为n个*/tmp = buf[j] ^ tmp;for (i = 0; i < 8; i++) {/*此处的8 -- 指每一个char类型又8bit,每bit都要处理*/if (tmp & 0x01) {tmp = tmp >> 1;tmp = tmp ^ 0xa001;} else {tmp = tmp >> 1;}}}/*CRC校验后的值*//*将CRC校验的高低位对换位置*/ret1 = tmp >> 8;ret1 = ret1 | (tmp << 8);return ret1;
}
//modbus处理
void modbus_work(void) {uint8_t i = 0;uint16_t crc; //CON低电平,RE高电平,允许发送数据if (rxcnt == 8) { //只响应字节长度8的if (rxbuf[0] == 0x01) { //地址正确crc = ((rxbuf[6] & 0x00ff) << 8) + rxbuf[7];if (crc = crc16(rxbuf)) { //校验码正确if (rxbuf[1] == 0x03) { //03H功能码sendstring("rtu_ok");/**这里返回modbus-rtu的数据给主机,这里面校验码通过了,*还需要有其他的异常处理,如数据域的异常查询**/}else { //收到不支持的功能码sendstring("fun_err");}} else { //校验码错误sendstring("crc_err");}}}
}
/*主函数*/
void main()
{IOinit();UartInit();Timer1Init();EA=1;//开总中断sendstring("--modbus-rtu test!--\r\n");sendstring("--作者:小谦·!--\r\n");sendstring("--请选择HEX显示与发送!--\r\n");while(1){if(rxend)//接收结束{rxend=0;modbus_work();rxcnt=0;}		 }
}
/*串口1中断服务函数*/
void Uart() interrupt 4 using 1
{if (RI) //接收中断?{RI = 0;                 //清除RI位,以便下一次因接收进入中断rxbuf[rxcnt++]=SBUF;//保存数据}	if (TI)//发送中断?{TI = 0;                 //清除TI位,以便下一次因发送进入中断busy = 0;               //清忙标志}
}
/*定时器1中断服务函数,用于串口1的数据接收结束判断*/
/********************* Timer1中断函数************************/
void timer1_int (void) interrupt 3
{static uint8_t oldcnt,newcnt,count;if(++count==10){count=0;oldcnt=newcnt;newcnt=rxcnt;	if((oldcnt==newcnt)&&rxcnt!=0)//发送已结束,且收到了数据{rxend=1;}}
} 

实现展示

正确输入查询码后会返回rtu_ok的字符串提示,其余异常数据或返回错提示或不响应。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CentOS 8安装Oracle 19c rpm包

一、环境 centos 8 oracle 19c rpm安装 二、安装前准备 1、创建用户组 groupadd oinstall groupadd dba useradd -g oinstall -G dba oracle passwd oracle2、安装依赖包 如果yum找不到安装包&#xff0c;可以去下载 https://centos.pkgs.org/ 点击跳转 缺少的依赖包可…

【JavaSE】程序逻辑控制

目录 【1】概念 【2】顺序结构 【3】分支结构 【3.1】if 语句 【3.2】switch 语句 【4】循环结构 【4.1】while 循环 【4.2】for 循环 【4.3】do while 循环 【4.4】break 关键字 【4.5】continue 关键字 【5】输入输出 【5.1】输出到控制台 【5.2】从键盘输入 …

stm32或gd32移植libcanard实现UAVCAN协议

一、源码下载 1、git下载 点击我下载 2、csdn下载 自己上传的点击下载 二、源码移植 我自己是使用rt-thread操作系统移植的。但是不局限与操作系统&#xff0c;裸机也可以。 1、首先将源码加入到工程 2、分别实现一个内存的分配与释放函数&#xff0c;他是一个指针函数&…

js 左右滑动切换图片

一、效果图 二、代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdev…

vscode设置可以搜索包含node_modules中的文件

步骤3中删除掉node_modules&#xff0c;再搜索的时候&#xff0c;node_modules的匹配到代码也会展示出来了。 如果不想要被搜索文件包含node_modules,再添加上就可以。

MySQL 连接的使用

MySQL 连接的使用 在前几章节中&#xff0c;我们已经学会了如何在一张表中读取数据&#xff0c;这是相对简单的&#xff0c;但是在真正的应用中经常需要从多个数据表中读取数据。 ​ 本章节我们将向大家介绍如何使用 MySQL 的 JOIN 在两个或多个表中查询数据。 你可以在 SEL…

webstorm配置vue开发环境

&#x1f333;&#x1f333;&#x1f333;前言&#xff1a;本文章针对于如何用IDE和webstorm运行一个别人的vue项目进行步骤记录。 &#x1f4d9;参考&#xff1a;(10条消息) idea配置vue开发环境_idea配置vue运行环境_drinkworld的博客-CSDN博客https://blog.csdn.net/drinkwo…

容器生态系统概念讲解

容器生态系统 这张图显示了 Docker、Kubernetes、CRI、OCI、containerd 和 runc 在这个生态系统中是如何结合的。 其工作流程简单来说是这样的&#xff1a; Docker&#xff0c;Kubernetes 等工具来运行一个容器时会调用容器运行时&#xff08;CRI&#xff09;比如 containerd…

探索Java集合框架的奥秘

文章目录 1. 引言2. Java 集合框架概览2.1 Collection接口2.1.1 List接口(1) ArrayList&#xff08;数组&#xff09;(2) Vector&#xff08;数组实现、线程同步&#xff09;(3) LinkedList&#xff08;链表&#xff09; 2.1.2 Set 接口(1) HashSet&#xff08;Hash 表&#xf…

选择高考志愿:聚焦计算机科学与技术,规避土木工程

选择高考志愿&#xff1a;聚焦计算机科学与技术&#xff0c;规避土木工程 高考季已至&#xff0c;各地高考成绩陆续公布&#xff0c;许多毕业生和家长开始面临疑惑&#xff1a;如何填报志愿、选专业还是选学校、什么专业好就业&#xff1f;张雪峰曾提到&#xff1a;“普通家庭…

nvm 和 nrm安装使用

前端工具推荐&#xff1a;nvm&#xff08;Node 版本管理工具&#xff09; 和 nrm&#xff08;管理npm源&#xff09;&#xff1a; 一、nvm 1.1 nvm 是什么 1.2 安装 nvm 1.3 使用 nvm 二、nrm 2.1 nrm 是什么 2.2 安装 nrm 2.3 使用 nrm 一、nvm 如果直接将 node 安装到…

常见面试题之线程中并发锁(一)

1. 讲一下synchronized关键字的底层原理&#xff1f; 1.1. 基本使用 如下抢票的代码&#xff0c;如果不加锁&#xff0c;就会出现超卖或者一张票卖给多个人 Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】&#xff0c;其它线程再想获取这…