0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

FPGA学习系列:28. 串口uart设计

FPGA学习交流 2018-08-14 12:05 次阅读

设计背景:

串口是串行接口的简称,也可称为串行通信接口通信协议是指通信双方的一种约定。约定包括对数据格式、同步方式、传送速度、传送步骤、检纠错方式以及控制字符定义等问题做出统一规定,通信双方必须共同遵守。串口通信的两种最基本的方式为:同步串行通信方式和异步串行通信方式。

同步串行通信是指SPISerial Peripheral interface)的缩写,顾名思义就是串行外围设备接口。SPI是一种高速的全双工通信总线。封装芯片上总共有四根线,PCB布局布线也简单,所以现在很多芯片集成了这个协议。主要用于CPU和各种外围器件进行通信TRM450SPI接口。

异步串行通信是指UARTUniversal Asynchronous Receiver/Transmitter),通用异步接收/发送。UART是一个并行输入成为串行输出的芯片,通常集成在主板上。UART包含TTL电平的串口和RS232电平的串口。RS232也称标准串口,也是最常用的一种串行通讯接口。RS-232-C 标准对两个方面作了规定,即信号电平标准和控制信号线的定义。RS-232C 采用负逻辑规定逻辑电平,信号电平与通常的TTL电平也不兼容,RS-232-C -5V-15V 规定为1”,+5V+15V 规定为0”。


设计原理:

uart的示意图如下:


端口对应的功能表如下:


在设计过程中只需要关心RS232_TXD和RS232_RXD两个信号,RS232_TXD是数据发送端口,RS232_RXD是数据接收端口。

本设计将通过串口建立起计算机和实验板(ZX_1)之间的通信和控制关系,也就是通常所说的上下位机通信。要实现这样的通信,首先需要用到一个外部的电平转换芯片MAX232,其具体配置电路原理图如下

image.png


注解:

MAX232芯片是美信(MAXIM)公司专为RS-232标准串口设计的单电源电平转换芯片,使用+5v单电源供电

主要特点:

1、符合所有的RS-232C技术标准

2、只需要单一+5V电源供电

3、片载电荷泵具有升压、电压极性反转能力,能够产生+10V-10V电压V+V-

4、功耗低,典型供电电流5mA

5、内部集成2RS-232C驱动器

6、高集成度,片外最低只需4电容即可工作

本设计还需要分析在通信过程中,UART所对应的数据格式,

起始位:线路空闲时为高电平,当截获第一个低电平比特时,则为起始位;

信息位:在起始位之后,按照低位首发原则,顺序发送信息位的最低位到最高位,信息位的宽度可以是45678中的一个;

奇偶校验位:信息位之后则是一个可选的奇偶校验位,它可以是无校验(NONE)、奇校验(ODD)、偶校验(EVEN)中的任意一个,无校验时,信息位之后就是停止位。奇偶校验是,使得信息位和校验位的所有1的个数保持奇数或者偶数

停止位:停止位的长度可以是11.52中的任意一个,它为高电平;

空闲位:持续的高电平;

波特率:每秒传输的数据位(bit)数为波特率。RS-232-C的波特率可以是5075100150300600120024004800960019200波特。

通过分析上述的数据格式,在本设计中,将波特率设置为9600,起始位设置为1比特,信息位设置为8比特,奇偶校验位设置为0比特,停止位设置为2比特,空闲位设置为1比特

因为在设计中只需要关注RS232_TXDRS232_RXD这两个信号,,既然只有两条线,所以只需要关注其数据收发时序即可,时序图如下:

image.png


设计架构图:

设计架构图如下

image.png


uart_pll模块是一个锁相环,通过50M的外部时钟ref_clk),倍频得到100M的上游接口的100M系统时钟(sys_clk);divider模块为UART的分频模块,通过用100Msys_clk作为输入,分频得到波特率为9600uart_clk时钟。

transmitter模块为串口发送模块,并配合与其对应的trans_fifo发送数据缓存FIFO进行使用,将储存在FIFO中的数据通过RS232-C协议发送出去;

receiver模块为串口接收模块,并配合与其对应的rec_fifo接收数据缓存FIFO进行使用,将储存在FIFO中的数据通过RS232-C协议接收进来;


UART发送器(transmitter)设计

UART发送器的时序如下图:

image.png


根据对UART发送器时序的分析可以得到如下的状态转移表(SMF:

image.png


UART接收器receiver)设计

根据对UART时序的分析可以得到如下的状态转移表(SMF):

image.png


设计代码:

根据上述的两个状态转移表则可得到如下的代码,transmitter模块代码:

0//uart发送模块LSM(线性序列机)

1moduletransmitter(clk,rst_n,empty,data,rdreq,txd);

2

3inputclk,rst_n;//输入时钟复位

4inputempty;//来自fifo的输入空标志信号

5input[7:0]data;//来自fifo的输入数据

6outputregrdreq;//输出到fifo的读请求

7outputregtxd;//输出发送线信号

8

9reg[7:0]temp;//中间寄存器

10reg[7:0]count;//8位计数

11

12`defineEP 192//终止符

13

14always@(posedgeclk ornegedgerst_n)

15begin:lsm_2s1 //线性序列机一段闭节点

16if(!rst_n)//复位

17count <=`EP;

18elseif((count >=`EP)&&!empty)//计数大于终止符和非空(empty=0

19count <=0;

20elseif(count <`EP)//计数小于终止符

21count <=count +1;

22end

23

24always@(posedgeclk ornegedgerst_n)

25begin:lsm_2s2 //线性序列机一段闭节点

26if(!rst_n)//复位

27begin

28txd <=1;//发送线为高

29rdreq <=0;//读请求为0

30temp <=0;//中间寄存器为0

31end

32elseif((count >=`EP)&&!empty)//计数大于终止符fifo为非空,读请求拉高

33rdreq <=1;

34else

35case(count)

360:begin

37rdreq <=0;//读请求拉低

38txd <=0;

39end

401:temp[7:0]<=data[7:0];//输入数据给中间寄存器

411*16:txd <=temp[0];//中间寄存器按位给发送线发送

422*16:txd <=temp[1];

433*16:txd <=temp[2];

444*16:txd <=temp[3];

455*16:txd <=temp[4];

466*16:txd <=temp[5];

477*16:txd <=temp[6];

488*16:txd <=temp[7];

499*16:txd <=1;//拉高

50endcase

51end

52

53endmodule


transmitter(发送)模块的测试代码:

0`include"uart_lsm_head.v"

1

2moduletransmitter_tb;

3

4regclk,rst_n;

5regempty;

6reg[7:0]data;

7wirerdreq;

8wiretxd;

9

10reg[7:0]temp;

11

12transmitter transmitter_dut(

13.clk(clk),

14.rst_n(rst_n),

15.empty(empty),

16.data(data),

17.rdreq(rdreq),

18.txd(txd)

19);

20

21initialbegin

22clk =1;

23rst_n =0;

24data =0;

25empty =1;

26temp =0;

27#200.1rst_n =1;

28

29#200.1empty=1;temp=8'h55;

30#`TBAUD_RATE

31data[0]=temp[0];//发送第一个信息位(LSB

32#`TBAUD_RATE

33data[1]=temp[1];

34#`TBAUD_RATE

35data[2]=temp[2];

36#`TBAUD_RATE

37data[3]=temp[3];

38#`TBAUD_RATE

39data[4]=temp[4];

40#`TBAUD_RATE

41data[5]=temp[5];

42#`TBAUD_RATE

43data[6]=temp[6];

44#`TBAUD_RATE

45data[7]=temp[7];

46#`TBAUD_RATE

47empty =0;

48#2000$stop;

49end

50

51always#`TUART_CLK_HALFclk =~clk;

52

53endmodule


receiver模块代码:

0`include"uart_lsm_head.v"

1

2modulereceiver(clk,rst_n,data,wrreq,rxd);//uart接收模块LSM(线性序列机)

3

4inputclk,rst_n;//输入时钟复位

5outputreg[7:0]data;//输出数据

6outputregwrreq;//输出写请求

7inputrxd;//输入接收线信号

8

9reg[7:0]count;

10//宏定义

11`defineEP 184//终止符

12`defineGET0 24

13`defineGET1 `GET0+16

14`defineGET2 `GET1+16

15`defineGET3 `GET2+16

16`defineGET4 `GET3+16

17`defineGET5 `GET4+16

18`defineGET6 `GET5+16

19`defineGET7 `GET6+16

20`defineGETW `GET7+16//wrreq=1

21`defineGLRW `GETW+1//wrreq=0

22

23always@(posedgeclk ornegedgerst_n)

24begin:lsm_2s1 //线性序列机一段闭节点

25if(!rst_n)

26count <=`EP;

27elseif((count >=`EP)&&!rxd)//rxd=0

28count <=0;

29elseif(count <`EP)

30count <=count +1;

31end

32

33always@(posedgeclk ornegedgerst_n)

34begin:lsm_2s2 //线性序列机二段闭节点

35if(!rst_n)

36begin

37data <=0;

38wrreq <=0;//写请求为0

39end

40else

41case(count)

42`GET0:data[0]<=rxd;//将接收的数据通过data输出

43`GET1:data[1]<=rxd;

44`GET2:data[2]<=rxd;

45`GET3:data[3]<=rxd;

46`GET4:data[4]<=rxd;

47`GET5:data[5]<=rxd;

48`GET6:data[6]<=rxd;

49`GET7:data[7]<=rxd;

50`GETW:wrreq <=1;//写请求拉高一拍,写进fifo

51`GLRW:wrreq <=0;//一拍后写请求为0

52endcase

53end

54

55endmodule


receiver(接收)模块的测试代码:

0`include"uart_lsm_head.v"

1

2modulereceiver_tb;

3

4regclk,rst_n;

5regrxd;

6wire[7:0]data;

7wirewrreq;

8

9reg[7:0]temp;//8位的中间寄存器,产生激励

10

11receiver receiver_dut(

12.clk(clk),

13.rst_n(rst_n),

14.data(data),

15.wrreq(wrreq),

16.rxd(rxd)

17);

18

19initialbegin

20clk =1;

21rst_n =0;

22temp =0;

23rxd =1;

24#`TEN_TUART_CLK//*代表异步 //10uart_clk周期

25rst_n =1;

26

27#`TEN_TUART_CLK//启动一个停止位

28rxd =0;

29temp =8'h55;

30#`TBAUD_RATE//数据使用波特率的周期

31rxd =temp[0];//发送一个信息位(LSB

32#`TBAUD_RATE

33rxd =temp[1];

34#`TBAUD_RATE

35rxd =temp[2];

36#`TBAUD_RATE

37rxd =temp[3];

38#`TBAUD_RATE

39rxd =temp[4];

40#`TBAUD_RATE

41rxd =temp[5];

42#`TBAUD_RATE

43rxd =temp[6];

44#`TBAUD_RATE

45rxd =temp[7];//发送最后一个信息位(HSB

46#`TBAUD_RATE

47rxd =1;

48

49#`TUART_CLK100$stop;//100uart_clk周期

50end

51

52always#`TUART_CLK_HALFclk =~clk;// uart_clk 的时钟,使用uart_clk的半周期

53

54endmodule


参数宏的头文件代码:

0/////uart_lsm_head.v

1

2//////////定义时标////////////

3`timescale1us/1ns

4

5/////////定义设计参数/////////

6`defineBAUD_RATE 9600//波特率=9600

7`defineSYS_CLK 100000000//系统时钟sys_clk 频率=100M

8`defineREF_CLK 50000000//系统时钟ref_clk频率=50M

9

10//////////使用宏自动计算的诸参数////////////

11`defineTBAUD_RATE (1000000.0/`BAUD_RATE)//波特率周期

12`defineUART_CLK (16*`BAUD_RATE)//uart_clk 等于16倍波特率

13`defineTUART_CLK (1000000.0/`UART_CLK)//uart_clk周期

14`defineTEN_TUART_CLK (10.0*`TUART_CLK)//10uart_clk周期

15`defineTUART_CLK100 (100.0*`TUART_CLK)//100uart_clk周期

16

17`defineTUART_CLK_HALF (`TUART_CLK/2.0)//uart_clk半周期

18`defineTREF_CLK (1000000.0/`REF_CLK)//参考时钟周期

19`defineTREF_CLK_HALF (`TREF_CLK/2.0)//参考时钟半周期

20

21//////////使用宏自动计算的分频数(占空比50%////////////

22`defineDW (`SYS_CLK/(2*`UART_CLK))


顶层文件代码:

0`include"uart_lsm_head.v"

1

2moduleuart_lsm(ref_clk,global_reset,tdata,twrreq,

3tfull,rdata,rrdreq,rempty,uart_txd,uart_rxd);

4

5inputref_clk,global_reset;//全局时钟复位

6input[7:0]tdata;//发送fifo输入数据

7inputtwrreq;//发送fifo写请求

8outputtfull;//发送fifo输出写满

9output[7:0]rdata;//接收fifo输出数据

10inputrrdreq;//接收fifo的输入读请求

11outputrempty;//接收fifo的输出入空

12outputuart_txd;//输出发送线信号

13inputuart_rxd;//输入接收线信号

14

15wiretrxd;

16

17wire[7:0]tf_data,rf_data;

18wiretf_rdreq,tf_empty,rf_wrreq;

19wiresys_clk,uart_clk,rst_n;

20

21

22assignrst_n =~global_reset;

23

24trans_fifo t_fifo(//发送fifo

25.data(tdata),

26.rdclk(uart_clk),

27.rdreq(tf_rdreq),

28.wrclk(sys_clk),

29.wrreq(twrreq),

30.q(tf_data),

31.rdempty(tf_empty),

32.wrfull(tfull)

33);

34

35transmitter trans(//发送模块

36.clk(uart_clk),

37.rst_n(rst_n),

38.empty(tf_empty),

39.data(tf_data),

40.rdreq(tf_rdreq),

41.txd(trxd)

42);

43

44rec_fifo r_fifo(//接收fifo

45.data(rf_data),

46.rdclk(sys_clk),

47.rdreq(rrdreq),

48.wrclk(uart_clk),

49.wrreq(rf_wrreq),

50.q(rdata),

51.rdempty(rempty)

52);

53

54receiver rece(//接收模块

55.clk(uart_clk),

56.rst_n(rst_n),

57.data(rf_data),

58.wrreq(rfwrreq),

59.rxd(trxd)

60);

61

62uart_pll u_pll(//锁相环产生系统时钟,作用于fifodivider

63.areset(global_reset),

64.inclk0(ref_clk),

65.c0(sys_clk)

66);

67

68divider_ebd_1s_mealy //分频模块分频uart_clk,作用于receiver transmitter

69#(.HW(`DW),.LW(`DW))

70div(

71.clk_in(sys_clk),

72.rst_n(rst_n),

73.clk_out(uart_clk)

74);

75

76endmodule

仿真:

分别为发送和接收做仿真测试,发送的仿真波形如下:

image.png


接收的仿真波形如下:

image.png


根据以上两个仿真波形,可以发现设计是正确的,之后则可利用串口猎人的上位机软件,实现自发自收。




声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FPGA
    +关注

    关注

    1592

    文章

    21207

    浏览量

    592139
收藏 人收藏

    评论

    相关推荐

    UART串口通信协议是什么?

    UART (Universal Asynchronous Receiver/Transmitter) 是一种通信接口协议,用于实现串口通信。它是一种简单的、可靠的、广泛应用的串口通信协议。它是由美国
    的头像 发表于 03-19 17:26 135次阅读

    fpga学习需要具备哪些课程

    FPGA(Field Programmable Gate Array)学习需要具备一系列的课程知识和实践技能
    的头像 发表于 03-14 15:51 159次阅读

    什么是串口(UART)?串口的组成和FPGA实现

    串口作为常用的三大低速总线(UART、SPI、IIC)之一,在设计众多通信接口和调试时占有重要地位。
    的头像 发表于 01-03 11:43 857次阅读
    什么是<b class='flag-5'>串口</b>(<b class='flag-5'>UART</b>)?<b class='flag-5'>串口</b>的组成和<b class='flag-5'>FPGA</b>实现

    stc32G12k128使用旧清翔51实验板学习UART通信实验

    stc32G12k128使用旧清翔51实验板学习UART通信实验程序,利用旧版,学习32位单片机的串口通信例程
    发表于 11-21 10:21 2次下载

    什么通信协议?UART自定义通信协议代码实现方法

    我们学习单片机,首先接触的可能是点灯(GPIO),再次就是串口UART)。
    的头像 发表于 11-02 09:03 757次阅读
    什么通信协议?<b class='flag-5'>UART</b>自定义通信协议代码实现方法

    MT7628/7688 openwrt下启用串口2 UART2入坑指南

    【入坑】MT7628/7688有3个串口, UART0,UART1和UART2, 但使用UART2 时碰到一些问题, MT7628/76
    的头像 发表于 10-30 09:37 3030次阅读
    MT7628/7688 openwrt下启用<b class='flag-5'>串口</b>2 <b class='flag-5'>UART</b>2入坑指南

    F030系列芯片UART3~UART6代码分享

    看了大家对F030复用串口的疑惑,这里继续给出“当同时使用UART3~UART6中的多个串口时,由于其中断响应函数都是同一个,需要自己在中断函数USART3_6_IRQHandler(
    的头像 发表于 10-13 14:14 563次阅读
    F030<b class='flag-5'>系列</b>芯片<b class='flag-5'>UART</b>3~<b class='flag-5'>UART</b>6代码分享

    MM32F0140 UART学习笔记

    MM32F0140 UART学习笔记
    的头像 发表于 09-26 16:45 383次阅读
    MM32F0140 <b class='flag-5'>UART</b><b class='flag-5'>学习</b>笔记

    串口通信学习笔记

    串口似乎是一个比较模糊的概念,UART、COM口、RS-232、RS-485等名称有时都会被称作串口,但是从应用电路上看,三者又显然存在差异。个人理解,我们通常所说的串口是使用串行通信
    发表于 09-20 15:23 290次阅读
    <b class='flag-5'>串口</b>通信<b class='flag-5'>学习</b>笔记

    嵌入式系统串口UART接口为啥没有数据输出

    点击关注,电磁兼容不迷路。1.简单解释SOC的串口UART接口做啥用雷卯大家常说嵌入式里面的串口,一般是指UART(UniversalAsynchronousReceiverTrans
    的头像 发表于 08-16 11:47 510次阅读
    嵌入式系统<b class='flag-5'>串口</b><b class='flag-5'>UART</b>接口为啥没有数据输出

    使用uart通信时,通过串口助手软件发送到FPGA并不能触发中断的原因?

    在使用uartuart0、uart1、uart2)通信时,uart通过中断处理uart接收函数
    发表于 08-16 08:20

    ESP32学习笔记:串口

    ESP32 芯片有3 个UART 接口,UART0,UART1,UART2,支持异步通信和 IrDA,通信速度最高可达 5Mbps,3 个接口可以被 DMA 或 CPU 直接访问,3
    的头像 发表于 07-13 17:09 1790次阅读
    ESP32<b class='flag-5'>学习</b>笔记:<b class='flag-5'>串口</b>

    【教程分享】FPGA零基础学习UART协议驱动设计

    系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以
    的头像 发表于 06-27 08:20 499次阅读

    实现上位机与FPGA uart交互

    目的:实现上位机与FPGAuart交互 开发环境:quatus prime 18.1,芯片 altera :EP4CE15F23C8。 实验现象: 1.使用uart:bps=9600(参数可调整
    发表于 05-08 10:28 2次下载
    实现上位机与<b class='flag-5'>FPGA</b> <b class='flag-5'>uart</b>交互

    FPGA说起的深度学习:数据并行性

    这是新的系列教程,在本教程中,我们将介绍使用 FPGA 实现深度学习的技术,深度学习是近年来人工智能领域的热门话题。
    的头像 发表于 05-04 11:22 673次阅读
    从<b class='flag-5'>FPGA</b>说起的深度<b class='flag-5'>学习</b>:数据并行性