实验一Nios-II编程入门

文章使用的工具及板子类型
工具:Quartus II 18.0
开发板:Cyclone IV E EP4CE115F29C7

一、Nios II软核实现流水灯

(一)硬件部分设计

1.完成基本的硬件部分设计

请先参考下面链接中的硬件部分设计,完成相应的硬件部分设计
https://blog.csdn.net/qq_43279579/article/details/115933154

2.添加其他IP核

添加PIO
在搜索框上输入pio,选择PIO(Parallel I/O),点击Add
alt
设置宽度(这里我设置为4,表示4个灯的流水灯),默认为8,其他保持默认设置

3.连接时钟和复位

alt

4.设置led的输出

alt

5.系统分配地址

选择System->Assign Base Address

6.使用FPGA资源

选择Generate->Generate,保持默认设置,点击Generate,选择Save

7.创建顶层文件

回到Quarters,选择New->Verilog HDL File
顶层文件内容

module hello_world(
	input clk,
	input reset_n,
	output  [7:0] led
);
system_qsys u0 (
        .clk_clk       (clk),       //   clk.clk
        .reset_reset_n (reset_n), // reset.reset_n
        .led_export    (led)     //   led.export
    );

endmodule

保存文件,并编译
alt

8.芯片引脚设置

菜单里选择 Assignments-device,点击 Device pin options
进行 unused pin 设置,可能会收到外部信号的干扰,将未用引脚设置为 As input tri-stated
alt
特殊引脚设置,设置为常规引脚
alt

9.编译完成后,分配管脚

ALT

(二)软件设计

1.基本软件设计过程

请参考下面链接中,软件设计的过程,完成文件的创建
https://blog.csdn.net/qq_43279579/article/details/115933154

2.修改代码文件

打开hello_world中的.c文件
内容如下

#include "system.h"
#include "altera_avalon_pio_regs.h"
#include "alt_types.h"
#include "stdio.h"
const alt_u8
led_data[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
int main (void) {
	int count=0;
	alt_u8 led;
	volatile int i;
	while (1)
	{
		if (count==7)
		{count=0;}
		else
		{count++;}
		led=led_data[count];
		IOWR_ALTERA_AVALON_PIO_DATA(PIO_0_BASE, led);
		i = 0;
		printf("Hello Nios-II\n");
		while (i<500000)
			i++;
	}
	return 0;
}

3.保存编译

点击保存,选择hello_wold_bsp,右键后,选择Nios II中的Generate BSP,编译应用文件,选择hello_world右键后,点击Build Project
alt

(三)下载硬件和软件

1.硬件的下载

ALT

2.软件的下载

在Nios II - Eclipse中
alt

(四)实验结果

alt

二、Verilog实现流水灯

编译烧录以下代码即可

module horse_led#(parameter TIME_1500MS = 75_000_000)(
    input               clk     ,
    input               rst_n   ,
    output  reg[3:0]    led
);

    //1.5s计数器
    reg     [26:0]      cnt     ;
    wire                add_cnt ;
    wire                end_cnt ;

    reg     [1:0]       cnt1    ;
    wire                add_cnt1;
    wire                end_cnt1;

    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt <= 27'b0;
        end
        else if(add_cnt)begin
            if(end_cnt)begin
                cnt <= 27'b0;
            end
            else begin
                cnt <= cnt + 1'b1;
            end
        end
        else begin
            cnt <= cnt;
        end
    end

    assign add_cnt = 1'b1;
    assign end_cnt = add_cnt && cnt == TIME_1500MS - 1;

        always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt1 <= 2'b0;
        end
        else if(add_cnt1)begin
            if(end_cnt1)begin
                cnt1 <= 2'b0;
            end
            else begin
                cnt1 <= cnt1 + 1'b1;
            end
        end
        else begin
            cnt1 <= cnt1;
        end
    end

    assign add_cnt1 = end_cnt;
    assign end_cnt1 = add_cnt1 && add_cnt == 3;

    //跑马灯
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            led <= 4'b0001;
        end
        else if(end_cnt)begin
            led <= {led[2:0],~led[3]};
        end
        else begin
            led <= led;
        end
    end

endmodule

三、Nios II软核实现UART通信

(一)硬件设计部分

1.添加其他IP核

添加UART
在搜索框上输入uart,选择UART(RS-232 Serial Port),点击Add
alt
进行数据设置
alt
连接时钟和复位,以及数据位,中断的设置,Export设置
alt

2.系统分配地址

选择System->Assign Base Address

3.使用FPGA资源

选择Generate->Generate,保持默认设置,点击Generate,选择Save

4.创建顶层文件

回到Quarters,选择New->Verilog HDL File
顶层文件内容

module uart(
	input clk,
	input reset_n,
	//uart的接收和发送端
	input rxd,//接收
	output txd//发送
);

system_qsys u0 (
        .clk_clk       (clk),       //   clk.clk
        .reset_reset_n (reset_n), // reset.reset_n
        .uart_rxd      (rxd),      //  uart.rxd
        .uart_txd      (txd)       //      .txd
    );

endmodule

保存文件,并编译

5.芯片引脚设置

菜单里选择 Assignments-device,点击 Device pin options
进行 unused pin 设置,可能会收到外部信号的干扰,将未用引脚设置为 As input tri-stated,特殊引脚设置,设置为常规引脚

6.编译完成后,分配管脚

alt
再次编译

(二)软件设计

1.修改代码文件

打开uart中的hello_world.c文件
内容如下

#include <stdio.h>
#include "unistd.h"
#include "system.h"
#include "alt_types.h"
#include "altera_avalon_uart_regs.h"
#include "sys\alt_irq.h"

alt_u8 txdata=0;
alt_u8 rxdata=0;

//UART中断服务函数
void IRQ_UART_Interrupts(){
	rxdata = IORD_ALTERA_AVALON_UART_RXDATA(UART_BASE);//将rxdata寄存器中存储的值读入变量rxdata中
	txdata = rxdata;//串口自收发,将变量rxdata的值赋给txdata
	while(!(IORD_ALTERA_AVALON_UART_STATUS(UART_BASE)& ALTERA_AVALON_UART_STATUS_TRDY_MSK));
	//查询发送准备接收信号,如果没有准备好,则等待
	IOWR_ALTERA_AVALON_UART_TXDATA(UART_BASE,txdata);//发送准备好,发送txdata
}

//中断初始化函数
void IRQ_init()
{
	//清除状态寄存器
	IOWR_ALTERA_AVALON_UART_STATUS(UART_BASE, 0);
	//使能接收准备中断,给控制寄存器相应位写1
	IORD_ALTERA_AVALON_UART_CONTROL(UART_BASE);

	alt_ic_isr_register(
			UART_IRQ_INTERRUPT_CONTROLLER_ID,//注册ISR
			UART_IRQ,//中断控制器标号,从system.h复制
			IRQ_UART_Interrupts,//UART中断服务函数
			0x0,//指向与设备驱动实例相关的数据结构体
			0x0);//flags,保留未用
}

int main()
{
  /*while(1){
	  IOWR_ALTERA_AVALON_UART_TXDATA(UART_BASE, "hello world!\n");
	  int i=0;
	  while(i<5000)
	  {
		  i++;
	  }
  }*/
  IRQ_init();
  while(1);
  return 0;
}

2.保存编译

点击保存,选择uart_bsp,右键后,选择Nios II中的Generate BSP,编译应用文件,选择uart右键后,点击Build Project

(三)下载硬件和软件

1.硬件下载

alt

2.软件下载

alt

四、Verilog实现UART通信

编译烧录以下代码即可

`timescale  1ns/1ns

module  rs232
(
    input   wire    sys_clk     ,    //系统时钟50MHz
    input   wire    sys_rst_n   ,   //全局复位
    input   wire    rx          ,   //串口接收数据
    
    output  wire    tx              //串口发送数据
);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   UART_BPS    =   20'd9600        ,   //比特率
            CLK_FREQ    =   26'd50_000_000  ;   //时钟频率

localparam  BAUD_CNT_MAX    =   CLK_FREQ/UART_BPS   ;
//wire  define
wire            en_h_flag;
wire    [7:0]   po_data;    //接收的数据
wire            po_flag;    //接收完1字节数据标志位,高电平有效
wire            flag;       //识别到接收数据与密码对应标志位
wire            tx_flag;    //发送完1字节数据标志位,高电平有效
reg     [39:0]  datain_reg; //存储接收的数据,5字节
reg     [47:0]  dataout_reg;//存储的要发送的数据,6字节
reg     [1:0]   state;      //状态位
reg     [7:0]   data_tx;    //发送的1字节数据
reg             en_tx;      //发送允许标志位
reg     [2:0]   tx_cnt;     //发送字节计数器,发送6个后置0
reg             en;         //发送控制开关
reg     [12:0]  baud_cnt;   //收到发送成功的tx_flag后延迟1个波特
reg             bit_flag;   //计满1baud有效
reg             work;       //波特计数器baud_cnt有效
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------------------ uart_rx_inst ------------------------
uart_rx
#(
    .UART_BPS    (UART_BPS  ),  //串口波特率
    .CLK_FREQ    (CLK_FREQ  )   //时钟频率
)
uart_rx_inst
(
    .sys_clk    (sys_clk    ),  //input             sys_clk
    .sys_rst_n  (sys_rst_n  ),  //input             sys_rst_n
    .rx         (rx         ),  //input             rx
            
    .po_data    (po_data    ),  //output    [7:0]   po_data
    .po_flag    (po_flag    )   //output            po_flag
);
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        en <= 1'b1;
    else if(en_h_flag)
        en <= 1'b1;
    else if(tx_cnt>=3'd5)
        en <= 1'b0;   
//接收数据寄存
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        datain_reg <= 40'd0;
    else if(po_flag)
        datain_reg <= {datain_reg[31:0],po_data[7:0]};
        
//接收到tx_flag后,延迟一个baud时间再发送下一个
always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        work <= 1'b0;
    else if(tx_flag)
        work <= 1'b1;
    else if(state != 2'd2)
        work <= 1'b0;

always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        baud_cnt <= 13'd0;
    else if((baud_cnt == BAUD_CNT_MAX - 1) || en_tx)
        baud_cnt <= 13'b0;
    else if(work)
        baud_cnt <= baud_cnt + 1'd1;

always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        bit_flag <= 1'b0;
    else if(baud_cnt == BAUD_CNT_MAX - 1)
        bit_flag <= 1'b1;
    else if(state != 2'd2) 
        bit_flag <= 1'b0;

                              //hello的ASCII码
assign flag = (datain_reg == 40'h68656c6c6f)? 1'b1:1'b0;

always@(posedge sys_clk or negedge sys_rst_n)
    if(!sys_rst_n)
        begin
            state <= 2'd0;
            dataout_reg <= 48'h6e692c68616f;//ni,hao的ASCII码
            data_tx <= 8'd0;
            en_tx <= 1'b0;
            tx_cnt <= 3'd0;
        end
    else
        case(state)
            2'd0:
                begin
                    if(flag && en)
                        state <= 2'd1;
                    else
                        state <= 2'd0;
                end
            2'd1://发送数据
                begin
                    state <= 2'd2;
                    data_tx <= dataout_reg[47:40];
                    en_tx <= 1'b1;
                    dataout_reg <= dataout_reg << 8;
                end            
            2'd2://等待数据发送完成,并计数+1
                begin
                    if(bit_flag)
                        begin
                            if(tx_cnt>=3'd5)begin
                                state <= 2'd0;
                                tx_cnt <= 3'd0;                         
                            end
                            else begin
                                state <= 2'd1;
                                tx_cnt <= tx_cnt + 1'd1;                            
                            end 
                        end
                    else
                        begin
                            en_tx <= 1'b0;
                            state <= 2'd2;
                        end
                end 
            default : state <= 2'd0;
        endcase            
//------------------------ uart_tx_inst ------------------------
uart_tx
#(
    .UART_BPS    (UART_BPS  ),  //串口波特率
    .CLK_FREQ    (CLK_FREQ  )   //时钟频率
)
uart_tx_inst
(
    .sys_clk    (sys_clk    ),  
    .sys_rst_n  (sys_rst_n  ),  
    .pi_data    (data_tx    ),  
    .pi_flag    (en_tx      ),     
    
    .tx         (tx         ),   
    .tx_flag    (tx_flag    )
);

endmodule

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值