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. 跟着百度学PHP[14]-PDO的错误处理模式&PDO执行SQL

    我们在使用PDO去执行sql语句的时候并不会报错.如下案例所示: <?php try { //$pdo = new pdo("mysql:host=主机;port=端口;dbname= ...

  2. spring quartz定时任务 配置

    cronExpression表达式: 字段 允许值 允许的特殊字符秒 0-59 , - * /分 0-59 , - * /小时 0-23 , - * /日期 1-31 , - * ? / L W C月 ...

  3. TCP/IP详解读书笔记:ARP-地址解析协议

    地址解析为两种不同的地址形式提供映射:32bit的IP和数据链路层使用的任何类型的地址. 当一台主机把以太网数据帧发送到位于同一局域网的另一台主机,是根据48bit的以太网地址而不是IP地址.设备驱动 ...

  4. YARN机制

    YARN是资源管理调度的机制,之前一直以来和MapReduce机制合在一起,之后才分开.正是因为YARN机制单独独立出来,才使得Hadoop框架更加具有普适性.MapReduce可以处理海量离线数据, ...

  5. Installing scipy on redhat with error “no lapack/blas resources found”

    这是更新scipy出现的结果,需要新版本的scipy,而机器上只装了0.7的版本,更新的时候报错,找到了一个解决方法: wget http://mirror.centos.org/centos/6/o ...

  6. C0304 备份最后一天所有修改的文件

    #! /bin/bash backupfile=backup-$(date +%m-%d-%Y) archive=${1:-$backupfile} # 上边内容, 参数替换 ${} echo $ar ...

  7. TP 框架 ajax[利用异步提交表单]

    //[] $(function () { $("#send-btn" ).click(function (){ //接受表单的值 var username=$('input[nam ...

  8. 第二百一十节,jQuery EasyUI,SearchBox(搜索框)组件

    jQuery EasyUI,SearchBox(搜索框)组件 学习要点: 1.加载方式 2.属性列表 3.方法列表 本节课重点了解 EasyUI 中 SearchBox(搜索框)组件的使用方法,这个组 ...

  9. 你是怎么理解java的泛型的?

    解答: 在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知 ...

  10. 边缘检测sobel算子

    sobel算子 - sophia_hxw - 博客园http://www.cnblogs.com/sophia-hxw/p/6088035.html #1,个人理解 网上查了很多资料,都说sobel算 ...