Nios实验入门——用Verilog编程方式完成LED流水灯显示并使用串口输出“Hello Nios-II”字符到笔记本电脑

文章目录

  • 前言
  • 一、Verilog编程方式完成LED流水灯显示
    • 1.1 新建工程并添加FPGA芯片
    • 1.2 新建.v文件并添加至顶层实体
    • 1.3 引脚分配
    • 1.4 编译(包含分析与综合)
    • 1.5 选择烧录器
    • 1.6 添加烧录文件
    • 1.7 下载
    • 1.8 实验现象
  • 二、Verilog编程方式实现串口
    • 2.1 uart_tx.v文件
    • 2.2 test.v文件
    • 2.3 top.v顶层文件
    • 2.5 串口代码讲解
    • 2.4 引脚分配
    • 2.5 实验现象
  • 总结
  • 参考


前言

主要目的:
(1)学习 Quartus Prime 、Platform Designer、Nios II SBT 的基本操作;
(2)初步了解 SOPC 的开发流程,基本掌握 Nios II 软核的定制方法;
(3)掌握 Nios II 软件的开发流程,软件的基本调式方法。

主要内容

  • 在DE2-115开发板上用Nios软件编程方式完成LED流水灯显示
  • 用Verilog编程方式通过DE2-115开发板串口输出“Hello Nios-II”字符到笔记本电脑串口助手

一、Verilog编程方式完成LED流水灯显示

1.1 新建工程并添加FPGA芯片

打开quartus新建工程:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一直next,到选择型号界面。
选择芯片型号,根据实际情况选择
在这里插入图片描述
点击finish
在这里插入图片描述

在这里插入图片描述

1.2 新建.v文件并添加至顶层实体

在这里插入图片描述

在这里插入图片描述

代码如下:

module led_flow #(parameter TIME_0_5S = 25_000_000)(input               sys_clk     ,input               sys_rst_n   ,output  reg [7:0]   led     
);reg     [24:0]      cnt     ;wire                add_cnt ;wire                end_cnt ;reg     [2:0]       cnt1;wire                add_cnt1;wire                end_cnt1;always @(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n) begincnt <= 25'b0;endelse if(add_cnt) beginif(end_cnt) begincnt <= 25'b0;endelse begincnt <= cnt+1'b1;endendelse begincnt <= cnt;endend// 异步复位always @(posedge sys_clk or negedge sys_rst_n) beginif(!sys_rst_n)begincnt1 <= 3'b0;endelse if(add_cnt1) beginif(end_cnt1)begincnt1 <= 3'b0;endelse begincnt1 <= cnt1 + 1'b1;endendendalways @(posedge sys_clk or negedge sys_rst_n)beginif(!sys_rst_n)beginled <= 8'b0;endelse begincase (cnt1)3'b000 : led <= 8'b0000_0001;3'b001 : led <= 8'b0000_0010;3'b010 : led <= 8'b0000_0100;3'b011 : led <= 8'b0000_1000;3'b100 : led <= 8'b0001_0000;3'b101 : led <= 8'b0010_0000;3'b110 : led <= 8'b0100_0000;3'b111 : led <= 8'b1000_0000;default: led <= led;endcaseendendassign add_cnt = 1'b1;assign end_cnt = add_cnt && cnt == TIME_0_5S - 1;assign add_cnt1 = (cnt == TIME_0_5S-1);assign end_cnt1 = add_cnt1 && cnt1 == 3'b111;endmodule

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1.3 引脚分配

在这里插入图片描述
引脚如下:
在这里插入图片描述

1.4 编译(包含分析与综合)

在这里插入图片描述

在这里插入图片描述

1.5 选择烧录器

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1.6 添加烧录文件

在这里插入图片描述
在这里插入图片描述

1.7 下载

在这里插入图片描述
在这里插入图片描述

1.8 实验现象

Verilog编程方式完成LED流水灯显示

在这里插入图片描述

二、Verilog编程方式实现串口

项目创建同第一章的LED流水灯

示例串口代码如下:

2.1 uart_tx.v文件

uart_tx.v 代码如下:

//波特率为115200bps,即每秒传送115200bit的数据,传送1bit数据需要434个时钟周期
//tx内部是并行数据,需要串行传出去,一般数据格式是1bit的起始位,8bit的数据位,1bit的停止位
//所以需要一个8bit的计数器,计算传送了多少个bit,起始位是低电平有效,停止位是持续的高电平
//需要接收8bit的数据
//需要1bit的传送出去
module uart_tx(input               clk     ,input               rst_n   ,//ininput    [7:0]      din ,//要发送的数据input               din_vld,//数据有效//outoutput  reg [3:0]   cnt_byte,//现在输出第几个byte了output  reg         tx    //串口数据
);parameter    Baud = 434;//波特率计时器
reg         [8:0]       cnt_baud     ;
wire            add_cnt_baud ;
wire            end_cnt_baud ;
reg                     flag;always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_baud <= 0;end else if(add_cnt_baud)begin if(end_cnt_baud)begincnt_baud <= 0;endelse begincnt_baud<=cnt_baud+1;endend else begin cnt_baud <= cnt_baud;end 
end
assign add_cnt_baud = flag;
assign end_cnt_baud = add_cnt_baud && cnt_baud == Baud - 1;always @(posedge clk or negedge rst_n)beginif(!rst_n)beginflag <= 1'b0;endelse if(din_vld)beginflag <= 1'b1;endelse if(end_cnt_bit)beginflag <= 1'b0;endelse beginflag <= flag;end
end//波特率计数完成,就可以发送下一个bit
//表示需要把第几位发送出去
reg               [3:0]      cnt_bit;//最多是8
wire            add_cnt_bit;
wire            end_cnt_bit;
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_bit <= 0;end else if(add_cnt_bit)begin if(end_cnt_bit)begincnt_bit <= 0;endelse begincnt_bit <= cnt_bit + 1;endend else begin cnt_bit <= cnt_bit;end 
end
assign  add_cnt_bit = end_cnt_baud;
assign  end_cnt_bit = add_cnt_bit && cnt_bit == 8;//发送到第几个字符,总共要发15个字符
wire                     add_cnt_byte ;
wire                     end_cnt_byte ;always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_byte <= 0;end else if(add_cnt_byte)begin if(end_cnt_byte)begincnt_byte <= 0;endelse begincnt_byte <= cnt_byte + 1;endend else begin cnt_byte <= cnt_byte;end 
endassign      add_cnt_byte = end_cnt_bit;//发送完8bit后
assign      end_cnt_byte = add_cnt_byte && cnt_byte == 14;//发送数据的逻辑,先加上起始位reg         [8:0]      data     ;
always @(posedge clk or negedge rst_n)beginif(!rst_n)begindata <= 9'h1ff;endelse if(din_vld)begindata <= {din,1'b0};  //数据加上起始位endelse begindata <= data;end
end//并行转串行逻辑
always @(posedge clk or negedge rst_n)begin if(!rst_n)begintx <= 0;end else if(cnt_baud == 1)begin //每发送完1bit,就发送一个tx;tx <= data[cnt_bit];//LSP,低位先发end else if(end_cnt_bit)begin//处理停止位tx <= 1'b1;endelse begin tx <= tx;end
endendmodule

2.2 test.v文件

test.v 代码如下:

module test(input               clk     ,input               rst_n   ,input  wire [3:0]   cnt_byte,//现在输出第几个byte了output   reg           dout_vld,//表示200us间隔实现output   reg [7:0]  led_data//表示输出的数据
);
//总共需要发送15个字符,所以需要15的计数器//200us计数器
parameter   TIME_200uS = 1_000_0;
reg         [13:0]      cnt_200uS;
wire                    add_cnt_200uS;
wire                    end_cnt_200uS;
always @(posedge clk or negedge rst_n)begin if(!rst_n)begincnt_200uS <= 0;end else if(add_cnt_200uS)begin if(end_cnt_200uS)begin cnt_200uS <= 0;endelse begin cnt_200uS <= cnt_200uS + 1;end endelse begincnt_200uS <= 0;end
end 
assign add_cnt_200uS = 1'b1;
assign end_cnt_200uS = add_cnt_200uS && cnt_200uS ==  TIME_200uS - 1;//定义输出数据//Hello Nios-II到串口always @(posedge clk or negedge rst_n)beginif(!rst_n)begindout_vld <= 1'b0;endelse if(end_cnt_200uS)begindout_vld <= 1'b1;case(cnt_byte)0     :   led_data = 8'b01001000;//H1     :   led_data = 8'b01100101;//e2     :   led_data = 8'b01101100;//l3     :   led_data = 8'b01101100;//l4     :   led_data = 8'b01101111;//o5     :   led_data = 8'b00100000;//space6     :   led_data = 8'b01001110;//N7     :   led_data = 8'b01101001;//i8     :   led_data = 8'b01101111;//o9      :   led_data = 8'b01110011;//s10      :   led_data = 8'b00101101;//-11      :   led_data = 8'b01001001;//I12      :   led_data = 8'b01001001;//I13      :   led_data = 8'b00001101;//\r14      :   led_data = 8'b00001010;//\ndefault :   led_data = 8'b0;endcaseendelse begindout_vld <= 1'b0;endend
endmodule

2.3 top.v顶层文件

**top.v**顶层文件代码:

module top(input           clk     ,input           rst_n   ,output          tx      
);wire    [7:0]           led_data    ;wire    [3:0]           cnt_byte   ;wire                   din_vld   ;uart_tx             inst_uart_tx(.clk            (clk      ),.rst_n          (rst_n    ),//in.din            (led_data),//如果串口占用时,uart_data.din_vld        (din_vld),
//out.cnt_byte       (cnt_byte),.tx           (tx     ) );test                inst_test(.clk            (clk        ),.rst_n          (rst_n      ),//in.cnt_byte       (cnt_byte),//out.led_data       (led_data   ),.dout_vld       (din_vld));endmodule

2.5 串口代码讲解

波特率(Band Rate):
串口协议中很重要的一点就是波特率,波特率的概念是每秒钟传送码元的个数,就是一秒钟传输了几个二进制的个数,他的单位是Bit/s和bps两种。常见的串口速度有115200bps 9600bps等等,串口(RS232)的最大传输速率是 115200bps,表示一秒钟传输了115200个二进制 。
波特率和字节的关系
1GB=1024MB
1MB=1024KB
1KB=1024B(字节)

我们需要串口接收的数据数每秒512字节,串口的波特率是115200位/秒

波特率115200=115200(位/秒)

如果没有校验位,就应该除以10,得到的是每秒字节数:波特率115200=115200(位/秒)=11520(字节/秒)

再除以1024,就是每秒KB数:波特率115200=115200(位/秒)=11.25(KB/秒)也就是满足每秒可以接收512字节。

在Verilog代码中,我们只需要理解计算这两个值就可以完成串口代码的梳理, 假设我们FPGA使用的是50MHZ的系统时钟 波特率使用的是9600bps 传输一个bit需要的时钟周期个数是50_000_000/9600个个数,得到个数之后再用这个个数乘以周期的时间便是传输1bit需要的时间50_000_000/9600*20便是1bit需要的时间。

Uart通信协议
1.串口通信的信号线只需要两条线就可以完成,TX和RX TX发送端 RX为接收端。
2.起始位,数据线从高变低,低有效为0,数据传输开始。
3.数据位,起始位传输之后便是数据位开始,一般为8位,传输时低位(LSB)在前,高位(MSB)在后。
4.校验位,校验位可以认为是一个特殊的数据位,通常使用的是奇偶校验,使用串口协议时通常取消奇偶校验位。
5.停止位,停止位高有效为1,他表示这一个个字节传输结束。
6.位时间,起始位、数据位、校验位的位宽度是一致的,停止位有0.5位、1位、1.5位格式,一般为1位。
7.空闲位,持续的高电平。
7.帧:从起始位开始到停止位结束的时间间隔称之为一帧。
在这里插入图片描述

将8位或者多位数据拆分为一位一位的发送出去的过程称为并转串。将一位一位接收的数据合并为8位或者多位数据的过程称为串转并。
对于串行通信设备来说,发送方都是在执行并转串,接收方都是在执行串转并。
UART设备为串行通信设备。

2.4 引脚分配

指定gpio口为tx和rx,编程实现硬件逻辑
在这里插入图片描述

2.5 实验现象

程序代码的编译及运行同LED流水灯显示一样

实现效果如下:
在这里插入图片描述


总结

在比较Verilog和Nios-II两种硬件描述语言(HDL)时,我们可以从它们的编程方式、易用性、灵活性以及对细节的要求等方面进行阐述。

Verilog编程

  • 选择性实现:Verilog提供了高度的灵活性,允许开发者根据需要选择性地实现特定的硬件功能,例如只编写串口通信部分的代码。
  • 时序敏感:Verilog编程需要对时序有非常精确的控制和理解,这要求开发者在编写代码时非常细心,以避免潜在的bug。
  • 简洁性:虽然Verilog代码可以非常简洁,但这也意味着开发者需要对硬件设计有深入的理解,才能确保设计的准确性。

Nios-II编程

  • 模块化设计:Nios-II采用模块化的IP核,使得开发者可以通过组合现成的模块来构建复杂的系统,类似于构建一个微型计算机。
  • 易用性:对于初学者来说,Nios-II相对容易上手,因为它提供了一种类似于拼图的编程方式,通过软件编程来实现硬件逻辑。
  • 深入理解的挑战:尽管Nios-II在表面上看起来简单,但要深入理解其内部工作原理和优化性能,仍然需要相当的专业知识和经验。

综合比较

  • 灵活性与控制:Verilog提供了更多的控制和灵活性,但这也意味着需要更高的专业知识和对细节的关注。
  • 易用性与构建速度:Nios-II通过提供预构建的模块和软件编程接口,简化了硬件开发过程,使得构建速度更快,但可能牺牲了一定的定制性。
  • 学习曲线:Verilog的学习曲线可能更陡峭,因为它要求开发者对硬件设计有更深入的理解;而Nios-II则提供了一个较为平缓的学习曲线,使得新手也能较快地开始项目开发。

总的来说,Verilog和Nios-II各有优势,选择哪一种取决于项目的具体需求、开发者的专业知识以及对开发时间和定制性的要求。

参考

Nios-II编程入门实验

Quartus II 17.1新建一个流水灯

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/698311.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL】sql表设计的注意事项

程序员的实用神器 文章目录 程序员的实用神器强烈推荐引言注意事项强烈推荐专栏集锦写在最后 强烈推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站:人工智能 推荐一个个人工作&#x…

Android面试题之Kotlin的apply、let、also、run函数

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 apply apply函数可以看作是一个配置函数&#xff0c;可以传入一个接收者&#xff0c;然后调用一系列函数来配置以便使用&#xff0c;如果提供l…

Redis-数据过期策略

文章目录 Redis数据持久化策略的作用是什么&#xff1f;Redis的数据过期策略有哪些&#xff1f;惰性删除定期删除 更多相关内容可查看 Redis数据持久化策略的作用是什么&#xff1f; Redis数据过期策略是指在Redis中设置数据的过期时间&#xff0c;并在数据过期时自动从数据库…

《安富莱嵌入式周报》第336期:开源计算器,交流欧姆表,高性能开源BLDC控制器,Matlab2024a,操作系统漏洞排名,微软开源MS-DOS V4.0

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 本周更新一期视频教程&#xff1a; BSP视频教程第30期&#xff1a;UDS ISO14229统一诊断服务CAN总线专题&#xff0c;常…

【SRC实战】无限获取优惠码

挖个洞先 https://mp.weixin.qq.com/s/HgMK4S8275VvFVbnSp6Qsw “ 以下漏洞均为实验靶场&#xff0c;如有雷同&#xff0c;纯属巧合 ” 01 — 漏洞证明 “ 获取优惠码有次数限制的情况下&#xff0c;如何绕过&#xff1f;” 1、新用户专属福利&#xff0c;免费领100元优惠…

聚观早报 | 小米与京东达成合作;比亚迪销量全球第一

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 5月14日消息 小米与京东达成合作 比亚迪销量全球第一 vivo X100s关键参数曝光 小鹏汽车进军澳大利亚市场 腾讯Q…

(接上一篇linux rocky 搭建DNS高阶版)实现不同网段访问解析不同的服务器并加域

上一篇链接&#xff1a;linux rocky 搭建DNS服务和禁止AD域控DNS&#xff0c;做到独立DNS并加域-CSDN博客文章浏览阅读417次&#xff0c;点赞13次&#xff0c;收藏7次。使用linux rocky 搭建DNS服务&#xff0c;用于独立AD域控DNS存在&#xff0c;并且实现加域。https://blog.c…

vue3修改eldialog弹窗css不生效

问题&#xff1a;子组件中的eldialog没有父标签 直接使用如下是不生效的 .el-dialog{ top: 10%; } 解决&#xff1a; 加一个父标签 使用deep深度查询 .dialogClass :deep(.el-dialog) { top: 10%; } 就可以修改了

「JavaEE」多线程案例分析2:实现定时器

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;JavaEE &#x1f387;欢迎点赞收藏加关注哦&#xff01; 实现定时器 &#x1f349;简介&#x1f349;模拟实现定时器 &#x1f349;简介 定时器类似一个闹钟&#xff0c;时间到了之后就会执行…

java 解决跨域时遇到问题,怎么来做一个跨域环境

今天遇到一个问题&#xff1a; 关于#java#的问题&#xff1a;java 解决跨域时遇到问题&#xff1a;为什么跨域访问时配置的CorsFilter没有进入&#xff1f;直接访问请求地址时进入了配置的CorsFilter 由于没有实际的跨域环境&#xff0c;因此打算在本机建一个跨域环境&#xff…

Java 实现Mybatis plus 批量删除

数据库实体字段并不映射的情况&#xff0c;直接请求体集合接收。 PostMapping("/removeIdsInfo")public R<Void> removeIdsInfo(RequestBody List<Integer> ids) {return exStudentService.removeIdsInfo(ids);} /**** 学生模块根据集合id 批量删除数据*…

深度解析Nginx:高性能Web服务器的奥秘(下)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《洞察之眼&#xff1a;ELK监控与可视化》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、Nginx概述 二、Nginx核心功能 1、URL重写与重…