1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > uart串口的verilog实现

uart串口的verilog实现

时间:2019-08-25 11:09:53

相关推荐

uart串口的verilog实现

前言

在FPGA的基础学习中,uart串口通信属于对FPGA认识达到一定的深度的时候,需要经过的一段历程,想要从简单的通信转到IIC、SPI等通信方式,uart也是新手最好入门的一种通信方式。

一、串口的基本知识了解

一个数据帧的发送和接收的起始位和停止位都是固定的,在uart串口通信中,一个数据帧包含8bit数据,图所示为一个数据帧(10101101).这里需要先了解通信的一些基本知识,波特率(bps):表示一秒钟能传输的最大的bit数,常用的有9600、19200、38400以及115200.这里拿我所使用的板子晶振(50MHz)来说,算出传输1bit需要的时间:1/115200=8680 ns ,转换成相应的时钟频率为434hz.

二、串口发送模块

1.设计介绍

利用上面算出的波特率以及一个数据帧的有效单元的知识,可以在一个数据帧传输的时候,设计两个计数器来计算波特率和一个帧结构的bit数,在一个帧结构的数据单元都发送完成, 设计一个发送结束信号,在发送模块还需要将并行数据转换为串行数据可以利用case查找表将数据帧中的数据一个一个的给到发送数据线TX,最终实现数据的发送,也可以使用移位操作将数据给到TX.

2.源代码

/* == == == == == == == == == ==filename :my_uart_txdescription: 串口的发送模块up file :my_uarttips :将计数器的知识理解透彻看代码的时候就会很好理解e-mail:1005916381@author:chenchenchen /*== == == == == == == == == == */ module my_uart_tx(input clk ,input rst_n ,input[7:0] data_in ,//需要传输的数据input dtx_vld ,//传输有效信号output reg TX //数据发送总线);/*===============================Parameter Declarations=============================*/parameterT_bsp = 434 ;//115200的对应计数最大值/*===============================end parameter======================================*//*===============================Internal wire/reg declarations=====================*/reg [9:0] data_reg;//停止位,数据,结束位数据寄存器reg start_flag ;//波特计数器开启标志信号reg [8:0] cnt_bsp ;//波特率计数器wire add_cnt_bsp ;wire end_cnt_bsp ;reg [3:0] cnt_bit ;//穿输的一帧数据的比特数计数器wire add_cnt_bit ;wire end_cnt_bit ;/*===============================end singal declare=================================*//*======================波特率计数器的开始条件========================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin start_flag <= 1'b0 ;endelse if(dtx_vld)beginstart_flag <= 1'b1 ;endelse if(end_cnt_bit)beginstart_flag <= 1'b0 ;endelse beginstart_flag <= start_flag; endend/*============================结束always模块========================================*//*===============================波特率计数器========================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_bsp <= 9'd0;endelse if(add_cnt_bsp)beginif(end_cnt_bsp)cnt_bsp <= 9'd0;elsecnt_bsp <= cnt_bsp + 9'd1;endelse begincnt_bsp <= 9'd0;//cnt_bsp <= cnt_bsp;//跑飞的情况下选择保持还是清0endendassign add_cnt_bsp = start_flag ; //计数器使能信号设计assign end_cnt_bsp = add_cnt_bsp && cnt_bsp >= T_bsp - 9'd1; //计数器结束信号设计/*==================================================================================*//*=============================传输的bit计数器=======================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_bit <= 4'd0;endelse if(add_cnt_bit)beginif(end_cnt_bit)cnt_bit <= 4'd0;elsecnt_bit <= cnt_bit + 4'd1;endelse begincnt_bit <= cnt_bit;//cnt_bit <= 4'd0;//跑飞的情况下选择保持还是清0endendassign add_cnt_bit = end_cnt_bsp ; //计数器使能信号设计assign end_cnt_bit = add_cnt_bit && cnt_bit >= 10 - 4'd1; //计数器结束信号设计/*==================================================================================*//*=====================给数据进行停止位结束位=========================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin data_reg <= 10'd0;endelse if(add_cnt_bsp)begindata_reg <= {1'b1,data_in,1'b0};//给到开始位停止位endend/*===========================结束always模块=========================================*/ /*===========================使串口发送数据==========================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin TX <= 1'b1 ; // 高电平空闲态endelse if(cnt_bit == 4'd0 && end_cnt_bsp)beginTX <= 1'b0 ; // 低电平开始工作endelse if(end_cnt_bsp == 1 && cnt_bit>4'b0 && cnt_bit < 4'd9)begin//在波特率结束且帧计数器数据在有效范围TX <= data_reg[cnt_bit];endelse if(cnt_bit == 4'd9&& end_cnt_bsp ==1)beginTX <= 1'b1;//一帧数据发送结束endelse beginTX <= TX;endend/*============================结束always模块========================================*/endmodule

二、串口接收模块

1.设计介绍

串口接收模块和串口发送模块相比较多了一个数据打拍和串行数据转并行数据,数据打拍操作是为了防止在数据接收到的时候产生干扰,打拍尽可能的消去数据传送中存在的干扰,也可以得到一个数据接收有效信号,在打拍之后判断是否信号有下降沿来到,作为数据的接收有效信号,串行数据转并行数据的操作可以参考并行数据转串行数据的方法,也可以自己使用不同的方法.

2.源代码

/* == == == == == == == == == ==filename :my_uart_rxdescription:串口接收模块up file :my_uarttips :贯彻自己的理解去思考e-mail:1005916381@author:chenchenchen/*== == == == == == == == == == */ module my_uart_rx(input clk ,input rst_n,input rx ,//接收的数据output reg dtx_vld ,//发送有效信号output reg [7:0] data_out);/*===============================Parameter Declarations=============================*/parameterT_bsp = 434 ;/*===============================end parameter======================================*//*===============================Internal wire/reg declarations=====================*/reg [9:0] cnt_bsp;//波特率计数器wire add_cnt_bsp;wire end_cnt_bsp;reg [3:0] cnt_bit;//一帧数据的比特数计数器wire add_cnt_bit;wire end_cnt_bit;reg uart_r1;//对接收信号进行打拍保证信号的稳定可靠reg uart_r2;//对接收信号进行打拍保证信号的稳定可靠wire nedge ;//对接收信号进行打拍保证信号的稳定可靠reg [9:0] data_reg;//数据寄存器reg flag;/*===============================end singal declare=================================*//*======================波特计数器的开启条件设计======================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin flag <= 1'b0;endelse if(nedge)beginflag <= 1'b1;endelse if(end_cnt_bit)beginflag <= 1'b0;endend/*============================结束always模块========================================*//*=================================波特率计数器,比特数计数器级联=======================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_bsp <= 10'd0;endelse if(add_cnt_bsp)beginif(end_cnt_bsp)cnt_bsp <= 10'd0;elsecnt_bsp <= cnt_bsp + 10'd1;endelse begincnt_bsp <= 'd0;//cnt_bsp <= cnt_bsp;//跑飞的情况下选择保持还是清0endendassign add_cnt_bsp = flag ; //计数器使能信号设计assign end_cnt_bsp = add_cnt_bsp && cnt_bsp >= T_bsp - 10'd1; //计数器结束信号设计always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_bit <= 4'd0;endelse if(add_cnt_bit)beginif(end_cnt_bit)cnt_bit <= 4'd0;elsecnt_bit <= cnt_bit + 4'd1;endelse begincnt_bit <= cnt_bit;//cnt_bit <= 'd0;//跑飞的情况下选择保持还是清0endendassign add_cnt_bit = end_cnt_bsp; //计数器使能信号设计assign end_cnt_bit = add_cnt_bit && cnt_bit >= 10 - 4'd1; //计数器结束信号设计/*==================================================================================*//*============================打两拍信号防止亚稳态====================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin uart_r1 <= 1'b1 ;uart_r2 <= 1'b1 ;endelse beginuart_r1 <= rx;uart_r2 <= uart_r1; endendassign nedge = ~uart_r1 & uart_r2 ;/*============================结束always模块========================================*//*======================串行转并行设计以接收数据的====================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin data_reg <= 10'b0;endelse if(cnt_bsp==1 && data_reg[0]==1'b0)begindata_reg[cnt_bit] <= uart_r2;//将串行数据转换成并行数据endend/*============================结束always模块========================================*//*========================= 串口发送模块的有效信号设计 =============================*/always@(posedge clk or negedge rst_n)begin//数据接收到之后在向上位机发送接受的数据确认是否正确if(!rst_n)begin data_out <= 8'b0;endelse if(end_cnt_bsp)begindata_out <= data_reg[8:1];endend/*============================结束always模块========================================*//*======================发送模块有效信号设计=========================================*/always@(posedge clk or negedge rst_n)beginif(!rst_n)begin dtx_vld <= 1'b0;endelse if(add_cnt_bsp)begindtx_vld <= 1'b1; endelse if(add_cnt_bsp == 0)begindtx_vld <= 1'b0;endelse begindtx_vld <= dtx_vld;endend/*============================结束always模块========================================*/endmodule

三、串口上的现象

总结

使用串口进行通信的时候,两条单向的数据线始终要考虑到他啥时候有效,啥时候接受数据,啥时候发送数据,理清楚了这一点的话,在后续的设计条件的时候就会变得简单一些,需要了解的是串行数据转并行数据以及并行数据转串行数据的操作方法和实现方式.

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。