网站首页
IC库存
IC展台
电子资讯
技术资料
PDF文档
我的博客
IC72论坛
ic72 logo
搜索关键字: 所有资讯 行业动态 市场趋势 政策法规 新品发布 技术资讯 价格快报 展会资讯
  • 达普IC芯片交易网 > 新闻中心 > 设计应用 > 正文
  • RSS
  • 用于ATmega128的软件UART范例程序
    http://www.ic72.com 发布时间:2008/8/18 9:59:50

      一般教科书上提供的UART收发的程序往往是一段采用轮循(Polling)方式完成收发的简单代码。但对于高速的AVR来讲,采用这种方式大大降低了 MUC的效率。在使用AVR时,应根据芯片本身的特点(片内大容量数据存储器RAM,更适合采用高级语言编写系统程序),编写高效可靠的UART收发接口(低层)程序。下面是一个典型的ATMEGA128的软件USART的接口程序。

    #include <mega128.h>

    #define RXB8 1
    #define TXB8 0
    #define UPE 2
    #define OVR 3
    #define FE 4
    #define UDRE 5
    #define RXC 7

    #define FRAMING_ERROR (1<<FE)
    #define PARITY_ERROR (1<<UPE)
    #define DATA_OVERRUN (1<<OVR)
    #define DATA_REGISTER_EMPTY (1<<UDRE)
    #define RX_COMPLETE (1<<RXC)

    // USART0 Receiver buffer
    #define RX_BUFFER_SIZE0 8
    char rx_buffer0[RX_BUFFER_SIZE0];
    unsigned char rx_wr_index0,rx_rd_index0,rx_counter0;
    // This flag is set on USART0 Receiver buffer overflow
    bit rx_buffer_overflow0;

    // USART0 Receiver interrupt service routine
    #pragma savereg-
    interrupt [USART0_RXC] void uart0_rx_isr(void)
    {
    char status,data;
    #asm
             push r26
                push r27
                push r30
                push r31
                in   r26,sreg
                push r26
    #endasm
    status=UCSR0A;
    data=UDR0;
    if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
       {
           rx_buffer0[rx_wr_index0]=data;
           if (++rx_wr_index0 == RX_BUFFER_SIZE0) rx_wr_index0=0;
           if (++rx_counter0 == RX_BUFFER_SIZE0)
              {
                  rx_counter0=0;
                  rx_buffer_overflow0=1;
              };
       };
    #asm
           pop  r26
           out  sreg,r26
           pop  r31
           pop  r30
           pop  r27
           pop  r26
    #endasm
    }
    #pragma savereg+

    #ifndef _DEBUG_TERMINAL_IO_
    // Get a character from the USART0 Receiver buffer
    #define _ALTERNATE_GETCHAR_
    #pragma used+
    char getchar(void)
    {
      char data;
      while (rx_counter0==0);
      data=rx_buffer0[rx_rd_index0];
      if (++rx_rd_index0 == RX_BUFFER_SIZE0) rx_rd_index0=0;
      #asm("cli")
        --rx_counter0;
      #asm("sei")
      return data;
    }
    #pragma used-
    #endif

    // USART0 Transmitter buffer
    #define TX_BUFFER_SIZE0 8
    char tx_buffer0[TX_BUFFER_SIZE0];
    unsigned char tx_wr_index0,tx_rd_index0,tx_counter0;

    // USART0 Transmitter interrupt service routine
    #pragma savereg-
    interrupt [USART0_TXC] void uart0_tx_isr(void)
    {
      #asm
          push r26
          push r27
          push r30
          push r31
          in   r26,sreg
          push r26
      #edasm
      if (tx_counter0)
      {
             --tx_counter0;
           UDR0=tx_buffer0[tx_rd_index0];
           if (++tx_rd_index0 == TX_BUFFER_SIZE0) tx_rd_index0=0;
       };
      #asm
          pop  r26
          out  sreg,r26
          pop  r31
          pop  r30
          pop  r27
          pop  r26
      #endasm
    }
    #pragma savereg+

    #ifndef _DEBUG_TERMINAL_IO_
    // Write a character to the USART0 Transmitter buffer
    #define _ALTERNATE_PUTCHAR_
    #pragma used+
    void putchar(char c)
    {
      while (tx_counter0 == TX_BUFFER_SIZE0);
      #asm("cli")
       if (tx_counter0 || ((UCSR0A & DATA_REGISTER_EMPTY)==0))
       {
           tx_buffer0[tx_wr_index0]=c;
           if (++tx_wr_index0 == TX_BUFFER_SIZE0) tx_wr_index0=0;
           ++tx_counter0;
       }
       else
           UDR0=c;
      #asm("sei")
    }
    #pragma used-
    #endif

    // Standard Input/Output functions
    #include <stdio.h>

    // Declare your global variables here

    void main(void)
    {

    // USART0 initialization
    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART0 Receiver: On
    // USART0 Transmitter: On
    // USART0 Mode: Asynchronous
    // USART0 Baud rate: 9600
    UCSR0A=0x00;
    UCSR0B=0xD8;
    UCSR0C=0x06;
    UBRR0H=0x00;
    UBRR0L=0x67;

    // Global enable interrupts
    #asm("sei")

    while (1)
          {
              // Place your code here

          };
    }

        这段由CVAVR程序生成器产生的UART接口代码是一个非常好的、高效可靠,并且值得认真学习和体会的。其特点如下:
       l. 它采用两个8字节的接收和发送缓冲器来提高MCU的效率,如当主程序调用Putchar()发送数据时,如果UART口不空闲,就将数据放入发送缓冲器中,MCU不必等待,可以继续执行其它的工作。而UART的硬件发送完一个数据后,产生中断,由中断服务程序负责将发送缓冲器中数据依次送出。
       2.数据缓冲器结构是一个线性的循环队列,由读、写和队列计数器3个指针控制,用于判断队列是否空、溢出,以及当前数据在队列中的位置。
       3. 用编译控制命令#pragma savereg-和#pragma savereg+,使得由CVAVR在生成的中断服务程序中不进行中断保护(CVAVR生成中断保护会将比较多的寄存器压入堆栈中),而在中断中嵌入汇编,只将5个在本中断中必须要保护的寄存器压栈。这样提高了UART中断处理的速度,也意味着提高了MCU的效率。
       4.由于在接口程序Putchar()、Getchar()和中断服务程序中都要对数据缓冲器的读、写和队列计数器3个指针判断和操作,为了防止冲突,在Putchar()、Getchar()中对3个指针操作时临时将中断关闭,提高了程序的可靠性。
        建议读者能逐字逐句地仔细分析该段代码,真正理解和领会每一句语句(包括编译控制命令的作用)的作用,从中体会和学习如何编写效率高,可靠性好,结构优良的系统代码。这段程序使用的方法和技巧,对编写SPI、I2C的串行通信接口程序都是非常好的借鉴。
        作为现在的单片机和嵌入式系统的工程师,不仅要深入全面的掌握芯片和各种器件的性能,具备丰富的硬件设计能力;同时也必须提高软件的设计能力。要学习和掌握有关数据结构、操作系统、软件工程、网络协议等方面的知识,具有设计编写大的复杂系统程序的能力。


    www.ic72.com 达普IC芯片交易网
  • 行业动态
  • 市场趋势
  • 政策法规
  • 新品发布
  • Baidu

    IC快速检索:abcdefghijklmnopqrstuvwxyz0123456789
    COPYRIGHT:(1998-2010) IC72 达普IC芯片交易网
    客户服务:service@IC72.com 库存上载:IC72@IC72.com
    (北京)联系方式: 在线QQ咨询:点击这里给我发消息 联系电话:010-82614113 传真:010-82614123
    京ICP备06008810号-21 京公网安备 11010802032910 号 企业资质