DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 252|回复: 0
打印 上一主题 下一主题

用于ATmega128的软件UART范例程序

[复制链接]
跳转到指定楼层
楼主
发表于 2012-1-27 14:10:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用于ATmega128的软件UART范例程序                  
  一般教科书上提供的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的串行通信接口程序都是非常好的借鉴。
    作为现在的单片机和[img]http://www.dianzi6.com/]嵌入式系统的工程师,不仅要深入全面的掌握芯片和各种器件的性能,具备丰富的硬件设计能力;同时也必须提高软件的设计能力。要学习和掌握有关数据结构、操作系统、软件工程、网络协议等方面的知识,具有设计编写大的复杂系统程序的能力。


                                    如果觉得 用于ATmega128的软件UART范例程序这篇文章不错,可以推荐给朋友分享哦。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2024-6-13 15:14 , 耗时 0.089081 秒, 19 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

快速回复 返回顶部 返回列表