NIOS II --- UART

目录

1. 了解UART IP核

2. 如何用串口发送数据,接收数据?中断如何使用?

方式1

1)新建inc文件夹,写sopc.h和uart.h

2)编写串口通信需要的函数   

3)main函数

方式2


目的功能:当串口接收数据时,触发中断,然后将接收到的数据再发送出去。

1. 了解UART IP核

        下图是FPGA实现NIOS II 软核的整个框架,在搭建NIOS II时,内部可能会调用很多IP核来完成数据,代码的存储、JTAG功能以及串口通信等。NIOS II核与内部其他的IP核之间的通信是通过Avalon 总线的内部互连线连接。

        从下面的图可以看出,UART核内部有6个寄存器,分别是divisor、 rxdata、 state、 txdata、 control、 endofpacket,endofpacket可以在设置中配置是否使用, rxdata和txdata保存从移位寄存器中接收的数据和需要发给移位寄存器的数据,然后从state状态寄存器可以查看uart在收发数据过程中的状态,control就是对应d额不同寄存器状态可以选择是否产生中断。

2. 如何用串口发送数据,接收数据?中断如何使用?

        为了方便控制uart,可以通过构建结构体,将uart操作过程中需要的函数、状态标志、缓存区以及中断等全部封装成结构体的成员。在使用时就可以直接对结构体操作。

方式1

1)新建inc文件夹,写sopc.h和uart.h

        SOPC.h中主要是UART对应用结构体的编写,用于直接对寄存器进行控制的代码。主要包含5个寄存器,存储接收到的数据的RXDATA寄存器(从I/O接收的数据会先存放到此处)、存储需要发送的数据的TXDATA寄存器(需要发送出去的数据,会先放到这个寄存器然后发送)、控制中断等的CONTROL寄存器、表示串口状态的STATUS寄存器,还有存储波特率数据的DIVISOR寄存器。

#ifndef SOPC_H
#define SOPC_H
#include "system.h"
#define _UART
typedef struct
{
	union
	{
		struct
		{
			volatile unsigned long int RECEIVE_DATA :8;
			volatile unsigned long int NC :24;
		}BITS;
		volatile unsigned long int WORD;
	}RXDATA;
	union
	{
		struct
		{
			volatile unsigned long int TRANSMIT_DATA :8;
			volatile unsigned long int NC: 24;
		}BITS;
		volatile unsigned long int WORD;
	}TXDATA;
	union
	{
		struct
		{
			volatile unsigned long int PE  :1;
			volatile unsigned long int FE  :1;
			volatile unsigned long int BRK :1;
			volatile unsigned long int ROE :1;
			volatile unsigned long int TOE :1;
			volatile unsigned long int TMT :1;
			volatile unsigned long int TRDY:1;
			volatile unsigned long int RRDY:1;
			volatile unsigned long int E   :1;
			volatile unsigned long int NC  :1;
			volatile unsigned long int DCTS:1;
			volatile unsigned long int CTS :1;
			volatile unsigned long int EOP :1;
			volatile unsigned long int NC1 :19;
		}BITS;
		volatile unsigned long int WORD;
	}STATUS;
	union
	{
		struct
		{
			volatile unsigned long int IPE  :1;
			volatile unsigned long int IFE  :1;
			volatile unsigned long int IBRK :1;
			volatile unsigned long int IROE :1;
			volatile unsigned long int ITOE :1;
			volatile unsigned long int ITMT :1;
			volatile unsigned long int ITRDY:1;
			volatile unsigned long int IRRDY:1;
			volatile unsigned long int IE   :1;
			volatile unsigned long int TRBK :1;
			volatile unsigned long int IDCTS:1;
			volatile unsigned long int RTS  :1;
			volatile unsigned long int IEOP :1;
			volatile unsigned long int NC   :19;
		}BITS;
		volatile unsigned long int WORD;
	}CONTROL;
	union
	{
		struct
		{
			volatile unsigned long int BAUD_RATE_DIVISOR:16;
			volatile unsigned long int NC :16;
		}BITS;
		volatile unsigned long int WORD;
	}DIVISOR;
}UART_ST;

#ifdef _UART
#define UART  ((UART_ST*)(UART_BASE|(1<<31)))
#endif //_UART
#endif //SOPC_H

        因为在NIOS II/F内核中开启了data cache,而我们应用中并不需要开启,因此通过软件关闭。只需要将第31位置1,cache即可关闭。

uart.h中主要是串口通信相关的函数变量结构体,便于管理和统一。

#ifndef UART_H_
#define UART_H_

#include".../inc/sopc.h"

#define BUFFER_SIZE

typedef struct
{
	unsigned int receive_flag;
	unsigned int receive_count;
	unsigned char receive_buffer[BUFFER_SIZE];
	int(*send_byte)(unsigned char data);
	void(*send_string)(unsigned int len, unsigned char *str);
	int(*init)(void);
	unsigned int(*baudrate)(unsigned int baudrate);
}UART_T;
extern UART_T uart; //extern声明变量,表明此变量若在别处定义,需要此处引用
#endif

2)编写串口通信需要的函数   

//结构体初始化
UART_T uart={
		.receive_flag=0,
		.receive_count=0,
		.send_byte=uart_send_byte,
		.send_string=uart_send_string,
		.init=uart_init,
		.baudrate=set_baudrate};

int uart_send_byte(unsigned char data)
{
	UART->TXDATA.BITS.TRANSMIT_DATA=data; //指针指向,必须用->,实体里面的成员用.
	//等待TRDY从0变成1
	while(UART->STATUS.BITS.TRDY==0);  //RRDY=0,txdata register is full,not ready。 =1,txdata register is empty,readey
	return 0;
}
void uart_send_string(unsigned int len, unsigned char * str)
{
	while(len--)
	{
		uart_send_byte(*str++);
	}
}
int set_baudrate(unsigned int baudrate)
{
	UART->DIVISOR.WORD=(unsigned int)(ALT_CPU_FREQ)/(baudrate-1);
	return 0;
}
int uart_init(void)
{
	// 寄存器初始化
	UART->CONTROL.BITS.IBRK=1;  // enable interrupt for every  detect  接收中断
	UART->STATUS.WORD=0;  //清空状态
	//波特率设置
	set_baudrate(115200);
	// 中断初始化 包含中断使能,中断注册表
	alt_ic__isr_register(UART_IRQ_INTERRUPT_CONTROLLER_ID,UART_IRQ,uart_ISR,NULL,0x0);
	return 0;
}
static void uart_ISR(void)
{
	//等待RRDT为1,当为1说明接收的数据已经存入到rxdata寄存器中
	while(UART->STATUS.BITS.RRDY==0);
	//将接收的放在寄存器中的数据存放到指定的buffer中
	uart.receive_buffer[uart.receive_count++]=UART->RXDATA.BITS.RECEIVE_DATA;
	//判断是否接收结束,以\n标志结束
	if(uart.receive_buffer[uart.receive_count-1]=='\n')
	{
		uart.receive_buffer[uart.receive_count]='\0';
		uart.receive_count=0;
		uart.receive_flag=1;
	}
}

中断的产生:这里选择IBRK作为中断。通过检测接口是否接收到低电平,也就是起始位。如果接收到,产生中断。

中断函数:产生中断后,需要先确认rxdata寄存中是否已准备好数据,如果准备好了,那么将数据寄存,然后将标志位置1,如果没有,不可以寄存数据,可能导致寄存的数据是错误的。

         如上图所示,发送数据,需要往txdata 寄存器中写入数据,并且需要看状态寄存器中的TRDY位,如下图,要写一个新的数据给txdata 寄存器,TRDY必须=1。

         波特率的设置如下: 

3)main函数

int main(void)
{
	//初始化字符串BUFFER
	unsigned char buffer[50]="HELLO, FPGA\n";
	//串口初始化
	uart.init();
	//检测是否接收到PC端发来的数据
	while(1)
	{
		//若串口收到PC的数据,执行中断函数,那么将存在buffer中的值寄存
		if(uart.receive_flag)
		{
			memset(buffer,0,50); //buffer清零
			strcpy(buffer,uart.receive_buffer);//复制
			uart.receive_flag=0;
		}
		//将寄存的值发送给PC
		uart.send_string(sizeof(buffer),buffer);
		usleep(500000);

	}
	return 0;
}

方式2

        方式1是通过自己将UART的寄存器封装成结构体,然后自己构建串口通讯需要的函数。但是在eclipse的模板中,也直接提供了相关的函数, 可以直接调用来实现我们的功能。关于串口的寄存器在altera_avalon_uart_regs.h中,里面还包含各种宏定义。

例如要实现串口中断函数,如下,直接对寄存器进行操作。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值