RS232串口经常使用在PC机与FPGA通信中,用于两者之间的数据传输,因为UART协议简单、易实现,故经常使用。

DB9接口只需要使用3根线,RXD(2)、TXD(3)和GND(5),如下图所示。而用FPGA实现控制器时只需要利用RXD和TXD两根线即可完成串口通信。

UART的异步通信协议如下所示:

1. 首先接受双方提前定义好通信的速度和格式等信息;

2. 如果是空闲状态,发送器一直将数据线拉高;

3. 开始通信时,发送器将数据线拉低,从而接收器能知道数据字节即将过来;

4. 数据位通常是8位,低位先发送,高位后发送;

5. 停止通信时,发送器将数据线再次拉高。

控制器包括3部分:波特率发生器、发送器和接收器,本设计发送器和接收器都带有异步FIFO缓存数据。本设计完成如下功能;串口助手发送数据字节给FPGA,FPGA将数据返回给串口助手。波特率采用11520bps,数据格式1位开始位、8位数据位和1位停止位,无校验位。

1. 波特率发生器

波特率发生器需要对主时钟进行分频生成发送器和接收器的工作时钟。发送器的时钟就等于波特率,而接收器的时钟频率是波特率的8倍或者16倍,即对发送器发过来的数据进行过采样以获得准确的数据。下面是接收器和发送器的分频系数。

parameter   Div_rcv     = Clk_freq/Bandrate/16-1;  //8倍
parameter   Div_trans   = Clk_freq/Bandrate/2-1;

发送完一个数据字节后,等待FIFO_T非空或者FIFO_R非空。

 module clk_generater(clk_rcv,clk_trans,clk_in,reset);

  parameter   Clk_freq    = ;
parameter Bandrate = ;
parameter Div_rcv = Clk_freq/Bandrate/-;
parameter Div_trans = Clk_freq/Bandrate/-; output clk_rcv,clk_trans;
input clk_in,reset; reg clk_rcv,clk_trans;
reg [:] counter_rcv;
reg [:] counter_trans; always @ ( posedge clk_in )
if(reset == ) begin
clk_rcv <= ;
clk_trans <= ;
counter_rcv <= ;
counter_trans <= ;
end else begin
if( counter_rcv == Div_rcv )begin
clk_rcv <= ~clk_rcv;
counter_rcv <= ;
end else counter_rcv <= counter_rcv + 'b1; if( counter_trans == Div_trans )begin
clk_trans <= ~clk_trans;
counter_trans <= ;
end else counter_trans <= counter_trans + 'b1;
end
endmodule

2. 发送器

发送器发送的数据从FIFO_T中读取,而FIFO_T数据是从FIFO_R获得。如果FIFO_T非空,读取一个数据字节并在末尾添加数据位0(开始通信位,拉低数据线),下一步进行9次右移操作,串行输出数据位。

XMT_shftreg <= { 1'b1,XMT_shftreg[word_size:1]};

assign Serial_out = XMT_shftreg[0];

 module UART_Transmitter(              //UART transmitter with 16Byte transmit FIFO
output Serial_out, //serial output to data channel
output Busy, //used to indicate FIFO is full
output reg Done, //used to indicate FIFO is empty
input [word_size - :] Data_Bus, //host data bus
input Load_XMT_datareg, //used by host to load data to FIFO
input clk_trans,
input Clk, //clk input
input reset //reset input
);
parameter word_size = ; //size of data word
parameter one_hot_count = ; //number of one-hot states
parameter state_count = one_hot_count; //munber of bits in state register
parameter size_bit_count = ; //size of the bit counter
//must count to word_size + 1 parameter idle = 'b001; //one-hot state encoding
parameter waiting = 'b010;
parameter sending = 'b100;
parameter all_ones = 'b1_1111_1111; //word+1 extra bit reg [word_size:] XMT_shftreg; //transmit shift register
reg Load_XMT_shftreg; //flag to load XMT_shftreg
reg [state_count - :] state,next_state; //state machine controller
reg [size_bit_count:] bit_count; //counts the bits that are transmitting
reg clear; //clears bit_count after last bit is sent
reg shift; //causes shift of data in XMT_shftreg
reg start; //signals start of transmission wire[word_size - :] FIFO_Data_Bus; //output of FIFO
wire empty; //indicates the FIFO is empty
wire Byte_ready; fifo_receiver FIFO_TRS(
.aclr(reset), //Dual clock FIFO generated by Altera megafunction wizard
.data(Data_Bus),//
.rdclk(clk_trans),//
.rdreq(Load_XMT_shftreg),//
.wrclk(Clk),//
.wrreq(Load_XMT_datareg),//
.q(FIFO_Data_Bus),//
.rdempty(empty),//
.wrfull(Busy));// assign Serial_out = XMT_shftreg[];
assign Byte_ready = ~empty; always@(state or Byte_ready or bit_count )begin:Output_and_next_state
Load_XMT_shftreg = ;
clear = ;
shift = ;
start = ;
Done = ;
next_state = state;
case(state)
idle: if(Byte_ready == )begin
Load_XMT_shftreg = ;
next_state = waiting;
end waiting: begin
start = ;
next_state = sending;
end sending: if(bit_count != word_size + )
shift = ;
else if(Byte_ready == )begin
clear = ;
Load_XMT_shftreg = ;
next_state = waiting;
end else begin
clear = ;
Done = ;
next_state = idle;
end default: next_state = idle;
endcase
end always@(posedge clk_trans or posedge reset)begin:State_Transitions
if(reset == )state <= idle; else state <= next_state; end always@(posedge clk_trans or posedge reset)begin:Register_Transfers
if(reset == )begin
XMT_shftreg <= all_ones;
bit_count <= ;
end else begin if(start == ) //starts the transmission
XMT_shftreg <= {FIFO_Data_Bus,'b0}; //添加一位起始位0 if(clear == ) bit_count <= ;
else if(shift == )bit_count <= bit_count + 'b1; if(shift == )
XMT_shftreg <= { 'b1,XMT_shftreg[word_size:1]}; //Shift riht, fill with 1's
end
end endmodule

3. 接收器

本设计采样时钟频率是波特率的8倍,数据有效的中间时刻采样数据,即在第4个采样时钟获取数据。先采样到起始数据0之后,通过一个计数器计满8个时钟采样下一个有效数据。当采样获得8位数据后将8位数据写入FIFO_R,从而产生非空信号准备供发送器FIFO_T读取。

RCV_shftreg <= {Serial_in,RCV_shftreg[word_size - 1:1]};

 // ============================================================
// File Name: UART_Receiver.v
// Module Name(s):
// UART Receiver with FIFO(8x256)
//
// Version: V1.0
// Date: 08/11/2014
// Author: Wang Zhongwei
// Copyright (C) 1896-2009 Beijing Jiao Tong University
// ************************************************************
// CAUTION:
// This module can only be used in Altera Quarus II environment.
// Use megafuncton wizard to generate a dual clock FIFO
// called "fifo_receiver" before synthesis this module.
// =============================================================
module UART_Receiver(
output [word_size - :] Data_bus_out,
//output [word_size - 1:0] RCV_datareg;
output empty,
// Error1,Error2;//Error1:asserts if host is not ready to receive data after last bit
//Error2:asserts if the stop-bit is missing
input Serial_in,Sample_clk,clk_in,reset,read
);
//(Data_bus_out,RCV_datareg,empty,Error1,Error2,Serial_in,read,Sample_clk,clk_in,reset);
//Samlpe _clk is 8x Bit_clk parameter word_size = ;
parameter half_word = word_size/;
parameter Num_counter_bits = ;
parameter Num_state_bits = ;
parameter idle = 'b001;
parameter starting = 'b010;
parameter receiving = 'b100; //reg [word_size - 1:0] Data_bus_out;
//reg [word_size - 1:0] RCV_datareg;
reg [word_size - :] RCV_shftreg;
reg [Num_counter_bits-:] Sample_counter;
reg [Num_counter_bits:] Bit_counter;
reg [Num_state_bits-:] state,next_state;
reg inc_Bit_counter,clr_Bit_counter;
reg inc_Sample_counter,clr_Sample_counter;
reg shift,load;
//reg Error1,Error2; //wire read_not_ready_in;
//instance of receive FIFO
fifo_receiver FIFO_RCV(
.aclr(reset),
.data(RCV_shftreg),
.rdclk(clk_in),
.rdreq(read),
.wrclk(Sample_clk),
.wrreq(load),
.q(Data_bus_out),
.rdempty(empty),
.wrfull()); //read_not_ready_in //we can also use the clk_50M as the clock,while Sample_clk is the enable signal reg[:] RXD_reg = 'b1111;
//synchronize the Serial_in(RX),
always @ (posedge Sample_clk or posedge reset)
if(reset) RXD_reg <= 'b1111;
else RXD_reg <= {RXD_reg[:],Serial_in}; always @ (posedge Sample_clk or posedge reset)
if(reset) state <= idle; else state <= next_state; //Combinational logic for next state and conditional outputs
always @ (*) begin
clr_Sample_counter = 'b0;
clr_Bit_counter = 'b0;
inc_Sample_counter = 'b0;
inc_Bit_counter = 'b0;
shift = 'b0;
// Error1 = 1'b0;
// Error2 = 1'b0;
load = 'b0;
next_state = state; case(state)
idle: if(RXD_reg == ) begin next_state = receiving; end //register 4 seria_in datas to capture the middle sample point of the data receiving: if(Sample_counter < word_size - ) inc_Sample_counter = 'b1;
else begin
clr_Sample_counter = 'b1;
if(Bit_counter != word_size)begin
shift = 'b1;
inc_Bit_counter = 'b1;
end
else begin
next_state = idle;
clr_Bit_counter = 'b1;
load = 'b1;
//read_not_ready_out = 1'b1;
// if(read_not_ready_in == 1'b1) Error1'b1 = 1'b1;
// else if(Serial_in == 0) Error2 = 1'b1;
// else load = 1'b1;
end
end
default: next_state = idle; endcase
end always @ (posedge Sample_clk or posedge reset)begin
if(reset)begin
Sample_counter <= 'd0;
Bit_counter <= 'd0;
// RCV_datareg <= 0;
RCV_shftreg <= 'd0;
end
else begin
if(clr_Sample_counter) Sample_counter <= 'd0;
else if(inc_Sample_counter) Sample_counter <= Sample_counter + 'b1; if(clr_Bit_counter)Bit_counter <= 'd0;
else if(inc_Bit_counter) Bit_counter <= Bit_counter + 'b1; if(shift) RCV_shftreg <= {Serial_in,RCV_shftreg[word_size - :]}; //RXD_reg[2] RXD_reg[1] RXD_reg[0] Serial_in are all ok // if(load == 1) RCV_datareg <= RCV_shftreg;
end
end
endmodule
4. 实验结果

在实验板测试UART通信,接收数据个数等于发送数据个数,能满足一般的通信要求。如果想提高准确度,可提高采样频率、增加校验位或者增加停止位个数(1.5或2)。

此外,3个模块可以共使用一个系统时钟clk。接收器和发送器工作时钟可以作为clk的时钟使能信号,这样这个设计就只使用了一个时钟。

RS232串口通信的更多相关文章

  1. RS232串口通信详解

    串口是计算机上一种非常通用的设备通信协议. ---------------------------------串口的引脚定义: 9芯 信号方向来自 缩写 描述 1 调制解调器 CD 载波检测 2 调制 ...

  2. RS-232串口通信简介

    1969年,美国电子工业协会将RS-232定为串行通信接口的电器标准,该标准定义了数据终端设备DTE(Date Teriminal Equipment)与数据通信设备DCE(Data Communic ...

  3. 在Linux中如何使用命令进行RS-232串口通信和数据包解析

    文章首发于浩瀚先森博客 1. 获取串口号 在Linux系统中一切皆为文件,所以串口端口号也不例外,都是以设备文件的形式出现.也就是说我们可以用访问文本文件的命令来访问它们. a. 一般串口都是以/de ...

  4. ARM学习笔记15——串口通信基本原理【转】

    计算机串口基本理论 1.什么是串口? 2,什么是RS-232? 3,什么是RS-422? 4,什么是RS-485? 5,什么是握手? 1,什么是串口? 串口是计算机上一种非常通用的设备通信的协议(不要 ...

  5. LabVIEW串口通信

    Instrument I/O 利用LabVIEW内置的驱动程序库和具有工业标准的设备驱动软件,可对 GPIB(通用接口总线).Ethernet(以太网)接口.RS-232(标准串行接口总线)/RS-4 ...

  6. C#中的串口通信

    关于串行接口 串行接口(Serial port)又称“串口”,主要用于串行式逐位数据传输.常见的有一般电脑应用的RS-232(使用 25 针或 9 针连接器)和工业电脑应用的半双工RS-485与全双工 ...

  7. Delphi 串口通信数据位长度对传输数据的影响 转

      针对串口通信,关于设置数据位长度对通信的影响,如图: 在串口数据通信中,会看到串口参数设置.其中“数据位”设置,共有四档选项,分别是8.7.6.5.那么改变这个参数会对数据的传输有什么影响呢? 我 ...

  8. Java串口通信具体解释

    序言 说到开源,恐怕非常少有人不挑大指称赞.学生通过开源码学到了知识,程序猿通过开源类库获得了别人的成功经验及可以按时完毕手头的project,商家通过开源软件赚到了钱……,总之是皆大欢喜.然而开源软 ...

  9. 自制单片机之七……RS232串口

    在我的板子上其它的部分都已完成了,现在就剩下RS232串口了.串口对于单片机很重要,有了它就可以和PC通信了,可以用PC来控制你的单片机,也可以将你单片机上采集的数据传到PC上. 留的位置好像有点挤. ...

随机推荐

  1. sql注入的防御和挖掘

    首先我们可以在PHP.ini当中将display_errror关闭,以防止报错型的注入. 1.字符型防护 is_number 正则来判断是否是数字. ctype_digit() intval() st ...

  2. VirtualBox下Linux加载Windows的共享目录

    1.Windows下,在VirtualBox安装增强功能. 菜单 -> 设备 -> 安装增强功能 2.Windows下,在VirtualBox设置共享目录. 设置 -> 共享文件夹 ...

  3. Unix系统编程()main函数的命令行参数

    命令行参数输入双引号是什么效果? 好像可以去空格化.

  4. 使用Data URL将图片嵌入到网页中

    早些时候,使用IE6浏览器,网页可以另存为mht,如果网页包含图片,那么图片也会存储到mht中. mht是微软提供的一种聚合HTML文档,它的本质其实是一个文本文件,那么我们也许会好奇,它的图片存储到 ...

  5. Linux平台使用Freetds连接SQL Server服务器,兼容PHP和Laravel

    本文在CentOS 7 64bit和Laravel 4.2环境测试通过.   1.下载源码并解压缩 wget ftp://ftp.freetds.org/pub/freetds/stable/free ...

  6. android动画效果(转载)

    一.动画基本类型: 如下表所示,Android的动画由四种类型组成,即可在xml中定义,也可在代码中定义,如下所示: XML CODE 渐变透明度动画效果 alpha AlphaAnimation 渐 ...

  7. DevelopmentValue

    DevelopmentValue mysql为utf8为什么网页返回数据及写入mysql数据库均为乱码? eclipse运行配了maven之后,创建包也弹出这个错误,每次都弹 c语言怎么建立txt文件 ...

  8. Enterprise Architect UML建模

    UML建模 前言 UML建模资料已经很多了,有人想用有人不用,有人会用也有人不会用,本文只是作者的一篇UML建模总结,不想去写太细,因为真正的你去用下,去画下就基本都会了.工具毕竟是工具,设计和思想才 ...

  9. EasyUI左右布居

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"><head runat=&quo ...

  10. 怎么用ChemDraw 15.1 Pro绘制彩色结构

    ChemOffice 15是最新的ChemDraw化学工具套件,合理的使用这套软件可以大幅度的提高研究人员的工作效率.也有一些化学老师使用这套化学绘图软件教学,其可以绘制彩色结构有效增强教案说服力并吸 ...