6410之UART使用中断方式

UART使用中断方式的流程:

1.组件有:DDR上面的一个buffer,UART上的FIFO,CPU

2.拿发送来说,UART上面FIFO可以设置一个阈值,当UART上的FIFO小于这个阈值的时候,UART就会发送一个中断给CPU,CPU就会将DDR上buffer中的数据自动发送给UART上的FIFO直到满为止,当FIFO又小于这个阈值的时候,又会进行这个操作。

如下图所示:


在上图中用到的buffer是一个环形缓冲区:

环形缓冲区相当与一个数组,比如:char buff[10],它分为下面几个情形(R:读指针,W:写指针):

1.环形缓冲区为空:R == W 都只想buff[0]

2.放入数据: buff[w] = val;w = (w+1)%10

3.取出数据 : val = buff[R] ; R = (R+1)%10     注:这个10是根据具体的环形缓冲区大小为定的。

4.环形缓冲区为满 : (w +1)%10 == R (这样的写法是为了和空的时候进行区别)


中断处理完成后,不仅要清中断源的中断,还要清中断控制器的中断:

列出部分代码:

uart初始化以及发送接受

#define ULCON0     (*((volatile unsigned long *)0x7F005000))
#define UCON0      (*((volatile unsigned long *)0x7F005004))
#define UFCON0     (*((volatile unsigned long *)0x7F005008))
#define UMCON0     (*((volatile unsigned long *)0x7F00500C))
#define UTRSTAT0   (*((volatile unsigned long *)0x7F005010))
#define UFSTAT0    (*((volatile unsigned long *)0x7F005018))
#define UTXH0      (*((volatile unsigned char *)0x7F005020))
#define URXH0      (*((volatile unsigned char *)0x7F005024))
#define UBRDIV0    (*((volatile unsigned short *)0x7F005028))
#define UDIVSLOT0  (*((volatile unsigned short *)0x7F00502C))
#define UINTP0      (*((volatile unsigned long *)0x7F005030))
 

#define UINTM0    (*((volatile unsigned long *)0x7F005038))         //uart 中断mask寄存器


#define GPACON     (*((volatile unsigned long *)0x7F008000))

#define ENABLE_FIFO 1

static delay(void)
{
	volatile int i = 10;
	while (i--);
}

void uart_tx_int_enable(void)         //使能uart中断源
{
	UINTM0 &= ~(1<<2);	
}

void uart_tx_int_disable(void)         //禁止uart中断源
{
	UINTM0 |= (1<<2);	
}


void init_uart(void)                  //初始化uart
{
	GPACON &= ~0xff;              //设置uart引脚为中断引脚,只有中断方式才会使用到
	GPACON |= 0x22;
	
	/* ULCON0 */
	ULCON0 = 0x3;  /* 数据位:8, 无较验, 停止位: 1, 8n1 */
	UCON0  = 0x5 | (1<<9);  /* 使能UART发送、接收, tx interrupt request type = level 使用电平触发*/
#ifdef ENABLE_FIFO
	UFCON0 = 0x07 | (1<<6); /* FIFO enable, tx fifo trigger level = 16 bytes 设置触发阈值*/	
#else
	UFCON0 = 0x00; /* FIFO disable */
#endif
	UMCON0 = 0;
	
	/* 波特率 */
	/* DIV_VAL = (PCLK / (bps x 16 ) ) - 1 
	 * bps = 57600
	 * DIV_VAL = (66500000 / (115200 x 16 ) ) - 1 
	 *         = 35.08
	 */
	UBRDIV0   = 35;

	/* x/16 = 0.08
	 * x = 1
	 */
	UDIVSLOT0 = 0x1;
    UINTM0 = 0xF;                     //初始化的时候先关闭中断源
}

unsigned char getc(void)              //读取一个字符
{
#ifdef ENABLE_FIFO
	while ((UFSTAT0 & (1<<6)) == 0 && (UFSTAT0 & 0x3f) == 0)delay();
#else	
	while ((UTRSTAT0 & (1<<0)) == 0);
#endif
	
	return URXH0;
}

int getc_nowait(unsigned char *pChar)     //非阻塞获取一个字符
{
#ifdef ENABLE_FIFO
	if ((UFSTAT0 & (1<<6)) == 0 && (UFSTAT0 & 0x3f) == 0)
#else
	if ((UTRSTAT0 & (1<<0)) == 0)
#endif		
	{
		return -1;
	}
	else
	{	
		*pChar = URXH0;
		return 0;
	}
}


#define TX_BUF_LEN   2048
static unsigned char txbuf[2047];
static unsigned int r_idx = 0;
static unsigned int w_idx = 0;

static int isFull(void)                          //判断环形缓冲区是否已经满
{
	if ((w_idx + 1) % TX_BUF_LEN == r_idx)
		return 1;
	else
		return 0;
}

static int isEmpty(void)                   //判断环形缓冲区是不是空
{
	return (w_idx == r_idx);
}

static int putData(unsigned char data)        //在环形缓冲区中放入数据
{
	if (isFull())
		return -1;
	else
	{
		txbuf[w_idx] = data;
		w_idx = (w_idx + 1) % TX_BUF_LEN;
		return 0;
	}
}

static int getData(unsigned char *pdata)          //从环形缓冲区获取数据
{
	if (isEmpty())
	{
		return -1;
	}
	else
	{
		*pdata = txbuf[r_idx];
		r_idx = (r_idx + 1) % TX_BUF_LEN;
		return 0;
	}
}

void putc(char c)
{
	putData(c);    /* 把数据放到缓冲区里去 */

	/* 如果"uart 发送中断"未使能的话,使能"uart 发送中断" */
	uart_tx_int_enable(); 
}

void do_uart_irq(void)         //uart的中断处理
{
	int i;
	int cnt;
	unsigned char c;
	
	if (UINTP0 & (1<<2))         
	{
		/* 对于发送中断 */
		 if (isEmpty())
		 {
		 	/* 禁止中断 */
			uart_tx_int_disable();
		 }
		 else
		 {
		 	/* 从环型缓冲区里取出数据, 放到TX FIFO里去 */
			cnt = (UFSTAT0 >> 8) & 0x3f;
			cnt = 64 - cnt;
			for (i = 0; i < cnt; i++)
			{
				if (getData(&c) == 0)
				{
					UTXH0 = c;
				}
				else
				{
					break;
				}
			}
		 }
	}

	else if (UINTP0 & (1<<0))
	{
		/* 对于接收中断, 从RX FIFO里取出数据 */
	}

	/* 清中断 */
	UINTP0 = 0xf;
}

irq中断控制器的设置:

#define GPNCON     (*((volatile unsigned long *)0x7F008830))
#define GPNDAT     (*((volatile unsigned long *)0x7F008834))

#define EINT0CON0  (*((volatile unsigned long *)0x7F008900))
#define EINT0MASK  (*((volatile unsigned long *)0x7F008920))

#define EINT0PEND  (*((volatile unsigned long *)0x7F008924))

#define PRIORITY    (*((volatile unsigned long *)0x7F008280))
#define SERVICE     (*((volatile unsigned long *)0x7F008284))
#define SERVICEPEND (*((volatile unsigned long *)0x7F008288))


#define VIC0IRQSTATUS  (*((volatile unsigned long *)0x71200000))
#define VIC0FIQSTATUS  (*((volatile unsigned long *)0x71200004))
#define VIC0RAWINTR    (*((volatile unsigned long *)0x71200008))
#define VIC0INTSELECT  (*((volatile unsigned long *)0x7120000c))
#define VIC0INTENABLE  (*((volatile unsigned long *)0x71200010))
#define VIC0INTENCLEAR (*((volatile unsigned long *)0x71200014))
#define VIC0PROTECTION (*((volatile unsigned long *)0x71200020))
#define VIC0SWPRIORITYMASK (*((volatile unsigned long *)0x71200024))
#define VIC0PRIORITYDAISY  (*((volatile unsigned long *)0x71200028))

#define VIC0VECTADDR0      (*((volatile unsigned long *)0x71200100))
#define VIC0VECTADDR1      (*((volatile unsigned long *)0x71200104))
#define VIC0ADDRESS        (*((volatile unsigned long *)0x71200f00))

#define VIC1IRQSTATUS  (*((volatile unsigned long *)0x71300000))
#define VIC1VECTADDR5      (*((volatile unsigned long *)0x71300114))
#define VIC1INTENABLE  (*((volatile unsigned long *)0x71300010))
#define VIC1ADDRESS        (*((volatile unsigned long *)0x71300f00))

void uart_irq_init(void);
void key_irq_init(void);


void eint0_3_irq(void)             //按键中断的处理
{
	int i;
	
	printf("eint0_3_irq\n\r");  /* K1~K4 */
	for (i = 0; i < 4; i ++)
	{
		if (EINT0PEND & (1<<i))
		{
			if (GPNDAT & (1<<i))
			{
				printf("K%d released\n\r", i+1);
			}
			else
			{
				printf("K%d pressed\n\r", i+1);
			}
		}
	}

}

void eint4_11_irq(void)
{
	int i;
	printf("eint4_11_irq\n\r"); /* K5~K6 */
	for (i = 4; i < 6; i ++)
	{
		if (EINT0PEND & (1<<i))
		{
			if (GPNDAT & (1<<i))
			{
				printf("K%d released\n\r", i+1);
			}
			else
			{
				printf("K%d pressed\n\r", i+1);
			}
		}
	}

}

void irq_init(void)       //中断初始化:按键和uart的中断初始化
{
	key_irq_init();
	uart_irq_init();
}


void uart_irq(void)
{
	/* 调用具体的中断处理函数 */
	do_uart_irq();            //处理中断,清中断源的中断
	/* 清中断 */
	VIC1ADDRESS = 0;         //清中断控制器的中断
}


void uart_irq_init(void)
{
	VIC1INTENABLE |= (1<<5); /* bit5: int_uart0 */ 使能中断控制器组的开关
	VIC1VECTADDR5 = uart_irq;//uart中断处理,会自动赋值给VIC1ADDRESS
}

void key_irq_init(void)
{
	/* 配置GPIO引脚为中断引脚 */
	/* GPN0~5 设为中断引脚 */
	GPNCON &= ~(0xfff);
	GPNCON |= 0xaaa;

	/* 设置中断触发方式为: 双边沿触发 */
	EINT0CON0 &= ~(0xfff);
	EINT0CON0 |= 0x777;

	/* 使能中断 */
	EINT0MASK &= ~(0x3f);

	/* 在中断控制器里使能这些中断 */
	VIC0INTENABLE |= (0x3); /* bit0: eint0~3, bit1: eint4~11 */ 

	VIC0VECTADDR0 = eint0_3_irq;
	VIC0VECTADDR1 = eint4_11_irq;

	/* 设置优先级 */
}


void do_irq(void)
{
	int i = 0;

	void (*the_isr)(void);

	if (VIC0IRQSTATUS)           //判断是哪个中断控制器发生的中断
	{
		the_isr = VIC0ADDRESS;
			
		/* 2.1 分辨是哪个中断 */
		/* 2.2 调用它的处理函数 */	
		/* 2.3 清中断 */	

		the_isr();
		
		EINT0PEND   = 0x3f;  /* 清中断 */
		VIC0ADDRESS = 0;
	}
	else if (VIC1IRQSTATUS)
	{
		the_isr = VIC1ADDRESS;
			
		/* 2.1 分辨是哪个中断 */
		/* 2.2 调用它的处理函数 */	
		/* 2.3 清中断 */	

		the_isr();
	}
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
博客园是一个知名的中文博客平台,提供了丰富的技术资讯和程序开发资源。下面是一个实现UART串口中断程序的示例,共计300字。 UART(Universal Asynchronous Receiver Transmitter)串口是一种常见的串行通信接口,用于在计算机和外部设备之间进行数据传输。串口中断程序是一种异步通信方式,通过触发中断信号来实现数据的传输和接收。 首先,在嵌入式开发中,我们需要先配置串口参数,包括波特率、数据位数、停止位数和奇偶校验等。然后,我们需要在芯片的中断向量表中设置一个中断服务函数来处理串口中断中断服务函数的主要功能是读取串口数据和发送数据,一般通过读取和写入相应的寄存器来完成。当检测到新的数据到达时,串口硬件会触发中断信号,并执行中断服务函数来处理数据。 在中断服务函数中,我们首先需要判断是否是接收到数据的中断,然后读取数据并进行相应的处理。例如,可以将接收到的数据存储到缓冲区中,或者根据接收到的命令执行相应的操作。 对于发送数据的中断,我们需要先判断是否需要发送数据,然后写入要发送的数据到发送寄存器中。发送完成后,可以通过中断标志位来判断发送是否成功,并进行相应的处理。 在实际开发中,我们需要注意一些细节问题,例如使用缓冲区来存储接收和发送的数据,以及设置优先级和开关中断等。此外,还需要根据具体的硬件平台和驱动库来编写相应的代码。 总结起来,博客园上可以找到关于UART串口中断程序的详细教程和示例代码,通过学习和实践可以掌握如何编写和使用UART串口中断程序。这对于嵌入式系统开发和通信应用非常有用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值