【FPGA学习笔记】之 UART模块

1.关于URAT的知识

2.UART模块设计中涉及到的状态机的知识

3.UART模块的编写:以UART_TX为例

4.UART模块的使用

============================================================================

1.关于UART的知识

(1)硬件工作原理及概念介绍
UART : Universal Asynchronous Receiver/Transmitter,通用异步接收/发送器,也就是通常所说的串口,是一种通用串行数据传输总线,可以实现全双工传输。

       在嵌入式领域,UART已经是一种最基本的模块,其发送和接收是两个完全独立的通路, 分别是发送“TX” 和接收“RX“通道,既然是独立的通路,发送和接收端又没有时钟参考,所以从协议上规定了串行通信必须按一定的数据速率来接收和发送,这个速率定义为 ”波特率“,即每秒发送的数据的位数。 常用的波特率有:9600/38400/57600/115200……, 波特率确定后,每一位所占用的时间就可以计算出来,例如:115200bps, 每一位的周期为:1/115200 = 8.68us, 因此用我们开发板上的计数器对外部50MHz进行计数的话,8680ns / 20ns = 1B2
(2)帧结构

       下面我们来看一下一个完整的数据帧,第一位为开始位,始终为0,最后一位为停止位,始终为1

=======================================================================================

2.UART模块设计中涉及到的状态机的知识

状态机:通过不同的状态迁移来实现一种顺序逻辑控制。一般有Mealy型和Moore型两种,写法一般有两端式和三段式,这里

采用三段式:即  D触发器 +  状态变换 +  指令控制,转换关系如下图所示:

 

 

===================================================================================

3.UART模块的编写:以UART_TX为例

程序编写涉及到两个部分:波特率的的控制,帧数据的状态机构成

(1)波特率的控制: 

//状态转换所需的控制信号.
assign BAUD_RATE   = (CLK_DIV_CNT == 16'h1B2);
assign TX_FINISH   = (TX_CS == IDLE);
assign DATA_FINISH = (TX_BIT_CNT == 3'h7);

//波特率的设置.
always @ (posedge SYSCLK or negedge RST_B)
begin
  if(!RST_B)
     CLK_DIV_CNT       <= `UD 16'h0;
  else
     CLK_DIV_CNT       <= `UD CLK_DIV_CNT_N;
end

always @ (*)
begin
  if(TX_FINISH)
     CLK_DIV_CNT_N   = 16'h0;
  else if(CLK_DIV_CNT == 16'h1B2)//baud rate is 115200
     CLK_DIV_CNT_N   = 16'h0;
  else
     CLK_DIV_CNT_N   = CLK_DIV_CNT + 16'h1;
end

//计算8位发送数据的位数,在状态Send_Data中将8位数据转换成串行数据.
always @ (posedge SYSCLK or negedge RST_B)
begin
  if(!RST_B)
     TX_BIT_CNT       <= `UD 3'h0;
  else
     TX_BIT_CNT       <= `UD TX_BIT_CNT_N;
end

always @ (*)
begin
  if(!TX_EN)
     TX_BIT_CNT_N    = 3'h0;

  else if((TX_BIT_CNT == 3'h7) && (BAUD_RATE))
     TX_BIT_CNT_N    = 3'h0;
  else if((TX_CS == SEND_DATA) && (BAUD_RATE))
     TX_BIT_CNT_N    = TX_BIT_CNT + 3'h1;
  else 
     TX_BIT_CNT_N    = TX_BIT_CNT;
end

//计算TX_EN置1时IDLE到SEND_START的缓冲的时间.
always @ (posedge SYSCLK or negedge RST_B)
begin
  if(!RST_B)
     TIME_CNT       <= `UD 4'h0;
  else
     TIME_CNT       <= `UD TIME_CNT_N;
end

always @ (*)
begin
  if(TX_CS != IDLE)
     TIME_CNT_N   = 4'h0;
  else
     TIME_CNT_N   = TIME_CNT + 4'h1;
end

 

(2)帧数据的状态机构成 

//D触发器段,存储状态值
always
@ (posedge SYSCLK or negedge RST_B) begin if(!RST_B) TX_CS <= `UD IDLE; else TX_CS <= `UD TX_NS; end
//状态转换段
always @ (*) begin case(TX_CS) IDLE : if((TX_EN)&&(TIME_CNT == 4'hF))// && BAUD_RATE) TX_NS = SEND_START; else TX_NS = TX_CS; SEND_START : if(BAUD_RATE) TX_NS = SEND_DATA; else TX_NS = TX_CS; SEND_DATA : if(DATA_FINISH && BAUD_RATE) TX_NS = SEND_STOP; else TX_NS = TX_CS; SEND_STOP : if(BAUD_RATE) TX_NS = SEND_END; else TX_NS = TX_CS; SEND_END : TX_NS = IDLE; default : TX_NS = IDLE; endcase end always @ (posedge SYSCLK or negedge RST_B) begin if(!RST_B) UART_TX <= `UD 1'h1; else UART_TX <= `UD UART_TX_N; end //指令控制段 always @ (*) begin if(TX_EN) begin case(TX_CS) IDLE : UART_TX_N = 1'h1; SEND_START : UART_TX_N = 1'h0; SEND_DATA : case(TX_BIT_CNT) 3'h0 : UART_TX_N = TX_DATA[0]; 3'h1 : UART_TX_N = TX_DATA[1]; 3'h2 : UART_TX_N = TX_DATA[2]; 3'h3 : UART_TX_N = TX_DATA[3]; 3'h4 : UART_TX_N = TX_DATA[4]; 3'h5 : UART_TX_N = TX_DATA[5]; 3'h6 : UART_TX_N = TX_DATA[6]; 3'h7 : UART_TX_N = TX_DATA[7]; default: UART_TX_N = 1'h1; endcase SEND_STOP : UART_TX_N = 1'h1; default : UART_TX_N = 1'h0; endcase end else UART_TX_N = 1'h1; end

 

 至此完成UART_TX发送模块的核心代码,我发现涉及到硬件驱动的都用状态机加时序控制来实现数据的传输. 

-------------------------------------------------------------------------------------------------------------

UART模块编写特点:

1.内部逻辑一共用三个寄存器:状态机状态 TX_CS、      波特率计数 CLK_DIV_CNT、          串行数据位数 BIT_CNT

   输出口用了一个寄存器:  UART串口发送端 UART_TX

2.虽然状态不同,但是步调一致,每次状态的改变用CLK_DIV_CNT与BAUD_RATE相互配合

 =================================================================================

4.UART模块的使用

(1)UART_TX.V

 

UART_TX I_UART_TX      //UART_TX模块
    (
    .SYSCLK        (SYSCLK),
    .RST_B        (RST_B),
    .TX_DATA    (TX_DATA),      //输入:要发送的数据
    .TX_EN        (TX_EN),      //输入:发送使能端
    .UART_TX    (UART_TX),     //输出:串行发送端
    .TX_FINISH    (TX_FINISH)   //输出:发送结束标志
    );

 

 

附:更改波特率改该模块下语句中的数据16‘h1b2

always @ (*)
begin
  if(TX_FINISH)
    CLK_DIV_CNT_N   = 16'h0;
  else if(CLK_DIV_CNT == 16'h1B2)    //baud rate is 115200
    CLK_DIV_CNT_N   = 16'h0;
  else
    CLK_DIV_CNT_N   = CLK_DIV_CNT + 16'h1;
end
assign BAUD_RATE   = (CLK_DIV_CNT == 16'h1B2);
 
 

 

转载于:https://www.cnblogs.com/Dingstart/p/5326721.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值