• RS485电工详解


    串口数据帧我们学过,但到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位。电脑还是不如单片机那样精准控制时间,实时性太差了。

    1. txshow(by, DateTime.Now.ToString("ss's'ffffff':'"));
    2. void txshow(byte[] bs, string tim)//日志
    3. {
    4. string num = string.Empty;
    5. foreach (var item in bs)
    6. {
    7. num += item.ToString("X2") + " ";
    8. }
    9. listBox2.Items.Insert(0, tim + num);
    10. //if (this.InvokeRequired)
    11. //{
    12. // this.Invoke(new Action(
    13. // () => { listBox2.Items.Insert(0, tim + num); }
    14. // ));
    15. //}
    16. //else
    17. //{
    18. // listBox2.Items.Insert(0, tim + num);
    19. //}
    20. }

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

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

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

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

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

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

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.IO.Ports;
    7. using System.Linq;
    8. using System.Text;
    9. using System.Threading.Tasks;
    10. using System.Windows.Forms;
    11. namespace portDemo
    12. {
    13. public partial class Form1 : Form
    14. {
    15. SerialPort com;
    16. static int wait=0;
    17. public Form1()
    18. {
    19. InitializeComponent();
    20. }
    21. private void button1_Click(object sender, EventArgs e)
    22. {
    23. com = new SerialPort();
    24. com.PortName=comboBox1.Text;
    25. com.BaudRate=int.Parse(comboBox2.Text );// 96
    26. switch (comboBox3.Text)// n
    27. {
    28. case "无": com.Parity = Parity.None; break;
    29. case "奇": com.Parity = Parity.Odd; break;
    30. case "偶": com.Parity = Parity.Even; break;
    31. case "高": com.Parity = Parity.Mark; break;
    32. case "低": com.Parity = Parity.Space; break;
    33. default:
    34. break;
    35. }
    36. com.DataBits=int.Parse(comboBox4.Text);
    37. switch (comboBox5.Text)// n
    38. {
    39. case "1": com.StopBits = StopBits.One; break;
    40. case "1.5": com.StopBits = StopBits.OnePointFive; break;
    41. case "2": com.StopBits = StopBits.Two; break;
    42. default:
    43. break;
    44. }
    45. com.ReceivedBytesThreshold = 1;// 单帧最低字节数
    46. com.ReadTimeout = 5;
    47. com.DataReceived += Com_DataReceived;//接收事件
    48. com.Open();
    49. button1.BackColor = Color.Green;
    50. }
    51. private void Com_DataReceived(object sender, SerialDataReceivedEventArgs e)
    52. {
    53. string tim = DateTime.Now.ToString("ss's'ffffff ':'"); // 毫秒
    54. byte[ ] rxbuff= new byte[com.BytesToRead];
    55. com.Read(rxbuff, 0, rxbuff.Length );
    56. rzshow(rxbuff ,tim);
    57. }
    58. private void button2_Click(object sender, EventArgs e)
    59. {
    60. com?.Close();
    61. com = null;
    62. button1.BackColor = Color.Gray;
    63. }
    64. private void button3_Click(object sender, EventArgs e)
    65. {
    66. string tim = DateTime.Now.ToString("ss's'fffff ':'"); // 毫秒
    67. byte by = Convert.ToByte(textBox1.Text, 16);
    68. com.Write(new byte[1]{ by },0,1);
    69. }
    70. void rzshow(byte[] bs,string tim)//日志
    71. {
    72. string num = string.Empty;
    73. foreach (var item in bs)
    74. {
    75. num += item.ToString("X2")+" ";
    76. }
    77. if(this.InvokeRequired)
    78. {
    79. this.Invoke(new Action(
    80. ()=> { listBox1.Items.Insert(0, tim +num); }
    81. ));
    82. }
    83. else
    84. {
    85. listBox1.Items.Insert(0, tim + num);
    86. }
    87. }
    88. private void button4_Click(object sender, EventArgs e)
    89. {// ↑
    90. com.ReadTimeout+=1;
    91. label7.Text= com.ReadTimeout.ToString();
    92. }
    93. private void button5_Click(object sender, EventArgs e)
    94. {
    95. com.ReadTimeout -= 1;
    96. label7.Text = com.ReadTimeout.ToString();
    97. }
    98. private async void button6_Click(object sender, EventArgs e)
    99. {//3tx
    100. listBox2.Items.Clear();
    101. label8.Text = wait.ToString();
    102. byte[] by = new byte[1] { Convert.ToByte(textBox1.Text, 16) };
    103. txshow(by, DateTime.Now.ToString("ss's'ffffff':'"));
    104. com.Write(by, 0, 1) ;
    105. await Task.Delay(wait);
    106. txshow(by, DateTime.Now.ToString("ss's'ffffff':'"));
    107. com.Write(by, 0, 1);
    108. await Task.Delay(wait);
    109. txshow(by, DateTime.Now.ToString("ss's'ffffff':'"));
    110. com.Write(by, 0, 1);
    111. await Task.Delay(wait);
    112. }
    113. void txshow(byte[] bs, string tim)//日志
    114. {
    115. string num = string.Empty;
    116. foreach (var item in bs)
    117. {
    118. num += item.ToString("X2") + " ";
    119. }
    120. listBox2.Items.Insert(0, tim + num);
    121. //if (this.InvokeRequired)
    122. //{
    123. // this.Invoke(new Action(
    124. // () => { listBox2.Items.Insert(0, tim + num); }
    125. // ));
    126. //}
    127. //else
    128. //{
    129. // listBox2.Items.Insert(0, tim + num);
    130. //}
    131. }
    132. private void button7_Click(object sender, EventArgs e)
    133. {// ↑
    134. wait += 1;
    135. label8.Text = wait.ToString();
    136. }
    137. private void button8_Click(object sender, EventArgs e)
    138. {
    139. wait -= 1;
    140. label8.Text = wait.ToString();
    141. }
    142. private void button9_Click(object sender, EventArgs e)
    143. {
    144. com.Write(new byte[3] { 0x30, 0x31, 0x32 }, 0, 3);
    145. }
    146. }
    147. }

     

  • 相关阅读:
    Springboot快递管理系统1k61h计算机毕业设计-课程设计-期末作业-毕设程序代做
    【Python基础-Pandas】解决Pandas会自动把None转成NaN的问题
    Spark 内核(四) --------- Spark 任务调度机制
    linux 使用yum给已安装的软件降级
    海外IP代理科普——API代理是什么?怎么用?
    Android sqlite 使用简介
    企业微信托管集成语聚AI,做AI智能客服助手,实现精准回答用户问题、创建群组自动化场景
    更轻便使用Siri!iOS 17让你用Siri的效率倍增
    Java之多线程
    自定义指令与生命周期函数
  • 原文地址:https://blog.csdn.net/cfqq1989/article/details/127989726