UART0串口编程系列(二)

来源:互联网 发布:丛云牙 知乎 编辑:程序博客网 时间:2024/06/06 00:07

三. 中断方式的串口编程

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)。

l U0IIR:提供状态码用于指示一个挂起中断的中断源和优先级。

l U0IER可以控制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>中断串口初始化需要配置的寄存器

(与轮循方式配置方法相同的寄存器在此处不在涉及)

l U0FCR(FIFO控制寄存器):U0FCR控制UART0 Rx和Tx FIFO的操作。

l U0IER(中断使能寄存器):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 串口波特率

* 出口参数: 无

****************************************************************************/

void UART0_Init(uint32 bps)

{

uint16 Fdiv;

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个字节的数据

* 入口参数:无

* 出口参数:无

**********************************************************/

uint8 rcv_buf[8]; // UART0数据接收缓冲区

void __irq IRQ_UART0(void)

{ uint8 i;

uint32 data;

data = U0IIR; //清除中断表示寄存器标志

VICVectAddr = 0; //清除中断

for(i=0; i<8; i++)

{

rcv_buf[i] = U0RBR; // 读取FIFO的数据

}

}

7. 看一个总程序:

[c-sharp] view plaincopyprint?
  1. /****************************************Copyright (c)**************************************************
  2. ** 西安邮电学院
  3. ** graduate school
  4. ** XNMS实验室
  5. ** Author:冀博
  6. ** Time:2011年1月20日
  7. ** http://blog.csdn.net/tigerjb
  8. **
  9. **--------------File Info-------------------------------------------------------------------------------
  10. ** File name: UART0_while
  11. ** Last modified Date: 2011-01-20
  12. ** Last Version: 1.0
  13. ** Descriptions: 通过上位机给串口发送8字节数据,ARM2200接收到串口数据后,把数据又发送回上位机
  14. **------------------------------------------------------------------------------------------------------*/
  15. /**********************************************************************************
  16. ** Modified by: TIGER0-JOHN
  17. ** Modified date: 2011-1-21
  18. ** Version: 2.0
  19. ** Descriptions: 测试成功
  20. 在用中断的时候在Startup.S文件中的InitStack子程序中,修改设置
  21. 系统模式堆栈处的代码为"MSR CPSR_c,#0x5f"
  22. 测试成功 ,在上面上发送16进制数时,每个之间用空格隔开
  23. 不加前缀
  24. ********************************************************************************/
  25. #include "config.h"
  26. uint8 recver_buffer[8];
  27. uint8 rcv_new;
  28. /**********************************************************
  29. * 名称: UART0_Init()
  30. * 功能: UART0初始化(通讯波特率115200,8位数据位,
  31. 1位停止位,无奇偶校验)
  32. * 入口参数: bps 串口波特率
  33. * 出口参数: 无
  34. **********************************************************/
  35. void UART0_Init(uint32 bps)
  36. {
  37. uint16 Fdiv;
  38. PINSEL0 = 0x00000005; //设置串口引脚
  39. U0LCR = 0x83; //置为除数锁存位,进行配置
  40. Fdiv = (Fpclk >> 4) / bps; // 设置波特率
  41. U0DLM = Fdiv >> 8;
  42. U0DLL = Fdiv & 0xff;
  43. U0LCR = 0x03; //清除除数锁存位,并设置工作模式模式
  44. U0FCR = 0x81; // 使能FIFO,并设置触发点为8字节
  45. U0IER = 0x01; // 允许RBR中断,即接收中断
  46. }
  47. /*********************************************************
  48. * 名 称: IRQ_UART0
  49. * 功 能: 串口UART0中断接收8个字节的数据
  50. * 入口参数: 无
  51. * 出口参数: 无
  52. **********************************************************/
  53. void __irq IRQ_UART0(void)
  54. { uint8 i;
  55. if( 0x04 == (U0IIR&0x0F) )
  56. {
  57. rcv_new = 1; // 设置接收到新的数据标志,并清除中断标志位
  58. for(i=0; i<8; i++)
  59. {
  60. recver_buffer[i] = U0RBR; // 读取FIFO的数据
  61. }
  62. VICVectAddr = 0;
  63. } //清除中断
  64. }
  65. /**********************************************************
  66. * 名称: Interrupt_Init
  67. * 功能: 初始化串口中断,给串口中断选择为向量中断,
  68. * 分配向量通道号1给串口
  69. * 入口参数: 无
  70. * 出口参数: 无
  71. **********************************************************/
  72. void Interrupt_Init (void)
  73. {
  74. VICIntSelect = 0x00000000; // 设置所有通道为IRQ中断
  75. VICVectCntl0 = 0x26; // UART0中断通道分配到IRQ slot 0,即优先级最高
  76. VICVectAddr0 = (int)IRQ_UART0; // 设置UART0向量地址
  77. VICIntEnable = 0x00000040; // 使能UART0中断
  78. }
  79. /**********************************************************
  80. * 名 称: UART0_SendByte
  81. * 功 能: 向串口发送字节数据,并等待发送完毕。
  82. * 入口参数: data 要发送的数据
  83. * 出口参数: 无
  84. **********************************************************/
  85. void UART0_SendByte(uint8 data)
  86. {
  87. U0THR = data;
  88. while(0 == (U0LSR & 0x40));
  89. }
  90. /**********************************************************
  91. * 名称: UART0_SendBuf()
  92. * 功能: 通过串口发送一帧数据
  93. * 入口参数: *buffer 存放一帧数据
  94. * 出口参数: 无
  95. **********************************************************/
  96. void UART0_SendBuf(uint8 *buffer)
  97. {
  98. uint8 *pbuffer;
  99. uint8 i;
  100. for(pbuffer = buffer,i = 0;i < 8; i++)
  101. UART0_SendByte(*(pbuffer++));
  102. }
  103. /**********************************************************
  104. * 名称: main()函数
  105. * 功能: 上位机接收的数据开头两个字符为0x10,0x11,
  106. * 则原样输出,否次输出0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
  107. * 入口参数: *buffer 存放一帧数据
  108. * 出口参数: 无
  109. **********************************************************/
  110. int main (void)
  111. {
  112. uint8 send_buffer[8] ={0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27}; //定义发送帧缓冲区
  113. UART0_Init(115200);
  114. Interrupt_Init();
  115. while(1)
  116. {
  117. if(1 == rcv_new) // 是否已经接收到8 Bytes的数据
  118. {
  119. rcv_new = 0; // 清除标志
  120. if(0x10 ==recver_buffer[0] && 0x11 == recver_buffer[1])
  121. {
  122. UART0_SendBuf(send_buffer);
  123. }
  124. else
  125. {
  126. UART0_SendBuf(recver_buffer);
  127. }
  128. }
  129. }
  130. return 0;
  131. }
  132. /*********************************************************************************************************
  133. ** End Of File
  134. ********************************************************************************************************/

四.用中断编写发送函数

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 串口波特率

* 出口参数: 无

**********************************************************/

void UART0_Init(uint32 bps)

{

uint16 Fdiv;

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. 用串口中断发送函数的总程序:

[c-sharp] view plaincopyprint?
  1. /****************************************Copyright (c)**************************************************
  2. ** 西安邮电学院
  3. ** graduate school
  4. ** XNMS实验室
  5. ** Author:冀博
  6. ** Time:2011年1月20日
  7. ** http://blog.csdn.net/tigerjb
  8. **
  9. **--------------File Info-------------------------------------------------------------------------------
  10. ** File name: UART0_while
  11. ** Last modified Date: 2011-01-20
  12. ** Last Version: 1.0
  13. ** Descriptions: 通过上位机给串口发送8字节数据,ARM2200接收到串口数据后,用中断方式把数据又发送回上位机
  14. **------------------------------------------------------------------------------------------------------*/
  15. /**********************************************************************************
  16. ** Modified by: TIGER0-JOHN
  17. ** Modified date: 2011-1-21
  18. ** Version: 2.0
  19. ** Descriptions: 测试成功
  20. 在用中断的时候在Startup.S文件中的InitStack子程序中,修改设置
  21. 系统模式堆栈处的代码为"MSR CPSR_c,#0x5f"
  22. 测试成功 ,在上面上发送16进制数时,每个之间用空格隔开
  23. 不加前缀
  24. ********************************************************************************/
  25. #include "config.h"
  26. uint8 recver_buffer[8];
  27. uint8 rcv_new;
  28. /****************************************************************************
  29. * 名称: UART0_Init
  30. * 功能: UART0初始化 通讯波特率115200,8位数据位,1位停止位,无奇偶校验
  31. * 使能TxFIFO,和THRE中断
  32. * 入口参数: bps 串口波特率
  33. * 出口参数: 无
  34. ****************************************************************************/
  35. void UART0_Init(uint32 bps)
  36. {
  37. uint16 Fdiv;
  38. PINSEL0 = (PINSEL0 & ~(0xf) | 0x05) ; //设置UART0的引脚
  39. U0LCR = 0x83; //置位除数锁存位,配置UART0帧格式
  40. Fdiv = (Fpclk>>4)/bps; //根据波特率计算分频值
  41. U0DLM = Fdiv>>8; //设置波特率
  42. U0DLL = Fdiv%256;
  43. U0LCR = 0x03; // 清除除数锁存位,并设置工作模式
  44. U0FCR = 0x05; // 使能TxFIFO,并使TxFIFO复位
  45. U0IER = 0x02; // 使能THRE中断
  46. }
  47. /****************************************************************************
  48. * 名 称: UART0_Exception
  49. * 功 能: 串口发送中断
  50. * 入口参数: 无
  51. * 出口参数: data 发送的数据
  52. ****************************************************************************/
  53. void __irq IRQ_UART0(void)
  54. {
  55. uint32 data;
  56. data = U0IIR; //清除中断表示寄存器标志
  57. VICVectAddr = 0; //清除中断
  58. }
  59. /**********************************************************
  60. * 名称: Interrupt_Init
  61. * 功能: 初始化串口中断,给串口中断选择为向量中断,
  62. * 分配向量通道号1给串口
  63. * 入口参数: 无
  64. * 出口参数: 无
  65. **********************************************************/
  66. void Interrupt_Init (void)
  67. {
  68. VICIntSelect = 0x00000000; // 设置所有通道为IRQ中断
  69. VICVectCntl0 = 0x26; // UART0中断通道分配到IRQ slot 0,即优先级最高
  70. VICVectAddr0 = (int)IRQ_UART0; // 设置UART0向量地址
  71. VICIntEnable = 0x00000040; // 使能UART0中断
  72. }
  73. /**********************************************************
  74. * 名 称: UART0_RcvByte
  75. * 功 能: 用查询方式接收一字节的数据
  76. * 入口参数: 无
  77. * 出口参数: data 要接收的数据
  78. **********************************************************/
  79. uint8 UART0_RcvByte(void)
  80. {
  81. uint8 rcv_data ;
  82. while((U0LSR&0X01)==0); //等待数据到达
  83. rcv_data = U0RBR; //从U0RBR中读出接收到的数据
  84. return rcv_data; //返回接收到的数据
  85. }
  86. /**********************************************************
  87. * 名称: UART0_RecBuf()
  88. * 功能: 接收串口发送过来的帧数据,
  89. * 入口参数: *buffer 存放一帧数据
  90. * 出口参数: 无
  91. **********************************************************/
  92. void UART0_RecBuf (uint8 *buffer)
  93. {
  94. uint8 *pbuffer;
  95. uint8 i;
  96. for(pbuffer = buffer, i = 0;i < 8; i++)
  97. {
  98. *(pbuffer++) = UART0_RcvByte();
  99. }
  100. }
  101. /**********************************************************
  102. * 名称: main()函数
  103. * 功能: 上位机接收的数据开头两个字符为0x10,0x11,
  104. * 则原样输出,否次输出0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
  105. * 入口参数: *buffer 存放一帧数据
  106. * 出口参数: 无
  107. **********************************************************/
  108. int main (void)
  109. {
  110. uint8 i;
  111. uint8 send_buffer[8] ={0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27}; //定义发送帧缓冲区
  112. UART0_Init(115200);
  113. Interrupt_Init();
  114. while(1)
  115. {
  116. UART0_RecBuf(recver_buffer); //接收8字节数据
  117. if(0x10 ==recver_buffer[0] && 0x11 == recver_buffer[1])
  118. {
  119. for(i = 0;i < 8 ;i++)
  120. {
  121. U0THR = send_buffer[i]; //用中断发送每次8字节
  122. }
  123. }
  124. else
  125. {
  126. for(i = 0;i < 8;i++) //用中断发送每次8字节
  127. {
  128. U0THR = recver_buffer[i];
  129. }
  130. }
  131. }
  132. return 0;
  133. }
  134. /*********************************************************************************************************
  135. ** End Of File
  136. ********************************************************************************************************/

原创粉丝点击