lemonHe

主要关注FPGA信号处理和数字图像处理技术,欢迎交流 邮箱:heliminlemon@163.com

基于nios的串口通信uart设计

0
阅读(9135)

开发环境:Quartus II 13.1 (64-Bit)  + Nios II 13.1 Software Build Tools for Eclipse

 

Uart(通用异步收发器,也称异步串口)主要用于作通信,既然有异步通信,那一定有同步通信,对,确实有,同步串口,也就是所谓的Usrt,Usrt带一个时钟信号,一般来说,usrt比uart通信速率要快,但uart使用更简单,因此应用非常广泛。

对于RS-232通信,只需两根信号线(对应收发),一根地线即可完成通信,但传输距离较短,一般近距离(10m内)都没有问题;RS-485通信更简单,两线传输(差分信号),半双工,传输距离可以达到1000m;RS-422为4线传输,全双工模式,采用差分传输,传输距离与RS-485差不多。

初学者很容易陷入误区,通常说的Uart包括RS-232、RS-485、RS-422,比如RS-422属于Uart,但不等同于Uart。

最开始写uart的Verilog代码是参考大神特权同学的教程,用起来也是相当的方便,共需编写3个模块,分别为比特率生成模块、串口发送模块、串口接收模块,综合后RTL视图如下:

clip_image002

学习nios后发现可以直接用qsys中的uart核,用起来也是相当的方便啊,在qsys中添加相关Uart核来做串口通信其实很简单,如下图所示,只需添加on-chip memory核、nios核、uart核即可,将uart核的输出连出来。

clip_image004

Altpll输入时钟为50MHz,输出时钟100MHz,nios在100MHz时钟下运行。

在quartus工程中例化qsys,如下图所示,代码很简单,有么有!!!

module nios_uart(
input clk,
input rst_n,
input uart_rxd,
output uart_txd
);
small_nios small_nios_inst(
.clk_clk(clk), // clk.clk
.reset_reset_n(rst_n), // reset.reset_n
.uart_rxd(uart_rxd), // uart.rxd
.uart_txd(uart_txd) // .txd
);
endmodule

新建nios工程,添加如下代码,使用中断的方式进行串口通信,即FPGA每通过串口接收到一次数据,就进行一次中断,我们可以将要控制的部分写入串口中断服务程序中。

#include <stdio.h>
#include "unistd.h"
#include "system.h"
#include "alt_types.h"
#include "altera_avalon_uart_regs.h"
#include "sys\alt_irq.h"
#include "stddef.h"
static alt_u8 txdata = 0;
static alt_u8 rxdata = 0;
//UART中断服务函数
static void uart_isr(void * context,alt_u32 id)
{
    rxdata = IORD_ALTERA_AVALON_UART_RXDATA(UART_BASE);
    txdata = rxdata; //进行串口自收发
    //查询发送准备好信号,如果没有准备好,则等待
    while(!((IORD_ALTERA_AVALON_UART_STATUS(UART_BASE)&ALTERA_AVALON_UART_STATUS_TRDY_MSK)));
    //发送准备好,发送txdata
    IOWR_ALTERA_AVALON_UART_TXDATA(UART_BASE,txdata);
}
void uart_init()
{
    //清除状态寄存器
    IOWR_ALTERA_AVALON_UART_STATUS(UART_BASE,0);
    //使能接受准备好中断
    IOWR_ALTERA_AVALON_UART_CONTROL(UART_BASE,0X80);
}
int main()
{
    printf("Hello from Nios II!\n");
    //注册UART中断服务函数
    alt_irq_register(UART_IRQ,NULL,uart_isr);
    uart_init();
    return 0;
}

编译quartus工程和nios工程,通过后进行管脚分配,再编译一次quartus工程,下载逻辑和nios至FPGA,使用串口调试助手进行测试,打开串口后,发送数据至FPGA,FPGA接收到数据后进入中断服务程序,中断服务程序中txdata = rxdata;部分代码将接收到的数据发送出去,这样就完成了串口的自收发,结果如下。

clip_image006

当然,对于一些简单的控制(少于256种方式),比较简单的协议(发送一个字节)完全可以搞定问题,比如发送01,执行一种操作,……,ff执行另外一种操作。但是当控制项比较多时,就需要制定比较复杂的协议了,一般的串口控制协议如下图所示,n等于8时,发送10个byte,为了提高准确率,需要加入包头、包尾和校验字。

clip_image008

综合来看,不管是用逻辑还是用nios的方式,都可以实现串口通信,对于不太复杂的系统,完全可以只用逻辑来搭建,当然也就不需要用基于nios的串口通信了,但是,如果系统比较复杂,需要有稍复杂一些的通信协议时,还是有必要跑nios来做管理的,此时使用基于nios的串口通信就变得非常合适了!!!