verilog语言RS232串口接收模块设计——串口调试工具发送数据在数码管显示

4 篇文章 0 订阅
2 篇文章 0 订阅

 

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上:

逻辑1(MARK) =-3V~-15V
逻辑0(SPACE)=+3~+15V
这与TTL的逻辑电平不相匹配,我们常采用 MAX232 芯片 完成TTL←→EIA双向电平转换
二、异步通信协议
 S-232使用异步通讯协议。也就是说数据的传输没有时钟信号。接收端必须有某种方式,使之与接收数据同步。
 对于RS-232来说,是这样处理的:
                       1、串行线缆的两端事先约定好串行传输的参数(传输速度、传输格式等)
                       2、当没有数据传输的时候,发送端向数据线上发送"1"
                       3、每传输一个字节之前,发送端先发送一个"0"来表示传输已经开始。这样接收端便可以知道有数据到来了。
                       4、开始传输后,数据以约定的速度和格式传输,所以接收端可以与之同步
                       5、每次传输完成一个字节之后,都在其后发送一个停止位("1")
与我前一篇博客中的ps2接口类似的是,数据都是通过一条总线传输,传输有效数据之前会先发送一个"0“,然后是一个或多个字节的有效数据(低位在前,高位在后),
接着发送的是校验位,与ps2接口不同的是该校验位可以是奇校验也可以是偶校验也可以无校验位。最后发送的值是高电平。
不同之处是,ps2接口有发送时钟,设备发送的数据在下降沿有效,而串口是没有发送时钟的。不过我们可以通过提取数据下降沿的方式构造出有效采样时钟。
数据的传输速度是用波特来描述的,亦即每秒钟传输的数据位,例如1000波特表示每秒钟传输1000比特的数据, 或者说每个数据位持续1毫秒。
波特率不是随意的,必须服从一定的标准,常用的串行传输速率值包括以下几种:
                                      1200 波特.
                                      9600 波特.
                                      38400 波特.
                                      115200 波特 (通常情况下是你可以使用的最高速度)
三、接收模块设计
  接收模块设计主要包括了有三个部分:
    波特率产生部分:这一部分主要是收到串口传输有效信号rs_ena,每间隔一定时间(波特率时间间隔)就产生一个时钟周期的(系统时钟)高电平rs_clk,
使得高电平时刻落在可采用串口数据的中间时刻点,以供接收时提供采样时刻。
   数据接收部分:这一部分的主要功能是对接收串行信号进行处理,提取到串行信号的下降沿,在下降沿处启动一个计数器。该计数器范围为0-11,在计数器有效范围
内令rs_ena为高电平传给第一部分,然后利用第一部分输出的rs_clk,在rs_clk有效位置将接收数据传给缓存区,首先接收的数据放在低存储位,等计数器计满后将buff
里的值传给输出寄存器。同时rs_ena,计数器等清零。等待下一次传输的到来。
  数码管显示部分:这一部分是前面工作的内容,可以参加博客:http://blog.csdn.net/baijingdong/article/details/20220363

第一部分代码:

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<N2-1)
				begin
					count3<=count3+1'b1;
					if(count3<(N2/2-1))
					  clk3<=1'b0;
					else
					  clk3<=1'b1;
				end 
			else
			begin
				count3<=17'd0;
				clk3<=1'b0;
			end	
	end
//==================state select================

reg[3:0] Num;
always @(posedge clk3)
begin
	case (sm_bit)
	'b01:  begin
			Num<=byte_data_out[7:4];
			sm_bit<='b10;
		end
	'b10:  begin
				Num<=byte_data_out[3:0];
				sm_bit<='b01;
			end
	default:
			Num<='d0;
	endcase
	
end
//=========================================================
  always @ (Num)//
	begin
		case (Num)  
			4'h0 : sm_seg = 8'h3f;   // "0"
			4'h1 : sm_seg = 8'h06;   // "1"
			4'h2 : sm_seg = 8'h5b;   // "2"
			4'h3 : sm_seg = 8'h4f;   // "3"
			4'h4 : sm_seg = 8'h66;   // "4"
			4'h5 : sm_seg = 8'h6d;   // "5"//共阴极数码管表
			4'h6 : sm_seg = 8'h7d;   // "6"
			4'h7 : sm_seg = 8'h07;   // "7"
			4'h8 : sm_seg = 8'h7f;   // "8"
			4'h9 : sm_seg = 8'h6f;   // "9"
			4'ha : sm_seg = 8'h77;   // "a"
			4'hb : sm_seg = 8'h7c;   // "b"
			4'hc : sm_seg = 8'h39;   // "c"
			4'hd : sm_seg = 8'h5e;   // "d"
			4'he : sm_seg = 8'h79;   // "e"
			4'hf : sm_seg = 8'h71;   // "f"
		endcase 
    end

//==============================================	 
endmodule


综合仿真之后效果:在pc端输入 A, B, C, 1,  2, 3等数据,串口调试器传输出的是该数据对应的16进制ASCII码值;

A对应的16进制ascii码为41H,数码管显示输出正确


 

  • 13
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
根据提供的引用内容,可以通过使用Verilog代码来实现串口通讯和数码管显示。在给出具体实现方法之前,需要明确一些前提条件。首先,需要一个FPGA开发板来进行开发和测试。其次,需要了解FPGA开发板的引脚分配和数码管的控制方式。 在Verilog代码中,可以使用串口通讯模块来实现与外部设备的数据交互。在给定的代码示例中,有一个名为rs_clk_gen的模块,其中包含了计数器和时钟翻转逻辑。这个模块可以用来生成串口通讯所需的时钟信号。 同时,可以使用数码管驱动模块来实现数码管的显示。具体的驱动方式可以根据FPGA开发板的引脚分配和数码管类型进行选择。一般来说,数码管需要通过FPGA的IO口来控制,可以使用状态机的方式来实现数码管的循环显示。 综合以上两个模块,可以在FPGA开发板上实现串口通讯和数码管显示的功能。通过串口通讯模块与外部设备进行数据交互,并将接收到的数据通过数码管驱动模块进行显示。 需要注意的是,在实际应用中,需要根据具体需求进行适当的修改和扩展。比如添加数据解析和处理的逻辑模块,以及数据的格式化显示等功能。 综上所述,可以通过Verilog代码来实现串口通讯和数码管显示。具体的实现方法可以根据实际需求和硬件平台进行调整和扩展。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [verilog语言RS232串口接收模块设计——串口调试工具发送数据数码管显示](https://blog.csdn.net/baijingdong/article/details/20460019)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [FPGA ise项目 实现点亮led灯,串口收发](https://blog.csdn.net/qq_44331916/article/details/120271553)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值