×
单片机 > 单片机程序设计 > 详情

典型的ATmega128的软件USART的接口程序

发布时间:2020-06-18 发布时间:
|

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

    #include

    #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<

    #define PARITY_ERROR (1<

    #define DATA_OVERRUN (1<

    #define DATA_REGISTER_EMPTY (1<

    #define RX_COMPLEte (1<

    // 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

    // 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的串行通信接口程序都是非常好的借鉴。

    作为现在的单片机和嵌入式系统的工程师,不仅要深入全面的掌握芯片和各种器件的性能,具备丰富的硬件设计能力;同时也必须提高软件的设计能力。要学习和掌握有关数据结构、操作系统、软件工程、网络协议等方面的知识,具有设计编写大的复杂系统程序的能力。


关键字:ATmega128  软件USART  接口程序 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
AVR熔丝位操作时的要点和需要注意的相关事项