RS485电工详解

本文深入解析RS485通信原理,包括其空闲状态、工作时的逻辑01跳变、电平逻辑特点及数据帧结构。通过示波器观察不同条件下的波形变化,阐述了起始位、数据位、校验位与停止位的作用,并讨论了串口发送接收时序问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

串口数据帧我们学过,但到RS485是不是就卡壳了?

空闲状态:AB线悬浮在2.3V的样子。GND是0V,+5V是4.75v

工作时,AB线在2.3v上做逻辑01(-2v,+2v)跳变。

这图是不是还不太好理解?我把B线下移3伏,给大家看看。

黄色是A相,绿色是B相。值是0x71

电平逻辑正好相反。永远对称。

RS-485的电气特性:逻辑“1”以两线间的电压差为  正(2~6)V 表示;逻辑“0”以两线间的电压差为    负(2~6)V 表示。

我们来看下:

逻辑正: A(2.3v+2v)约4v      B(2.3v-2v)约0v    差值   正4V

逻辑负: A(2.3v-2v)约0v      B(2.3v+2v)约4v    差值   负4V

所以 B相 是电平参考线。

//===========================

电压的问题讲完了,就该讲时序了。 

我们先把示波器的GND接到B相上。

 这2图是同一个波形,只是GND参考线换成了B相。

空闲时:AB都是2.3V相当于没电压,是0伏。逻辑正负切换时,波形振幅放大了。一个格子是2v,逻辑1正3.5v,逻辑0负3.5v

RS-485的电气特性:逻辑“1”以两线间的电压差为  正(2~6)V 表示;逻辑“0”以两线间的电压差为    负(2~6)V 表示。

我们来看下:

逻辑正: A(2.3v+2v)约4v      B(2.3v-2v)约0v    差值   正4V

逻辑负: A(2.3v-2v)约0v      B(2.3v+2v)约4v    差值   负4V

B相 是电平参考线。这样,逻辑就对上了。起始位要保持一个低电平,0伏怎么保持低电平呢?所以要先拉高4v,再拉低 (负4v)并保持一位长度

我们来看下数据帧:

n长度高电平,一个起始位低电平,8个数据位电平,一个校验位,一个停止位。

所以,空闲是n长的0v。

一个起始位低电平:为了这个条件,所以至少拉高1个位的高电平再保持一个位的低电平。

8个数据位电平,D0D1D2D3D4D5D6D7  我发的是0xF1

这个是(96N81)的时序图,你会发现,没有校验位的电平宽度,因为你是无校验,所以校验电平宽度就没有。

为了看校验位,我发的值要改成0x71(0111 0001),串口(96o81)奇校验

 为了看校验位,我发的值要改成0x71(0111 0001),串口(96E81)偶校验

 0x71(0111 0001)括号里的1数量,加 校验位电平值,是偶数就是偶校验   4+0等于4是偶数

好,下面看个无校验的(96N81) 

可以看到,校验位的电平长度没了。 

 校验位,实际还可以强制:一直为1,或者一直为0;

注意:串口刚打开后,发送的第2帧有延迟,之后会没这个问题。

打开串口,连续发送3次字节,看下时序图

 我也不明白,为什么刚打开串口后,发送的第2帧会延迟。之后再连续发送就不会再延迟。可能是C#底层类库的问题。

接收:出现数据帧过短字节,可以用 com.ReceivedBytesThreshold = 1;// 单帧最低字节数

com.ReceivedBytesThreshold = 5;// 单帧最低字节数

设置5后,间歇发送的字节必须达到5字节,才能触发串口接收事件。

发送部分:

虽然是连续发单字节,实际代码有延迟。还是要用示波器,逻辑分析仪,监视

com.Write(by, 0, 1) ;

 

上位机上也能明显看出第3帧有延迟,我精确到毫秒4位。电脑还是不如单片机那样精准控制时间,实时性太差了。

txshow(by, DateTime.Now.ToString("ss's'ffffff':'"));




  void txshow(byte[] bs, string tim)//日志
        {
            string num = string.Empty;
            foreach (var item in bs)
            {
                num += item.ToString("X2") + " ";
            }

            listBox2.Items.Insert(0, tim + num);
            //if (this.InvokeRequired)
            //{
            //    this.Invoke(new Action(
            //        () => { listBox2.Items.Insert(0, tim + num); }
            //    ));
            //}
            //else
            //{
            //    listBox2.Items.Insert(0, tim + num);
            //}

        }

数据包发送才可以实现 连续字节发送

 private void button9_Click(object sender, EventArgs e)
        {
            com.Write(new byte[3] { 0x30, 0x31, 0x32 }, 0, 3);
        }

这3字节没出现等待情况。 

总之,电脑的时间实时性比较差,频繁读写,会造成卡顿。可能线程的问题。会出现字节帧过短,过长,空字节触发串口接收事件。

要么发送后,等待固定的时间,再去读取接收数据帧。或者判断载波检测,空字节可以再等待一会,再去读字节。

以下是我对串口的简单调试,写的C#,可以参考下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace portDemo
{
    public partial class Form1 : Form
    {
        SerialPort com;

        static int wait=0;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            com = new SerialPort();
            com.PortName=comboBox1.Text;
            com.BaudRate=int.Parse(comboBox2.Text );// 96
            switch (comboBox3.Text)// n
            {
                case "无": com.Parity = Parity.None; break;
                case "奇": com.Parity = Parity.Odd; break;
                case "偶": com.Parity = Parity.Even; break;
                case "高": com.Parity = Parity.Mark; break;
                case "低": com.Parity = Parity.Space; break;
               
                default:
                    break;
            }
            com.DataBits=int.Parse(comboBox4.Text);
            switch (comboBox5.Text)// n
            {
                case "1": com.StopBits = StopBits.One; break;
                case "1.5": com.StopBits = StopBits.OnePointFive; break;
                case "2": com.StopBits = StopBits.Two; break;
                
                default:
                    break;
            }

            com.ReceivedBytesThreshold = 1;// 单帧最低字节数
            com.ReadTimeout = 5;


            com.DataReceived += Com_DataReceived;//接收事件

            com.Open();
            button1.BackColor = Color.Green;
        }

        private void Com_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            string tim = DateTime.Now.ToString("ss's'ffffff ':'"); // 毫秒
            
            byte[ ] rxbuff= new byte[com.BytesToRead];
            com.Read(rxbuff, 0, rxbuff.Length );


            rzshow(rxbuff ,tim);

            
        }

        private void button2_Click(object sender, EventArgs e)
        {
            com?.Close();
            com = null;
            button1.BackColor = Color.Gray;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            string tim = DateTime.Now.ToString("ss's'fffff ':'"); // 毫秒
            byte by = Convert.ToByte(textBox1.Text, 16);
            com.Write(new byte[1]{ by },0,1);
        }

        void rzshow(byte[] bs,string tim)//日志
        {
            string num = string.Empty;
            foreach (var item in bs)
            {
                num += item.ToString("X2")+" ";
            }
            
            if(this.InvokeRequired)
            {
                this.Invoke(new Action(
                    ()=> { listBox1.Items.Insert(0, tim +num); }
                ));
            }
            else
            {
                listBox1.Items.Insert(0, tim + num);
            }
            
        }

        private void button4_Click(object sender, EventArgs e)
        {// ↑
            com.ReadTimeout+=1;
            label7.Text= com.ReadTimeout.ToString();
        }

        private void button5_Click(object sender, EventArgs e)
        {
            com.ReadTimeout -= 1;
            label7.Text = com.ReadTimeout.ToString();
        }

        private async void button6_Click(object sender, EventArgs e)
        {//3tx
            listBox2.Items.Clear();
            label8.Text = wait.ToString();
            byte[] by = new byte[1] { Convert.ToByte(textBox1.Text, 16) };
            txshow(by, DateTime.Now.ToString("ss's'ffffff':'"));
            com.Write(by, 0, 1) ;
            
            await Task.Delay(wait);
            txshow(by, DateTime.Now.ToString("ss's'ffffff':'"));
            com.Write(by, 0, 1);
            
            await Task.Delay(wait);
            txshow(by, DateTime.Now.ToString("ss's'ffffff':'"));
            com.Write(by, 0, 1);
            
            await Task.Delay(wait);
        }

        void txshow(byte[] bs, string tim)//日志
        {
            string num = string.Empty;
            foreach (var item in bs)
            {
                num += item.ToString("X2") + " ";
            }

            listBox2.Items.Insert(0, tim + num);
            //if (this.InvokeRequired)
            //{
            //    this.Invoke(new Action(
            //        () => { listBox2.Items.Insert(0, tim + num); }
            //    ));
            //}
            //else
            //{
            //    listBox2.Items.Insert(0, tim + num);
            //}

        }

        private void button7_Click(object sender, EventArgs e)
        {// ↑
            wait += 1;
            label8.Text = wait.ToString();

        }

        private void button8_Click(object sender, EventArgs e)
        {
            wait -= 1;
            label8.Text = wait.ToString();
        }

        private void button9_Click(object sender, EventArgs e)
        {
            com.Write(new byte[3] { 0x30, 0x31, 0x32 }, 0, 3);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值