tiny6410裸机实验第8章--------------中断(中断版UART)
2014-03-07 12:06
281 查看
【说明】
我们在第4章已经介绍了UART的原理,但是当时我们在发送数据的时候是用查询方式的,也就是如果FIFO满了,我们就一直循环等待,这显然太浪费时间了。这一节我们就用中断的方式操作UART,我们只介绍发送,接收其实和发送擦不多的。
【原理】
6410的UART有个中断模式,记得FIFO缓冲区吗?
1)我们将设置UART控制器根据缓冲区的内容多少来发送中断,具体地,当发送FIFO中内容数目低于一个值,就会产生一个中断
2)我们的putc 函数不是直接往缓冲区写数据,而是放在一个我们自己定义的内存缓冲区中,其实就是一个环形队列。
3)当中断来的时候说明FIFO中的内容数目已经低于一个值,我们就在中断处理函数中将环形队列中的数据复制到FIFO中,到FIFO满为止
4)复制好后CPU管自己工作,UART控制器就是一个一个发送数据,当FIFO又低于一个值时,又会产生中断,我们又回到第3步。
【环形缓冲区】
![](http://img.blog.csdn.net/20140307115651937?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20140307115611218?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20140307115833921?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20140307115931437?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20140307115959500?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20140307120037703?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
【初始化】
这个寄存器我们原来只设置为0X5,现在需要把第9位设置为1,使其可以触发中断
![](http://img.blog.csdn.net/20140307112931140?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20140307112959734?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
下面这个寄存器我们现在需要把第6,7位设置成01.,其实设置成别的也可以,它表示当缓冲区里面数据数目少于多少的时候产生中断
![](http://img.blog.csdn.net/20140307113303187?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20140307113349140?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
在初始化的时候我们得先关闭中断,因为我们的缓冲区中根本就没有数据,什么时候打开呢?在下面的发送函数中
![](http://img.blog.csdn.net/20140307113746812?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20140307113810250?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGludXhfZm9yX3lvdQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
【中断处理函数关键代码】
【UART中断代码】
其他内容直接看源代码的注释比较好
我们在第4章已经介绍了UART的原理,但是当时我们在发送数据的时候是用查询方式的,也就是如果FIFO满了,我们就一直循环等待,这显然太浪费时间了。这一节我们就用中断的方式操作UART,我们只介绍发送,接收其实和发送擦不多的。
【原理】
6410的UART有个中断模式,记得FIFO缓冲区吗?
1)我们将设置UART控制器根据缓冲区的内容多少来发送中断,具体地,当发送FIFO中内容数目低于一个值,就会产生一个中断
2)我们的putc 函数不是直接往缓冲区写数据,而是放在一个我们自己定义的内存缓冲区中,其实就是一个环形队列。
3)当中断来的时候说明FIFO中的内容数目已经低于一个值,我们就在中断处理函数中将环形队列中的数据复制到FIFO中,到FIFO满为止
4)复制好后CPU管自己工作,UART控制器就是一个一个发送数据,当FIFO又低于一个值时,又会产生中断,我们又回到第3步。
【环形缓冲区】
【初始化】
这个寄存器我们原来只设置为0X5,现在需要把第9位设置为1,使其可以触发中断
下面这个寄存器我们现在需要把第6,7位设置成01.,其实设置成别的也可以,它表示当缓冲区里面数据数目少于多少的时候产生中断
在初始化的时候我们得先关闭中断,因为我们的缓冲区中根本就没有数据,什么时候打开呢?在下面的发送函数中
【中断处理函数关键代码】
void irq_init(void) { 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; } 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(); } }
【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)) #define GPACON (*((volatile unsigned long *)0x7F008000)) #define ENABLE_FIFO 1 static void delay(void) { volatile int i = 10; while (i--); } void uart_tx_int_enable(void) { UINTM0 &= ~(1<<2); } void uart_tx_int_disable(void) { UINTM0 |= (1<<2); } void init_uart(void) { GPACON &= ~0xff; 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) { 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; }
相关文章推荐
- tiny6410裸机实验第8章--------------中断(原理及代码)
- tiny6410裸机实验第8章--------------中断(中断向量寄存器)
- tiny6410裸机实验第4章--------------UART(原理分析)
- MAX32630/MAX32625学习:UART串口初始化、发送函数,接收中断及实验(绝对实用)
- S02_CH09_UART串口中断实验
- mini2440 uart串口实验(fifo模式+中断)
- tiny6410裸机实验第4章--------------UART(printf, scanf)
- STM32单片机学习(5) 定时器中断实验
- MOOC清华《面向对象程序设计》第8章:悬挂指针实验
- MOOC清华《面向对象程序设计》第8章:装饰模式实验
- ZigBee基础实验(六)--UART(串口收发)
- 基于platform的ok6410按键中断实验
- STM32实验1:定时器中断同时产生两路不同频率的信号
- 定时器中断 流水灯实验
- tiny6410裸机实验第1章--------------ARM汇编和编程基础(ATPCS 简介)
- OpenRisc-26-openrisc中断实验
- 单片机UART中断应用中TXE和TC的顺序
- 第8章 信号(4)_中断的系统调用和函数可重入性
- 外部中断实验
- Linux内核分析(实验五)分析system_call中断处理过程