带 PIC 微控制器串行端口的 PicRS232 控件
你可以构建一个小型家庭自动化系统,控制串口和PIC单片机。
引言
本文演示了一个名为PicRS232的应用程序,用于监控串口。在串口上,我们连接了一个PIC单片机,它可以控制电机、风扇、灯的开关等。
背景
PIC单片机内部知道它从串口接收到的某些字节。例如,如果你以十六进制发送字母“t”(0x74),就可以打开或关闭LED。在PIC内部,你可以选择ASCII表中哪个字节用于识别操作,当它检测到该字节时。
基本工作原理如下:
Visual C# <-----> PC <-----> MAX232 <-----> PIC <-----> 任何外围设备。
使用代码
发送帧
在本例中,我提供了一个通过按下按钮从串口发送字节的示例。
private void button_t_Click(object sender, EventArgs e)
{
byte[] mBuffer = new byte[1];
mBuffer[0] = 0x74; //ASCII letter "t".
serialPort1.Write(mBuffer, 0, mBuffer.Length);
}
你也可以将多个字节发送到帧中。
private void button_t_Click(object sender, EventArgs e)
{
byte[] mBuffer = new byte[5];
mBuffer[0] = 0x74;
mBuffer[1] = 0x75;
mBuffer[2] = 0x89;
mBuffer[3] = 0x20;
mBuffer[4] = 0x6C;
serialPort1.Write(mBuffer, 0, mBuffer.Length);
}
如果你决定连续发送多个字节,最好在ASCII中使用以下代码:
private void button_b_Click(object sender, EventArgs e)
{
byte[] mBuffer = Encoding.ASCII.GetBytes("Hello World");
serialPort1.Write(mBuffer, 0, mBuffer.Length);
}
这是完整的源代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports; // Do not forget.
namespace PicRS232
{
public partial class Form1_Principal : Form
{
// Use a string as the receive buffer.
string Recibidos;
public Form1_Principal()
{
InitializeComponent();
// Open port while running the application.
if (!serialPort1.IsOpen)
{
try
{
serialPort1.Open();
}
catch (System.Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
// Run the Reception function by triggering the Event 'DataReived'.
serialPort1.DataReceived += new
System.IO.Ports.SerialDataReceivedEventHandler(Recepcion);
}
// Upon receiving the data.
private void Recepcion(object sender,
System.IO.Ports.SerialDataReceivedEventArgs e)
{
// Collecting the characters received to our 'buffer' (string).
Recibidos += serialPort1.ReadExisting();
// Invoke or call the process of hatching.
this.Invoke(new EventHandler(Actualizar));
}
// Process the data received in the full frame buffer and extract.
private void Actualizar(object s, EventArgs e)
{
// Assign the value of the plot to the RichTextBox.
richTextBox_visualizar_mensaje.Text = Recibidos;
}
private void button_t_Click(object sender, EventArgs e)
{
byte[] mBuffer = new byte[1];
mBuffer[0] = 0x74; //ASCII letter "t".
serialPort1.Write(mBuffer, 0, mBuffer.Length);
}
private void button_b_Click(object sender, EventArgs e)
{
byte[] miBuffer = new byte[1];
miBuffer[0] = 0x62; //ASCII letter "b".
serialPort1.Write(miBuffer, 0, miBuffer.Length);
}
private void button_a_Click(object sender, EventArgs e)
{
byte[] mBuffer = new byte[1];
mBuffer[0] = 0x61; //ASCII letter "a".
serialPort1.Write(mBuffer, 0, mBuffer.Length);
}
private void button_l_Click(object sender, EventArgs e)
{
byte[] mBuffer = new byte[1];
mBuffer[0] = 0x6C; //ASCII letter "l".
serialPort1.Write(mBuffer, 0, mBuffer.Length);
}
private void button_Espacio_Click(object sender, EventArgs e)
{
byte[] mBuffer = new byte[1];
mBuffer[0] = 0x20; //ASCII letter "Space".
serialPort1.Write(mBuffer, 0, mBuffer.Length);
}
// Show local time.
private void timer1_Tick(object sender, EventArgs e)
{
statusStrip1.Items[0].Text = DateTime.Now.ToLongTimeString();
}
// We always show the message below.
private void richTextBox_visualizar_mensaje_TextChanged(object sender, EventArgs e)
{
richTextBox_visualizar_mensaje.SelectionStart =
richTextBox_visualizar_mensaje.TextLength;
richTextBox_visualizar_mensaje.ScrollToCaret();
}
}
}
关注点
前段时间,我制作了一份关于如何控制串口以控制PIC单片机的指南。你可以在这里 查看。
RS232规范,简介
RS232标准定义的通信是一种异步串行通信方法。串行意味着信息一次发送一位。异步则告诉我们信息不是以预定义的时间槽发送的。数据传输可以在任何给定时间开始,接收器的任务是检测消息何时开始和结束。异步通信有一些优点和缺点,这些将在下一段中讨论。
RS232比特流
RS232标准描述了一种通信方法,其中信息通过物理通道逐位发送。信息必须分解为数据字。数据字的长度是可变的。在PC上,可以选择5到8位之间的长度。这个长度是每个字净信息的长度。为了正确传输,会添加额外的位用于同步和错误检查。传输器和接收器使用相同数量的位非常重要。否则,数据字可能会被误解,甚至根本不被识别。
在同步通信中,必须存在一个时钟或触发信号,指示每次传输的开始。没有时钟信号使得异步通信通道的运行成本更低。我们只需要电缆中的较少线路。缺点是接收器可能在错误的时间点开始接收信息。然后需要重新同步,这会花费时间。在重新同步期间接收到的所有数据都将丢失。另一个缺点是数据流中需要额外的位来指示有用信息的开始和结束。这些额外的位会占用带宽。
数据位以预定义的频率(波特率)发送。传输器和接收器都必须编程为使用相同的比特频率。接收到第一个比特后,接收器会计算其他数据比特将在何时接收。它将在这些时刻检查线路电压电平。
在RS232中,线路电压电平可以有两种状态。开启状态也称为标记(mark),关闭状态称为空间(space)。不可能有其他线路状态。当线路空闲时,它保持在标记状态。
起始位
RS232定义了一种异步通信类型。这意味着发送数据字可以在任何时刻开始。如果可以在任何时刻开始,这可能会给接收器带来一些问题,即如何知道要接收的第一个位是哪个。为了解决这个问题,每个数据字都以一个注意位开始。这个注意位,也称为起始位,总是由空间线路电平识别。因为线路在空闲时处于标记状态,所以起始位很容易被接收器识别。
数据位
起始位之后直接发送数据位。比特值为1会使线路进入标记状态,比特值0由空间表示。最低有效位总是最先发送的位。
奇偶校验位
为了进行错误检测,可以自动为数据字添加一个额外的位。传输器根据发送的信息计算该位的值。接收器执行相同的计算,并检查实际的奇偶校验位值是否与计算值匹配。这一点将在另一段中进一步讨论。
停止位
假设接收器由于传输线路上的噪声而错过了起始位。它从第一个后续数据位开始,值为空间。这会导致接收器收到乱码数据。必须存在一个机制来重新同步通信。为此,引入了帧。帧意味着所有数据位和奇偶校验位都包含在一个起始位和停止位对的帧中。起始位和停止位之间的时间段由波特率和数据位以及奇偶校验位的数量定义的恒定值。起始位始终是空间值,停止位始终是标记值。如果接收器在停止位应该出现在线路上时检测到非标记值,它就知道存在同步失败。这会导致接收UART中的帧错误。然后设备会尝试在新传入的比特上重新同步。
为了重新同步,接收器会扫描传入的数据以查找有效的起始位和停止位对。只要数据字的比特模式有足够的变异,这就有效。例如,如果重复发送值为零的数据,则无法重新同步。
标识数据帧结束的停止位可以有不同的长度。实际上,它不是一个真正的位,而是线路在每个字结束时必须保持空闲(标记状态)的最小时间段。在PC上,这个周期可以有三种长度:等于1、1.5或2个比特的时间。1.5个比特仅用于5位长度的数据字,2个比特用于更长的数据字。对于所有数据字大小,停止位长度为1个比特是可能的。
RS232物理特性
RS232标准描述了一种能够在不同环境中通信的方法。这对引脚上的最大允许电压等产生了影响。在原始定义中,考虑了当时的技术可能性。例如,定义的最高波特率为20 kbps。使用像16550A UART这样的现代设备,最高速度可达1.5 Mbps。
电压
RS232引脚的信号电平可以有两种状态。高位或标记状态由负电压识别,低位或空间状态使用正值。这可能有点令人困惑,因为在正常情况下,高逻辑值也由高电压定义。电压限制如下所示。
RS232电压值
Level
Transmitter
capable (V)
Receiver
capable (V)
Space state (0)
+5 ... +15
+3 ... +25
Mark state (1)
-5 ... -15
-3 ... -25
Undefined
-
-3 ... +3
有关RS232和其他串行接口电压水平的更多信息,请参阅接口比较表。
计算机在其端口上产生的最大电压摆幅会影响允许的最大电缆长度和通信速度。此外,如果电压差很小,数据失真会更快发生。例如,我的东芝笔记本电脑的标记电压是-9.3V,而我的台式电脑是-11.5V。在有高噪声的工业环境中,笔记本电脑与三菱PLC通信存在困难,而台式电脑使用相同的电缆完全没有数据错误。因此,即使远远超过最低电压水平,额外的2伏特也能极大地改善通信质量。
尽管存在高电压,但通过短路无法损坏串口。只有施加高电流的外部电压最终可能会烧毁驱动芯片。即使那样,在大多数情况下,UART也不会损坏。
最大电缆长度
电缆长度是RS232领域讨论最多的问题之一。该标准有一个明确的答案:最大电缆长度为50英尺,或电容为2500 pF的电缆长度。后一个规则经常被遗忘。这意味着使用低电容的电缆可以跨越更长的距离而不超出标准限制。例如,如果使用电容为17 pF/ft的UTP CAT-5电缆,则允许的最大电缆长度为147英尺。
标准中提到的电缆长度允许达到最大通信速度。如果速度降低2倍或4倍,最大长度会急剧增加。德州仪器多年前在不同波特率下进行了一些实际实验,以测试允许的最大电缆长度。请记住,RS232标准最初是为了20 kbps而开发的。通过将最大通信速度减半,允许的电缆长度会增加十倍!
德州仪器根据RS232电缆长度
Maximum cable length (ft)
19200
50
9600
500
4800
1000
2400
3000
错误检测
一种错误检测方法已经讨论过。它是用于测试传入比特是否正确地被起始位和停止位对包围的帧检测机制。为了进一步进行错误检查,可以使用奇偶校验位。但是,使用此位不是强制性的。如果错误比特的出现很少(例如,与内部调制解调器通信时),或者如果使用更高层协议进行错误检测和纠正(如Z-modem、RAS等),则可以通过不使用UART上的奇偶校验功能来提高通信速度。
奇偶校验是一种简单的数据字编码方法,用于检测信息中的错误。串行通信中使用的方法为每个数据字添加一个位。该位的值取决于数据字的值。传输器和接收器必须使用相同的算法来计算奇偶校验位的值。否则,接收器可能会检测到不存在的错误。
偶校验
基本上,奇偶校验位可以通过两种方式计算。当使用偶校验时,发送的信息位的数量将始终包含偶数个逻辑1。如果高数据位的数量是奇数,则添加高值奇偶校验位;否则,使用低位。
奇校验
奇校验系统与偶校验系统非常相似,但在这种情况下,高位数的数量将始终是奇数。
奇偶校验系统的缺点
每个数据字使用一位的奇偶校验系统无法发现所有错误。只有导致奇数位翻转的错误才能被检测到。第二个问题是无法知道哪个位是错误的。如有必要,需要一个更高层协议来通知发送者必须重新发送此信息。因此,在有噪声的线路上,通常使用其他检测系统来确保发送的信息被正确接收。
历史
你可以在我的 博客 上找到更多更新和项目。