uart 串口 接收 和 发送

在这里插入图片描述

串口发送

`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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值