RS-232是常用的传输接口,是硬件学习的入门级接口。
一、接口特性
常见的9脚接口管脚分配如下图,参考链接:http://zh.wikipedia.org/wiki/RS-232
DE-9 Male (Pin Side) DE-9 Female (Pin Side) ------------- ------------- \ 1 2 3 4 5 / \ 5 4 3 2 1 / \ 6 7 8 9 / \ 9 8 7 6 / --------- ---------
信号 | DB-25 | DE-9 | EIA/TIA 561 | Yost |
---|---|---|---|---|
公共接地 | 7 | 5 | 4 | 4,5 |
发送数据(TD、TXD) | 2 | 3 | 6 | 3 |
接受数据(RD、RXD) | 3 | 2 | 5 | 6 |
数据终端准备(DTR) | 20 | 4 | 3 | 2 |
数据准备好(DSR) | 6 | 6 | 1 | 7 |
请求发送(RTS) | 4 | 7 | 8 | 1 |
清除发送(CTS) | 5 | 8 | 7 | 8 |
数据载波检测(DCD) | 8 | 1 | 2 | 7 |
振铃指示(RI) | 22 | 9 | 1 | - |
RS-232设计之初是用来连接调制解调器做传输之用,也因此它的脚位意义通常也和调制解调器传输有关,而我们做硬件与PC接口通常只用到两个管脚即可:TXD,RXD.
由于发送接收数据分别采用两条串行总线进行传输,因此rs232接口是可以全双工工作的,最大速率可达10KB/s.
根据美国电子工业学会(EIA)的标准。在TxD和RxD上:
第一部分代码:
module rs_clk_gen(
clk,rst,rs_clk,rs_ena
);
input clk;//系统时钟
input rst;//复位信号
input rs_ena; //串口通信允许信号
output rs_clk; //输出允许的波特率信号时钟
parameter N1=5207;//5208,9600bps 50M的系统时钟;
parameter N2=2603;//2604,这里是0-2603,共计数2604次
reg rs_clk='b0;
reg [13:0] count='d0;//计数器
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
count<='d0; //复位信号到来时,count计数器清零
end
else
if(count==N1 || !rs_ena) count<='d0;//当count计满或者无串口通信使能时count都不计数
else count<=count+'b1;//当且仅当count不为0,通信使能时count计数。
end
always @(posedge clk or negedge rst)
begin
if (!rst)
rs_clk<='b0;
else
if(count==N2&&rs_ena)//当且仅当count计数到一半且通信使能时允许时钟翻转
rs_clk<='b1; //
else
rs_clk<='b0;//使得rs_clk是一个小波峰的时钟信号,在有效信号的数据位为高电平。
end
endmodule
第一部分的仿真结果:由于分频系数太大,不容易观察,这里采用N1=3,N2=2来仿真。仿真之后要改回不然会出错。
接收模块代码
module rs_receive(
input rx_data,//接收到的串口数据
input clk,
input rst,
output [7:0] byte_data_out,//接收完成的一字节数据输出
input rs_clk,//输入的数据有效采样时刻时钟
output reg rs_ena='b0//有效数据到来标志
);
//++++++++++++++++++++++++++++++++++++++++++++++
reg rx_data0='b0;
reg rx_data1='b0;
reg rx_data2='b0;//声明寄存器用于提取有效数据的下降沿;
wire neg_rx_data=~rx_data1 & rx_data2;//下降沿时该信号电平为高
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
rx_data0<='b0;
rx_data1<='b0;
rx_data2<='b0;
end
else
begin
rx_data0<=rx_data;
rx_data1<=rx_data0;
rx_data2<=rx_data1;
end
end
//+++++++++++++++++++++++++++++++++++++++++++++
reg rx_int='b0;//接收中断信号
//reg rs_ena;
reg [3:0]num='d0;
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
rx_int<='b0;
rs_ena<='bz;
end
else
if(neg_rx_data)
begin
rx_int<='b1;//下降沿到来时,产生接收中断--此期间即使有下降沿到来也不理会,此时使能模块1,即rs_ena为高电平。
rs_ena<='b1;
end
else
if(num=='d10)
begin
rx_int<='b0;//num==10,即数据接收完成时,中断结束。
rs_ena<='b0;
end
end
reg [7:0]rx_data_buf='d0;//接收信号缓存区,由于数据一位一位传输,不能立刻赋值输出,用于缓存数据,到接收完成再赋值给输出
reg [7:0]data_byte_r='d0;//寄存器型,用于完成赋值,最后赋给输出。
assign byte_data_out=data_byte_r;
always @(posedge clk or negedge rst)
begin
if(!rst)
num<='d0;
else
if(rx_int)
begin
if(rs_clk)//在接收中断的情况下,到来一次采样时钟进行一次如下运算,
begin
num<=num+1'b1;
case(num)
'd1:rx_data_buf[0]<=rx_data;
'd2:rx_data_buf[1]<=rx_data;
'd3:rx_data_buf[2]<=rx_data;
'd4:rx_data_buf[3]<=rx_data;//数据依次加入到缓存区
'd5:rx_data_buf[4]<=rx_data;
'd6:rx_data_buf[5]<=rx_data;
'd7:rx_data_buf[6]<=rx_data;
'd8:rx_data_buf[7]<=rx_data;
default:;
endcase
end
else
if(num=='d10)
begin//数据接收完成,将缓存数据交给寄存器,同时计数器清零
num<='d0;
data_byte_r<=rx_data_buf;
end
end
end
endmodule
顶层模块代码:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: bupt abs_lab
// Engineer: mr.bai
//
// Create Date: 18:44:58 03/03/2014
// Design Name: rs232_receive_module
// Module Name: rs232_top
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module rs232_top(
input clk,
input rst,
input rs232_rx,
output reg [7:0] sm_seg,
output reg [1:0]sm_bit='b01
);
wire rs_clk,rs_ena;
rs_clk_gen M1(
.clk(clk),.rst(rst),.rs_clk(rs_clk),.rs_ena(rs_ena)
);
wire [7:0] byte_data_out;
rs_receive M2(
.rx_data(rs232_rx),
.clk(clk),
.rst(rst),
.byte_data_out(byte_data_out),
.rs_clk(rs_clk),
.rs_ena(rs_ena)
);
//====================数码管显示接收数据部分===================================
parameter N2=50000;
reg clk3=1'b0;
reg [16:0]count3=17'd0;
//assign clk_out=clk3;
always @(posedge clk or negedge rst)
begin
if (!rst)
begin
count3<=17'd0;
clk3<=1'b0;
end
else
if(count3
综合仿真之后效果:在pc端输入 A, B, C, 1, 2, 3等数据,串口调试器传输出的是该数据对应的16进制ASCII码值;
A对应的16进制ascii码为41H,数码管显示输出正确