ARM中断方式串口编程
---------------------------------------------------------
本文引用地址:https://www.eepw.com.cn/article/201611/317903.htmfrom:blog.csdn.net/tigerjb
Email:jibo.tiger@gmail.com
---------------------------------------------------------
三.中断方式的串口编程
1.用中断方式编写串口程序由那几部分组成
2.硬件上的支持
1>UART0发送FIFO缓冲区
A.UART0含有1个16字节的发送FIFO缓冲区
B.U0THR是UART0发送FIFO的最高字节
C.UART的发送FIFO是一直使能的
2>UART0接收FIFO缓冲区
A.UART0含有一个16字节的接收FIFO缓冲区。
B.软件设置接收FIFO缓冲区的触发字节。
3>中断接口:UART0的中断接口包含中断使能寄存器(U0IER)和中断标识寄存器(U0IIR)。
lU0IIR:提供状态码用于指示一个挂起中断的中断源和优先级。
lU0IER可以控制UART0的4个中断源。
4>UART0有4个中断源:
A.RLS(接收线状态)中断:
(1)优先级最高
(2)它在以下条件发生时产生错误
l帧错误(FE)
l溢出错误(OE)
l奇偶错误(PE)
l间隔中断(BI)
注:
Ø可以通过查看U0LSR[4:1]中的值看到产生该中断的错误条件
Ø读取U0LSR寄存器时清除该中断。
B.RDA(接收数据可用)中断:
(1)与CTI中断并列第二优先级。
(2)在以下情况触发中断:
l当接收的有效数据到达接收FIFO设置寄存器(U0FCR)中设置的触发点时,RDA被激活。当接收FIFO中的有效数据少于触发点时,RDA复位。
l中断过程:
1>移位寄存器(U0RSR)从RxD引脚接收串行数据后,送入接收FIFO中
2>当接收FIFO中的有效数据数量达到预定的触发点时,置位RDA中断。
3>从U0RBR寄存器中读取FIFO中最早到达的数据,当FIFO中的有效数据小于触发点时,清零RDA中断。
C.CTI(字符超时指示)中断
(1)优先级为2.
(2)在以下情况发生中断:
l当接收FIFO中的有效数据少于预定的触发点数量时,如果在一定时间内仍没有接收到新的数据,那将触发该中断。
(3)上面的时间指的是:3.5~4.5个字节所需要的时间。
(4)对接收FIFO的任何操作都会清零该中断标志。
(5)中断过程:
l移位寄存器(U0RSR)从RxD0引脚接收串行数据后,送入接收FIFO中。
l当接收FIFO中的有效数据少于触发个数,但如果长时间没有数据到达,则触发CTI中断。
l从U0RBR中读取接收FIFO中的数据,或者有新的数据送入接收FIFO,都将清零CTI中断。
注:
Ø3.5~4.5个字节的时间:指在串口当前的波特率下,发送3.5~4.5个字节所需要的时间。
Ø当接收FIFO中存放多个数据,从U0RBR读取数据,但是没有读完所有数据,那么在经过3.5~4.5个字节的时间后触发CTI中断。
D.THRE(发送)中断
(1)优先级为第三级优先级。
(2)当FIFO为空并且在以下情况触发中断:
l系统启动时,虽然发送FIFO为空,但不会产生THRE中断。
l在上一次发生THRE中断后,向发送FIFO中写入1个字节数据,将在一个字节加上一个停止位后发生THRE中断
(because:如果发送移位寄存器为空,那么写入发送FIFO的数据将直接进入发送移位寄存器。此时发送FIFO仍然为空,如果立即产生THRE中断,就会影响紧接着写入发送FIFO的数据。
所以在发送完该一个字节以及一个停止位后,才产生THRE中断。
l如果在发送FIFO中有过两个字节以上的数据,但是现在发送FIFO为空时,将立即触发THRE中断。
l当THRE中断为当前有效的最高优先级中断时,往U0THR写数或者对U0IIR的读操作,将使THRE中断复位
我们来看看这些中断源与存储器之间的关系:
注:
Ø由上图可知:UART0有4个中断源:分别是RLS(线状态)中断,RDA(接收数据)中断,CTI(字符超时)中断,THRE(发送数据)中断。
Ø4个中断源的优先级如下图所示:
3.串口中断接收初始化
1>串口中断接收初始化流程
l设置I/O引脚连接到UART0
l置位除数锁存位,配置UART0帧数据格式
l根据波特率计算分频值
l设置波特率
l清除除数锁存位,并设置工作模式
l使能FIFO,并设置触发点
l允许RBR中断
注:我们可以发现与轮训方式相比,中断方式只是增加了使能FIFO,并设置中断触发点和允许RBR中断两步。2>中断串口初始化需要配置的寄存器
(与轮循方式配置方法相同的寄存器在此处不在涉及)
lU0FCR(FIFO控制寄存器):U0FCR控制UART0 Rx和Tx FIFO的操作。
lU0IER(中断使能寄存器):U0IER用于使能4个UART0中断源。
3>具体寄存器的配置
(1)U0FCR
A作用:控制UART0 Rx和Tx的操作。
B长度:8位寄存器。
C:每一位的含义:
l第0位:表示FIFO使能
置1:表示使能对UART0 Rx和Tx的FIFO以及U0FCR[7:1]的访问。
置0:表示不能使用Rx和Tx的FIFO以及步能对U0FCR[7:1]的访问。
注:该位的任何变化都将使UART0 FIFO清空。
l第1位:表示Rx FIFO的复位。
置1:会清零UART0 RxFIFO中的所有字节并复位指针逻辑。该位自动清零。
l第2位:表示Tx FIFO的复位。
置1:会清零UART0 TxFIFO中的所有字节并复位指针逻辑。改位自动清零。
l第[5:3]位:保留位,用户不能对其进行操作。从保留位读出的值未被定义。
l第[7:6]位:表示Rx触发选择
00:触发点为0(默认为1字节)
01:触发点为1(默认为4字节)
10:触发点为2(默认为8字节)
11:触发点为3(默认为14字节)
注:这两个位决定在激活中断之前,接收UART0 FIFO必须写入个字符。
(2)U0IER(中断使能寄存器)
A作用:U0IER用于使能4个UART0中断源
B长度:8位寄存器
C每一位的含义:
l第0位:表示RBR中断使能
置1:使能RDA中断
置0:禁止RDA中断
注:U0IEER第零位使能UART0接收数据可用中断。它还控制(CTI)字符接收超时中断。
l第1位:表示THRE中断使能
置1:使能THRE中断
置0:禁止THRE中断
l第2位:表示Rx线状态中断使能
置1:使能Rx线状态中断
置0:禁止RX线状态中断
注:U0IER第二位使能UART0 Rx线状态中断。该中断的状态可从U0LSR[4:1]读出
l第[7:3]位:是保留位
注:用户不能向其写入1.
4>串口初始化程序:
*
*作者:tiger-john
*时间:2011年1月18日
*名称:UART0_Init
*功能:UART0初始化通讯波特率115200,8位数据位,1位停止位,无奇偶校验
*接收FIFO触发点为8字节,使能RDR(接收数据)中断
*入口参数:bps串口波特率
*出口参数:无
/
voidUART0_Init(uint32 bps)
{
uint16Fdiv;
PINSEL0 = (PINSEL0 & ~(0xf) | 0x05) ;//设置UART0的引脚
U0LCR = 0x83;//置为除数锁存位,进行配置
Fdiv = (Fpclk>>4)/bps;
U0DLM = Fdiv>>8;
U0DLL = Fdiv%256;
U0LCR = 0x03;//清除除数锁存位,并设置工作模式
U0FCR = 0x81;//使能FIFO,并设置触发点为8字节
U0IER = 0x01;//允许RBR中断,即接收中断
}
5.中断初始化
先来看一下UART0和VIC之间的关系:
1>中断初始化流程:
l选择中断为向量中断或快速中断
l分配中断通道
l设置UART0向量地址
l使能UART0中断
2>关于ARM中断编程方法和寄存器的使用在此不做涉及(如果想知道的话,可以看这篇文章http://blog.csdn.net/tigerjb/archive/2010/11/30/6045409.aspx
3>中断初始化程序:
/
*作者:tiger-john
*时间:2011年1月18日
*名称:Interrupt_Init
*功能:初始化串口中断,给串口中断选择为向量中断,分配向量通道号1给串口
*入口参数:无
*出口参数:无
/
void Interrupt_Init (void)
{
VICIntSelect = 0x00000000;//设置所有通道为IRQ中断
VICVectCntl1 = (0x20 | 6);// UART0中断通道分配到IRQ slot 1
VICVectAddr1 = (uint32)UART0_Exception; //设置UART0向量地址
VICIntEnable = 1 << 6;//使能串口中断
}
6.用中断编写接收函数
1>中断服务函数流程
l清除串口中断标识寄存器(U0IIR)
l清除中断标志
l读取接收FIFO中的数据
2>中断函数服务函数中需要配置的寄存器
(1)U0IIR中断标识寄存器。
l第0位:表示中断挂起
置1:表示没有挂起的中断
置0:表示至少有一个中断挂起
l第[3:1]位:中断标识,这三位表示了对应UART0 Rx FIFO的中断。
001:表示发送中断(THRE)
010:表示接收数据可用中断(RDA)
011:表示接收线状态中断(RLS)
110:表示字符超时中断(CTI)
l第[7:4]:是保留位
注:
1.U0IIR提供的状态码可用于指示一个挂起中断的中断源和优先级。
2.在访问U0IIR过程中,中断被冻结
3.如果在访问U0IIR时,产生了中断,该中断被记录。在下次访问U0IIR时可以读出,避免中断的丢失。
3>中断服务函数程序:
/* *名称:IRQ_UART0()
*功能:串口UART0中断接收8个字节的数据
*入口参数:无
*出口参数:无
/
uint8rcv_buf[8];// UART0数据接收缓冲区
void__irq IRQ_UART0(void)
{uint8i;
uint32 data;
data = U0IIR;//清除中断表示寄存器标志
VICVectAddr = 0;//清除中断
for(i=0; i<8; i++)
{
rcv_buf[i] = U0RBR;//读取FIFO的数据
}
}
7.看一个总程序:
- /Copyright(c)
- 西安邮电学院
- graduateschool
- XNMS实验室
- Author:冀博
- Time:2011年1月20日
- http://blog.csdn.net/tigerjb
- --------------FileInfo-------------------------------------------------------------------------------
- Filename:UART0_while
- LastmodifiedDate:2011-01-20
- LastVersion:1.0
- Descriptions:通过上位机给串口发送8字节数据,ARM2200接收到串口数据后,把数据又发送回上位机
- ------------------------------------------------------------------------------------------------------*/
- /
- Modifiedby:TIGER0-JOHN
- Modifieddate:2011-1-21
- Version:2.0
- Descriptions:测试成功
- 在用中断的时候在Startup.S文件中的InitStack子程序中,修改设置
- 系统模式堆栈处的代码为"MSRCPSR_c,#0x5f"
- 测试成功,在上面上发送16进制数时,每个之间用空格隔开
- 不加前缀
- /
- #include"config.h"
- uint8recver_buffer[8];
- uint8rcv_new;
- /
- *名称:UART0_Init()
- *功能:UART0初始化(通讯波特率115200,8位数据位,
- 1位停止位,无奇偶校验)
- *入口参数:bps串口波特率
- *出口参数:无
- /
- voidUART0_Init(uint32bps)
- {
- uint16Fdiv;
- PINSEL0=0x00000005;//设置串口引脚
- U0LCR=0x83;//置为除数锁存位,进行配置
- Fdiv=(Fpclk>>4)/bps;//设置波特率
- U0DLM=Fdiv>>8;
- U0DLL=Fdiv&0xff;
- U0LCR=0x03;//清除除数锁存位,并设置工作模式模式
- U0FCR=0x81;//使能FIFO,并设置触发点为8字节
- U0IER=0x01;//允许RBR中断,即接收中断
- }
- /*
- *名称:IRQ_UART0
- *功能:串口UART0中断接收8个字节的数据
- *入口参数:无
- *出口参数:无
- /
- void__irqIRQ_UART0(void)
- {uint8i;
- if(0x04==(U0IIR&0x0F))
- {
- rcv_new=1;//设置接收到新的数据标志,并清除中断标志位
- for(i=0;i<8;i++)
- {
- recver_buffer[i]=U0RBR;//读取FIFO的数据
- }
- VICVectAddr=0;
- }//清除中断
- }
- /
- *名称:Interrupt_Init
- *功能:初始化串口中断,给串口中断选择为向量中断,
- *分配向量通道号1给串口
- *入口参数:无
- *出口参数:无
- /
- voidInterrupt_Init(void)
- {
- VICIntSelect=0x00000000;//设置所有通道为IRQ中断
- VICVectCntl0=0x26;//UART0中断通道分配到IRQslot0,即优先级最高
- VICVectAddr0=(int)IRQ_UART0;//设置UART0向量地址
- VICIntEnable=0x00000040;//使能UART0中断
- }
- /
- *名称:UART0_SendByte
- *功能:向串口发送字节数据,并等待发送完毕。
- *入口参数:data要发送的数据
- *出口参数:无
- /
- voidUART0_SendByte(uint8data)
- {
- U0THR=data;
- while(0==(U0LSR&0x40));
- }
- /
- *名称:UART0_SendBuf()
- *功能:通过串口发送一帧数据
- *入口参数:*buffer存放一帧数据
- *出口参数:无
- /
- voidUART0_SendBuf(uint8*buffer)
- {
- uint8*pbuffer;
- uint8i;
- for(pbuffer=buffer,i=0;i<8;i++)
- UART0_SendByte(*(pbuffer++));
- }
- /
- *名称:main()函数
- *功能:上位机接收的数据开头两个字符为0x10,0x11,
- *则原样输出,否次输出0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
- *入口参数:*buffer存放一帧数据
- *出口参数:无
- /
- intmain(void)
- {
- uint8send_buffer[8]={0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27};//定义发送帧缓冲区
- UART0_Init(115200);
- Interrupt_Init();
- while(1)
- {
- if(1==rcv_new)//是否已经接收到8Bytes的数据
- {
- rcv_new=0;//清除标志
- if(0x10==recver_buffer[0]&&0x11==recver_buffer[1])
- {
- UART0_SendBuf(send_buffer);
- }
- else
- {
- UART0_SendBuf(recver_buffer);
- }
- }
- }
- return0;
- }
- /*
- EndOfFile
- /
四.用中断编写发送函数
1.中断初始化
同上和用中断接收函数时的中断初始化是一样的
2.串口初始化
1>串口初始化流程:
l设置I/O引脚连接到UART0
l置位除数锁存位,配置UART0帧格式
l根据波特率计算分频值
l设置波特率
l清除除数锁存位,并设置工作模式
l使能FIFO,并使TxFIFO复位
l使能THRE中断
2>串口初始化函数:
/
*名称:UART0_Init
*功能:UART0初始化通讯波特率115200,8位数据位,1位停止位,无奇偶校验
*使能TxFIFO,和THRE中断
*入口参数:bps串口波特率
*出口参数:无
/
voidUART0_Init(uint32 bps)
{
uint16Fdiv;
PINSEL0 = (PINSEL0 & ~(0xf) | 0x05) ;//设置UART0的引脚
U0LCR = 0x83;//置位除数锁存位,配置UART0帧格式
Fdiv = (Fpclk>>4)/bps;//根据波特率计算分频值
U0DLM = Fdiv>>8;//设置波特率
U0DLL = Fdiv%256;
U0LCR = 0x03;//清除除数锁存位,并设置工作模式
U0FCR = 0x05;//使能TxFIFO,并使TxFIFO复位
U0IER = 0x02;//使能THRE中断
}
3中断服务函数:
1>中断服务函数流程:
l清除串口中断标识寄存器
l清除中断控制标识寄存器
2>中断发送服务函数程序:
/
*名称:UART0_Exception
*功能:串口发送中断
*入口参数:无
*出口参数:data发送的数据
/
void__irq IRQ_UART0(void)
{
uint32 data;
data = U0IIR;//清除中断表示寄存器标志
VICVectAddr = 0;//清除中断
}
4.用串口中断发送函数的总程序:
- /Copyright(c)
- 西安邮电学院
- graduateschool
- XNMS实验室
- Author:冀博
- Time:2011年1月20日
- http://blog.csdn.net/tigerjb
- --------------FileInfo-------------------------------------------------------------------------------
- Filename:UART0_while
- LastmodifiedDate:2011-01-20
- LastVersion:1.0
- Descriptions:通过上位机给串口发送8字节数据,ARM2200接收到串口数据后,用中断方式把数据又发送回上位机
- ------------------------------------------------------------------------------------------------------*/
- /
- Modifiedby:TIGER0-JOHN
- Modifieddate:2011-1-21
- Version:2.0
- Descriptions:测试成功
- 在用中断的时候在Startup.S文件中的InitStack子程序中,修改设置
- 系统模式堆栈处的代码为"MSRCPSR_c,#0x5f"
- 测试成功,在上面上发送16进制数时,每个之间用空格隔开
- 不加前缀
- /
- #include"config.h"
- uint8recver_buffer[8];
- uint8rcv_new;
- /
- *名称:UART0_Init
- *功能:UART0初始化通讯波特率115200,8位数据位,1位停止位,无奇偶校验
- *使能TxFIFO,和THRE中断
- *入口参数:bps串口波特率
- *出口参数:无
- /
- voidUART0_Init(uint32bps)
- {
- uint16Fdiv;
- PINSEL0=(PINSEL0&~(0xf)|0x05);//设置UART0的引脚
- U0LCR=0x83;//置位除数锁存位,配置UART0帧格式
- Fdiv=(Fpclk>>4)/bps;//根据波特率计算分频值
- U0DLM=Fdiv>>8;//设置波特率
- U0DLL=Fdiv%256;
- U0LCR=0x03;//清除除数锁存位,并设置工作模式
- U0FCR=0x05;//使能TxFIFO,并使TxFIFO复位
- U0IER=0x02;//使能THRE中断
- }
- /
- *名称:UART0_Exception
- *功能:串口发送中断
- *入口参数:无
- *出口参数:data发送的数据
- /
- void__irqIRQ_UART0(void)
- {
- uint32data;
- data=U0IIR;//清除中断表示寄存器标志
- VICVectAddr=0;//清除中断
- }
- /
- *名称:Interrupt_Init
- *功能:初始化串口中断,给串口中断选择为向量中断,
- *分配向量通道号1给串口
- *入口参数:无
- *出口参数:无
- /
- voidInterrupt_Init(void)
- {
- VICIntSelect=0x00000000;//设置所有通道为IRQ中断
- VICVectCntl0=0x26;//UART0中断通道分配到IRQslot0,即优先级最高
- VICVectAddr0=(int)IRQ_UART0;//设置UART0向量地址
- VICIntEnable=0x00000040;//使能UART0中断
- }
- /
- *名称:UART0_RcvByte
- *功能:用查询方式接收一字节的数据
- *入口参数:无
- *出口参数:data要接收的数据
- /
- uint8UART0_RcvByte(void)
- {
- uint8rcv_data;
- while((U0LSR&0X01)==0);//等待数据到达
- rcv_data=U0RBR;//从U0RBR中读出接收到的数据
- returnrcv_data;//返回接收到的数据
- }
- /
- *名称:UART0_RecBuf()
- *功能:接收串口发送过来的帧数据,
- *入口参数:*buffer存放一帧数据
- *出口参数:无
- /
- voidUART0_RecBuf(uint8*buffer)
- {
- uint8*pbuffer;
- uint8i;
- for(pbuffer=buffer,i=0;i<8;i++)
- {
- *(pbuffer++)=UART0_RcvByte();
- }
- }
- /
- *名称:main()函数
- *功能:上位机接收的数据开头两个字符为0x10,0x11,
- *则原样输出,否次输出0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
- *入口参数:*buffer存放一帧数据
- *出口参数:无
- /
- intmain(void)
- {
- uint8i;
- uint8send_buffer[8]={0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27};//定义发送帧缓冲区
- UART0_Init(115200);
- Interrupt_Init();
- while(1)
- {
- UART0_RecBuf(recver_buffer);//接收8字节数据
- if(0x10==recver_buffer[0]&&0x11==recver_buffer[1])
- {
- for(i=0;i<8;i++)
- {
- U0THR=send_buffer[i];//用中断发送每次8字节
- }
- }
- else
- {
- for(i=0;i<8;i++)//用中断发送每次8字节
- {
- U0THR=recver_buffer[i];
- }
- }
- }
- return0;
- }
- /*
- EndOfFile
- /
评论