目录

一、研究背景

二、硬件准备

三、软件准备

四、实验原理

五、单片机代码

六、Python读取串口处理数据

七、开发总结


一、研究背景

学院给了14天的时间,一枚专业课紧的大三狗匆忙做出来。探索出一种研究阳极氧化工艺电解液中金属离子浓度在线测量和监控的设备和方式

二、硬件准备

阳极氧化工艺电解液金属离子浓度在线监控仪,主要由高精度耐腐蚀溶液密度传感器探头、显示控制器、声光提醒装置、通讯端口、单片机以及控制PC组成。

三、软件准备

除了Keil5、Pycharm还有ISP-STC软件,考虑到会同时使用单片机和Pycharm读取串口,因此还需要额外准备虚拟串口软件MX虚拟串口。

四、实验原理

(1)RS485原理

RS-485是串口通讯标准,常用于工业、自动化、汽车和建筑物管理等领域。相比于RS232总线, RS485总线采用AB双线进行差分传输,弥补了通信距离短且速率低下的特点。

长距离布线传输时会有信号衰减,且噪声和干扰很大,传输线上的电压幅度变化体现这一点。但是采用AB线差分传输时,以A线作为信号传输线,以B线为传输参考线,利用运算元件进行差值相减可以排除干扰,输出正确的信号,这种方式叫做共模抑制,其原理如图

RS485总线有两线制和四线制两种接线方式,四线制只能支持一对一之间的通信,现实中生活生产中多采用两线制度。如图7所示,RS485总线支持单主机单从机模式以及单主机多从机这两种通信结构,本项目实践采用的是单主机单从机结构。

RS485通信设备需要使用单片机上MX485模块,如图8所示,为一个MCU控制RS485通信的示意图。如图9和图10,根据《A7双核开发板原理图》需要将RXD2与P3.0、TXD2与P3.1以及485_RE与P1.1相连。AB接口为总线,RXD2为接收器输入,TXD2为发送器输出。485_RE控制485模块的工作方式,当485_RE为1时,设置为接收器;当485_RE为0时,设置为发送器。

主机发送给从机或从机发送给主机时都会占用AB总线,所以RS485多采用半双工模式。主机通过485_RE引脚控制MX485为发送模式,从PC端串口向MX485的TXD2引脚发送一个字节,MX485将该字节数据转化为差分信息流通过AB线进行传输。当数据发送完毕时,主机立即设置MX485为接收模式。从机的信息传输与主机类似。

(2)Modbus通讯协议

泽耀科技数传电台,可以通过RS485总线进行通信,通信协议是Modbus协议。

Modbus通信协议分为“03”、“04”“06”和“10”功能码,“03”表示读多路寄存输入,输出电台采用即为“03”功能码模式。如表1和表2所示,表1为主机发送报文,表2为从机回复报文,参考数传电台说明书,得到相应的寄存器说明,如图11所示。主机和从机之间发送的字节均为bytes格式.

(3)单片机与PC串口通讯

如图12和图13所示所示,51单片机内部自带UART(Universal Asynchronous Receiver Transmitter,通用异步收发器),可以实现单片机的单向或双向串口通讯。

   

SCON寄存器

SCON寄存器格式如图14所示,其中SM0和SM1控制串口的工作方式,如图15所示。SM2:允许方式2或方式3多机通信控制位;REN:允许/禁止穿行接收控制位。由软件置位REN,REN=1为允许串行接收状态,可启动串行接收器RxD,开始接收信息;软件复位REN,即REN=0,则禁止接收;

TI: 发送中断请求标志位。在方式0,当串行发送数据第8位结束时,由内部硬件自动置位,即TI=1,向主机请求中断,响应中断后必须用软件复位,即TI=0。在其他方式中,则在停止位开始发送时由内部硬件置位,必须用软件复位;

RI:接收中断请求标志位。在方式0,当串行接收到第8位结束时由内部硬件自动置位RI=1,向主机请求中断,响应中断后必须用软件复位,即RI=0。在其他方式中,串行接收到停止位的中间时刻由内部硬件置位,即RI=1(例外情况见SM2说明),必须由软件复位,即RI=0。

PCON寄存器

PCON寄存器的格式如图16所示,SMOD作为波特率选择位。当用软件置位SMOD,即SMOD=1,则使串行通信方式1、2、3的波特率加倍;当SMOD=0,则各工作方式的波特率不加倍。复位时SMOD=0。

TMOD寄存器

TMOD寄存器的格式如图17所示,分为定时器1 T1和定时器0 T0。定时器的工作方式由M1和M0决定,如图18所示。

五、单片机代码

首先用Keil对485头文件设置

#include <reg52.h>
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;sbit RS485DIR=P1^1;//为0时处于接收状态,为1时处于发送状态
bit flagFrame = 0;  //帧接收完成标志,即接收到一帧新数据
bit flagTxd = 0;    //单字节发送完成标志,用来替代TXD中断标志位
unsigned char cntRxd = 0;   //接收字节计数器
unsigned char pdata bufRxd[64];  //接收字节缓冲区extern void UartAction(u8 *buf, u8 len);
void ConfigUart(u16 baud)//串口初始化
{RS485DIR = 0; //RS485设置为接收方向SCON  = 0x50;  //配置串口为模式1TMOD &= 0x0F;  //清零T1的控制位TMOD |= 0x20;  //配置T1为模式2TH1 = 256 - (11059200/12/32)/baud;  //计算T1重载值TL1 = TH1;     //初值等于重载值ET1 = 0;       //禁止T1中断ES  = 1;       //使能串口中断TR1 = 1;       //启动T1
}
void delay10us(u16 i)//延时10us函数
{do{_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}while(--i);
}
void RS485_write(u8 *buf,u8 len)//发送请求读取命令
{RS485DIR=1;//RS485设置为发送状态while(len--)//循环发送所有字节{flagTxd=0;//清零发送标志SBUF=*buf++;//发送一个字节数据while(!flagTxd);//等待该字节发送完成}delay10us(5);//等待停止位完成RS485DIR=0;//RS485设置为接收状态
}
unsigned char RS485_read(u8 *buf,u8 len)//接收数据命令
{u8 i;RS485DIR=0;//RS485设置为接收状态if(len>cntRxd)//指定读取长度大于实际接收的长度时{len=cntRxd;}for(i=0;i<len;i++)//拷贝接收到的数据到接收指针上{*buf++=bufRxd[i];}cntRxd=0;//接收计数器清零RS485DIR=1;//RS485设置为接收状态return len;//返回实际读取长度
}
void RS485Monitor(u8 ms)//串口接收监控,由于空闲时间判定帧结束,需在定时中断中调用,ms定时间间隔
{static u8 cntbkp=0;static u8 idletmr=0;if(cntRxd>0)//当接收计数器大于零时,监控总线空闲时间{if(cntbkp!=cntRxd)//当接收计数器改变,即为刚刚接收到数据时,清零空闲计时{cntbkp=cntRxd;idletmr=0;}else//总线空闲时,累计空闲时间{if(idletmr<30)//空闲时间小于30ms,继续增加{idletmr+=ms;if(idletmr>=30)//空闲时间达到30ms时刻,判定一帧接收完毕{flagFrame=1;//设置帧数接收完成}}}}else{cntbkp=0;}
}
void RS485_Driver()//串口驱动函数,监测数据帧数的接收
{unsigned char len;unsigned char pdata buf[40];if(flagFrame)//有点命令到达时,读取处理命令{flagFrame=0;len=RS485_read(buf,sizeof(buf)-2);//将接收到的命令读取到缓冲区中UartAction(buf,len);//传递数据帧数,调用动作执行函数}
}
void InteruptRS485() interrupt 4//串口中断服务函数
{if(RI)//接收到新字节{RI=0;//清零接收中断标志if(cntRxd<sizeof(bufRxd))//接收缓冲区尚未用完时,{bufRxd[cntRxd++]=SBUF;}}if(TI)//字节发送完毕{TI=0;//清零发送中断标志位flagTxd=1;//设置字节发送完成标志}}

接着是主程序的设置。

#include <reg52.h>
#include "485测试.h"
#include "intrins.h"
unsigned char T0RH = 0;  //T0重载值的高字节
unsigned char T0RL = 0;  //T0重载值的低字节void ConfigTimer0(unsigned int ms);
extern void RS485_Driver();
extern void ConfigUart(unsigned int baud);
extern void Rs485Monitor(unsigned char ms);
extern void RS485_write(unsigned char *buf, unsigned char len);void main()
{EA = 1;              //开总中断ConfigTimer0(1);   //配置T0定时1msConfigUart(9600);  //配置波特率为9600while (1){RS485_Driver();  //调用串口驱动}}
void UartAction(unsigned char *buf, unsigned char len)//串口动作函数
{RS485_write(buf, len);//RS485_read(buf,len);
}void ConfigTimer0(unsigned int ms)//配置启动t0,ms为定时时间
{unsigned long tmp;  //临时变量tmp = 11059200 / 12;       //定时器计数频率tmp = (tmp * ms) / 1000;  //计算所需的计数值tmp = 65536 - tmp;         //计算定时器重载值tmp = tmp + 33;            //补偿中断响应延时造成的误差T0RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节T0RL = (unsigned char)tmp;TMOD &= 0xF0;   //清零T0的控制位TMOD |= 0x01;   //配置T0为模式1TH0 = T0RH;     //加载T0重载值TL0 = T0RL;ET0 = 1;        //使能T0中断TR0 = 1;        //启动T0
}
void InterruptTimer0() interrupt 1/* T0中断服务函数,执行串口接收监控 */
{TH0 = T0RH;  //重新加载重载值TL0 = T0RL;RS485Monitor(1);  //串口接收监控}

将程序生成的Hex文件通过isp烧入51单片机中。所示连接好接线方式。然后将文件通过ISP烧录给单片机,启动单片机,向串口助手输入01 03 00 01 00 05 f5 cb,每1s自动发送一次,请求比重浓度、波美度、百分比浓度、温度、状态运行码。如图20所示,当串口助手接受区有从机回复数据接收(01 03 0a 27 03 00 00 00 00 00 d0 00 01 40 cf),电台红绿交替闪烁,证明单片机代码可以成功实现控制数据接收的功能。

  

六、Python读取串口处理数据

由于要一个串口只能被一个程序范围,而COM6端口要同时被单片机和Pycharm访问,所以需要使用一个虚拟串口软件。

保密一部分,嘿嘿~反正都能前面485通讯那么难的都做完了,用Python写个读串口还不简简单单?直接上图!

七、开发总结

事实上,我刚做这个项目就上网遍历了一下,几乎没有人做普中51单片机与485通讯的案例。于是想着应该是创新,就没有用Arduino或者STM32来做。于是踩了个比较大的坑,你也看到了,看法过程中足足用了4个软件,改bug的过程中相当繁琐,然后这个UI做得也不行。这个方案不是没有人做,而是太麻烦了导致没有人做。我的方案有效代码拢共500多行,而且还时不时报错;我同组有Arduino开发的同学也就300多行的代码就解决了。

下次加把劲用Arduino ESP32 试一下。感谢你的阅读!

利用51单片机实现与RS485通讯,接收数据相关推荐

  1. php接收rs485的数据如何处理,记录STM32F7 RS485通讯接收数据卡死接收中断的解决方法...

    问题描述:用原子哥的RS485通讯示例对伺服进行控制时,发现当通讯速度过快时,经常会卡死在接收中断里.楼主使用的波特率为1Mbps,一帧发送数据包为10-20字节,一帧接收数据包20-30字节,接收速 ...

  2. 51单片机——USART全双工模式通讯-波特率可选1.3版本

    1.优化<51单片机--USART半双工模式通讯-波特率可选1.2版本>里的代码. 2.主要修改了串口中断里的代码和主函数里的发送代码,接收缓存50字节(这个可自行调整串口缓存大小). 3 ...

  3. 利用51单片机+0.96寸iic接口oled显示图片或动图

    利用51单片机+0.96寸iic接口oled显示图片或动图 前言:之前讲过如何使用oled显示数字以及字符,但并未讲述如何显示BMP格式的图片, 这篇将在之前的基础上加以封装一些函数用来显示图片 硬件 ...

  4. 利用51单片机+hc595芯片配合在led点阵上玩贪吃蛇 第一篇“显示贪吃蛇”

    利用51单片机+hc595芯片配合在led点阵上玩贪吃蛇 第一篇"显示贪吃蛇" 完整的项目链接: https://github.com/linxinloningg/51_chip_ ...

  5. 利用51单片机+hc595芯片配合在led点阵上玩贪吃蛇 第二篇“自动运行函数”

    利用51单片机+hc595芯片配合在led点阵上玩贪吃蛇 第二篇"自动运行函数" 完整的项目链接: https://github.com/linxinloningg/51_chip ...

  6. 利用51单片机统计脉冲个数,即时输出显示

    ;利用51单片机设计一个计数显示系统,要求8个数码管显示T1输入脉冲的个数. ;最好用汇编语言,加注释,尽量别太复杂.尽量快些哈! ;悬赏分:30 | 解决时间:2011-7-20 19:15 | ; ...

  7. 利用51单片机演奏《猪猪侠》

    今天的目标很明确,那就是我们如何使用51单片机演奏一首音乐. 先听一下演奏效果: 51单片机播放<猪猪侠>音乐(音频) 1.有一个很重要的问题,那就是如何将乐谱转换51单片机的16进制或十 ...

  8. 利用51单片机制作一个秒表的详细过程

    利用51单片机制作一个秒表的详细过程 前面的话: 和很多朋友一样,在学51单片机的过程中我们肯定会涉及到制作一个秒表,牵涉到把单片机的多个部分组合起来使用,这对于我们初学者来说可能显得有些困难,我同大 ...

  9. 利用51单片机制作从左至右再从右制作的的流水灯

    利用51单片机制作从左至右再从右制作的的流水灯 简述: 1.打开keil 4,新建工程 2.选择Atmel ,选择AT89C51芯片 3.新建文件另存为,将文件名末尾加上".c" ...

最新文章

  1. 别在 Java 代码里乱打日志了,这才是正确的日志打印姿势!
  2. 计算机网络-物理层设备
  3. WP8.1学习系列(第十二章)——全景控件Panorama开发指南
  4. 解决Win7英文版显示中文乱码
  5. MyBatis 实际使用案例-objectFactory【重点】
  6. mongodb 安装、启动
  7. 前端学习(1936)vue之电商管理系统电商系统之再关闭对话框defkeys
  8. 黑龙江对口学计算机上机,2009年黑龙江省职高对口升学计算机应用专业技能试卷十.doc...
  9. *++p和*p++的区别
  10. linux-基本权限-chown-chod
  11. 大数据分析工程师证书_CDA数据分析就业班、大数据就业班就业情况怎么样?
  12. HTML5拖放API(代码展示)
  13. java季度第一天_Java得到年在一个季度的错误的第一天
  14. yum安装Jenkins
  15. mysql索引和事务_mysql的索引和事务详细解读
  16. Windows Phone 7(WP7)开发 获取网络状态
  17. Adobe 软件清理工具AdobeCreativeCloudCleanerTool.exe
  18. caxa 拉伸命令的使用(一次拉伸很多线)
  19. androidnbsp;框架构图
  20. Apple 宣布 2021 年 Apple Design Awards 获奖者

热门文章

  1. noip2014day1题解
  2. 3D视觉检测:智能工业机器人从平面到立体的“视界”升级
  3. VIEW PUSHED PREDICATE(谓词推入)引发的惨剧
  4. 你会想谈一场诗书传情,相知相敬的爱情吗?
  5. 【深度学习】网络训练的原理:什么是梯度下降?学习率的作用是什么?
  6. iOS-No such file or directory没有这个文件
  7. nodemcu 智能插座
  8. 企业闪存应用八年回顾
  9. 伊登十二色环——欢迎评论指导
  10. zuk z2 android 7.0,联想ZUK Z2兑现承诺,即将推出安卓7.0更新