当前位置:   article > 正文

TQ2440-UART(查询及中断方式)_uart项目中如何去验证中断

uart项目中如何去验证中断

1.S3C2440 UART 介绍

    UART(Universal Asynchronous Receiver/Transmitter,通用异步接收/发送装置)用于异步通信,可以实现全双工发送和接收。它不仅可以实现不同嵌入式系统之间的通信,还可以实现与PC之间的通信。

    s3c2440提供了三个UART端口,它们都可以通过查询、中断和DMA方式传输数据,而且每个UART都分别有一个64个字节的接收FIFO和一个64个字节的发送FIFO。在这里,我们只给出非FIFO模式,即传输数据不利用FIFO缓存,一个字节一个字节地传输。

    下面我们就给出如何用s3c2440来实现非FIFO的UART通信。要实现某种通信,就必须遵循该通信协议。UART的协议包括传输数据的位数,停止位的位数,以及是否进行奇偶校验,这些设置是利用ULCONn寄存器完成的。另一个很重要的地方就是设置波特率。s3c2440波特率的时钟源有三个:PCLK、FCLK/n和UEXTCLK。时钟源的选择是由UCONn的第10位和第11位来完成的。波特率的具体计算公式为:

        时钟源频率÷(波特率×16)-1      

这个计算结果很可能是小数,把该小数取最接近的整数,放入寄存器UBRDIVn中就完成了波特率的设置。如我们选择波特率的时钟源为PCLK,它为50MHz,我们设置的波特率为115.2kHz,通过上式计算的结果为26.13,取整后得到26,那么我们把26放入UBRDIVn中即可。由于我们没有使用FIFO和MODEM,所以可以不用设置FIFO控制寄存器UFCONn和MODEM控制寄存器UMCONn。通过以上寄存器的设置,UART就可以正常传输数据。

    接收到的数据是放到接收缓存器URXHn中,要发送数据时,是把数据放入发送缓存器UTXHn中。由于UART是通过字节方式传输数据的,因此要区分是大端模式还是小端模式,也就是说这两个寄存器在这两种模式下,所在的地址是不同。为了了解当前数据传输的各种状态,还需要一些状态寄存器。传输状态寄存器UTRSTATn非常有用,它的第0位可以用来判断接受缓存器内是否有可接收的数据,第1位和第2位可以用来判断发送缓存器中是否为空,为空时可以发送数据。由于在这里我们不进行传输数据时错误的判断,因此错误状态寄存器UERSTATn不需要,FIFO状态寄存器UFSTATn和MODEM状态寄存器UMSTATn在这里也不需要。

    我们给出UART通信的两种方法:查询和中断。为了验证程序,使用任一款的串行通信软件来实现PC和s3c2440之间的通信即可。 (我用的是SecureCRT)

 

2.代码分析

下载地址:http://download.csdn.net/detail/forsakening/5492335

a)查询方式

  1. /*
  2. * UART查询方式 forsakening @hdu @2013-5-31
  3. */
  4. #include "2440addr.h"
  5. #define TXD0READY (1 << 2)
  6. #define RXD0READY (1 << 0)
  7. #define PCLK 50000000//时钟源设为PCLK
  8. /*
  9. * 初始化UART:
  10. * GPHCON寄存器设置GPH2,GPH3的模式,分别设置为UART0的TX和RX模式,相应位置写入10即可,见DATASHEET
  11. * GPHUP上拉使能寄存器,为0使能上拉
  12. * ULCON0 = 0x03,8位数据,1位停止位
  13. * UCON0 = 0x05,默认是PCLK作为输入时钟,设置为中断或查询方式
  14. * UBRDIVn = (int)(被选时钟 / ( 波特率 × 16) ) - 1
  15. */
  16. void Uart0_Init(unsigned int bandrate)
  17. {
  18. rGPHCON &= ~((3 << 4) | (3 << 6)) ;//GPH2-GPH3是RX/TX
  19. rGPHCON |= ((2 << 4) | (2 << 6)) ;//GPH2--TXD[0];GPH3--RXD[0]
  20. rGPHUP = 0x00 ;
  21. rULCON0 |= 0x03 ; //8位数据,1位停止位
  22. rUCON0 = 0x05 ;
  23. rUBRDIV0 = PCLK / bandrate / 16 - 1 ;
  24. rURXH0 = 0;
  25. }
  26. /*
  27. * UART发送一个字符:
  28. * 将c写入UTXH0寄存器中,硬件会自动将其发送到缓冲区
  29. * 若发送完毕rUTRSTAT0 & TXD0READY = 1
  30. */
  31. void Uart_putc(unsigned char c)
  32. {
  33. rUTXH0 = c ;
  34. while(!(rUTRSTAT0 & TXD0READY)) ;//等待上个字符发送完毕
  35. }
  36. /* UART接收一个字符 */
  37. unsigned char Uart_getc(void)
  38. {
  39. unsigned char c ;
  40. while(!(rUTRSTAT0 & RXD0READY)) ;
  41. c = rURXH0 ;
  42. return c ;
  43. }
  44. void Uart_print(unsigned char *p) //打印字符串的函数
  45. {
  46. while(0 != *p)
  47. {
  48. Uart_putc(*p++);
  49. }
  50. }
  51. /* 串口打印回车:SecureCRT需要\n\r,而超级终端只需要\n */
  52. void Uart_Print_NR(void)
  53. {
  54. Uart_putc('\n');
  55. Uart_putc('\r');
  56. }
  57. int Main()
  58. {
  59. unsigned char Title[] = "UART TEST:";
  60. unsigned char Info[] = "Your Input Is:";
  61. unsigned char Symbol[] = "*********************";
  62. unsigned char a ;
  63. Uart0_Init(115200) ;
  64. Uart_print(Title);
  65. Uart_Print_NR();
  66. Uart_print(Symbol);
  67. Uart_Print_NR();
  68. while(1)
  69. {
  70. a = Uart_getc();
  71. if (0 != a)
  72. {
  73. Uart_print(Info);
  74. Uart_putc(a);
  75. Uart_Print_NR();
  76. }
  77. }
  78. return 0;
  79. }

运行结果是这样的:

  1. UART TEST:
  2. *********************
  3. Your Input Is:1
  4. Your Input Is:2
  5. Your Input Is:3
  6. Your Input Is:a
  7. Your Input Is:b
  8. Your Input Is:c


b)中断方式

  1. /*
  2. * UART中断方式 forsakening @hdu @2013-5-31
  3. */
  4. #include <stdarg.h>
  5. #include "2440addr.h"
  6. #include "def.h"
  7. #define TXD0READY (1 << 2)
  8. #define RXD0READY (1 << 0)
  9. #define PCLK 50000000//时钟源设为PCLK
  10. /* 作为RX接收buf */
  11. unsigned char buf ;
  12. /***************************************************************/
  13. /* UART部分 */
  14. /***************************************************************/
  15. /*
  16. * 初始化UART:
  17. * GPHCON寄存器设置GPH2,GPH3的模式,分别设置为UART0的TX和RX模式,相应位置写入10即可,见DATASHEET
  18. * GPHUP上拉使能寄存器,为0使能上拉
  19. * ULCON0 = 0x03,8位数据,1位停止位
  20. * UCON0 = 0x05,默认是PCLK作为输入时钟,设置为中断或查询方式
  21. * UBRDIVn = (int)(被选时钟 / ( 波特率 × 16) ) - 1
  22. */
  23. void Uart0_Init(unsigned int bandrate)
  24. {
  25. rGPHCON &= ~((3 << 4) | (3 << 6)) ;//GPH2-GPH3是RX/TX
  26. rGPHCON |= ((2 << 4) | (2 << 6)) ;//GPH2--TXD[0];GPH3--RXD[0]
  27. rGPHUP = 0x00 ;
  28. rULCON0 |= 0x03 ; //8位数据,1位停止位
  29. rUCON0 = 0x05 ;
  30. rUBRDIV0 = PCLK / bandrate / 16 - 1 ;
  31. rURXH0 = 0;
  32. }
  33. /*
  34. * UART发送一个字符:使用查询方式
  35. * 将c写入UTXH0寄存器中,硬件会自动将其发送到缓冲区
  36. * 若发送完毕会触发中断
  37. */
  38. void Uart_putc(unsigned char c)
  39. {
  40. if('\n' == c)
  41. {
  42. while(!(rUTRSTAT0 & TXD0READY)) ;//等待上个字符发送完毕
  43. rUTXH0 = '\r' ;
  44. }
  45. while(!(rUTRSTAT0 & TXD0READY)) ;
  46. rUTXH0 = c ;
  47. }
  48. /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
  49. /* 中断方式下接收数据是被动的,不需要单独函数,在中断服务程序中处理 */
  50. /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
  51. void Uart_print(unsigned char *p) //打印字符串的函数
  52. {
  53. while(*p)
  54. {
  55. Uart_putc(*p++);
  56. }
  57. }
  58. /*
  59. * 可变参数打印,需要包括头文件#include <stdarg.h>,这样用起来就和C库的打印方式一样啦
  60. * 从TQ2440自带的裸机代码copy的
  61. */
  62. void Uart_Printf(char *fmt,...)
  63. {
  64. va_list ap;
  65. unsigned char string[256];
  66. va_start(ap,fmt);
  67. vsprintf(string,fmt,ap);
  68. Uart_print(string);
  69. va_end(ap);
  70. }
  71. /***************************************************************/
  72. /* 中断部分 */
  73. /***************************************************************/
  74. /*
  75. * 打开UART对应的中断,和UART0对应的RX子中断,TX子中断不打开,
  76. * 发送由查询方式
  77. */
  78. void Uart0_Interrupt_Init(void)
  79. {
  80. rINTMSK &= ~(1 << 28) ;
  81. rINTSUBMSK &= ~(1 << 0);
  82. }
  83. /*
  84. * 中断服务程序:清除子中断,清除总中断
  85. */
  86. void __irq Uart0_Isr(void)
  87. {
  88. rSUBSRCPND |= 1 << 0 ; //清除接收中断
  89. rSRCPND |= 1 << 28 ;
  90. rINTPND |= 1 << 28 ;
  91. if(rUTRSTAT0 & 1) //接收数据处理部分
  92. {
  93. buf = rURXH0 ; //接收字节数据
  94. if ( 0!= buf)
  95. {
  96. Uart_Printf("Your Input Is:%c\n", buf);
  97. buf = 0;
  98. }
  99. }
  100. }
  101. /*
  102. * 安装中断服务程序
  103. * UART执行中断的流程:
  104. * a)发生UART中断,跳转到0X18执行IRQ中断
  105. * b)通过中断向量表查找对应的中断服务程序,这里就是pISR_UART0,也就是Uart0_Isr
  106. */
  107. void Isr_Init(void)
  108. {
  109. pISR_UART0 = (U32)Uart0_Isr ;
  110. }
  111. /***************************************************************/
  112. /* Main部分 */
  113. /***************************************************************/
  114. int Main()
  115. {
  116. unsigned char Title[] = "UART TEST:\n";
  117. unsigned char Symbol[] = "*********************\n";
  118. Uart0_Init(115200) ;
  119. Uart0_Interrupt_Init();
  120. Isr_Init();
  121. Uart_print(Title);
  122. Uart_print(Symbol);
  123. while(1);
  124. return 0;
  125. }

运行结果和上面是一致的。

3. 注意点

最后还要强调几点关于非FIFO模式下UART中断的一些注意事项:

1. 对于s3c2440来说,接收数据是被动的,发送数据是主动的,因此一般来说,接收数据用中断方式,发送数据用查询方式较好

2. 在中断方式下,当接收到数据时,尽管可能该数据无用,但也一定要读取它,否则下次再接收数据时,不会再引起中断,因为接收数据缓存器被上次接收到的数据所霸占,只要没有读取它,它就永远在那里;

3. 由于UART中断涉及到SUBSRCPND寄存器,因此在中断处理程序中不仅要清SRCPND寄存器,还要清SUBSRCPND寄存器,它们的顺序一定是先清SUBSRCPND寄存器,再清SRCPND寄存器,否则就会引起一个中断两次响应的问题。因为是否中断由SRCPND寄存器决定,而SRCPND寄存器的相关状态位由SUBSRCPND寄存器决定,如果先清SRCPND寄存器,而还没有清SUBSRCPND寄存器的话,SRCPND寄存器的相关位还是会被置1,而一旦被置1,则一定还会引起中断。

 

4. Reference:

[1].http://blog.csdn.net/zhaocj/article/details/5364412

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/nx123/article/detail/62765
推荐阅读
相关标签
  

闽ICP备14008679号