verilog RS232 串口通信 verilog

//=============================顶层模块=====================================

module uart_top(clk,rs232_rx,rs232_tx);

input clk; //时钟信号50M
input rs232_rx; //数据输入信号
output rs232_tx; //数据输出信号
wire clk_bps1,clk_bps2;
wire bps_start1,bps_start2;
wire [7:0] rx_data;
reg [7:0] tx_data;
reg [7:0] rx_data1;
reg [7:0] rx_data2;
reg [7:0] rx_data3;
reg [7:0] rx_data4; //接收数据存储器,用来存储接收到的数据,直到下一个数据接收
wire rx_int; //接收数据中断信号,接收过程中一直为高,
reg [29:0] rst_cnt;
reg rst_n;
initial begin
rst_cnt<=0;
rst_n<=0;
end

always @(posedge clk ) begin
if(rst_cnt<20000000) rst_cnt<=rst_cnt+1'b1;
if (rst_cnt>10000) begin
rst_n<=1;
end
else
begin
rst_n<=0;
end
end

speed_select_rx speed_rx(//波特率选择模块
.clk(clk),
.rst_n(rst_n),
.clk_bps(clk_bps1),
.bps_start(bps_start1)
);
uart_rx uart_rx(//数据接收模块
.clk(clk),
.rst_n(rst_n),
.bps_start(bps_start1),
.clk_bps(clk_bps1),
.rs232_rx(rs232_rx),
.rx_data(rx_data),
.rx_int(rx_int)
);

reg [7:0] int_cnt;

reg [1:0] addr;
wire data_flg;

always @(posedge clk or posedge rx_int)
begin
if(rx_int)
int_cnt<=8'd0;
else
begin
if(int_cnt<250) int_cnt<=int_cnt+1'b1;
end
end

assign data_flg=(int_cnt==10)?1'b1:1'b0;

always @(posedge data_flg or negedge rst_n)
begin
if(!rst_n)
addr<=0;
else
begin
addr<=addr+1'b1;
end
end

always @(negedge data_flg )
begin
if(addr==0)
rx_data1<=rx_data;
else if(addr==1)
rx_data2<=rx_data;
else if(addr==2)
rx_data3<=rx_data;
else if(addr==3)
rx_data4<=rx_data;
end
reg [21:0] out_cnt;
reg [1:0]addr_r;
reg data_flg_r;
always @(posedge clk or posedge rx_int)
begin
if(rx_int)
out_cnt<=20'd0;
else
begin
if(out_cnt<4194300) out_cnt<=out_cnt+1'b1;
if((out_cnt<60000)||((out_cnt>1000000)&&(out_cnt<1060000))||((out_cnt>2000000)&&(out_cnt<2060000))||((out_cnt>3000000)&&(out_cnt<3060000)))
begin
data_flg_r<=1'b1;
end
else
begin
data_flg_r<=1'b0;
end
end



end
always @(posedge data_flg_r or negedge rst_n)
begin
if(!rst_n)
addr_r<=8'd0;
else
begin
addr_r<=addr_r+1'b1;
end
end
always @(negedge data_flg_r )
begin
if(addr_r==0)
tx_data<=rx_data4;
else if(addr_r==1)
tx_data<=rx_data3;
else if(addr_r==2)
tx_data<=rx_data2;
else if(addr_r==3)
tx_data<=rx_data1;
end
speed_select_rx speed_tx( //波特率选择模块
.clk(clk)

,
.rst_n(rst_n),
.bps_start(bps_start2),
.clk_bps(clk_bps2)
);
uart_tx uart_tx(//发送数据模块
.clk(clk),
.rst_n(rst_n),
.clk_bps(clk_bps2),
.rs232_tx(rs232_tx),
.tx_data(tx_data),
.tx_int(data_flg_r),
.bps_start(bps_start2)
);
endmodule




module speed_select_rx(clk,rst_n,clk_bps,bps_start);//波特率设定

input clk; //50M时钟
input rst_n; //复位信号
input bps_start;//接收到数据后,波特率时钟启动信号置位
//或者开始发送数据时,波特率时钟启动信号置位

output clk_bps; //clk_bps的高电平为发送或者接收数据中间采样点,

/* 波特率
parameter bps9600 = 5207, //波特率为9600bps
bps19200 = 2603, //波特率为19200bps
bps38400 = 1301, //波特率为38400bps
bps57600 = 867, //波特率为57600bps
bps115200 = 433; //波特率为115200bps

parameter bps9600_2 = 2603,
bps19200_2 = 1301,
bps38400_2 = 650,
bps57600_2 = 433,
bps115200_2 = 216;
*/

//-----------------------------------------------------------------------------
//以下波特率分频计数值可参照上面的参数进行更改
//计算方法:
//以9600bps为例,9600bps表示每秒9600bit,则传输1bit需要10^9/9600=104166ns,
//所以再我们使用50MHz的时钟频率的前提下,需要104166/20=5208个时钟周期
//5208个时钟周期内传送了1bit位,则在中间的时刻处,进行取样(接收模块)或者
//将中间时刻作为发送数据的数据改变点(发送模块)

reg[12:0] cnt;//分频计数器
reg clk_bps_r;//波特率时钟寄存器
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt<=13'd0;
else if((cnt==5207||!bps_start))//判断计数是否达到1个脉宽
cnt<=13'd0;
else
cnt<=cnt+1'b1;//波特率时钟启动

always @(posedge clk or negedge rst_n) begin
if(!rst_n)
clk_bps_r<=1'b0;
else if(cnt== 2603)//当波特率计数到一半时,进行采样存储
clk_bps_r<=1'b1;
else
clk_bps_r<=1'b0;
end
assign clk_bps = clk_bps_r;//将采样数据输出给uart_rx模块
endmodule

module uart_rx(//串口接收模块
clk,
rst_n,
bps_start,
clk_bps,
rs232_rx,
rx_data,
rx_int
);
input clk; //50MHz时钟
input rst_n; //低电平复位信号
input rs232_rx; //接收数据信号
input clk_bps; //高电平时为接收信号中间采样点
output bps_start; //接收信号时,波特率时钟信号置位
output [7:0] rx_data;//接收数据寄存器
output rx_int; //接收数据中断信号,接收过程中为高

reg rs232_rx0,rs232_rx1,rs232_rx2,rs232_rx3;//接收数据寄存器
wire neg_rs232_rx;/

/表示数据线接收到下沿

always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
rs232_rx0 <= 1'b0;
rs232_rx1 <= 1'b0;
rs232_rx2 <= 1'b0;
rs232_rx3 <= 1'b0;
end

else begin
rs232_rx0 <= rs232_rx;
rs232_rx1 <= rs232_rx0;
rs232_rx2 <= rs232_rx1;
rs232_rx3 <= rs232_rx2;
end
end

assign neg_rs232_rx = rs232_rx3 & rs232_rx2 & ~rs232_rx1 & ~rs232_rx0;//串口传输线的下沿标志,接收到下降沿后neg_rs232_rx置高一个时钟周期

reg bps_start_r;
reg [3:0] num;//移位次数
reg rx_int; //接收中断信号,接收到数据期间始终为高电平

always @(posedge clk or negedge rst_n)
if(!rst_n) begin
bps_start_r <=1'b0;
rx_int <= 1'b0;
end
else if(neg_rs232_rx) begin//接收到串口接收线rs232_rx的下降沿标志信号
bps_start_r <= 1'b1; //启动串口,准备接收数据
rx_int <= 1'b1; //接收数据中断使能
end
else if(num==4'd10) begin //接收完有用的信号,
bps_start_r <=1'b0; //接收完毕,改变波特率置位,方便下次接收
rx_int <= 1'b0; //接收信号关闭
end

assign bps_start = bps_start_r;

reg [7:0] rx_data_r;//串口数据寄存器,保存直至下一个数据来到
reg [7:0] rx_temp_data;//当前数据寄存器

always @(posedge clk or negedge rst_n)
if(!rst_n) begin
rx_temp_data <= 8'd0;
num <= 4'd0;
rx_data_r <= 8'd0;
end
else
begin //接收数据处理
if(clk_bps)
begin//读取并保存数据,接收数据为一个起始位,8bit数据,1或2个结束位
num <= num+1'b1;
case(num)
4'd1: rx_temp_data[0] <= rs232_rx;
4'd2: rx_temp_data[1] <= rs232_rx;
4'd3: rx_temp_data[2] <= rs232_rx;
4'd4: rx_temp_data[3] <= rs232_rx;
4'd5: rx_temp_data[4] <= rs232_rx;
4'd6: rx_temp_data[5] <= rs232_rx;
4'd7: rx_temp_data[6] <= rs232_rx;
4'd8: rx_temp_data[7] <= rs232_rx;
default: ;
endcase
end
else if(num==4'd10) begin //4'd12
num <= 4'd0; //数据接收完毕
rx_data_r <= rx_temp_data;//把数据锁存到数据寄存器rx_data中
end
end
assign rx_data = rx_data_r;
endmodule
module speed_select_rx(clk,rst_n,clk_bps,bps_start);//波特率设定

input clk; //50M时钟
input rst_n; //复位信号
input bps_start;//接收到数据后,波特率时钟启动信号置位
//或者开始发送数据时,波特率时钟启动信号置位

output clk_bps; //clk_bps的高电平为发送或者接收数据中间采样点,

/* 波特率
parameter bps9600 = 5207, //波特率为9600bps
bps19200 = 2603, //波特率为19200bps
bps38400 = 1301, //波特率为38400bps
bps57600 = 867, //波特率为57600bps
bps115200 = 433; //波特率为115200bps

parameter bps9600_2

= 2603,
bps19200_2 = 1301,
bps38400_2 = 650,
bps57600_2 = 433,
bps115200_2 = 216;
*/

//-----------------------------------------------------------------------------
//以下波特率分频计数值可参照上面的参数进行更改
//计算方法:
//以9600bps为例,9600bps表示每秒9600bit,则传输1bit需要10^9/9600=104166ns,
//所以再我们使用50MHz的时钟频率的前提下,需要104166/20=5208个时钟周期
//5208个时钟周期内传送了1bit位,则在中间的时刻处,进行取样(接收模块)或者
//将中间时刻作为发送数据的数据改变点(发送模块)

reg[12:0] cnt;//分频计数器
reg clk_bps_r;//波特率时钟寄存器
always @(posedge clk or negedge rst_n)
if(!rst_n)
cnt<=13'd0;
else if((cnt==5207||!bps_start))//判断计数是否达到1个脉宽
cnt<=13'd0;
else
cnt<=cnt+1'b1;//波特率时钟启动

always @(posedge clk or negedge rst_n) begin
if(!rst_n)
clk_bps_r<=1'b0;
else if(cnt== 2603)//当波特率计数到一半时,进行采样存储
clk_bps_r<=1'b1;
else
clk_bps_r<=1'b0;
end
assign clk_bps = clk_bps_r;//将采样数据输出给uart_rx模块
endmodule

module uart_tx(
clk,
rst_n,
clk_bps,
rs232_tx,
tx_data,
tx_int ,
bps_start
);


input clk;
input rst_n;
input clk_bps;//中间采样点
input [7:0] tx_data;//接收数据寄存器
input tx_int;//数据接收中断信号
output rs232_tx;//发送数据信号
output bps_start;
reg tx_int0,tx_int1,tx_int2;//信号寄存器,捕捉下降沿
wire neg_tx_int; //下降沿标志
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
tx_int0 <= 1'b0;
tx_int1 <= 1'b0;
tx_int2 <= 1'b0;
end
else begin
tx_int0 <= tx_int;
tx_int1 <= tx_int0;
tx_int2 <= tx_int1;
end
end

assign neg_tx_int = ~tx_int1 & tx_int2;//捕捉下沿

reg [7:0] tx_data_r;//待发送数据
reg bps_start_r;
assign bps_start = bps_start_r;
reg [3:0] num;

always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
bps_start_r <= 1'b0;
tx_data_r <= 8'd0;
end
else if(neg_tx_int) begin//当检测到下沿的时候,数据开始传送
bps_start_r <= 1'b1;
tx_data_r <= tx_data;
end
else if(num==4'd10) begin
bps_start_r <= 1'b0;
end
end
reg rs232_tx_r;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
num<=4'd0;
rs232_tx_r <= 1'b1;
end
else
begin
if(clk_bps)
begin
num<=num+1'b1;
case(num)
4'd0: rs232_tx_r <= 1'b0;//起始位
4'd1: rs232_tx_r <= tx_data_r[0];//数据位 开始
4'd2: rs232_tx_r <= tx_data_r[1];
4'd3: rs232_tx_r <= tx_data_r[2];
4'd4: rs232_tx_r <= tx_data_r[3];
4'd5: rs232_tx_r <= tx_data_r[4];
4'd6: rs232_tx_r <= tx_data_r[

5];
4'd7: rs232_tx_r <= tx_data_r[6];
4'd8: rs232_tx_r <= tx_data_r[7];//数据位结束
4'd9: rs232_tx_r <= 1'b1;//结束位

default: rs232_tx_r <= 1'b1;
endcase
end

else if(num==4'd10)
num<=4'd0;//发送完成,复位


end
end
assign rs232_tx =rs232_tx_r;
endmodule






相关文档
最新文档