搜索
bottom↓
回复: 36

在GCCAVR中C++的类成员函数如何定义函数指针数组

[复制链接]

出0入0汤圆

发表于 2006-2-7 21:44:26 | 显示全部楼层 |阅读模式
虽是链接但我相信对大家会有很大的帮助的

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2006-2-7 21:48:22 | 显示全部楼层
求助后的总结报告

hotpower 发表于 2005-6-30 18:23 AVR 单片机 ←返回版面   



正确而简单地说应该使用静态类成员的指针而非指向类成员的指针



正如John_Lee所述的两个方法的分析,后者确实把简单问题复杂话了.

因为静态类成员是属于该类的全局对象和函数,它的指针是普通指针.引用该指针不需要类对象.

而类成员的指针必须总是通过特定的对象或指向该类类型的对象的指针来访问.





再者GCCAVR取FLASH数据必须通过pgm_read_word函数形成汇编代码LPM指令才能取出跳转地址.

而且将其转换为类成员的指针我和John_Lee一样都不能找到更好地方法,只能通过嵌入汇编语句完成.

这样也失去了C++的特色.



所以,静态类成员的指针应该是不错的方法.所以Key00()等函数必须声明为静态函数,这样才能在

KeyCommandTab[]函数指针数组中以函数名即函数的装载地址的身份出现,这样就实现了不同函数的散转.



至于函数指针数组是定义为静态类成员或在类成员函数中出现都无关紧要,但有一点是可以肯定的,那就是也必须

定义为静态数组,而且前者必须在类体外初始化,后者可以直接初始化. 特别注意后者虽可不定义为静态数组,但它

将会将数组装载在RAM中.例:



class KeyObj {

public:

  KeyObj(void);

  void Exec(void);//每2.5mS中断调用一次, KeyCount会自动+1

private:

  void KeyInit(void);

  unsigned char GetKeyVal(void);

  void KeyCommandExec(unsigned char);//测试时需声明为public

//................

  static void Key00(void);//必须声明为static!!!

//................

  static void Key24(void);//必须声明为static!!!

};//键盘模块





typedef void (* PFV)(void);//普通函数指针

void KeyObj::KeyCommandExec(unsigned char mode)

{

static PFV KeyCommandTab[3][5] PROGMEM = {//键盘放事件处理表//必须声明为static!!!否则忽略PROGMEM

  {Key00, Key01, Key02, Key03, Key04}, //键释放事件处理

  {Key10, Key11, Key12, Key13, Key14}, //压键事件处理

  {Key20, Key21, Key22, Key23, Key24}  //长压键事件处理

};

PFV func;//定义普通函数指针

  KeyCount &= 0x07;//取键盘序号//使用1602字节(.text),运行正确

  if (KeyCount <= 4) {//只有5个键,KeyCount>=5为3个短接线.

    func = reinterpret_cast<PFV>(pgm_read_word(&KeyCommandTab[mode][KeyCount]));//取flash键盘放事件处理表

    func();//运行KeyX0()~KeyX4()

  }

}



最后感觉KeyCommandTab[]函数数组指针还是定义在类成员函数KeyCommandExec()为好,因为其他成员并不需要访问KeyCommandTab[].

当然这样做会在不了解KeyCommandTab[]要取Key00()等函数指针时会把对Key00()等定义为静态函数产生疑问.

如果其他成员并需要访问KeyCommandTab[],则改为:



PFV func;//定义普通函数指针

class KeyObj {

public:

  KeyObj(void);

  void Exec(void);//每2.5mS中断调用一次, KeyCount会自动+1

private:

  void KeyInit(void);

  unsigned char GetKeyVal(void);

  void KeyCommandExec(unsigned char);//测试时需声明为public

//................

  static const PFV KeyCommandTab[3][5];//必须声明为static!!!

  static void Key00(void);//必须声明为static!!!

//................

  static void Key24(void);//必须声明为static!!!

};//键盘模块



//初始化键盘放事件处理表,因为KeyCommandTab数组为静态成员,故必须在类体外进行初始化

const PFV KeyObj::KeyCommandTab[3][5] PROGMEM = {//键盘放事件处理表

  {Key00, Key01, Key02, Key03, Key04}, //键释放事件处理

  {Key10, Key11, Key12, Key13, Key14}, //压键事件处理

  {Key20, Key21, Key22, Key23, Key24}  //长压键事件处理

};



void KeyObj::KeyCommandExec(unsigned char mode)

{

PFV func;//定义普通函数指针

  KeyCount &= 0x07;//取键盘序号//使用1602字节(.text),运行正确

  if (KeyCount <= 4) {//只有5个键,KeyCount>=5为3个短接线.

//由于KeyCommandExec()函数也是KeyObj的类成员函数,故可直接访问KeyCommandTab[]数组  

    func = reinterpret_cast<PFV>(pgm_read_word(&KeyCommandTab[mode][KeyCount]));//取flash键盘放事件处理表

    func();//运行KeyX0()~KeyX4()

  }

}



现在和求助帖对比发现也就"static"一词之差,但结果却相差万里.



此帖到此讨论结束,也作为我对求助的总结"报告".

我认为求助而不总结的都是些"白帖",总结后就会知道自己永远还是一只不会飞的大菜鸟.



我很菜但我肯吃苦,我虽笨但我更努力.

我灌水但我不害人,我无翅但我梦飞翔.



再次感谢John_Lee和testcode两位网友!

出0入0汤圆

 楼主| 发表于 2006-2-7 21:53:36 | 显示全部楼层
实战程序片段









inline

KeyObj::KeyObj(void)

{

  KeyInit();

}





inline

void KeyObj::KeyInit(void)

{

  KeyDir &= ~((1 << KeySel) | (1 << KeyUp) | (1 << KeyDown));//设置键盘为输入模式

  KeyPort |= (1 << KeySel) | (1 << KeyUp) | (1 << KeyDown);//键盘输入上拉

  KeyDir &= ~((1 << KeyTestA) | (1 << KeyTestB) | (1 << KeyTestC));//设置信号为输入模式

  KeyPort &= ~((1 << KeyTestA) | (1 << KeyTestB) | (1 << KeyTestC));//信号输入不上拉(外部下拉)

  for (unsigned char i = 0; i < 8; i ++) {

    KeyTest = 0;//清除压键计数器

//    KeyWaitCount = 0;//键盘压键释放计数器

  }

}





/*-----------------------------------------------------------

-----------------------------------------------------------*/

//取串行键盘键值

inline

unsigned char KeyObj::GetKeyVal(void)

{

unsigned char KeyTestVal = 0xff;

  switch(KeyCount) {

    case 0: //KeySel(低有效)

          if ((KeyPin & (1 << KeySel)) == 0) KeyTestVal = 0;

          break;

    case 1: //KeyUp(低有效)

          if ((KeyPin & (1 << KeyUp)) == 0) KeyTestVal = 1;

          break;

    case 2: //KeyDown(低有效)

          if ((KeyPin & (1 << KeyDown)) == 0) KeyTestVal = 2;

          break;

    case 3://保留键

          break;

    case 4: //KeyTestA(高有效)

          if (KeyPin & (1 << KeyTestA)) KeyTestVal = 4;

          break;

    case 5: //KeyTestB(高有效)

          if (KeyPin & (1 << KeyTestB)) KeyTestVal = 5;

          break;

    case 6: //KeyTestC(高有效)

          if (KeyPin & (1 << KeyTestC)) KeyTestVal = 6;

          break;

    case 7://保留键

          break;

  }

  return KeyTestVal;//无键压下为0

}



//键扫描及运行

//inline

void KeyObj::Exec(void)

{

  KeyCount &= 0x07;//只有8个键

//  if (KeyCount == GetKeyVal()) {//有键压下(每次只取1键以实现“零耗时消除键盘抖动”)

//  if ((SystemFlage & (1 << SystemStart)) && (KeyCount == GetKeyVal())) {//有键压下(每次只取1键以实现“零耗时消除键盘抖动”)

  if (KeyCount == GetKeyVal()) {//有键压下(每次只取1键以实现“零耗时消除键盘抖动”)

        if ((SystemFlage & (1 << SystemStart)) == 0) {

      ::Ctrl.StartTime = SystemStartTime;

      ::Ctrl.StartMenu();

    }

    if (KeyTest[KeyCount] < SystemKeyPushTime) {//100*20mS=2S//压键长短判别

          KeyTest[KeyCount] ++;//计数每20mS键盘压键的次数(选2较好些)

          if (KeyTest[KeyCount] == SystemKeyPushNum) {//键刚压下//短压键

//                KeyWaitCount[KeyCount] = 8000;//键盘压键释放计数器

            KeyCommandExec(1);//短压键事件处理(1)

        ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发1声

          }

        }

        else {//长压键 20mS*100=2S

          KeyTest[KeyCount] = SystemKeyPushNum;//再压3S继续执行下一次长压键

//          if (KeyWaitCount[KeyCount] == 0) {

//            KeyWaitCount[KeyCount] = 8000;//键盘压键释放计数器

//          }

      KeyCommandExec(2);//长压键3S事件处理(2)

//      ::Ctrl.BeepStart(DefBeep_2);//蜂鸣器发2声

        }

  }

  else {//无键压下

    if (KeyTest[KeyCount] >= SystemKeyPushNum) {//键释放

//          KeyWaitCount[KeyCount] = 8000;//键盘压键释放计数器

          KeyCommandExec(0);//键释放事件处理(0)

        }

        else {//无键压下或干扰

        }

    KeyTest[KeyCount] = 0;//清除压键计数器

  }

  KeyCount ++;//为下次扫描做准备

  KeyCount &= 0x07;//只有8个键

}



typedef void (KeyObj::* PFV)(void);

typedef void (* PV)(void);

//inline

void KeyObj::KeyCommandExec(unsigned char mode)

{

static PFV KeyCommandTab[3][8] PROGMEM = {//键盘放事件处理表

  {&KeyObj::Key00, &KeyObj::Key01, &KeyObj::Key02, &KeyObj::Key03, &KeyObj::Key04, &KeyObj::Key05, &KeyObj::Key06, &KeyObj::Key07}, //键释放事件处理

  {&KeyObj::Key10, &KeyObj::Key11, &KeyObj::Key12, &KeyObj::Key13, &KeyObj::Key14, &KeyObj::Key15, &KeyObj::Key16, &KeyObj::Key17}, //压键事件处理

  {&KeyObj::Key20, &KeyObj::Key21, &KeyObj::Key22, &KeyObj::Key23, &KeyObj::Key24, &KeyObj::Key25, &KeyObj::Key26, &KeyObj::Key27}  //长压键事件处理

};

  KeyCount &= 0x07;//取键盘序号//使用1602字节(.text),运行正确

PV func;//声明一般函数指针

  if (!((KeyCount >= 0x04) && (SystemFlage & (1 <<SystemWork)))) {//在调整状态拒绝显示测试状态

    wdt_reset();// Watchdog 复位

    func = reinterpret_cast<PV>(pgm_read_word(&KeyCommandTab[mode][KeyCount]));//取flash键盘放事件处理表

    func();//运行KeyX0()~KeyX7()

  }

}



/*------------------------

     键释放事件处理

------------------------*/



/*----------------------------------

   释放选择键

--------------------------------*/

inline

void KeyObj::Key00(void)

{

}



/*----------------------------------

   释放上调键

--------------------------------*/

inline

void KeyObj::Key01(void)

{

}



/*----------------------------------

   释放下调键

--------------------------------*/

inline

void KeyObj::Key02(void)

{

}



/*----------------------------------

   释放保留键

--------------------------------*/

inline

void KeyObj::Key03(void)

{

}



/*----------------------------------

   释放信号A

--------------------------------*/

inline

void KeyObj::Key04(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(2, 0);

    ::Lcd.LcdDisplay("按键: 红外  无效");

    ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发1声//工作开始

  }

}



/*----------------------------------

   释放信号B

--------------------------------*/

inline

void KeyObj::Key05(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(3, 0);

    ::Lcd.LcdDisplay("按键: TV/XGA无效");

    ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发1声//工作开始

  }

}



/*----------------------------------

   释放信号C

--------------------------------*/

inline

void KeyObj::Key06(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(3, 0);

    ::Lcd.LcdDisplay("按键: Y/C   无效");

    ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发1声//工作开始

  }

}



inline

void KeyObj::Key07(void)

{

}



/*------------------------

     压键事件处理

------------------------*/

/*----------------------------------

   单击选择键

--------------------------------*/



inline

void KeyObj::Key10(void)

{

  ::Ctrl.SysSelePushNum = 0;

  if (SystemFlage & (1 <<SystemWork)) {//在调整状态

    ::Lcd.LcdVrefSeleSubMenu();

  }

}



/*----------------------------------

   单击上调键

--------------------------------*/

inline

void KeyObj::Key11(void)

{

  ::Ctrl.SysPushNum = 0;

  if (SystemFlage & (1 <<SystemWork)) {//在调整状态

    ::Lcd.LcdVrefIncDecNum = 10;

        ::Lcd.LcdVrefIncDecSubMenu();

  }

}



/*----------------------------------

   单击下调键

--------------------------------*/

inline

void KeyObj::Key12(void)

{

  ::Ctrl.SysPushNum = 0;

  if (SystemFlage & (1 <<SystemWork)) {//在调整状态

    ::Lcd.LcdVrefIncDecNum = -10;

        ::Lcd.LcdVrefIncDecSubMenu();

  }

}



/*----------------------------------

   单击保留键

--------------------------------*/

inline

void KeyObj::Key13(void)

{

}



/*----------------------------------

   单击信号A

--------------------------------*/

inline

void KeyObj::Key14(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(2, 0);

    ::Lcd.LcdDisplay("按键: 红外  有效");

  }

}



/*----------------------------------

   单击信号B

--------------------------------*/

inline

void KeyObj::Key15(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(3, 0);

    ::Lcd.LcdDisplay("按键: TV/XGA有效");

  }

}



/*----------------------------------

   单击信号C

--------------------------------*/

inline

void KeyObj::Key16(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(3, 0);

    ::Lcd.LcdDisplay("按键: Y/C   有效");

  }

}



inline

void KeyObj::Key17(void)

{

}



/*------------------------

     长压键事件处理

------------------------*/

/*----------------------------------

   长压选择键

--------------------------------*/



inline

void KeyObj::Key20(void)

{

  ::Ctrl.SysSelePushNum ++;

  if (::Ctrl.SysSelePushNum > 8) {

    ::Ctrl.SysSelePushNum = 0;

    if ((SystemFlage & (1 <<SystemWork)) == 0) {//在工作状态

      switch(::Ctrl.WorkNum) {

        case 0://电源板测试仪

              ::Ctrl.WorkNum = 1;//驱动板测试仪

              break;

        case 1://驱动板测试仪

              ::Ctrl.WorkNum = 2;//转换板测试仪

              break;

        case 2://转换板测试仪

              ::Ctrl.WorkNum = 0;//电源板测试仪

              break;

      }

          eeprom_write_byte((unsigned char *)&eeromWorkNum, ::Ctrl.WorkNum);//工作号初始化

          ::Lcd.LcdMainMenu();//显示工作主菜单

    }

  }

  ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发1声//工作开始

}



inline

void KeyObj::Key2122(void)

{

  ::Ctrl.SysPushNum ++;

  if (::Ctrl.SysPushNum > 8) {

    if ((SystemFlage & (1 <<SystemWork)) == 0) {//在工作状态

      SystemFlage |= (1 << SystemWork);//转换为调整状态

          ::Lcd.LcdVrefSeleMenu();//显示调整主菜单

    }

  }

}





/*----------------------------------

   长压上调键

--------------------------------*/

inline

void KeyObj::Key21(void)

{

//Key2122();

//return;

  if (SystemFlage & (1 <<SystemWork)) {//在调整状态

    ::Ctrl.SysPushNum = 0;

    ::Lcd.LcdVrefIncDecNum = 50;

        ::Lcd.LcdVrefIncDecSubMenu();

  }

  else {

    Key2122();

  }

  ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发3声//工作开始

}



/*----------------------------------

   长压下调键

--------------------------------*/

inline

void KeyObj::Key22(void)

{

//Key2122();

//return;

  if (SystemFlage & (1 <<SystemWork)) {//在调整状态

    ::Ctrl.SysPushNum = 0;

    ::Lcd.LcdVrefIncDecNum = -50;

        ::Lcd.LcdVrefIncDecSubMenu();

  }

  else {

    Key2122();

  }

  ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发3声//工作开始

}



/*----------------------------------

   长压保留键

--------------------------------*/

inline

void KeyObj::Key23(void)

{

}



/*----------------------------------

   长压信号A

--------------------------------*/

inline

void KeyObj::Key24(void)

{

  ::Ctrl.BeepStart(DefBeep_2);//蜂鸣器发2声

}



/*----------------------------------

   长压信号B

--------------------------------*/

inline

void KeyObj::Key25(void)

{

  ::Ctrl.BeepStart(DefBeep_2);//蜂鸣器发2声

}



/*----------------------------------

   长压信号C

--------------------------------*/

inline

void KeyObj::Key26(void)

{

}



inline

void KeyObj::Key27(void)

{

}



int main(void)

{

  OSCCAL = eeprom_read_byte(&osc_address);

  wdt_enable(WDTO_2S);// Watchdog 使能,Watchdog 定时器1秒超时

  wdt_reset();// Watchdog 复位

  if (SystemRamTest != 0x55aa) {//这句是必须加的

//    SystemTime = 0;

        if (eeprom_read_word(&eeromTest) != 0x55aa) {//这句是必须加的

//          wdt_reset();// Watchdog 复位

          eeprom_write_byte((unsigned char *)&eeromWorkNum, 0);//工作号初始化

          eeprom_write_word((unsigned int *)&eeromTest, 0x55aa);//完成内存测试

        }

        SystemRamTest = 0x55aa;//完成内存测试

//        while(1);//自毁,测试Watchdog的好坏

  }

//SystemTime ++;

  SystemFlage = 0;

  ::Ctrl.SysPushNum = 0;

  ::Ctrl.SysSelePushNum = 0;

  ::Ctrl.StartTime = 0;

  ::Ctrl.WorkNum = eeprom_read_byte(&eeromWorkNum);

//  wdt_enable(WDTO_2S);// Watchdog 使能,Watchdog 定时器1秒超时

//  wdt_reset();// Watchdog 复位

  ::Lcd.LcdStartMenu();//启动菜单

  ::Ctrl.BeepStart(DefBeep_3);//蜂鸣器发3声

//  set_sleep_mode(SLEEP_MODE_IDLE);

  for(;;) {//死循环

    sei();

    TIMSK |= (1 << TOIE1);

        SystemFlage |= (1 << SystemWdt);//设置软件狗

//    sleep_mode();//进入休眠模式

//    wdt_reset();// Watchdog 复位

  }

  return 0;//正常返回操作系统(实际不可能,MCU一般也不需要)

}



SIGNAL(SIG_INTERRUPT0)

{

}



SIGNAL(SIG_INTERRUPT1)

{

}



SIGNAL(SIG_OVERFLOW0)

{

}



/*-----------------------------------------------

        2.5mS定时器主工作测试控制模块

------------------------------------------------*/

SIGNAL(SIG_OVERFLOW1)

{

出0入0汤圆

 楼主| 发表于 2006-2-7 21:57:14 | 显示全部楼层
晕到~~~



总结报告怎么和实战片段成了联体儿了...



我又被忽悠了...

出0入0汤圆

 楼主| 发表于 2006-2-7 21:59:44 | 显示全部楼层
重帖:实战应用片段





inline

KeyObj::KeyObj(void)

{

  KeyInit();

}





inline

void KeyObj::KeyInit(void)

{

  KeyDir &= ~((1 << KeySel) | (1 << KeyUp) | (1 << KeyDown));//设置键盘为输入模式

  KeyPort |= (1 << KeySel) | (1 << KeyUp) | (1 << KeyDown);//键盘输入上拉

  KeyDir &= ~((1 << KeyTestA) | (1 << KeyTestB) | (1 << KeyTestC));//设置信号为输入模式

  KeyPort &= ~((1 << KeyTestA) | (1 << KeyTestB) | (1 << KeyTestC));//信号输入不上拉(外部下拉)

  for (unsigned char i = 0; i < 8; i ++) {

    KeyTest = 0;//清除压键计数器

//    KeyWaitCount = 0;//键盘压键释放计数器

  }

}





/*-----------------------------------------------------------

-----------------------------------------------------------*/

//取串行键盘键值

inline

unsigned char KeyObj::GetKeyVal(void)

{

unsigned char KeyTestVal = 0xff;

  switch(KeyCount) {

    case 0: //KeySel(低有效)

          if ((KeyPin & (1 << KeySel)) == 0) KeyTestVal = 0;

          break;

    case 1: //KeyUp(低有效)

          if ((KeyPin & (1 << KeyUp)) == 0) KeyTestVal = 1;

          break;

    case 2: //KeyDown(低有效)

          if ((KeyPin & (1 << KeyDown)) == 0) KeyTestVal = 2;

          break;

    case 3://保留键

          break;

    case 4: //KeyTestA(高有效)

          if (KeyPin & (1 << KeyTestA)) KeyTestVal = 4;

          break;

    case 5: //KeyTestB(高有效)

          if (KeyPin & (1 << KeyTestB)) KeyTestVal = 5;

          break;

    case 6: //KeyTestC(高有效)

          if (KeyPin & (1 << KeyTestC)) KeyTestVal = 6;

          break;

    case 7://保留键

          break;

  }

  return KeyTestVal;//无键压下为0

}



//键扫描及运行

//inline

void KeyObj::Exec(void)

{

  KeyCount &= 0x07;//只有8个键

//  if (KeyCount == GetKeyVal()) {//有键压下(每次只取1键以实现“零耗时消除键盘抖动”)

//  if ((SystemFlage & (1 << SystemStart)) && (KeyCount == GetKeyVal())) {//有键压下(每次只取1键以实现“零耗时消除键盘抖动”)

  if (KeyCount == GetKeyVal()) {//有键压下(每次只取1键以实现“零耗时消除键盘抖动”)

        if ((SystemFlage & (1 << SystemStart)) == 0) {

      ::Ctrl.StartTime = SystemStartTime;

      ::Ctrl.StartMenu();

    }

    if (KeyTest[KeyCount] < SystemKeyPushTime) {//100*20mS=2S//压键长短判别

          KeyTest[KeyCount] ++;//计数每20mS键盘压键的次数(选2较好些)

          if (KeyTest[KeyCount] == SystemKeyPushNum) {//键刚压下//短压键

//                KeyWaitCount[KeyCount] = 8000;//键盘压键释放计数器

            KeyCommandExec(1);//短压键事件处理(1)

        ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发1声

          }

        }

        else {//长压键 20mS*100=2S

          KeyTest[KeyCount] = SystemKeyPushNum;//再压3S继续执行下一次长压键

//          if (KeyWaitCount[KeyCount] == 0) {

//            KeyWaitCount[KeyCount] = 8000;//键盘压键释放计数器

//          }

      KeyCommandExec(2);//长压键3S事件处理(2)

//      ::Ctrl.BeepStart(DefBeep_2);//蜂鸣器发2声

        }

  }

  else {//无键压下

    if (KeyTest[KeyCount] >= SystemKeyPushNum) {//键释放

//          KeyWaitCount[KeyCount] = 8000;//键盘压键释放计数器

          KeyCommandExec(0);//键释放事件处理(0)

        }

        else {//无键压下或干扰

        }

    KeyTest[KeyCount] = 0;//清除压键计数器

  }

  KeyCount ++;//为下次扫描做准备

  KeyCount &= 0x07;//只有8个键

}



typedef void (KeyObj::* PFV)(void);

typedef void (* PV)(void);

//inline

void KeyObj::KeyCommandExec(unsigned char mode)

{

static PFV KeyCommandTab[3][8] PROGMEM = {//键盘放事件处理表

  {&KeyObj::Key00, &KeyObj::Key01, &KeyObj::Key02, &KeyObj::Key03, &KeyObj::Key04, &KeyObj::Key05, &KeyObj::Key06, &KeyObj::Key07}, //键释放事件处理

  {&KeyObj::Key10, &KeyObj::Key11, &KeyObj::Key12, &KeyObj::Key13, &KeyObj::Key14, &KeyObj::Key15, &KeyObj::Key16, &KeyObj::Key17}, //压键事件处理

  {&KeyObj::Key20, &KeyObj::Key21, &KeyObj::Key22, &KeyObj::Key23, &KeyObj::Key24, &KeyObj::Key25, &KeyObj::Key26, &KeyObj::Key27}  //长压键事件处理

};

  KeyCount &= 0x07;//取键盘序号//使用1602字节(.text),运行正确

PV func;//声明一般函数指针

  if (!((KeyCount >= 0x04) && (SystemFlage & (1 <<SystemWork)))) {//在调整状态拒绝显示测试状态

    wdt_reset();// Watchdog 复位

    func = reinterpret_cast<PV>(pgm_read_word(&KeyCommandTab[mode][KeyCount]));//取flash键盘放事件处理表

    func();//运行KeyX0()~KeyX7()

  }

}



/*------------------------

     键释放事件处理

------------------------*/



/*----------------------------------

   释放选择键

--------------------------------*/

inline

void KeyObj::Key00(void)

{

}



/*----------------------------------

   释放上调键

--------------------------------*/

inline

void KeyObj::Key01(void)

{

}



/*----------------------------------

   释放下调键

--------------------------------*/

inline

void KeyObj::Key02(void)

{

}



/*----------------------------------

   释放保留键

--------------------------------*/

inline

void KeyObj::Key03(void)

{

}



/*----------------------------------

   释放信号A

--------------------------------*/

inline

void KeyObj::Key04(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(2, 0);

    ::Lcd.LcdDisplay("按键: 红外  无效");

    ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发1声//工作开始

  }

}



/*----------------------------------

   释放信号B

--------------------------------*/

inline

void KeyObj::Key05(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(3, 0);

    ::Lcd.LcdDisplay("按键: TV/XGA无效");

    ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发1声//工作开始

  }

}



/*----------------------------------

   释放信号C

--------------------------------*/

inline

void KeyObj::Key06(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(3, 0);

    ::Lcd.LcdDisplay("按键: Y/C   无效");

    ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发1声//工作开始

  }

}



inline

void KeyObj::Key07(void)

{

}



/*------------------------

     压键事件处理

------------------------*/

/*----------------------------------

   单击选择键

--------------------------------*/



inline

void KeyObj::Key10(void)

{

  ::Ctrl.SysSelePushNum = 0;

  if (SystemFlage & (1 <<SystemWork)) {//在调整状态

    ::Lcd.LcdVrefSeleSubMenu();

  }

}



/*----------------------------------

   单击上调键

--------------------------------*/

inline

void KeyObj::Key11(void)

{

  ::Ctrl.SysPushNum = 0;

  if (SystemFlage & (1 <<SystemWork)) {//在调整状态

    ::Lcd.LcdVrefIncDecNum = 10;

        ::Lcd.LcdVrefIncDecSubMenu();

  }

}



/*----------------------------------

   单击下调键

--------------------------------*/

inline

void KeyObj::Key12(void)

{

  ::Ctrl.SysPushNum = 0;

  if (SystemFlage & (1 <<SystemWork)) {//在调整状态

    ::Lcd.LcdVrefIncDecNum = -10;

        ::Lcd.LcdVrefIncDecSubMenu();

  }

}



/*----------------------------------

   单击保留键

--------------------------------*/

inline

void KeyObj::Key13(void)

{

}



/*----------------------------------

   单击信号A

--------------------------------*/

inline

void KeyObj::Key14(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(2, 0);

    ::Lcd.LcdDisplay("按键: 红外  有效");

  }

}



/*----------------------------------

   单击信号B

--------------------------------*/

inline

void KeyObj::Key15(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(3, 0);

    ::Lcd.LcdDisplay("按键: TV/XGA有效");

  }

}



/*----------------------------------

   单击信号C

--------------------------------*/

inline

void KeyObj::Key16(void)

{

  if (::Ctrl.WorkNum == 0) {//电源板测试仪

    ::Lcd.SetLcdDisplayPos(3, 0);

    ::Lcd.LcdDisplay("按键: Y/C   有效");

  }

}



inline

void KeyObj::Key17(void)

{

}



/*------------------------

     长压键事件处理

------------------------*/

/*----------------------------------

   长压选择键

--------------------------------*/



inline

void KeyObj::Key20(void)

{

  ::Ctrl.SysSelePushNum ++;

  if (::Ctrl.SysSelePushNum > 8) {

    ::Ctrl.SysSelePushNum = 0;

    if ((SystemFlage & (1 <<SystemWork)) == 0) {//在工作状态

      switch(::Ctrl.WorkNum) {

        case 0://电源板测试仪

              ::Ctrl.WorkNum = 1;//驱动板测试仪

              break;

        case 1://驱动板测试仪

              ::Ctrl.WorkNum = 2;//转换板测试仪

              break;

        case 2://转换板测试仪

              ::Ctrl.WorkNum = 0;//电源板测试仪

              break;

      }

          eeprom_write_byte((unsigned char *)&eeromWorkNum, ::Ctrl.WorkNum);//工作号初始化

          ::Lcd.LcdMainMenu();//显示工作主菜单

    }

  }

  ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发1声//工作开始

}



inline

void KeyObj::Key2122(void)

{

  ::Ctrl.SysPushNum ++;

  if (::Ctrl.SysPushNum > 8) {

    if ((SystemFlage & (1 <<SystemWork)) == 0) {//在工作状态

      SystemFlage |= (1 << SystemWork);//转换为调整状态

          ::Lcd.LcdVrefSeleMenu();//显示调整主菜单

    }

  }

}





/*----------------------------------

   长压上调键

--------------------------------*/

inline

void KeyObj::Key21(void)

{

//Key2122();

//return;

  if (SystemFlage & (1 <<SystemWork)) {//在调整状态

    ::Ctrl.SysPushNum = 0;

    ::Lcd.LcdVrefIncDecNum = 50;

        ::Lcd.LcdVrefIncDecSubMenu();

  }

  else {

    Key2122();

  }

  ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发3声//工作开始

}



/*----------------------------------

   长压下调键

--------------------------------*/

inline

void KeyObj::Key22(void)

{

//Key2122();

//return;

  if (SystemFlage & (1 <<SystemWork)) {//在调整状态

    ::Ctrl.SysPushNum = 0;

    ::Lcd.LcdVrefIncDecNum = -50;

        ::Lcd.LcdVrefIncDecSubMenu();

  }

  else {

    Key2122();

  }

  ::Ctrl.BeepStart(DefBeep_1);//蜂鸣器发3声//工作开始

}



/*----------------------------------

   长压保留键

--------------------------------*/

inline

void KeyObj::Key23(void)

{

}



/*----------------------------------

   长压信号A

--------------------------------*/

inline

void KeyObj::Key24(void)

{

  ::Ctrl.BeepStart(DefBeep_2);//蜂鸣器发2声

}



/*----------------------------------

   长压信号B

--------------------------------*/

inline

void KeyObj::Key25(void)

{

  ::Ctrl.BeepStart(DefBeep_2);//蜂鸣器发2声

}



/*----------------------------------

   长压信号C

--------------------------------*/

inline

void KeyObj::Key26(void)

{

}



inline

void KeyObj::Key27(void)

{

}



int main(void)

{

  OSCCAL = eeprom_read_byte(&osc_address);

  wdt_enable(WDTO_2S);// Watchdog 使能,Watchdog 定时器1秒超时

  wdt_reset();// Watchdog 复位

  if (SystemRamTest != 0x55aa) {//这句是必须加的

//    SystemTime = 0;

        if (eeprom_read_word(&eeromTest) != 0x55aa) {//这句是必须加的

//          wdt_reset();// Watchdog 复位

          eeprom_write_byte((unsigned char *)&eeromWorkNum, 0);//工作号初始化

          eeprom_write_word((unsigned int *)&eeromTest, 0x55aa);//完成内存测试

        }

        SystemRamTest = 0x55aa;//完成内存测试

//        while(1);//自毁,测试Watchdog的好坏

  }

//SystemTime ++;

  SystemFlage = 0;

  ::Ctrl.SysPushNum = 0;

  ::Ctrl.SysSelePushNum = 0;

  ::Ctrl.StartTime = 0;

  ::Ctrl.WorkNum = eeprom_read_byte(&eeromWorkNum);

//  wdt_enable(WDTO_2S);// Watchdog 使能,Watchdog 定时器1秒超时

//  wdt_reset();// Watchdog 复位

  ::Lcd.LcdStartMenu();//启动菜单

  ::Ctrl.BeepStart(DefBeep_3);//蜂鸣器发3声

//  set_sleep_mode(SLEEP_MODE_IDLE);

  for(;;) {//死循环

    sei();

    TIMSK |= (1 << TOIE1);

        SystemFlage |= (1 << SystemWdt);//设置软件狗

//    sleep_mode();//进入休眠模式

//    wdt_reset();// Watchdog 复位

  }

  return 0;//正常返回操作系统(实际不可能,MCU一般也不需要)

}



SIGNAL(SIG_INTERRUPT0)

{

}



SIGNAL(SIG_INTERRUPT1)

{

}



SIGNAL(SIG_OVERFLOW0)

{

}



/*-----------------------------------------------

        2.5mS定时器主工作测试控制模块

------------------------------------------------*/

SIGNAL(SIG_OVERFLOW1)

{

出0入0汤圆

 楼主| 发表于 2006-2-7 22:02:09 | 显示全部楼层
晕到~~~怎么又被多加了"序言"...



又被忽悠了...



本想写点"暂别语"...哈哈...写不成了...
头像被屏蔽

出0入0汤圆

发表于 2006-2-7 22:59:17 | 显示全部楼层
天冷了,给菜农加条裤子 ...

出0入0汤圆

 楼主| 发表于 2006-2-8 01:32:03 | 显示全部楼层
哈哈...不冷...我裤子很多...



不过这是我在此得到的第1条裤子,我会珍惜的...



如果我想真开口,估计肯定穿的走不动路了...



哈哈...

出0入0汤圆

发表于 2006-2-8 01:35:46 | 显示全部楼层
等那天hotpower开个裤子展,大拍卖...

出0入0汤圆

 楼主| 发表于 2006-2-8 01:39:17 | 显示全部楼层
晕到,这有70条破裤子,再穿成了裤贩子了...



今天要上班了...舒服日子到"点"了...
-----此内容被hotpower于2006-02-08,01:41:01编辑过

出0入0汤圆

 楼主| 发表于 2006-2-10 18:02:31 | 显示全部楼层
经过6个小时的"苦战"终于在Keil的RealView编译器上移植了本主题的在C++中定义类成员函数指针数组...



快要晕到~~~,喜悦之中---爽~~~



终于在ARM里打开了通往ARTX+C++的大门.


-----此内容被hotpower于2006-02-10,18:04:45编辑过

出0入0汤圆

发表于 2006-2-11 10:42:56 | 显示全部楼层
hotpower 菜农 你好!

   请教一个问题:

出0入0汤圆

发表于 2006-2-11 10:49:24 | 显示全部楼层
hotpower 菜农 你好!

   请教一个问题:

   temp=ccc+7;

      while(ccc<temp)asm("sleep
\t");

      ccc是一个秒计数器,编译后是一个死循环,这是winavr 05版的一个bug吗?

   请回复,谢谢

出0入0汤圆

发表于 2006-2-11 14:00:09 | 显示全部楼层
全局变量,如果会在中断服务程序中被修改,须加volatile限定

volatile unsigned int ccc;

出0入0汤圆

 楼主| 发表于 2006-2-11 19:05:54 | 显示全部楼层
晕到~~~天大的bug...

temp=ccc+7;//temp永远比ccc大7,即ccc永远小于temp!!!!!!!

假定它们都是unsigned char,那么

ccc=0~59,temp=7~66.

while(ccc<temp) {//晕到~~~ccc永远小于temp!!!!!!!

  asm("sleep
\t");//不死找谁???此句有现成的函数sleep_mode();//在avr/sleep.h中

}



至于HJJourAVR说的全局变量ccc(秒计数器)肯定在定时中断中操作过,一般须加volatile限定,但如果在初始化中ccc清过0.即主程序有过读写这两个过程

ccc=0;//写过程

while(ccc<temp) {//读过程.

那么,ccc是可以不加volatile限定的.



编译器只要测试出在主程序或中断程序中经过读写这两个过程的变量肯定不会优化.



若编译器要优化了,那这个编译器肯定是个垃圾!!!



故分别在主程序和中断程序中只经过单独的读或写的变量最好加volatile限定符以阻止编译器采取忽悠的行为...

出0入0汤圆

发表于 2006-2-11 19:44:57 | 显示全部楼层
Hotpower,我这次要推翻你的非典了。

我记得在写 [中断使用范例] ,即使在主程序或中断程序中经过读写这两个过程的变量,依然须加volatile限定。

SIGNAL(SIG_INTERRUPT2) //INT2中断服务程序

{

    FLAG=!FLAG;                //修改全局变量

    _delay_ms(10);

}

int main(void)

{

    FLAG=0;

    sei();        //使能全局中断

    while (1)

    {

        while (FLAG==0);

        LED2_ON();                //如果FLAG不加volatile限定(即has_volatile=0),程序将永远都运行不到这里。

        while (FLAG!=0);

        LED2_OFF();

    }

}

出0入0汤圆

 楼主| 发表于 2006-2-12 00:50:46 | 显示全部楼层
推翻非典很难...以下是反汇编的例子



//全局变量



#define has_volatile 0 //这里是条件编译

//可以修改has_volatile=1或0来看程序运行的效果

#if has_volatile

//volatile//开始设has_volatile 0和干脆去掉volatile结果肯定一样

unsigned char FLAG; //全局变量,会在中断服务程序中被修改,须加volatile限定

#else

unsigned char FLAG; //全局变量.

#endif





94:                   FLAG=!FLAG; //修改全局变量

+0000008D:   E090        LDI     R25,0x00         Load immediate

+0000008E:   91800060    LDS     R24,0x0060       Load direct from data space

+00000090:   2388        TST     R24              Test for Zero or Minus

+00000091:   F409        BRNE    PC+0x02          Branch if not equal

+00000092:   E091        LDI     R25,0x01         Load immediate

+00000093:   93900060    STS     0x0060,R25       Store direct to data space

+00000095:   EA88        LDI     R24,0xA8         Load immediate

+00000096:   E691        LDI     R25,0x61         Load immediate

+00000097:   9701        SBIW    R24,0x01         Subtract immediate from word

+00000098:   F7F1        BRNE    PC-0x01          Branch if not equal

+00000099:   919F        POP     R25              Pop register from stack

+0000009A:   918F        POP     R24              Pop register from stack

+0000009B:   900F        POP     R0               Pop register from stack

+0000009C:   BE0F        OUT     0x3F,R0          Out to I/O location

+0000009D:   900F        POP     R0               Pop register from stack

+0000009E:   901F        POP     R1               Pop register from stack

+0000009F:   9518        RETI                     Interrupt return

@000000A0: main

98:           {

+000000A0:   E5CF        LDI     R28,0x5F         Load immediate

+000000A1:   E0D8        LDI     R29,0x08         Load immediate

+000000A2:   BFDE        OUT     0x3E,R29         Out to I/O location

+000000A3:   BFCD        OUT     0x3D,R28         Out to I/O location

100:             PORTA =0xFF; //不用的管脚使能内部上拉电阻。

+000000A4:   EF8F        SER     R24              Set Register

+000000A5:   BB8B        OUT     0x1B,R24         Out to I/O location

101:             PORTC =0xFF;

+000000A6:   BB85        OUT     0x15,R24         Out to I/O location

102:             PORTD =0xFF;

+000000A7:   BB82        OUT     0x12,R24         Out to I/O location

103:             DDRB = (1<<LED2)|(1<<LED1)|(1<<LED0); //输出

+000000A8:   E08B        LDI     R24,0x0B         Load immediate

+000000A9:   BB87        OUT     0x17,R24         Out to I/O location

104:             PORTB =~((1<<LED2)|(1<<LED1)|(1<<LED0)); //低电平,灯灭

+000000AA:   EF84        LDI     R24,0xF4         Load immediate

+000000AB:   BB88        OUT     0x18,R24         Out to I/O location

106:             MCUCR=(1<<ISC11)|(0<<ISC10)|(1<<ISC01)|(0<<ISC00); //注意该寄存器有多个功能

+000000AC:   E08A        LDI     R24,0x0A         Load immediate

+000000AD:   BF85        OUT     0x35,R24         Out to I/O location

113:             MCUCSR&=~(1<<ISC2); //注意该寄存器有多个功能

+000000AE:   B784        IN      R24,0x34         In from I/O location

+000000AF:   7B8F        ANDI    R24,0xBF         Logical AND with immediate

+000000B0:   BF84        OUT     0x34,R24         Out to I/O location

118:             GIFR=(1<<INTF1)|(1<<INTF0)|(1<<INTF2);//写1清除标志位,在使能中断前最好先把对应

+000000B1:   EE80        LDI     R24,0xE0         Load immediate

+000000B2:   BF8A        OUT     0x3A,R24         Out to I/O location

120:             GICR=(1<<INT1)|(1<<INT0)|(1<<INT2); //使能三个外部中断

+000000B3:   BF8B        OUT     0x3B,R24         Out to I/O location

121:             FLAG=0;

+000000B4:   92100060    STS     0x0060,R1        Store direct to data space

122:             sei(); //使能全局中断

+000000B6:   9478        SEI                      Global Interrupt Enable

+000000B7:   91800060    LDS     R24,0x0060       Load direct from data space

125:                   while (FLAG==0);

+000000B9:   2388        TST     R24              Test for Zero or Minus

+000000BA:   F3F1        BREQ    PC-0x01          Branch if equal

126:                      LED2_ON(); //如果FLAG不加volatile限定(即has_volatile=0),

+000000BB:   9AC3        SBI     0x18,3           Set bit in I/O register

128:                   while (FLAG!=0);

+000000BC:   2388        TST     R24              Test for Zero or Minus

+000000BD:   F7F1        BRNE    PC-0x01          Branch if not equal

129:                      LED2_OFF();

+000000BE:   98C3        CBI     0x18,3           Clear bit in I/O register

+000000BF:   CFF9        RJMP    PC-0x0006        Relative jump

出0入0汤圆

 楼主| 发表于 2006-2-12 01:10:55 | 显示全部楼层
还是帖大图方便...4个断点已经证明FLAG没有被优化.



证明理由:



由于全局变量(FLAG)在主函数被至少读和至少写了一此,那么这个变量(FLAG)肯定有意义!!!

编译器应用很清楚这是合法的行为.



实际上,如果1个变量在某个函数中(包括中断函数),若在它的有效访问区域内只进行了N次读且不写操作,或只进行了N次写且不读操作,那么编译器认为是可以优化的.



所以,像操作IO的特殊寄存器在定义时都必须加volatile修饰以阻止编译器自做小聪明的"大事"



因为我们经常开机后只做PORTD=0xff;在也不管的事情.



反证:

    若教主的正典正确,则所有的全局变量都必须加volatile修饰!!!因为我们定义全局变量就是为了读写的!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!





出0入0汤圆

 楼主| 发表于 2006-2-12 01:16:52 | 显示全部楼层
12楼病症主要是以下2句有病!!!

   temp=ccc+7;

      while(ccc<temp)asm("sleep
\t");



可能被聪明的GCCAVR优化为:



      while(1)asm("sleep
\t");



所以与ccc的修饰无关!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

出0入0汤圆

 楼主| 发表于 2006-2-12 01:18:43 | 显示全部楼层
很多人都想击败菜农,...大多都是"理想"...

出0入0汤圆

 楼主| 发表于 2006-2-12 02:46:56 | 显示全部楼层
唱一曲<<黄河颂>>---再次感谢TestCode
-----此内容被hotpower于2006-02-12,02:47:50编辑过

出0入0汤圆

发表于 2006-2-12 10:23:00 | 显示全部楼层
Hotpower 怎么会没有问题?

125:                   while (FLAG==0);

+000000B9:   2388        TST     R24              Test for Zero or Minus

+000000BA:   F3F1        BREQ    PC-0x01          Branch if equal

在这里,根本就没有重新检测 FLAG (位于SRAM 0x0060地址),而只是检测临时缓冲寄存器R24,绝对有问题:因为SIGNAL(SIG_INTERRUPT2)中修改的是FLAG的原始数据 SRAM 0x0060。



当时[实际运行]的结果是

while (FLAG==0);

        LED2_ON();      //如果FLAG不加volatile限定(即has_volatile=0),程序将永远都运行不到这里。

出0入0汤圆

 楼主| 发表于 2006-2-12 10:43:51 | 显示全部楼层
承认错误!!!这次你正典了!!!

看来GCCAVR在这里认为连续地读时,第2次读"没必要再取原始变量"了,但它没考虑中断.

确实第2个while (FLAG==0);被优化了...

看来若中断参与的变量时,必须用volatile限定了...

出0入0汤圆

 楼主| 发表于 2006-2-12 10:49:14 | 显示全部楼层
搞技术的最怕不承认错误...只有"低头认罪"才能"宽大处理"!!!



谢谢HJJourAVR!!!

出0入0汤圆

发表于 2006-2-12 11:19:52 | 显示全部楼层
高手過招, 精彩!

出0入0汤圆

发表于 2006-2-12 15:04:28 | 显示全部楼层
承让,呵呵。



主要是GCCAVR的这个volatile特点,已经让很多人中招了,我是有备而来的。

出0入0汤圆

发表于 2006-2-12 20:00:01 | 显示全部楼层
感谢HJJourAVR 和hotpower 菜农两位老师

  若在主程序中置数,在中断程序中判断的全局变量需加volatile限定吗?

     感谢

出0入0汤圆

发表于 2006-2-12 21:15:36 | 显示全部楼层
"若在主程序中置数,在中断程序中判断的全局变量需加volatile限定吗? "

需要!!

出0入0汤圆

发表于 2006-2-13 13:18:51 | 显示全部楼层
感谢單騙皇帝,不骗百姓!

  若将所有的全局变量加volatile限定可以吗?会出现什么情况.

谢!

出0入0汤圆

发表于 2006-2-13 14:54:23 | 显示全部楼层
"  若将所有的全局变量加volatile限定可以吗?会出现什么情况. 谢!"

當然可以了, 不過會影響程序執行效率!!

出0入0汤圆

发表于 2006-2-15 22:46:58 | 显示全部楼层
又一问题,该程序在51中通过,在AVR中不能得到正确答案

volatile uchar ccc1[2],tm[4];



void hextoasc( uint div, uint *P, uchar x, uchar xd)

{ uchar i; uchar dd;



                dd=0;

     for(i=0;i<x;i++)

     tm1[i+xd]=0;   

     for(i=0;i<x;i++)

     {

         while(*P>=div){dd+=1;*P-=div;}

     tm1[i+xd]=dd+=0x30;div/=10;dd=0;}

}





int main(void)

{

        uchar azsz1[2];

        .   

        .

        .

        .

        azsz1[0]=0;

                   azsz1[1]=ccc1[0];

                 hextobcd(10,( uint*)&azsz1[0],2,0);

        .

        .

        .

       

}

  汇编不熟,正在学习中.

出0入0汤圆

发表于 2006-2-15 23:43:43 | 显示全部楼层
tm1[i+xd]=dd+=0x30  這句看了發暈!!

出0入0汤圆

发表于 2006-2-16 13:27:57 | 显示全部楼层
tm1[i+xd]=dd+=0x30  這句看了發暈!! 不至余吧.

xd为偏移量,xd=0,tm=dd+=0x30,dd为所求的扩展bcd码,+0x30后为ASCII码.

ccc1[0]<100的正整数.

        hextobcd(10,( uint*)&azsz1[0],2,0);

应为        hextoasc(10,( uint*)&azsz1[0],2,0);

你有空吗?用WINAVR 05版编译仿真试试.有状况告之.

另问C语言中数组n[0]...n[9]是从左至右排列的吗?数据123456也是从左至右排列的吗?

谢谢!

出0入0汤圆

发表于 2006-2-16 14:35:00 | 显示全部楼层
這樣寫不是易看點嗎?

dd+=0x30;

tm=dd;



可能問題出在這

hextoasc(10,( uint*)&azsz1[0],2,0);



( uint*)&azsz1[0] 這到底是什麼來的? 是指針的指針嗎? 可能winavr沒有keil這樣智能, 看不懂,建議你把代碼整理一下! 這樣因寫法不嚴緊而出問是司空見慣的!

出0入0汤圆

发表于 2006-12-27 12:41:25 | 显示全部楼层
把酷帖顶起!把酷帖顶齐!

出0入0汤圆

发表于 2011-12-15 18:08:43 | 显示全部楼层
mark
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-28 00:41

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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