【精品博文】串口接收模块电路设计

概述

串口通信指串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。这里主要讲解串口接收模块的电路设计。

图1 串口传输时序图

如图1所示为串口传输时序图,空闲时刻数据线线路一直处于高电平状态(即逻辑1)。当有数据传送时,数据帧从起始位开始,到停止位结束。起始位为低电平(即逻辑0),停止位为高电平。一帧数据包括1位起始位,8位数据位,1位校验位以及1位停止位,总计11位。

本文分两个模块来讲解,一个是时钟模块(这里假设通信速率是9600bps),一个是串口接收模块。

时钟模块

FPGA主频一般比较高(这里以50M为例),而串口通信速度又很慢(9600),这里就需要设计一个分频模块。那么分频多少合适呢?是直接分频到9600呢?还是多少呢?这里分频的主要目的是为后面的采样提供一个时钟,而采样肯定是在数据保持稳定的时候采样最佳。那什么时候采样数据才是稳定的呢?没错,就是在每位数据的中间时刻采样最稳定。那么问题来了,如何确定每位数据的中间时刻呢?

我们知道传输速率是9600,要保证在数据中间时刻采样,那么分频肯定比9600大。假设我们分频后的频率为9600*16,那么我们在9600*8的时刻采样基本上可以算是中间时刻采样了。如图2所示,分频时钟频率为数据传输速率的16倍,在其8倍时刻采样,可近似为数据中间时刻采样。

图2 数据中间时刻采样

串口接收模块

这里采用状态机来设计串口接收模块。首先根据串口通信的特性定义5个状态,分别为:空闲状态、起始~、数据接收~、校验~、停止~。

初始化为空闲状态,当检测到数据线拉低的时候,进入起始状态。在起始状态需要判断信号线是真的拉低了还是由于其它原因导致的错误信号。若确认为拉低起始标志信号,则在“下一个时钟”进入数据接收状态,这里需要连续接收八位数据,然后进入校验状态。由于我们自己写的串口大多速率低,传输数据量小,要求也不是特别高,所以很多时候都没有用校验位,也就是说,校验位可以不采样,直接跳过进入停止位。停止状态接收到的数据肯定是1,否则说明这个设计有问题。停止状态之后再次回到空闲状态,等待下一次的数据接收。

源码

分频模块较简单,这里只贴出接收模块的代码:

module uart_r

(

clk,  //50M

rst_n,

clk_dev, //9600 * 16

uart_rxd,

cnt,

state,

cnt_data,

rxd_data

);

input clk, rst_n, clk_dev;

input uart_rxd; //串口输入数据

output [3:0]cnt;

output [2:0]state, cnt_data;

output [7:0]rxd_data;

reg [7:0]rxd_data;

//*********检测clk_dev上升沿***************

reg clkr0, clkr1;

always@(posedge clk or negedge rst_n)

begin

if(!rst_n)

begin

clkr0 <= 0;

clkr1 <= 0;

end

else

begin

clkr0 <= clk_dev;

clkr1 <= clkr0;

end

end

wire clk_devp = (~clkr1 & clkr0) ? 1'b1 : 1'b0;

//*****************************************

localparam IDLE = 3'd0;

localparam STAR = 3'd1;

localparam RECEIVE = 3'd2;

localparam CHECK = 3'd3;

localparam STOP = 3'd4;

localparam cnt_center = 4'd7;

localparam cnt_top = 4'd15;

reg [3:0]cnt; //clk_dev上升沿计数

reg [2:0]state; //串口状态

reg [2:0]cnt_data; //接收数据计数

always@(posedge clk or negedge rst_n)

begin

if(!rst_n)

begin

cnt <= 0;

state <= IDLE;

cnt_data <= 0;

end

else

begin

case(state)

IDLE:

begin

cnt <= 0;

cnt_data <= 0;

if(uart_rxd)

state <= IDLE;

else

state <= STAR;

end

STAR:

begin

if(clk_devp)

begin

cnt <= cnt + 1'b1;

if((cnt == cnt_center) && (uart_rxd)) //数据无效

state <= IDLE;

else if(cnt == cnt_top)

begin

cnt <= 0;

state <= RECEIVE;

end

end

end

RECEIVE:

begin

if(clk_devp)

begin

cnt <= cnt + 1'b1;

if(cnt == cnt_top) //接收一位数据

begin

cnt <= 0;

if(cnt_data < 3'd7)

cnt_data <= cnt_data + 1'b1;

else

begin

cnt_data <= 3'd7;

state <= CHECK;

end

end

else

begin

state <= RECEIVE;

cnt_data <= cnt_data;

end

end

end

CHECK:

begin

if(clk_devp)

begin

cnt <= cnt + 1'b1;

if(cnt == cnt_top)

begin

cnt <= 0;

state <= STOP;

end

else

state <= state;

end

end

STOP:

begin

if(clk_devp)

begin

cnt <= cnt + 1'b1;

if(cnt == cnt_top)

begin

cnt <= 0;

state <= IDLE;

end

else

state <= state;

end

end

default: state <= IDLE;

endcase

end

end

//********************

always@(posedge clk or negedge rst_n)

begin

if(!rst_n)

begin

rxd_data <= 0;

end

else if((cnt == cnt_center) && (state == RECEIVE) && (clk_devp))

begin

case(cnt_data)

3'd0 : rxd_data[0] <= uart_rxd;

3'd1 : rxd_data[1] <= uart_rxd;

3'd2 : rxd_data[2] <= uart_rxd;

3'd3 : rxd_data[3] <= uart_rxd;

3'd4 : rxd_data[4] <= uart_rxd;

3'd5 : rxd_data[5] <= uart_rxd;

3'd6 : rxd_data[6] <= uart_rxd;

3'd7 : rxd_data[7] <= uart_rxd;

default: rxd_data <= 0;

endcase

end

end

endmodule

(0)

相关推荐

  • 一天一个设计实例-3万字讲解UART和实例

    用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART.它将要传输的资料在串行通信与并行通信之间加以转换.作为把并行输入信号转成串 ...

  • 凔海笔记之FPGA(八):Verilog描述RS232 UART

    在我看来,有些代码会用,但未必理解,有些代码理解,但未必会写,有些代码会写,但未必能用自己的话说出来.当能够以自己的想法深入浅出的讲解所学知识,那也就可以说自己掌握了,所以,我还是来发帖吧. 记得刚用 ...

  • 连载-iMX6ULL 软件定制应用笔记 -9个知识点讲解

    接上篇: 连载-iMX6ULL 软件定制应用笔记 -3个常见问题解决思路   点击了解 本文以飞凌OKMX6ULL-S开发板为基础讲解,系统为Linux,一共总结了14个iMX6ULL小知识点,分三期 ...

  • 串口协议FPGA实现

    嵌入式专栏 152篇原创内容 公众号 来源 | 电子电路开发学习 标准串口协议的Verilog实现 基于Verilog实现标准串口协议发送8位数据:起始位 + 8位数据位 + 校验位 + 停止位 = ...

  • 一天一个设计实例-基于FPGA的模数转换器应用设计

    基于FPGA的模数转换器应用设计 1.1.1八通道AD7606应用设计 7.3.1.1 AD7606简介 AD7606 是一款集成式 8 通道数据采集系统,片内集成输入放大器.过压保护电路.二阶模拟抗 ...

  • 【精品博文】FPGA串口通信及数据解析

    之前博客中介绍过FPGA中uart的实现,最近做了一个上位机,用于控制红外相机的工作状态,当然,协议也是自定义的.界面如下,包含相机校正算法的选择.图像增强算法参数的调整.不同算法的切换.参数的调整以 ...

  • 【精品博文】详细解析基于FPGA的串口通信

    赢一个双肩背包 有多难? 戳一下试试看! →_→ 长摁识别 [主题]:详细解析基于FPGA的串口通信 [作者]:LinCoding [时间]:2016.11.28 串口通信,用的实在太广泛了,原理也很 ...

  • 【精品博文】基于FPGA的串口通信时序设计

    这篇博文主要总结一下串口通信的收发时序.上周基于IIC,SPI,RS232串口写了几个简单的小实验,感觉对于这种常用协议的写法大体上都差不多,主要是读懂时序图,然后根据时序图,用HDL语言描述出来就可 ...

  • 【精品博文】嵌入式开发中串口配置知多少

    串口是计算机一种常用的接口,常用的串口有RS-232-C接口.它是于1970年由美国电子工业协会(EIA)联合贝尔系统.调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准,它的全称是&qu ...

  • 【精品博文】干货|一个工科生的职业规划(转)

    我今年39岁了,25岁研究生毕业,工作14年,回头看看,应该说走了不少的弯路,有一些经验和教训.现在开一个小公司,赚的钱刚够养家糊口的.看看这些刚毕业的学生,对前景也很迷茫,想抛砖引玉,谈谈自己的看法 ...

  • 【精品博文】一种借助EBR实现数据延时的方法

    数据延时线(Delay Line)在数字信号处理中具有广泛的应用,例如FIR滤波器设计中就会需要用到数据延时线.实际上,在绝大部分的Pipeline设计中都会需要用到数据延时.本文介绍一种基于EBR( ...

  • 【精品博文】PWM蜂鸣器驱动之引脚分配

    【精品博文】PWM蜂鸣器驱动之引脚分配

  • 【精品博文】聊一聊数字电路中时钟抖动

    随着通信系统中的时钟速率迈入GHz级,抖动这个在模拟设计中十分关键的因素,也开始在数字设计领域中日益得到人们的重视.在高速系统中,时钟或振荡器波形的时序误差会限制一个数字I/O接口的最大速率.不仅如此 ...

  • 【精品博文】MIPI扫盲——DSI介绍(二)

    目录篇地址:http://blog.chinaaet.com/justlxy/p/5100052503  这一篇来简单的介绍一下MIPI DSI Video Mode的三种操作模式: Non-Busr ...