首页 技术 正文
技术 2022年11月10日
0 收藏 699 点赞 2,194 浏览 7169 个字

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

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

RS232串口通信

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

RS232串口通信

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

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

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

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

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

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

RS232串口通信

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的时钟使能信号,这样这个设计就只使用了一个时钟。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,484
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,899
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,732
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,485
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,125
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,285