串口发送
`timescale 1 ns / 1 ps
module uart_transmission(
clk, //串口时钟,9600bps对应的时钟频率 50M/9600/16=326分频
rst_n, //复位信号
data_in, //需要发送的8bit数据
t_sig, //发送使能信号,上升沿有效
idle, //线路状态指示,0表示线路空闲,1表示线路占用
data_tx //串行发送数据,1bit
);
input clk, rst_n, t_sig;
input [7:0] data_in;
output idle, data_tx;
reg idle = 1'b0;
reg data_tx = 1'b1;
reg t_sig_tmp = 1'b0;
reg t_sig_flag = 1'b0;
reg [7:0] cnt = 8'd0;
reg send = 1'b0;
reg patrit_result = 1'b0;
parameter patritmode = 1'b0; //奇偶校验模式,0为偶校验,1为奇校验
always @(posedge clk)
begin
t_sig_tmp <= t_sig;
t_sig_flag <= (~t_sig_tmp) & t_sig;
end
always @(posedge clk)
begin
if(t_sig_flag && (~idle))
begin
send <= 1'b1;
end
else if(cnt == 8'd176)
begin
send <= 1'b0;
end
end
always @(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
idle <= 1'b0;
data_tx <= 1'b1;
cnt <= 8'd0;
patrit_result <= 1'b0;
end
else if(send == 1'b1)
begin
case(cnt)
8'd0: //起始位,发送低电平
begin
idle <= 1'b1;
data_tx <= 1'b0;
cnt <= cnt + 8'd1;
patrit_result <= patritmode;
end
8'd16: //数据位1
begin
idle <= 1'b1;
data_tx <= data_in[0];
cnt <= cnt + 8'd1;
patrit_result <= patrit_result ^ data_in[0];
end
8'd32: //数据位2
begin
idle <= 1'b1;
data_tx <= data_in[1];
cnt <= cnt + 8'd1;
patrit_result <= patrit_result ^ data_in[1];
end
8'd48: //数据位3
begin
idle <= 1'b1;
data_tx <= data_in[2];
cnt <= cnt + 8'd1;
patrit_result <= patrit_result ^ data_in[2];
end
8'd64: //数据位4
begin
idle <= 1'b1;
data_tx <= data_in[3];
cnt <= cnt + 8'd1;
patrit_result <= patrit_result ^ data_in[3];
end
8'd80: //数据位5
begin
idle <= 1'b1;
data_tx <= data_in[4];
cnt <= cnt + 8'd1;
patrit_result <= patrit_result ^ data_in[4];
end
8'd96: //数据位6
begin
idle <= 1'b1;
data_tx <= data_in[5];
cnt <= cnt + 8'd1;
patrit_result <= patrit_result ^ data_in[5];
end
8'd112: //数据位7
begin
idle <= 1'b1;
data_tx <= data_in[6];
cnt <= cnt + 8'd1;
patrit_result <= patrit_result ^ data_in[6];
end
8'd128: //数据位8
begin
idle <= 1'b1;
data_tx <= data_in[7];
cnt <= cnt + 8'd1;
patrit_result <= patrit_result ^ data_in[7];
end
8'd144: //奇偶校验位
begin
idle <= 1'b1;
data_tx <= patrit_result;
cnt <= cnt + 8'd1;
patrit_result <= 1'b0;
end
8'd160: //停止位,发送高电平
begin
idle <= 1'b1;
data_tx <= 1'b1;
cnt <= cnt + 8'd1;
patrit_result <= 1'b0;
end
8'd176: //发送数据结束
begin
idle <= 1'b0;
data_tx <= 1'b1;
cnt <= cnt + 8'd1;
patrit_result <= 1'b0;
end
default:
begin
idle <= idle;
data_tx <= data_tx;
cnt <= cnt + 8'd1;
patrit_result <= patrit_result;
end
endcase
end
else
begin
idle <= 1'b0;
data_tx <= 1'b1;
cnt <= 8'd0;
patrit_result <= 1'b0;
end
end
endmodule
串口接收
`timescale 1 ns / 1 ps
module uart_receive(
clk, //9600bps对应的时钟频率 50M/9600/16=326分频
rst_n, //复位信号,低电平使能
data_in, //接收到的串行数据
idle, //线路状态指示,0表示线路空闲,1表示线路占用
data_rx, //接收到的8bit数据
r_sig, //数据接收完毕指示信号,1表示数据接收完毕
error_data, //校验位出错信号,1表示奇偶校验错误
error_frame //停止位出错信号,1表示停止位错误
);
input clk, rst_n, data_in;
output idle, r_sig, error_data, error_frame;
output [7:0] data_rx;
reg idle = 1'b0;
reg [7:0] data_rx = 8'b0;
reg r_sig = 1'b0;
reg error_data = 1'b0;
reg error_frame = 1'b0;
reg [7:0] cnt = 8'd0; //时钟计数
reg receive = 1'b0; //当有接收信号时为1
reg data_in_tmp = 1'b1;
reg data_in_fall = 1'b0;
reg patrit_result = 1'b0; //对校验位进行比较的结果
parameter patritmode = 1'b0; //奇偶校验模式,0为偶校验,1为奇校验
always @(posedge clk)
begin
data_in_tmp <= data_in;
data_in_fall <= data_in_tmp & (~data_in);
end
always @(posedge clk)
begin
if(data_in_fall && (~idle))
begin
receive <= 1'b1;
end
else if(cnt == 8'd176)
begin
receive <= 1'b0;
end
end
always @(posedge clk or negedge rst_n)
begin
if(~rst_n)
begin
cnt <= 8'd0;
idle <= 1'b0;
data_rx <= 8'b0;
r_sig <= 1'b0;
error_data <= 1'b0;
error_frame <= 1'b0;
patrit_result <= 1'b0;
end
else if(receive == 1'b1)
begin
case(cnt)
8'd0: //起始位
begin
cnt <= cnt + 8'd1;
idle <= 1'b1;
data_rx <= 8'b0;
r_sig <= 1'b0;
error_data <= error_data;
error_frame <= error_frame;
patrit_result <= 1'b0;
end
8'd24: //第1数据位
begin
cnt <= cnt + 8'd1;
idle <= 1'b1;
data_rx[0] <= data_in;
r_sig <= 1'b0;
error_data <= error_data;
error_frame <= error_frame;
patrit_result <= patritmode ^ data_in;
end
8'd40: //第2数据位
begin
cnt <= cnt + 8'd1;
idle <= 1'b1;
data_rx[1] <= data_in;
r_sig <= 1'b0;
error_data <= error_data;
error_frame <= error_frame;
patrit_result <= patrit_result ^ data_in;
end
8'd56: //第3数据位
begin
cnt <= cnt + 8'd1;
idle <= 1'b1;
data_rx[2] <= data_in;
r_sig <= 1'b0;
error_data <= error_data;
error_frame <= error_frame;
patrit_result <= patrit_result ^ data_in;
end
8'd72: //第4数据位
begin
cnt <= cnt + 8'd1;
idle <= 1'b1;
data_rx[3] <= data_in;
r_sig <= 1'b0;
error_data <= error_data;
error_frame <= error_frame;
patrit_result <= patrit_result ^ data_in;
end
8'd88: //第5数据位
begin
cnt <= cnt + 8'd1;
idle <= 1'b1;
data_rx[4] <= data_in;
r_sig <= 1'b0;
error_data <= error_data;
error_frame <= error_frame;
patrit_result <= patrit_result ^ data_in;
end
8'd104: //第6数据位
begin
cnt <= cnt + 8'd1;
idle <= 1'b1;
data_rx[5] <= data_in;
r_sig <= 1'b0;
error_data <= error_data;
error_frame <= error_frame;
patrit_result <= patrit_result ^ data_in;
end
8'd120: //第7数据位
begin
cnt <= cnt + 8'd1;
idle <= 1'b1;
data_rx[6] <= data_in;
r_sig <= 1'b0;
error_data <= error_data;
error_frame <= error_frame;
patrit_result <= patrit_result ^ data_in;
end
8'd136: //第8数据位
begin
cnt <= cnt + 8'd1;
idle <= 1'b1;
data_rx[7] <= data_in;
r_sig <= 1'b0;
error_data <= error_data;
error_frame <= error_frame;
patrit_result <= patrit_result ^ data_in;
end
8'd152: //奇偶校验位
begin
cnt <= cnt + 8'd1;
idle <= 1'b1;
data_rx <= data_rx;
r_sig <= 1'b1;
if(patrit_result == data_in)
error_data <= 1'b0;
else
error_data <= 1'b1;
error_frame <= error_frame;
patrit_result <= patrit_result;
end
8'd168: //停止位
begin
cnt <= cnt + 8'd1;
idle <= 1'b1;
data_rx <= data_rx;
r_sig <= 1'b1;
error_data <= error_data;
if(1'b1 == data_in)
error_frame <= 1'b0;
else
error_frame <= 1'b1;
patrit_result <= patrit_result;
end
default:
begin
cnt <= cnt + 8'd1;
idle <= idle;
data_rx <= data_rx;
r_sig <= r_sig;
error_data <= error_data;
error_frame <= error_frame;
patrit_result <= patrit_result;
end
endcase
end
else
begin
cnt <= 8'd0;
idle <= 1'b0;
data_rx <= data_rx;
r_sig <= 1'b0;
error_data <= 1'b0;
error_frame <= 1'b0;
patrit_result <= 1'b0;
end
end
endmodule
时钟分频(针对9600bps)
`timescale 1 ns / 1 ps
module uart_clkdiv(
clk_in,
rst_n,
clk_out
);
input clk_in, rst_n;
output clk_out;
reg clk_out = 1'b0;
//时钟50MHz,串口速率9600bps,每一bit数据分配16个时钟,50M/9600/16=326分频
reg [7:0] cnt = 8'd0;
always @(posedge clk_in or negedge rst_n)
begin
if(~rst_n)
begin
clk_out <= 1'b0;
cnt <= 8'd0;
end
else
begin
if(cnt >= 8'd0 && cnt < 8'd162)
begin
clk_out <= clk_out;
cnt <= cnt + 8'd1;
end
else if(cnt == 8'd162)
begin
clk_out <= ~clk_out;
cnt <= 8'd0;
end
else
begin
clk_out <= 1'b0;
cnt <= 8'd0;
end
end
end
endmodule