DTU (Data Transfer unit),是专门用于将串口数据转换为IP数据或将IP数据转换为串口数据通过无线通信网络进行传送的无线终端设备。DTU广泛应用于气象、水文水利、地质等行业。
-
2014-03-17 23:17:00
转载于:https://www.cnblogs.com/shuenjian901/p/3606453.html
更多相关内容 -
基于TCP/IP的串口数据流传输的实现
2020-12-01 17:15:35本文主要对基于TCP/IP的串口数据流做了阐述,并提出了基于硬件与软件相结合实现的串口服务器的系统整体解决方案,对硬件系统的总体、组成框架和应用架构做了阐述。 关键词: 串口数据流 TCP/IP 串口服务器 着... -
C#通过串口读取和发送数据
2019-03-16 06:24:56C#通过串口读取和发送数据,简单的串口读取发送数据例子,简单易懂,适合初学者,欢迎下载 -
串口数据采集入MySQL数据库V2.0
2018-04-19 16:37:29串口数据采集入MySQL数据库V2.0 串口数据采集入MySQL数据库V2.0 -
TCP/IP通信或串口通信数据类型转换
2016-09-27 15:39:40TCP/IP通信或串口通信数据类型转换/// <summary> /// string转换为byte[]数组 /// </summary> /// <param name="str"></param> /// <returns></returns> public static byte[] GetBytes(string str) { byte[] bytes = new byte[str.Length * sizeof(char)]; System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length); return bytes; } /// <summary> /// byte[]数组转换为strng /// </summary> /// <param name="bytes"></param> /// <returns></returns> public static string GetString(byte[] bytes) { char[] chars = new char[bytes.Length / sizeof(char)]; System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length); return new string(chars); } /// <summary> /// 字节数组转16进制字符串 /// </summary> /// <param name="bytes"></param> /// <returns></returns> public static string byteToHexStr(byte[] bytes) { string returnStr = ""; if (bytes != null) { for (int i = 0; i < bytes.Length; i++) { returnStr += bytes[i].ToString("X2"); } } return returnStr; } /// <summary> /// byte转换为string /// </summary> /// <param name="bytes"></param> /// <param name="len"></param> /// <returns></returns> public static string ToHexString(byte[] bytes, int len) { return ToHexString(bytes, 0, len); } public static string ToHexString(byte[] bytes, int start, int len) { string strReturn = ""; for (int i = start; i < (start + len); i++) { byte bt = bytes[i]; strReturn += bt.ToString("x2"); } return strReturn; } /// <summary> /// 16进制转ASCII /// </summary> /// <param name="Msg"></param> /// <returns></returns> public static string HexToASCII(string Msg) { byte[] buff = new byte[Msg.Length / 2]; string Message = ""; for (int i = 0; i < buff.Length; i++) { buff[i] = byte.Parse(Msg.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber); } System.Text.Encoding chs = System.Text.Encoding.ASCII; Message = chs.GetString(buff); return Message; } /// <summary> /// 字符串转16进制字节数组 /// </summary> /// <param name="hexString"></param> /// <returns></returns> private static byte[] strToToHexByte(string hexString) { hexString = hexString.Replace(" ", ""); if ((hexString.Length % 2) != 0) hexString += " "; byte[] returnBytes = new byte[hexString.Length / 2]; for (int i = 0; i < returnBytes.Length; i++) returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); return returnBytes; } /// <summary> /// 16进制转换为byte[] /// </summary> /// <param name="hexStr"></param> /// <returns></returns> public static byte[] ToByesByHex(string hexStr) { int len = hexStr.Length; byte[] data = new byte[len / 2]; for (int k = 0; k < data.Length; k++) { data[k] = Convert.ToByte(hexStr.Substring(k * 2, 2), 16); //k = k* 2; } return data; } /// <summary> /// 从汉字转换到16进制 /// </summary> /// <param name="s"></param> /// <param name="charset">编码,如"utf-8","gb2312"</param> /// <param name="fenge">是否每字符用逗号分隔</param> /// <returns></returns> public static string ToHex(string s, string charset, bool fenge) { if ((s.Length % 2) != 0) { s += " ";//空格 //throw new ArgumentException("s is not valid chinese string!"); } System.Text.Encoding chs = System.Text.Encoding.GetEncoding(charset); byte[] bytes = chs.GetBytes(s); string str = ""; for (int i = 0; i < bytes.Length; i++) { str += string.Format("{0:X}", bytes[i]); if (fenge && (i != bytes.Length - 1)) { str += string.Format("{0}", ","); } } return str.ToLower(); } ///<summary> /// 从16进制转换成汉字 /// </summary> /// <param name="hex"></param> /// <param name="charset">编码,如"utf-8","gb2312"</param> /// <returns></returns> public static string UnHex(string hex, string charset) { if (hex == null) throw new ArgumentNullException("hex"); hex = hex.Replace(",", ""); hex = hex.Replace("\n", ""); hex = hex.Replace("\\", ""); hex = hex.Replace(" ", ""); if (hex.Length % 2 != 0) { hex += "20";//空格 } // 需要将 hex 转换成 byte 数组。 byte[] bytes = new byte[hex.Length / 2]; for (int i = 0; i < bytes.Length; i++) { try { // 每两个字符是一个 byte。 bytes[i] = byte.Parse(hex.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber); } catch { // Rethrow an exception with custom message. throw new ArgumentException("hex is not a valid hex number!", "hex"); } } System.Text.Encoding chs = System.Text.Encoding.GetEncoding(charset); return chs.GetString(bytes); } /// <summary> /// Unicode转汉字 /// </summary> /// <param name="text"></param> /// <returns></returns> public static string UnicodeToGB(string text) { System.Text.RegularExpressions.MatchCollection mc = System.Text.RegularExpressions.Regex.Matches(text, "\\\\u([\\w]{4})"); if (mc != null && mc.Count > 0) { foreach (System.Text.RegularExpressions.Match m2 in mc) { string v = m2.Value; string word = v.Substring(2); byte[] codes = new byte[2]; int code = Convert.ToInt32(word.Substring(0, 2), 16); int code2 = Convert.ToInt32(word.Substring(2), 16); codes[0] = (byte)code2; codes[1] = (byte)code; text = text.Replace(v, Encoding.Unicode.GetString(codes)); } } else { } return text; } public static string unicodetogbx(string text) { System.Text.RegularExpressions.MatchCollection mc = System.Text.RegularExpressions.Regex.Matches(text, "\\\\u([\\w]{4})"); string a = text.Replace("\\u", ""); char[] arr = new char[mc.Count]; for (int i = 0; i < arr.Length; i++) { arr[i] = (char)Convert.ToInt32(a.Substring(i * 4, 4), 16); } string c = new string(arr); return c; } /// <summary> /// Unicode转汉字(测试通过) /// </summary> /// <param name="text"></param> /// <returns></returns> public static string UnicodeToCn(string text) { string cd = text; string cd2 = cd.Replace(" ", ""); cd2 = cd2.Replace("\r", ""); cd2 = cd2.Replace("\n", ""); cd2 = cd2.Replace("\r\n", ""); cd2 = cd2.Replace("\t", ""); if (cd2.Length % 4 != 0) { //MessageBox.Show("Unicode编码为双字节,请删多或补少!确保是二的倍数。"); return ""; } else { int len = cd2.Length / 2; byte[] b = new byte[len]; for (int i = 0; i < cd2.Length; i += 2) { string bi = cd2.Substring(i, 2); b[i / 2] = (byte)Convert.ToInt32(bi, 16); } string o = Encoding.Unicode.GetString(b); //textBox2.Text = o; return o; } } /// <summary> /// 字符串转为UniCode码字符串 /// </summary> /// <param name="s"></param> /// <returns></returns> public static string StringToUnicode(string s) { char[] charbuffers = s.ToCharArray(); byte[] buffer; StringBuilder sb = new StringBuilder(); for (int i = 0; i < charbuffers.Length; i++) { buffer = System.Text.Encoding.Unicode.GetBytes(charbuffers[i].ToString()); sb.Append(String.Format("//u{0:X2}{1:X2}", buffer[1], buffer[0])); } return sb.ToString(); } /// <summary> /// Unicode字符串转为正常字符串 /// </summary> /// <param name="srcText"></param> /// <returns></returns> public static string UnicodeToString(string srcText) { string dst = ""; string src = srcText; int len = srcText.Length / 6; for (int i = 0; i <= len - 1; i++) { string str = ""; str = src.Substring(0, 6).Substring(2); src = src.Substring(6); byte[] bytes = new byte[2]; bytes[1] = byte.Parse(int.Parse(str.Substring(0, 2), NumberStyles.HexNumber).ToString()); bytes[0] = byte.Parse(int.Parse(str.Substring(2, 2), NumberStyles.HexNumber).ToString()); dst += Encoding.Unicode.GetString(bytes); } return dst; }
-
第67节:利用外部中断实现模拟串口数据的收发
2020-07-27 18:24:03从业十年的工程师为大家总结了关于单片机入门的知识,这节主要介绍了利用外部中断实现模拟串口数据的收发。 -
C#实现串口通讯和TCP/IP通讯的示例程序
2018-01-17 15:15:40包含一个与PLC进行网络通讯和与外部设备进行串口通讯的程序 -
CC3200_串口解析数据+WiFi-TCP透传
2018-07-25 14:16:25功能:解析串口数据(此程序中以回车符作为解析对象,如需要解析其他字符可以自行参考修改),并将解析后的串口数据通过Wi-Fi透传。 测试过程:使用PC端串口助手软件,通过串口分别按照115200至1382400波特率(实际... -
采用单片机和串口服务器的数据终端采集设计
2020-08-13 11:04:35绍一种通过串口服务器在单片机与远程PC机间建立通信的方法,实现的远程数据采集系统。该系统是 应用一款低电压,高性能的 CMOS的8位单片机AT89C52构成的数据采集系统,利用嵌入式串口服务器DNE-18将数据封装并联入... -
QT串口数据发送接收以及UDP发送功能.zip
2019-11-07 21:54:14软件能够实现,串口设置串口号、波特率、奇偶校验位、停止位、流控制,以及发送数据格式转换等问题。同时具备网络传输协议,能够通过网络发送数据,自己若能够进行改进能够实现串口网络数据接口的互联互通。 -
C#通过串口通信读取电子称上数据
2020-10-15 00:30:17串口通信,电子称数据读取。程序详细易懂,可以扩展到其他应用。 串口通信,电子称数据读取。程序详细易懂,可以扩展到其他应用。 -
通信与网络中的基于FPGA+DSP的多串口数据通信的实现
2020-11-03 03:58:59摘要: 串口传输常用于基于FPGA和DSP结构的信号处理板和外部设备之间的数据交换。以GPS RTK定位应用为基础,针对单个串口全双工传输不足以应对多种数据类型同时输入输出的情形,设计并实现了一种面向多串口不同类型... -
串口转TCP/IP
2016-06-12 11:52:11功能: 1.本工具兼串口调试工具的相关功能 2.本工具是一个串口转TCP/IP模块,可做TCP/IP客户端 -
多功能型嵌入式以太网串口数据转换模块资料汇总-电路方案
2021-04-22 09:49:40这是一款多功能型嵌入式以太网串口数据转换模块, 它内部集成了 TCP/IP 协议栈, 用户利用它可以轻松完成嵌入式设备的网络功能, 节省人力物力和开发时间, 使产品更快的投入市场, 增强竞争力。 串口数据转换模块集成 10... -
基于单片机和串口服务器的远程数据采集系统
2020-08-26 07:46:51绍一种通过串口服务器在单片机与远程PC机间建立通信的方法,实现的远程数据采集系统。该系统是应用一款低电压,高性能的CMOS的8位单片机AT89C52构成数据采集系统,利用嵌入式串口服务器DNE-18将数据封装并联入... -
Linux下串口数据转tcp发送
2018-09-02 17:38:58利用select机制进行串口监听,然后通过tcp转发给服务器 -
STM32F407ZG+DP83848+UART1+LWIP)网口串口双向数据透传.rar
2021-04-22 22:51:53本次例程使用KEIL开发环境,UART1DMA实现不定长度数据收发,同时转发至网口,IP:192.168.1.240:2040,同样 网口,IP:192.168.1.240:2040可转发不定数据至UART1串口。 uart1波特率115200。 KEIL开发环境。 -
串口服务器RS485转以太网网口TCP/IP转串口模块导轨式通信网络数据传输通讯设备
2021-08-12 09:25:20串口服务器RS485转以太网网口TCP/IP转串口模块导轨式通信网络数据传输通讯设备串口服务器RS485转以太网网口TCP/IP转串口模块导轨式通信网络数据传输通讯设备导轨型单串口服务器5143D 串口服务器RS485转以太网网口TCP...串口服务器RS485转以太网网口TCP/IP转串口模块导轨式通信网络数据传输通讯设备
串口服务器RS485转以太网网口TCP/IP转串口模块导轨式通信网络数据传输通讯设备
导轨型单串口服务器5143D
ZLAN5143D是一款专门为工业环境设计的RS485设备数据采集器/物联网网关,兼具串口服务器、Modbus网关、MQTT网关、RS485转JSON等多种功能于一体。它具有一个RS485接口和一个10M/100M以太网接口。它采用导轨型安装方式,体积小巧安装方便。采用接线端子式电源接入,9~24V宽电压输入。由于只有RS485接口,取消了工业仪表上不常用的RS232接口,节约了成本和体积,和普通产品相比具有更高的性价比。
一、硬件特点:-
导轨型设计:适合工业领域机柜内部安装。
-
体积小巧:相对于普通的串口服务器,宽度较小,不占空间。
-
端子式供电,9~24V宽电压输入,具备反接反电源保护。
-
端子式RS485接口,支持32台从设备,波特率支持300~115200bps。
-
丰富的面板指示灯方便调试:在连接方面,不仅有指示网线有无连接好的100M_LINK灯,也有指示TCP连接建立的LINK灯;数据指示灯方面有“串口到网口”、“网口到串口”独立的指示灯。
二、软件特点
-
1.支持TCP服务端、TCP客户端,UDP模式,UDP组播。作为TCP客户端的时候同时支持TCP服务器端功能。作为TCP服务器支持30个TCP连接,作为TCP客户端支持7个目的IP。
2 .波特率支持1200~115200bps,数据位支持5~9位,校验位可以为无校验、奇校验、偶校验、标记、空格这五种方式。
3 .支持设备连接上发送MAC地址功能,方便云端管理设备。
4 .提供计算机端搜索、配置设备的二次开发包DLL开发库。
5 .支持Web浏览器配置、支持DHCP动态获得IP、DNS协议连接域名服务器地址。
6 .支持云端远程搜索设备、配置设备参数、设备程序升级。
7 .支持远程通过软件查看设备的TCP连接状态、串口数据发送、接收状态。虚拟串口支持数据监视功能。
-
-
串口和tcp/ip调试工具
2018-04-26 13:55:50用于串口或 TCP/IP 数据接收和调试,C# 版本,需要。net 3.5 运行环境 -
串口和网口数据相互转发
2013-03-16 12:22:39实现串口和网口数据收发,使用select函数轮询端口,涉及socket编程,多线程等,该程序可以用在工业控制上下位机的通信与控制 -
openmv串口数据 串口助手_串口发送模块——1字节数据发送
2020-11-20 20:45:30设计思想与代码规范均借鉴明德扬至简设计法,有不足之处希望大家多提...串口是电子设计中非常常见,可以说掌握了串口数据收发,就明白了最基本的时序操作。串口的数据收发过程有其固定的数据格式。下面是本次实验使...设计思想与代码规范均借鉴明德扬至简设计法,有不足之处希望大家多提建议,真正做到至简设计。本篇着重提出FPGA通用设计思想,以计数器为核心的代码规范以及VIVADO debug操作流程。
此次试验旨在通过串口试验,讲述FPGA的硬件设计思想和通用设计流程。串口是电子设计中非常常见,可以说掌握了串口数据收发,就明白了最基本的时序操作。串口的数据收发过程有其固定的数据格式。下面是本次实验使用的数据格式,在满足串口格式规范前提下是可变的:
空闲状态下为高电平,当发送数据时,先发送低电平起始位,后从低位开始逐位发送有效数据比特,数据位位数由双方约定,此处设定为8位。可在数据位后添加数据校验位,但这不是必须的。发送完后发送高电平停止位并持续空闲状态直至下一次发送。虽然本次实验没有用到,但这里简要讲一下奇偶校验的原理:
奇偶校验是一种非常简单常用的数据校验方式,分为奇校验和偶校验。奇校验需要保证传输的数据总共有奇数个逻辑高电平,若是偶校验则要保证传输的数据有偶数个逻辑高电平。即“奇偶”的意思就是数据中(包括该校验位)中1的个数。例如:传输的数据位是0100_0011。如果是奇校验,校验位是0,偶校验校验位是1。
在串口通信中,波特率是一个非常重要的概念。串口通信中常用的波特率是9600、19200、38400、57600、115200。波特率是每个码元传输的速率,在二进制数据传输中,和比特率相同,都是每个比特数据传输的速率,其倒数为1bit数据的位宽,也就是1bit数据持续的时间。有了这一时间段,就可用FPGA构造计数器实现比特周期的延时,从而实现特定的数据传输波特率。
有了这些预备知识,我们开始设计串口发送模块。第一步要明确设计目的:要设计的模块功能当一个时钟周期使能信号有效时,将输入数据通过串口发送给PC机。后续可以通过FIFO缓存数据,实现多个数据的发送。知道设计目的后,通常要开始根据大体功能进行模块划分,模块之间的接口定义以及各模块内部的硬件设计。本次实验只有一个模块,所以直接从模块接口定义开始。每个模块都要有必要的时钟和复位输入,另外串口发送模块需要确保数据不重复发送,因此要有发送使能信号。为了满足不同速率需求,需要波特率设定输入信号来选通不同的波特率。最重要的是待发送数据输入端口。发送侧要有数据串行输出端口和发送完成指示输出。综上,串口发送模块接口示意图如下:
现在开始模块内部功能的硬件实现。首先需要一个参数可变的分频计数器满足不同波特率要求。为此需要一个查找表结构对输入的波特率设定指令进行译码,改变计数器参数。然后要将数据进行并串转换可以通过一个比特位计数器控制数据选择器实现,这样可以将发送比特位数与待发送数据位数相对应。至于发送完成指示信号只需根据比特计数器的数值改变即可。在设计代码前先画出主要信号的时序波形图有助于理清思路:(此处假设比特计数器每个时钟周期计数一次便于画图)
到目前为止最重要的设计工作已经做完了,接下来的代码编写也就没有任何难度可言。
串口发送模块代码:
1 `timescale 1ns / 1ps 2 3 module uart_tx( 4 input clk, 5 input rst_n, 6 input [2:0] baud_set, 7 input send_en, 8 input [7:0] data_in, 9 10 output reg data_out,11 output tx_done12 );13 14 reg [15:0] CYC;15 reg [15:0] cnt_div;16 (*mark_debug = "true"*)reg [3:0] cnt_bit;17 reg add_flag;18 19 wire add_cnt_div;20 (*mark_debug = "true"*)wire end_cnt_div;21 wire add_cnt_bit,end_cnt_bit;22 23 //分频计数器24 always@(posedge clk or negedge rst_n)begin25 if(!rst_n)26 cnt_div <= 0;27 else if(add_cnt_div)begin28 if(end_cnt_div)29 cnt_div <= 0;30 else 31 cnt_div <= cnt_div + 1'b1;32 end33 end34 35 assign add_cnt_div = add_flag;36 assign end_cnt_div = add_cnt_div && cnt_div == CYC - 1;37 38 //比特位数计数器39 always@(posedge clk or negedge rst_n)begin40 if(!rst_n)41 cnt_bit <= 0;42 else if(add_cnt_bit)begin43 if(end_cnt_bit)44 cnt_bit <= 0;45 else 46 cnt_bit <= cnt_bit + 1'b1;47 end48 end49 50 assign add_cnt_bit = end_cnt_div;51 assign end_cnt_bit = add_cnt_bit && cnt_bit == 10 - 1;52 53 //发送使能后分频计数器开始计数,直到将起始位、数据位、停止位发送完成为止54 always@(posedge clk or negedge rst_n)begin55 if(!rst_n)56 add_flag <= 0;57 else if(send_en)58 add_flag <= 1;59 else if(end_cnt_bit)60 add_flag <= 0;61 end62 //波特率查找表63 always@(*)begin64 case(baud_set)65 3'b000:CYC <= 20833;//960066 3'b001:CYC <= 10417;//1920067 3'b010:CYC <= 5208;//3840068 3'b011:CYC <= 3472;//5760069 3'b100:CYC <= 1736;//11520070 default:CYC <= 20833;//960071 endcase72 end73 //根据比特计数器得到对应比特位74 always@(posedge clk or negedge rst_n)begin75 if(!rst_n)76 data_out <= 1;77 else if(send_en)78 data_out <= 0;79 else if(add_cnt_bit && cnt_bit >= 0 && cnt_bit < 8)80 data_out <= data_in[cnt_bit];81 else if((add_cnt_bit && cnt_bit == 8) || end_cnt_bit)82 data_out <= 1;//结束位或者空闲状态均为高电平83 end84 85 assign tx_done = end_cnt_bit;86 87 endmodule
现编写测试激励,观察仿真波形是否与预期一致:
1 `timescale 1ns / 1ps 2 3 module uart_tx_tb; 4 5 reg clk,rst_n; 6 reg [2:0] baud_set; 7 reg send_en; 8 reg [7:0] data_in; 9 10 wire data_out;11 wire tx_done;12 13 uart_tx uart_tx(14 .clk(clk),15 .rst_n(rst_n),16 .baud_set(baud_set),//[2:0]17 .send_en(send_en),18 .data_in(data_in),//[7:0] 19 20 .data_out(data_out),21 .tx_done(tx_done)22 );23 24 parameter CYCLE = 5,25 RST_TIME = 2;26 27 initial begin28 clk = 0;29 forever #(CYCLE / 2) clk = ~clk;30 end31 32 initial begin33 rst_n = 1;34 #1;35 rst_n = 0;36 #(CYCLE * RST_TIME);37 rst_n = 1;38 end39 40 initial begin41 baud_set = 3'b000;42 send_en = 0;43 data_in = 0;44 #1;45 #(CYCLE * RST_TIME);46 #(CYCLE * 10);47 send_en = 1;48 data_in = 8'b0101_0110;49 #(CYCLE * 1);50 send_en = 0;51 #2_000_000;52 $stop;53 end54 55 endmodule
仿真波形如下:
可以看出该模块真确将待发送数据8'b0101_0110 按照串口数据格式发送了出去,分频计数器计数完成后分别发送了0_0110_1010_1.此刻,串口发送模块逻辑功能验证完毕。为了在开发板中运行,添加按键消抖模块,将按键有效输出信号作为发送模块的发送使能,并建立顶层模块。按键消抖模块在上一篇博文中已详细讲述,仅稍作改动调用。下面是顶层模块:
1 `timescale 1ns / 1ps 2 3 module send_data_top( 4 input sys_clk_p, 5 input sys_clk_n, 6 input rst_n, 7 input key, 8 output dout, 9 output tx_done_out10 );11 (*mark_debug = "true"*)wire tx_done;12 (*mark_debug = "true"*)wire key_en;13 // 差分时钟转单端时钟14 // IBUFGDS是IBUFG差分形式,当信号从一对差分全局时钟引脚输入时,必须使用IBUFGDS作为全局时钟输入缓冲15 wire sys_clk_ibufg;16 IBUFGDS #17 (18 .DIFF_TERM ("FALSE"),19 .IBUF_LOW_PWR ("FALSE")20 )21 u_ibufg_sys_clk22 (23 .I (sys_clk_p), //差分时钟的正端输入,需要和顶层模块的端口直接连接24 .IB (sys_clk_n), // 差分时钟的负端输入,需要和顶层模块的端口直接连接25 .O (sys_clk_ibufg) //时钟缓冲输出26 );27 28 key_jitter key_jitter(29 .clk(sys_clk_ibufg),30 .rst_n(rst_n),31 .key_i(key),32 .key_vld(key_en)33 );34 35 uart_tx uart_tx(36 .clk(sys_clk_ibufg),37 .rst_n(rst_n),38 .baud_set(3'b000),//[2:0]39 .send_en(key_en),40 .data_in(8'h32),//[7:0] 41 42 .data_out(dout),43 .tx_done(tx_done));44 45 assign tx_done_out = ~tx_done;46 47 48 endmodule
打开分析后的设计原理图,方便地观察设计整体结构:
HDL代码设计完毕,后需添加约束文件,这里只需为每个端口添加对应的端口号和电平标准即可。注意:当某个信号为多个位时,在后边的方括号内需要用大括号把每一位信号括起来,如:set_property PACKAGE A5 [{led[0]}]
仿真只是通过软件来模拟硬件的场景,尤其在只做了最理想情况下的行为仿真时,并不能完全的体现出所有硬件特性,这时就要进行“在线调试”,也就是使用嵌入式逻辑分析仪,直接抓取芯片内部真实运行的信号数值。它的基本原理是通过IP核的形式嵌入到FPGA芯片内部,不断将要观测数据存入RAM中,当触发条件有效时,停止检测并将信号数据以类似仿真波形的形式显示出来。那么如何选择所要观测的信号呢?观察上面的HDL代码会发现,某些信号定义之前有(*mark_debug = "true"*)。这就是“抓取信号”的方式,在信号定义之前加上这条语句之后,点击Run synthesis,并打开综合后的设计。打开调试界面,点击Set Up Debug 执行ILA调试IP核的生成向导。之前被标注的信号已经自动添加了进来,当然,你可以添加更多的需要观测的信号。
Run implementation并生成比特流后,打开硬件管理器,并自动连接开发板下载比特流。此时debug probles file也同时被加载进来:
下载完毕后debug界面自动打开:
按照图中数字的顺序依次完成抓取模式设置,设置触发条件,启动触发,观测波形。2中设置key_en为高电平时启动触发,观察核心信号数据。
可以看出key_en高电平后发送“0”。由于设置RAM深度太小,导致没有观察到串口数据完整格式。再次将触发条件改为tx_done高电平触发,并修改触发条件所在观测窗口的位置:
tx_done高电平之前比特计数器正确计数到9,tx_done高电平之后一个时钟周期计数值变为0,证明内部逻辑功能正常运行。也可以自行回到综合后界面,再次打开Set Up Debug界面修改数据采样深度观察完整波形:
此时观察串口调试助手,设置好波特率和数据格式,将显示方式设定为16进制。打开串口后,按下按键并松手后,串口调试助手接收到一个8位数据,这里固定让其发送数字8'h32,以下是按两次按键收到的数据:
到此,串口发送模块已设计完毕,将ILA IP核的标注和相关约束去掉可节省逻辑资源。
Version:1.0 StartHTML:000000528 EndHTML:000068149 StartFragment:000005720 EndFragment:000068075 StartSelection:000006282 EndSelection:000068075 SourceURL:https://user.qzone.qq.com/proxy/domain/b.qzone.qq.com/cgi-bin/blognew/blog_output_data?uin=1241003385&blogid=1552133579&styledm=qzonestyle.gtimg.cn&imgdm=qzs.qq.com&bdm=b.qzone.qq.com&mode=2&numperpage=15×tamp=1552437642&dprefix=&blogseed=0.4023615612971605&inCharset=gb2312&outCharset=gb2312&ref=qzone&g_iframedescend=1&entertime=1552437641384&cdn_use_https=1 var isInPengyou = false; var CONTENT_JS_PATH = "v6/script/"; var g_exBlogType = 3; var pubtime = 1552133579; var g_sec_only_title = 0; var g_NonFriendReplyFlag = 0; var g_qSafeLevel = 0; var g_default_no_comment = 0; var g_insertSwfNum = 0; var swfInit = function(){g_insertSwfNum++;} var getParameter = function(name){ var r = new RegExp("(?|#|&)" + name + "=([^&#]*)(&|#|$)"); var m = location.href.match(r); return (!m?"":m[2]); }; var _bJs = function(src, c){return '<script type="text/javascript" charset="'+(c || 'utf-8')+'" src="//'+parent.siDomain+src+'"></script>';}; var _bCss = function(href){return '<link rel="stylesheet" rev="stylesheet" href="//'+parent.siDomain+href+'" media="screen"/>';}; var _dw = function(h){return document.write(h)}; (function(){ try { if(!window.frameElement || parent.document.domain != document.domain){ var uin = getParameter('uin'); uin = /^(w+)$/g.test(uin) ? uin : 0; var blogId = parseInt(getParameter('blogid'), 10); blogId = blogId === undefined ? '' : blogId; top.location.href = 'http://user.qzone.qq.com/'+uin+'/blog/'+blogId; } } catch(ex){ top.location.href = 'http://qzone.qq.com/'; } })(); if (parent.ua){ var htmlClass; if (parent.ua.windows && parent.ua.windows > 6){ htmlClass = "os_win7" }else if(parent.ua.windows && parent.ua.windows == 6){ htmlClass = "os_vista"; }else if(parent.ua.windows){ htmlClass = "os_winxp"; }else{ htmlClass = "os_mac"; } document.documentElement.className += htmlClass; } parent.bcSpeedBasePoint = new Date(); parent.blogSpeedBasePoint = (new Date()).getTime(); _dw(_bCss('/qzone_v6/gb/skin/'+parent.QZONE.FP.getQzoneConfig().styleId+'.css')+_bCss('/qzone_v6/blog_app.css'));串口发送模块——1字节数据发送
设计思想与代码规范均借鉴明德扬至简设计法,有不足之处希望大家多提建议,真正做到至简设计。本篇着重提出FPGA通用设计思想,以计数器为核心的代码规范以及VIVADO debug操作流程。
此次试验旨在通过串口试验,讲述FPGA的硬件设计思想和通用设计流程。串口是电子设计中非常常见,可以说掌握了串口数据收发,就明白了最基本的时序操作。串口的数据收发过程有其固定的数据格式。下面是本次实验使用的数据格式,在满足串口格式规范前提下是可变的:
空闲状态下为高电平,当发送数据时,先发送低电平起始位,后从低位开始逐位发送有效数据比特,数据位位数由双方约定,此处设定为8位。可在数据位后添加数据校验位,但这不是必须的。发送完后发送高电平停止位并持续空闲状态直至下一次发送。虽然本次实验没有用到,但这里简要讲一下奇偶校验的原理:
奇偶校验是一种非常简单常用的数据校验方式,分为奇校验和偶校验。奇校验需要保证传输的数据总共有奇数个逻辑高电平,若是偶校验则要保证传输的数据有偶数个逻辑高电平。即“奇偶”的意思就是数据中(包括该校验位)中1的个数。例如:传输的数据位是0100_0011。如果是奇校验,校验位是0,偶校验校验位是1。
在串口通信中,波特率是一个非常重要的概念。串口通信中常用的波特率是9600、19200、38400、57600、115200。波特率是每个码元传输的速率,在二进制数据传输中,和比特率相同,都是每个比特数据传输的速率,其倒数为1bit数据的位宽,也就是1bit数据持续的时间。有了这一时间段,就可用FPGA构造计数器实现比特周期的延时,从而实现特定的数据传输波特率。
有了这些预备知识,我们开始设计串口发送模块。第一步要明确设计目的:要设计的模块功能当一个时钟周期使能信号有效时,将输入数据通过串口发送给PC机。后续可以通过FIFO缓存数据,实现多个数据的发送。知道设计目的后,通常要开始根据大体功能进行模块划分,模块之间的接口定义以及各模块内部的硬件设计。本次实验只有一个模块,所以直接从模块接口定义开始。每个模块都要有必要的时钟和复位输入,另外串口发送模块需要确保数据不重复发送,因此要有发送使能信号。为了满足不同速率需求,需要波特率设定输入信号来选通不同的波特率。最重要的是待发送数据输入端口。发送侧要有数据串行输出端口和发送完成指示输出。综上,串口发送模块接口示意图如下:
现在开始模块内部功能的硬件实现。首先需要一个参数可变的分频计数器满足不同波特率要求。为此需要一个查找表结构对输入的波特率设定指令进行译码,改变计数器参数。然后要将数据进行并串转换可以通过一个比特位计数器控制数据选择器实现,这样可以将发送比特位数与待发送数据位数相对应。至于发送完成指示信号只需根据比特计数器的数值改变即可。在设计代码前先画出主要信号的时序波形图有助于理清思路:(此处假设比特计数器每个时钟周期计数一次便于画图)
到目前为止最重要的设计工作已经做完了,接下来的代码编写也就没有任何难度可言。
串口发送模块代码:
1 `timescale 1ns / 1ps 2 3 module uart_tx( 4 input clk, 5 input rst_n, 6 input [2:0] baud_set, 7 input send_en, 8 input [7:0] data_in, 9 10 output reg data_out,11 output tx_done12 );13 14 reg [15:0] CYC;15 reg [15:0] cnt_div;16 (*mark_debug = "true"*)reg [3:0] cnt_bit;17 reg add_flag;18 19 wire add_cnt_div;20 (*mark_debug = "true"*)wire end_cnt_div;21 wire add_cnt_bit,end_cnt_bit;22 23 //分频计数器24 always@(posedge clk or negedge rst_n)begin25 if(!rst_n)26 cnt_div <= 0;27 else if(add_cnt_div)begin28 if(end_cnt_div)29 cnt_div <= 0;30 else 31 cnt_div <= cnt_div + 1'b1;32 end33 end34 35 assign add_cnt_div = add_flag;36 assign end_cnt_div = add_cnt_div && cnt_div == CYC - 1;37 38 //比特位数计数器39 always@(posedge clk or negedge rst_n)begin40 if(!rst_n)41 cnt_bit <= 0;42 else if(add_cnt_bit)begin43 if(end_cnt_bit)44 cnt_bit <= 0;45 else 46 cnt_bit <= cnt_bit + 1'b1;47 end48 end49 50 assign add_cnt_bit = end_cnt_div;51 assign end_cnt_bit = add_cnt_bit && cnt_bit == 10 - 1;52 53 //发送使能后分频计数器开始计数,直到将起始位、数据位、停止位发送完成为止54 always@(posedge clk or negedge rst_n)begin55 if(!rst_n)56 add_flag <= 0;57 else if(send_en)58 add_flag <= 1;59 else if(end_cnt_bit)60 add_flag <= 0;61 end62 //波特率查找表63 always@(*)begin64 case(baud_set)65 3'b000:CYC <= 20833;//960066 3'b001:CYC <= 10417;//1920067 3'b010:CYC <= 5208;//3840068 3'b011:CYC <= 3472;//5760069 3'b100:CYC <= 1736;//11520070 default:CYC <= 20833;//960071 endcase72 end73 //根据比特计数器得到对应比特位74 always@(posedge clk or negedge rst_n)begin75 if(!rst_n)76 data_out <= 1;77 else if(send_en)78 data_out <= 0;79 else if(add_cnt_bit && cnt_bit >= 0 && cnt_bit < 8)80 data_out <= data_in[cnt_bit];81 else if((add_cnt_bit && cnt_bit == 8) || end_cnt_bit)82 data_out <= 1;//结束位或者空闲状态均为高电平83 end84 85 assign tx_done = end_cnt_bit;86 87 endmodule
现编写测试激励,观察仿真波形是否与预期一致:
1 `timescale 1ns / 1ps 2 3 module uart_tx_tb; 4 5 reg clk,rst_n; 6 reg [2:0] baud_set; 7 reg send_en; 8 reg [7:0] data_in; 9 10 wire data_out;11 wire tx_done;12 13 uart_tx uart_tx(14 .clk(clk),15 .rst_n(rst_n),16 .baud_set(baud_set),//[2:0]17 .send_en(send_en),18 .data_in(data_in),//[7:0] 19 20 .data_out(data_out),21 .tx_done(tx_done)22 );23 24 parameter CYCLE = 5,25 RST_TIME = 2;26 27 initial begin28 clk = 0;29 forever #(CYCLE / 2) clk = ~clk;30 end31 32 initial begin33 rst_n = 1;34 #1;35 rst_n = 0;36 #(CYCLE * RST_TIME);37 rst_n = 1;38 end39 40 initial begin41 baud_set = 3'b000;42 send_en = 0;43 data_in = 0;44 #1;45 #(CYCLE * RST_TIME);46 #(CYCLE * 10);47 send_en = 1;48 data_in = 8'b0101_0110;49 #(CYCLE * 1);50 send_en = 0;51 #2_000_000;52 $stop;53 end54 55 endmodule
仿真波形如下:
可以看出该模块真确将待发送数据8'b0101_0110 按照串口数据格式发送了出去,分频计数器计数完成后分别发送了0_0110_1010_1.此刻,串口发送模块逻辑功能验证完毕。为了在开发板中运行,添加按键消抖模块,将按键有效输出信号作为发送模块的发送使能,并建立顶层模块。按键消抖模块在上一篇博文中已详细讲述,仅稍作改动调用。下面是顶层模块:
1 `timescale 1ns / 1ps 2 3 module send_data_top( 4 input sys_clk_p, 5 input sys_clk_n, 6 input rst_n, 7 input key, 8 output dout, 9 output tx_done_out10 );11 (*mark_debug = "true"*)wire tx_done;12 (*mark_debug = "true"*)wire key_en;13 // 差分时钟转单端时钟14 // IBUFGDS是IBUFG差分形式,当信号从一对差分全局时钟引脚输入时,必须使用IBUFGDS作为全局时钟输入缓冲15 wire sys_clk_ibufg;16 IBUFGDS #17 (18 .DIFF_TERM ("FALSE"),19 .IBUF_LOW_PWR ("FALSE")20 )21 u_ibufg_sys_clk22 (23 .I (sys_clk_p), //差分时钟的正端输入,需要和顶层模块的端口直接连接24 .IB (sys_clk_n), // 差分时钟的负端输入,需要和顶层模块的端口直接连接25 .O (sys_clk_ibufg) //时钟缓冲输出26 );27 28 key_jitter key_jitter(29 .clk(sys_clk_ibufg),30 .rst_n(rst_n),31 .key_i(key),32 .key_vld(key_en)33 );34 35 uart_tx uart_tx(36 .clk(sys_clk_ibufg),37 .rst_n(rst_n),38 .baud_set(3'b000),//[2:0]39 .send_en(key_en),40 .data_in(8'h32),//[7:0] 41 42 .data_out(dout),43 .tx_done(tx_done));44 45 assign tx_done_out = ~tx_done;46 47 48 endmodule
打开分析后的设计原理图,方便地观察设计整体结构:
HDL代码设计完毕,后需添加约束文件,这里只需为每个端口添加对应的端口号和电平标准即可。注意:当某个信号为多个位时,在后边的方括号内需要用大括号把每一位信号括起来,如:set_property PACKAGE A5 [{led[0]}]
仿真只是通过软件来模拟硬件的场景,尤其在只做了最理想情况下的行为仿真时,并不能完全的体现出所有硬件特性,这时就要进行“在线调试”,也就是使用嵌入式逻辑分析仪,直接抓取芯片内部真实运行的信号数值。它的基本原理是通过IP核的形式嵌入到FPGA芯片内部,不断将要观测数据存入RAM中,当触发条件有效时,停止检测并将信号数据以类似仿真波形的形式显示出来。那么如何选择所要观测的信号呢?观察上面的HDL代码会发现,某些信号定义之前有(*mark_debug = "true"*)。这就是“抓取信号”的方式,在信号定义之前加上这条语句之后,点击Run synthesis,并打开综合后的设计。打开调试界面,点击Set Up Debug 执行ILA调试IP核的生成向导。之前被标注的信号已经自动添加了进来,当然,你可以添加更多的需要观测的信号。
Run implementation并生成比特流后,打开硬件管理器,并自动连接开发板下载比特流。此时debug probles file也同时被加载进来:
下载完毕后debug界面自动打开:
按照图中数字的顺序依次完成抓取模式设置,设置触发条件,启动触发,观测波形。2中设置key_en为高电平时启动触发,观察核心信号数据。
可以看出key_en高电平后发送“0”。由于设置RAM深度太小,导致没有观察到串口数据完整格式。再次将触发条件改为tx_done高电平触发,并修改触发条件所在观测窗口的位置:
tx_done高电平之前比特计数器正确计数到9,tx_done高电平之后一个时钟周期计数值变为0,证明内部逻辑功能正常运行。也可以自行回到综合后界面,再次打开Set Up Debug界面修改数据采样深度观察完整波形:
此时观察串口调试助手,设置好波特率和数据格式,将显示方式设定为16进制。打开串口后,按下按键并松手后,串口调试助手接收到一个8位数据,这里固定让其发送数字8'h32,以下是按两次按键收到的数据:
到此,串口发送模块已设计完毕,将ILA IP核的标注和相关约束去掉可节省逻辑资源。 -
QT编写的读取串口数据的总结(2021-05-06)
2021-05-06 14:17:44QT编写的读取串口数据的总结 本文为作者从实际项目中脱离出来对串口配置、读取数据的总结,仅供参考。 若有发现问题,欢迎留言补充。 转载请注明出处。 1. 在项目的.pro文件中添加依赖: QT += serialport 2. 在... -
不出错发送接收数据测试,节省资源3根线串口,可以学习ip core用法verilog写
2021-03-18 20:30:17实测亲测xilinx fpga uart 串口rs232例子实例工程,ISE打包工程,不出错发送接收数据测试,无状态机,节省资源3根线串口,可以学习rs232串口和倍频ip core用法,字节编写,用verilog编写 基于一个xilinx的学习板子... -
VC6.0【学习心得】如何把串口数据通过socket发送到远程服务器并存入数据库。
2021-02-06 14:28:57【我真的没有很花心要写这么多语言,但是我们老师总是有杂七杂八的项目要交给...然后我使用Taltech这个软件,将串口数据转为socket发送到远程电脑上,里面只需要填写RemoteHostIPAddress和RemotePort,IP使用2001... -
通信与网络中的实现基于TCP/IP的多串口转换网关
2020-12-13 14:18:40随着企业规模的扩大和Internet技术的广泛普及,全球各个领域的不同企业...它能连接多个RS232串口设备,并将串口数据进行选择和处理,把RS232接口的数据流转化成以太网数据流,这样就可以进行网络化的数据处理,实现串 -
求linux下串口采集的数据通过tcp/ip协议进行实时通信的程序。
2017-06-09 00:57:15linux下将串口RS232采集到的数据通过232/usb转接线采集到PC上,现在要把PC上接收到的串口数据通过tcp/ip协议进行数据传输以实现实时通信,请问该程序要如何编写或者有没有相似的范例参考。谢谢! -
Ubuntu USB串口数据 读取及显示
2018-10-11 10:15:35显示串口接受的数据命令 1.1 在终端输入 lsusb 显示所有连接的usb设备 1.2 在终端输入 ls /dev/ttyA* 显示所有连接的虚拟USB设备端口号 1.3 在终端输入 ls /dev/ttyU* 显示所有连接的USB设备端口号 ... -
嵌入式系统/ARM技术中的LabVIEW与单片机串口在数据采集系统中的应用
2020-10-21 20:37:45LabVIEW是一种程序开发环境,由美国国家仪器(NI)公司研制开发的,类似于C和BASIC开发环境,但是LabVIEW与其他计算机语言的显着区别是:其他计算机语言都是采用基于文本的语言产生代码,而LabVIEW使用的是图形化... -
串口、TCP接受传输数据
2022-06-28 17:23:44串口接受扫码枪数据TCP传输 -
Matlab使用串口进行数据通信
2022-05-30 11:20:50Matlab进行串口通信 文章目录Matlab进行串口通信前言问题解决方案方法一:Instrument Control Toolbox方法二.编写通信脚本 前言 在电机运行过程中,需要将电机的姿态等参数通过串口传输至PC端,然后在Matlab进行...