串口UART

今天主要记录一下使用黑金开发板EP4CE6F17C8型号的串口的经历。因为这块黑金开发板只有usb转串口,所以实验使用的是USB转串口的通信。如下图:


一、任务:采用串口调试助手发送指令控制开发板上面的LED0打开和关闭。
二、实现的RTL图如下:

三、代码实现过程
1、顶层模块uart_top

module uart_top(input           sys_clk,          //外部50M时钟input           sys_rst_n,        //外部复位信号,低有效//uart接口input           uart_rxd,         //UART接收端口output          uart_txd,         //UART发送端口output           led);//parameter define
parameter  CLK_FREQ = 50000000;       //定义系统时钟频率
parameter  UART_BPS = 115200;         //定义串口波特率//wire define
wire       uart_en_w;                 //UART发送使能
wire [7:0] uart_data_w;               //UART发送数据
wire       led_open_flag;                 //串口接收到打开led的标记
wire       led_close_flag;                //串口接收到关闭led的标记
wire       clk_1m_w;                  //1MHz时钟,用于Signaltap调试//*****************************************************
//**                    main code
//*****************************************************
clk_div u_pll(                        //时钟分频模块,用于调试.inclk0         (sys_clk),.c0             (clk_1m_w)
);uart_recv #(                          //串口接收模块.CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率.UART_BPS       (UART_BPS))       //设置串口接收波特率
u_uart_recv(                 .sys_clk        (sys_clk), .sys_rst_n      (sys_rst_n),.uart_rxd       (uart_rxd),.uart_done      (uart_en_w),.uart_data      (uart_data_w),.led_open_flag  (led_open_flag),.led_close_flag  (led_close_flag));uart_send #(                          //串口发送模块.CLK_FREQ       (CLK_FREQ),       //设置系统时钟频率.UART_BPS       (UART_BPS))       //设置串口发送波特率
u_uart_send(                 .sys_clk        (sys_clk),.sys_rst_n      (sys_rst_n),.uart_en        (uart_en_w),.uart_din       (uart_data_w),.uart_txd       (uart_txd));led    led_u1(.clk                 (sys_clk        ),.rst_n                    (sys_rst_n      ),.led_open_flag            (led_open_flag  ),.led_close_flag           (led_close_flag  ),.led                 (led            )
);
endmodule

2、串口接收模块uart_recv

module uart_recv(input               sys_clk,                  //系统时钟input             sys_rst_n,                //系统复位,低电平有效input             uart_rxd,                 //UART接收端口output  reg       uart_done,                //接收一帧数据完成标志信号output  reg [7:0] uart_data,                 //接收的数据output  reg      led_open_flag,                  //打开led的标记output  reg       led_close_flag                  //关闭led的标记     );//parameter define
parameter  CLK_FREQ = 50000000;                 //系统时钟频率
parameter  UART_BPS = 9600;                     //串口波特率
localparam BPS_CNT  = CLK_FREQ/UART_BPS;        //为得到指定波特率,//需要对系统时钟计数BPS_CNT次
//reg define
reg        uart_rxd_d0;
reg        uart_rxd_d1;
reg [15:0] clk_cnt;                             //系统时钟计数器
reg [ 3:0] rx_cnt;                              //接收数据计数器
reg        rx_flag;                             //接收过程标志信号
reg [ 7:0] rxdata;                              //接收数据寄存器//wire define
wire       start_flag;//*****************************************************
//**                    main code
//*****************************************************
//捕获接收端口下降沿(起始位),得到一个时钟周期的脉冲信号
assign  start_flag = uart_rxd_d1 & (~uart_rxd_d0);    //对UART接收端口的数据延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) begin uart_rxd_d0 <= 1'b0;uart_rxd_d1 <= 1'b0;          endelse beginuart_rxd_d0  <= uart_rxd;                   uart_rxd_d1  <= uart_rxd_d0;end
end//当脉冲信号start_flag到达时,进入接收过程
always @(posedge sys_clk or negedge sys_rst_n) begin         if (!sys_rst_n)                                  rx_flag <= 1'b0;else beginif(start_flag)                          //检测到起始位rx_flag <= 1'b1;                    //进入接收过程,标志位rx_flag拉高else if((rx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))rx_flag <= 1'b0;                    //计数到停止位中间时,停止接收过程elserx_flag <= rx_flag;end
end//进入接收过程后,启动系统时钟计数器与接收数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         if (!sys_rst_n) begin                             clk_cnt <= 16'd0;                                  rx_cnt  <= 4'd0;end                                                      else if ( rx_flag ) begin                   //处于接收过程if (clk_cnt < BPS_CNT - 1) beginclk_cnt <= clk_cnt + 1'b1;rx_cnt  <= rx_cnt;endelse beginclk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零rx_cnt  <= rx_cnt + 1'b1;       //此时接收数据计数器加1endendelse begin                              //接收过程结束,计数器清零clk_cnt <= 16'd0;rx_cnt  <= 4'd0;end
end//根据接收数据计数器来寄存uart接收端口数据
always @(posedge sys_clk or negedge sys_rst_n) begin if ( !sys_rst_n)  rxdata <= 8'd0;                                     else if(rx_flag)                            //系统处于接收过程if (clk_cnt == BPS_CNT/2) begin         //判断系统时钟计数器计数到数据位中间case ( rx_cnt )4'd1 : rxdata[0] <= uart_rxd_d1;   //寄存数据位最低位4'd2 : rxdata[1] <= uart_rxd_d1;4'd3 : rxdata[2] <= uart_rxd_d1;4'd4 : rxdata[3] <= uart_rxd_d1;4'd5 : rxdata[4] <= uart_rxd_d1;4'd6 : rxdata[5] <= uart_rxd_d1;4'd7 : rxdata[6] <= uart_rxd_d1;4'd8 : rxdata[7] <= uart_rxd_d1;   //寄存数据位最高位default:;                                    endcaseendelse rxdata <= rxdata;elserxdata <= 8'd0;
end//数据接收完毕后给出标志信号并寄存输出接收到的数据
always @(posedge sys_clk or negedge sys_rst_n) begin        if (!sys_rst_n) beginuart_data <= 8'd0;                               uart_done <= 1'b0;endelse if(rx_cnt == 4'd9) begin               //接收数据计数器计数到停止位时           uart_data <= rxdata;                    //寄存输出接收到的数据uart_done <= 1'b1;                      //并将接收完成标志位拉高endelse beginuart_data <= 8'd0;                                   uart_done <= 1'b0; end
end//判断接收到的是不是打开led标记,即接收到十六进制20always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)led_open_flag   <=  1'b0;else if(uart_data == 8'h20)led_open_flag   <=  1'b1;elseled_open_flag <=  1'b0;
end//判断接收到的是不是关闭led标记,即接收到十六进制40always@(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)led_close_flag  <=  1'b0;else if(uart_data == 8'h40)led_close_flag  <=  1'b1;elseled_close_flag    <=  1'b0;
end
endmodule

3、串口发送模块uart_send,主要用来将FPGA接受到的数据再发送给串口调试助手。


module uart_send(input        sys_clk,                  //系统时钟input         sys_rst_n,                //系统复位,低电平有效input         uart_en,                  //发送使能信号input  [7:0]  uart_din,                 //待发送数据output  reg   uart_txd                  //UART发送端口);//parameter define
parameter  CLK_FREQ = 50000000;             //系统时钟频率
parameter  UART_BPS = 9600;                 //串口波特率
localparam BPS_CNT  = CLK_FREQ/UART_BPS;    //为得到指定波特率,对系统时钟计数BPS_CNT次//reg define
reg        uart_en_d0;
reg        uart_en_d1;
reg [15:0] clk_cnt;                         //系统时钟计数器
reg [ 3:0] tx_cnt;                          //发送数据计数器
reg        tx_flag;                         //发送过程标志信号
reg [ 7:0] tx_data;                         //寄存发送数据//wire define
wire       en_flag;//*****************************************************
//**                    main code
//*****************************************************
//捕获uart_en上升沿,得到一个时钟周期的脉冲信号
assign en_flag = (~uart_en_d1) & uart_en_d0;//对发送使能信号uart_en延迟两个时钟周期
always @(posedge sys_clk or negedge sys_rst_n) begin         if (!sys_rst_n) beginuart_en_d0 <= 1'b0;                                  uart_en_d1 <= 1'b0;end                                                      else begin                                               uart_en_d0 <= uart_en;                               uart_en_d1 <= uart_en_d0;                            end
end//当脉冲信号en_flag到达时,寄存待发送的数据,并进入发送过程
always @(posedge sys_clk or negedge sys_rst_n) begin         if (!sys_rst_n) begin                                  tx_flag <= 1'b0;tx_data <= 8'd0;end else if (en_flag) begin                 //检测到发送使能上升沿                      tx_flag <= 1'b1;                //进入发送过程,标志位tx_flag拉高tx_data <= uart_din;            //寄存待发送的数据endelse if ((tx_cnt == 4'd9)&&(clk_cnt == BPS_CNT/2))begin                               //计数到停止位中间时,停止发送过程tx_flag <= 1'b0;                //发送过程结束,标志位tx_flag拉低tx_data <= 8'd0;endelse begintx_flag <= tx_flag;tx_data <= tx_data;end
end//进入发送过程后,启动系统时钟计数器与发送数据计数器
always @(posedge sys_clk or negedge sys_rst_n) begin         if (!sys_rst_n) begin                             clk_cnt <= 16'd0;                                  tx_cnt  <= 4'd0;end                                                      else if (tx_flag) begin                 //处于发送过程if (clk_cnt < BPS_CNT - 1) beginclk_cnt <= clk_cnt + 1'b1;tx_cnt  <= tx_cnt;endelse beginclk_cnt <= 16'd0;               //对系统时钟计数达一个波特率周期后清零tx_cnt  <= tx_cnt + 1'b1;       //此时发送数据计数器加1endendelse begin                              //发送过程结束clk_cnt <= 16'd0;tx_cnt  <= 4'd0;end
end//根据发送数据计数器来给uart发送端口赋值
always @(posedge sys_clk or negedge sys_rst_n) begin        if (!sys_rst_n)  uart_txd <= 1'b1;        else if (tx_flag)case(tx_cnt)4'd0: uart_txd <= 1'b0;         //起始位 4'd1: uart_txd <= tx_data[0];   //数据位最低位4'd2: uart_txd <= tx_data[1];4'd3: uart_txd <= tx_data[2];4'd4: uart_txd <= tx_data[3];4'd5: uart_txd <= tx_data[4];4'd6: uart_txd <= tx_data[5];4'd7: uart_txd <= tx_data[6];4'd8: uart_txd <= tx_data[7];   //数据位最高位4'd9: uart_txd <= 1'b1;         //停止位default: ;endcaseelse uart_txd <= 1'b1;                   //空闲时发送端口为高电平
end
endmodule

4、led模块led

module  led(clk,rst_n,led_open_flag,led_close_flag,led);
input                   clk;
input                   rst_n;
input                   led_open_flag;
input                   led_close_flag;
output   reg            led;always@(posedge clk or negedge rst_n)beginif(!rst_n)led    <=  1'b0;else if(led_open_flag)led <=  1'b1;else if(led_close_flag)led    <=  1'b0;
end
endmodule

四、Signal Tap仿真
将程序下载到开发版之后,打开串口调试助手,设置好波特率115200,停止位为1位,数据位为8位,无奇偶校验位(根据上面的程序设置,保持一致)

然后打开串口,注意串口调试助手默认以ASCII码的格式一个字节一个字节的发送(比如需要发送23,那么它会先发送第一个字节2,再发送第二个字节3),所以这里选择16进制发送格式,不发送新行。如果发送新行,我们接受到一个回车键的ASCII码即13。那么我们打开SignalTap,然后在串口调试助手的发送窗口发送16进制的20,可以看到仿真如下:

可以看出接收端口uart_rxd的开始位为0,接着是8位的数据位为00000100,最后是一个停止位为1。请注意最先接收的是数据的最低位,所以真正接收到的数据需要颠倒顺序,即00100000,我们可以看到这就是16进制的20。可以证明我们接收到的数据是正确的。同时看到led信号在接收到20之后,被拉高即led0被点亮。同理我们发送16进制的40,led0将被熄灭。如图:

FPGA verilog基本外设练习(五)-串口通信相关推荐

  1. 【K210】K210学习笔记五——串口通信

    [K210]K210学习笔记五--串口通信 前言 K210如何进行串口通信 K210串口配置 K210串口发送相关定义 K210串口接收相关定义 K210串口发送接收测试 完整源码 前言 本人大四学生 ...

  2. 7天搞定FPGA精录总结Episode.6 串口通信,系统设计【基于Robei、Altera QuartusⅡ与Python】

    之前参加&组织学校排球比赛的时候,商量到我们可以学习那些正规排球大赛一样,决赛的时候在学校体育馆进行,而且我可以在一旁准备一点EDM热歌作为暖场音乐.然后就有同学用一脸奇怪的表情问我:&quo ...

  3. FPGA verilog基本外设练习(六)- 以太网通信模块

    以太网模块 1.实验任务 上位机通过网口调试助手发送数据给FPGA,FPGA开发板通过以太网接口接收数据,并将接收到的数据发送给上位机,完成以太网数据的环回. 2.硬件模块 采用的是黑金的AN8211 ...

  4. 树莓派外设开发基础—串口通信

    文章目录 一.串口通信的一些概念 二.树莓派串口通信设置 三.树莓派串口通信API 四.树莓派与PC通信 1.接线 2.程序与测试 拓展 一.串口通信的一些概念 串口通信通常用在多机通信中. 串口通信 ...

  5. 实现FPGA Verilog HDL与NIOS II的通信数据交换——利用AVALON总线

    平时用FPGA基本都是全程用Verilog HDL编程,当遇到液晶的时候,发现Verilog的还不如C语言来的方便,但是用NIOS来编写的时候,实现NIOS与Verilog的通信又是一个问题,今天用了 ...

  6. FPGA学习笔记(四)——串口通信之接收数据(调试过程)

    本学习笔记主要参考小梅哥B站教学视频,网址如下: https://www.bilibili.com/video/BV1va411c7Dz?p=1 使用的编译器为Vivado,HDL语言为verilog ...

  7. FPGA自学笔记--串口通信发送多字节数据(verilog版)

    1.需求分析 关于uart协议实现这部分大家可以参考我上一篇的博客.<FPGA自学笔记--串口通信实现(vivado&verilog版)>.在上一篇博客中,主要实现了将单字节的数据 ...

  8. 基于FPGA的红外遥控解码与PC串口通信

    基于FPGA的红外遥控解码与PC串口通信 zouxy09@qq.com http://blog.csdn.net/zouxy09 这是我的<电子设计EDA>的课程设计作业(呵呵,这个月都拿 ...

  9. 【FPGA】——UART串口通信

    UART串口简介   串行通信分为两种方式:同步串行通信和异步串行通信.同步串行通信要求通信双方使用同一时钟,异步则没有这个要求.UART是一种采用异步串行通信方式的通用异步收发传输器(univers ...

  10. fpga板子怎么和电脑连_FPGA与PC串口通信设计与实现

    FPGA 与 PC 串口通信设计与实现 朱泽锋 1 赵丹辉 2 王鹏宇 1 [摘 要] 本文采用 Verilog 硬件描述语言,利用 Xilinx 公司的 FPGA 芯片实现 其与 PC 间的串行通信 ...

最新文章

  1. UE4.18预览第一版发布,共享XR引擎层降低硬件支持难度
  2. linux:uabntu日常操作
  3. Fabric 学习笔记-架构初探
  4. 如何选择MBA教育 读MBA前必答10个问题
  5. java输出华氏摄氏温度转换表_Python练习题2.10输出华氏-摄氏温度转换表
  6. SLAM方向公众号、知乎、博客学习参考
  7. 启动程序端口被占用Address already in use: bind解决方案
  8. linux 17 中文输入,Rethat Linux Fedora17添加中文输入法
  9. [android底层]jni中获取自定义的类函数编写
  10. 一个软件工程师在北京的反省
  11. Linux关闭桌面进程,Centos进入桌面和退出桌面的方法
  12. 计算机硬盘满了怎么解决,电脑磁盘满了怎样清理
  13. Protell99中的铺铜设置
  14. 问道手游平民玩家什么职业好
  15. 深度解读Coatue:向加密行业转舵的「老虎环球基金」
  16. 刨根问底,5问分析法
  17. 良心推荐5款Python编辑器,请择优选用!
  18. Epplus获取数据区域的第一行或最后一行
  19. RecycleView 刷新显示错乱(刷新之后上一个界面的显示还在,出现部分错乱)
  20. Word怎么转换成PDF免费?分享适合你的Word转PDF方法

热门文章

  1. win11 edge怎么卸载?win11 edge浏览器彻底卸载的方法教程
  2. 第三十七课.宽度学习
  3. 高彩色显示图标(转)
  4. SDN是什么,与传统分布式网络有什么区别
  5. MindManager 2020注册机下载
  6. cass打开dwg文件无效_DWG文件软件打开显示图形文件无效
  7. cad中拖动文字时卡顿_cad移动图时卡顿 - 卡饭网
  8. c语言有开始菜单的flybird,C语言实现Flybird
  9. 1、mac:jdk 8下载和安装步骤
  10. 量产HLW8032串口通讯芯片的三相电参数采集系统项目资料