qjhu0433的笔记 https://bbs.21ic.com/?353566 [收藏] [复制] [RSS]

日志

使用gcc在AVR单片机模拟51单片机IO口操作

已有 2375 次阅读2006-4-19 13:25 |系统分类:单片机

这个想法主要是为了一个目的:就是在51上已经开发了好多的有关IO口操作的驱动程序,要移植到
AVR之上,要求做最小的改动,同时兼顾效率问题就更好了。


我有一个好方法,假如我有一段51上的程序如下:


#include<reg52.h>


sbit Led = P1^0;


void Delay(int n)
{
    while(--n>0);
}


int main()
{
    while(1)
    {
        Led = 1;
 Delay(1000);
 Led = 0;
 Delay(1000);
    }
}


上面这段程序作了一件非常简单的事情,就是让一发光二极管不停的闪烁。
那么移植到AVR上我们希望作最小的改动:


#include <avr/io.h>
#include "tPortClass.h"


Tport<PB,0>Led(1);  // 在avr中IO定义发生改变


void Delay(int n)
{
    while(--n>0);
}


int main()
{
    while(1)
    {
        Led = 1;
 Delay(1000);
 Led = 0;
 Delay(1000);
    }
}


上面的程序包含的头文件改变了,其中包含了一个神秘的头文件"tPortClass.h",我们
暂且不去管它,请看只有在IO定义的地方发生了改变,而对于使用这个IO口的地方,两
种不同的单片机对其操作方式可以做到一模一样.上面还只是一个简单的例子,想象一
项较大的项目中有好多IO操作,没有一个良好的IO移植方法,恐怕要大量的修改源文件
了.


其中对这个IO移植起到了好处的正是那个神秘的tPortClass.h头文件,那么让我们看看
这个头文件里都做了那些事情.


#ifndef _tPortClass
#define _tPortClass


#include <avr/io.h>
#include <stdint.h>
                // IO寄存器地址定义区域
#if   defined   (__AVR_ATmega8__ )
#define PD 0x12
#define PC 0x15
#define PB 0x18
#elif defined   (__AVR_ATmega16__)
#define PD 0x12
#define PC 0x15
#define PB 0x18
#define PA 0x1B
#elif defined   (__AVR_ATmega32__)
#define PD 0x12
#define PC 0x15
#define PB 0x18
#define PA 0x1B
#else
#error"this device type PortPin not defined"
#endif


template<uint8_t portx,uint8_t pxx>         // 模板参数:IO寄存器地址以及引脚偏移量
class Tport {
public:
 Tport(uint8_t direction = 0)
 {
  if(direction > 0)
  { 
   _SFR_IO8(portx-1) |= (1<<pxx); // 设置方向寄存器 ddrx=portx-1
  }
  else
  {
   _SFR_IO8(portx-1) &= ~(1<<pxx);
  }
 }
 void in (void) { _SFR_IO8(portx-1) &= ~(1<<pxx); }
 void out(void) { _SFR_IO8(portx-1) |=  (1<<pxx); }
 uint8_t operator =(uint8_t rt)
 {
  if(rt > 0)
  {
   _SFR_IO8(portx) |= (1<<pxx);            // IO输出操作
   return 1;
  }
  else
  {
   _SFR_IO8(portx) &= ~(1<<pxx); 
   return 0;
  }  
 }
 operator uint8_t()        // IO输入操作 pinx=portx-2
        {
  return ( (_SFR_IO8(portx-2) & (1<<pxx)) ? 1 : 0 ) ;
 }
private:
 uint8_t config;
};


#endif


这里用到C++中的概念类模板,听到这个先不要拿砖头,想想上面的例子带给我们的好处先.
由于avr-gcc支持C++语言编译,于是就利用它做IO移植喽.整个文件看起来很抽象,不容易
看懂,我们先不要管它,就像51里面sbit定义的IO变量一样,我们不必去理会编译器是如何
实现的一样.


sbit Led = P1^0;
Tport<PB,0>Led(1);


好好看这两个表达式,它们有两分相象,PB相当于P1,Tport中的0相当于sbit中的0同样代表
某个IO口上的偏移量.只有Tport中Led后面有个(1),这个"1"到底是起什么作用的呢?AVR
和51到底有很大的区别。这个1是用来设置该IO口方向的,"1"表示输出,"0"表示输入。而
51不用设置IO方向。


写道这里,我想有人已迫不及待得去做实验了,把上面的定义粘贴到一新头文件中去。并且
在makefile中把"CC = avr-gcc"改写为"CC = avr-g++",即使用C++编译整个项目文件,即可。
有兴趣的可以看看该语句生成的汇编代码,会让你非常的吃惊。因为模板相当于一种高级宏
定义,不会产生冗余代码。


demo程序 miracleIO.rar


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)