打印
[ZLG-MCU]

不抛弃不放弃---类成员函数终成中断函数(发帖自贺)

[复制链接]
9775|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hotpower|  楼主 | 2008-2-9 04:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
哈哈~~~终于了却了在Cortex M3上的C++类成员函数做中断函数的心愿~~~

又是一个4点钟~~~菜农"跳出黄河"的时间此生几乎都在后半夜...

C++之路----全扫荡完了...发帖自贺

菜农HotPower@126.com  2008.2.9 4:08 于西安大雁塔菜地

相关下载

相关帖子

来自 2楼
hotpower|  楼主 | 2008-2-10 00:35 | 只看该作者

不声明为静态函数就得不到类的实际地址

类的声明和变量的类型声明实际是一样的,它们并不实际存在.
只有在定义并分配空间后,才能得到实际的物理地址.

由于类的成员变量的备份可能有许多,而类的成员函数实际是共享的.
所以类的成员函数的地址应该是唯一的.

声明为静态函数实际和生存期有关,不声明为静态函数,编译器将找不到
成员函数的物理地址.

基于以上的理解,类的(静态)成员函数做中断函数后,由于类的成员变量的备份可能有许多,

所以IAR要求访问时需要:实际类名称.类成员(变量/函数),想来也真是有道理的~~~

特别是: 实际类名称.类成员变量.

不过再饶着站在GCC的立场上想: 类的(静态)成员函数做中断函数肯定是唯一的.
所以指明类的实际名称是多余的~~~

总之两者都各有自己的道理~~~所以编程者就遵守各自的约定好了~~~

使用特权

评论回复
板凳
hotpower|  楼主 | 2008-2-9 04:46 | 只看该作者

哈哈~~~许三多!!!不抛弃不放弃,才能做成"有意义的事"

使用特权

评论回复
地板
phoenixmy| | 2008-2-9 11:24 | 只看该作者

~~~~~~~~~~



GX

不过又是这么晚,估计地球那边的才能拼的过。。。

使用特权

评论回复
5
hotpower|  楼主 | 2008-2-9 12:19 | 只看该作者

类成员函数做中断函数的三个主要步骤

1.在类中声明ISP()
class SystemObj
{
public:
//................
//类成员函数做中断函数
    static void HibernateISR(void);//必须声明为静态函数!!!
    static void SysTickISR(void);//必须声明为静态函数!!!
public:
    volatile unsigned int RamTest;
    union
    {
        volatile unsigned char WorkFlag;
        struct
        {
            unsigned char Watchdog:         1;//允许喂狗
            unsigned char SysTickFlag:      1;//节拍中断
            unsigned char MainLoopFlag:     1;//主循环运行
            unsigned char MainWatchdog:     1;//主循环喂狗
        };
    };
};

class UartObj {
public:
//.........
//类成员函数做中断函数
    static void UART0ISR(void);//必须声明为静态函数!!!
};

2.构造类成员函数
//5mS定时中断服务程序(类成员函数做中断函数)
//static//此处不能加static!!!
//类成员变量必须指明实际的类!!!(System.MainWatchdog 不能写成MainWatchdog)
void SystemObj::SysTickISR(void)
{
    Keyboard.Exec();//"零耗时键盘"消抖及运行命令
    if (System.Watchdog)//允许喂狗
    {
      if (!System.MainWatchdog)//中断喂狗论
        {
            if (!System.SysTickFlag && System.MainLoopFlag)//主程序在工作
            {
                WatchdogIntClear(WATCHDOG_BASE);//真正的硬件喂狗!!!
            }
        }
    }
    System.SysTickFlag = true;//通知主循环节拍中断正常工作
}

//休眠激活中断服务程序(类成员函数做中断函数)
//static//此处不能加static!!!
void SystemObj::HibernateISR(void)
{
   HWREG(HIB_CTL) &= ~ HIB_CTL_HIBREQ;
   HibernateIntClear(HIBERNATE_INT_PIN_WAKE    | HIBERNATE_INT_LOW_BAT |
                 HIBERNATE_INT_RTC_MATCH_0 | HIBERNATE_INT_RTC_MATCH_1);
}

//串口中断服务程序(类成员函数做中断函数)
//static//此处不能加static!!!
void UartObj::UART0ISR(void)
{

    unsigned long ulStatus;
    ulStatus = UARTIntStatus(UART0_BASE, true);
    UARTIntClear(UART0_BASE, ulStatus);
    while(UARTCharsAvail(UART0_BASE))
    {
        UARTCharPutNonBlocking(UART0_BASE, UARTCharGetNonBlocking(UART0_BASE));
    }
}

3.在startup.c内的中断向量表内填写需要中断的类成员函数地址
__root static const uVectorEntry g_pfnVectors[] @ "INTVEC" =
{
    { .ulPtr = __sfe( "CSTACK" ) },
    __program_start,                        // The reset handler
//    ResetISR,                             // The reset handler
    NmiSR,                                  // The NMI handler
    FaultISR,                               // The hard fault handler
    IntDefaultHandler,                      // The MPU fault handler
    IntDefaultHandler,                      // The bus fault handler
    IntDefaultHandler,                      // The usage fault handler
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // SVCall handler
    IntDefaultHandler,                      // Debug monitor handler
    0,                                      // Reserved
    IntDefaultHandler,                      // The PendSV handler
    &SystemObj::SysTickISR,                 // The SysTick handler
//不能用下列写法
//    &System.SysTickISR,                     // The SysTick handler
//...................
    &UartObj::UART0ISR,                     // UART0 Rx and Tx
//不能用下列写法
//    &Uart.UART0ISR,                         // UART0 Rx and Tx
    IntDefaultHandler,                      // UART1 Rx and Tx
//...................
    IntDefaultHandler,                      // Ethernet
    &SystemObj::HibernateISR                // Hibernate
//不能用下列写法
//    &System.HibernateISR                    // Hibernate
};


可以看出IAR实在不如GCC~~~不过还是能过得去的~~~

请看:
//static//此处不能加static!!!
//类成员变量必须指明实际的类!!!(System.MainWatchdog 不能写成MainWatchdog)
void SystemObj::SysTickISR(void)
{
    Keyboard.Exec();//"零耗时键盘"消抖及运行命令
    if (System.Watchdog)//允许喂狗
//...................

哈哈~~~看看gcc的2个步骤吧(它隐含了中断向量表)
1.在类中声明ISP()
class AdcObj {
public:
//................
//类成员函数做中断函数
  void SIG_ADC(void)  __attribute__ ((signal));
private:
  unsigned char AdcNum;//加volatile将增大空间72个字节
  unsigned char AdcCount;//加volatile将增大空间4个字节
  volatile unsigned int AdcSum[8];//不改变
  unsigned int AdcMax[8];//加volatile将增大空间4个字节
  volatile unsigned int AdcMin[8];//不改变
};

2.构造类成员函数
void AdcObj::SIG_ADC(void)
{
unsigned int adcval;
  adcval = ADC & 0x3ff;//取ADC转换电压,并保存
  SetAdcChNum(AdcNum + 1);//设置新通道
/*-----------------------------------------------------------
  求最大值,最小值,累加和(0,5不用侧)
------------------------------------------------------------*/
  if (AdcNum & 1) {//偶数不测试
    AdcSum[AdcNum] += adcval;//存累加和
    if (adcval > AdcMax[AdcNum]) {
      AdcMax[AdcNum] = adcval;//最大值
    }
    if (adcval < AdcMin[AdcNum]) {
      AdcMin[AdcNum] = adcval;//存最小值
    }
  }
//...........................
}

可以看出gcc才是最完美的类成员函数做中断函数~~~
而IAR的类成员函数做中断函数后不能访问自己类的其他成员实在倒塌~~~

哈哈~~~估计是菜农还没彻底将其倒塌...估计还要求助TestCode同志~~~

使用特权

评论回复
6
phoenixmy| | 2008-2-9 12:47 | 只看该作者

为啥有的要声明为静态?



    static void HibernateISR(void);//必须声明为静态函数!!!
    static void SysTickISR(void);//必须声明为静态函数!!!

使用特权

评论回复
7
hotpower|  楼主 | 2008-2-9 13:00 | 只看该作者

IAR环境下LM中C++类成员函数做中断函数源码下载

注意本例程用LM LINK下载程序后应该将LM LINK去掉!!!

进入休眠要先按Key1不放再长压Key4进入休眠状态!!!

这样按WAKE才能从休眠中唤醒~~~

菜农 HotPower@126.com  2008.2.9 4:08 于雁塔村菜地


相关链接:https://bbs.21ic.com/upfiles/img/20082/200829125942997.rar

使用特权

评论回复
8
hotpower|  楼主 | 2008-2-10 01:19 | 只看该作者

静态成员函数访问非静态类数据成员的一般方法...(John_Lee)

最常用和普通的方法是:可以在声明静态成员函数时增加一个类指针参数,用来访问非静态类数据成员,其实就相当于将 this 显示化了而已。在调用该静态函数时,调用者需要传递一个类指针参数。

例:
class foo_t
{
    ...
    static uint8_t static_data;                // 静态数据成员
    uint8_t ordinary_data;                     // 普通数据成员
    static void static_func (foo_t *, ...);    // 静态成员函数
    void ordinary_func (...);                  // 普通成员函数
    ...
};

void foo_t::ordinary_func (...)
{
    ...
    static_func (this, ...);          // 调用静态成员函数,将 this 指针传递给 static_func 以便访问 普通数据成员
    ...
}

void foo_t::static_func (foo_t *foo, ...)
{
    foo->ordinary_data = static_data;     // 直接访问 static_data,通过 foo 访问 ordinary_data
}

相关链接:http://www.21icbbs.com/club/bbs/ShowAnnounce.asp?v=&ID=1718995

使用特权

评论回复
9
hotpower|  楼主 | 2008-2-10 01:36 | 只看该作者

IAR遵守了静态成员不能直接访问类的其他成员的约定

静态成员不能直接访问类的其他成员 
 BitFu 发表于 2005-6-30 20:28 AVR 单片机 ←返回版面    

所以,感觉这样用的局限太大了。
 

例如:
//5mS定时中断服务程序(类成员函数做中断函数)
//static//此处不能加static!!!
//类成员变量必须指明实际的类!!!
//(System.MainWatchdog 不能写成MainWatchdog)
//IAR遵守了静态成员不能直接访问类的其他成员的约定
void SystemObj::SysTickISR(void)
{
    Keyboard.Exec();//"零耗时键盘"消抖及运行命令
    if (System.Watchdog)//允许喂狗
    {
      if (!System.MainWatchdog)//中断喂狗论
        {
            if (!System.SysTickFlag && System.MainLoopFlag)//主程序在工作
            {
                WatchdogIntClear(WATCHDOG_BASE);//真正的硬件喂狗!!!
            }
        }
    }
    System.SysTickFlag = true;//通知主循环节拍中断正常工作
}
 

相关链接:http://www.21icbbs.com/club/bbs/ShowAnnounce.asp?v=&ID=1718681

使用特权

评论回复
10
hotpower|  楼主 | 2008-2-10 01:41 | 只看该作者

xwj说俺在挖坟~~~看坟中之源泉吧,肯定会有更大的收获~~~

哈哈~~~菜农的很多帖就是这样被沉下去的~~~

准备有空多挖些这样的坟墓~~~
相关链接:http://www.21icbbs.com/club/bbs/ShowAnnounce.asp?v=&ID=1713555

使用特权

评论回复
11
PHOENIXMY| | 2008-2-10 10:55 | 只看该作者

学习了~~~~~~~~~~



不过关于嵌入式c++的使用应该有一套标准吧
按理说应该各个嵌入式编译环境都遵守才对啊

这样才好叫文盲变菜鸟
否则总是摸不到头脑~~~~~~~~~~~

使用特权

评论回复
12
hotpower|  楼主 | 2008-2-10 16:48 | 只看该作者

哈哈~~~放假刚好补习作业~~~

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1460

主题

21619

帖子

506

粉丝