eBox的中断结构参考了mbed,和我们平时所用的中断结构有些差异,不容易理解,最近仔细看了底层代码,终于搞清楚了,总结一下

        一  首先要要搞清楚的几个概念:类的静态成员,实例成员
                1  静态成员(static)对类以及类的所有实例有意义。即在该类的范围内所有类共享该成员。即使未创建实例,静态成员也存在,可以访问
                2  类的实例成员仅对每个实例有意义,在创建实例之前,未分配内存,无法访问
        成员分为属性和方法,对于属性:
                1  静态属性,对应一块内存. 静态属性在使用前必须初始化
                2  实例属性,每个实例属性个对应一块内存
         对于方法:不管是静态方法还是实例方法,都是同一块内存,区别在于
                1  静态方法,可以通过类名或者实例对象名调用。 例如:class::call(),object.call() . 静态方法不能直接调用实例方法(实例方法此时还未分配内存空间),可以通过对象名间接访问
                2  实例方法,只可以通过实例对象名调用 object.call() ;实例方法可以调用静态方法
        二 接下来在来看ebox中的中断相关代码 
                先来看绑定中断的过程
                 1  在类声明里如下两个,绑定中断的过程就是通过模版变量pirq的attach方法保存回调函数指针
  1. // 绑定静态回调函数
  2. void attach(void(*fptr)(void)){
  3. pirq.attach(fptr);
  4. }
  5. FunctionPointer pirq;
                2  声明了两个变量,一个函数指针,一个数组       
  1. typedefvoid(*exti_irq_handler)(uint32_t id);
  2. static exti_irq_handler irq_handler;
  3. staticuint32_t exti_irq_ids[16];
               其中,  数组用来保存实例对象地址(id),函数指针指向类的静态方法(handel)
  1. int exti_irq_init(uint8_t index,exti_irq_handler handler,uint32_t id)
  2. {
  3. exti_irq_ids[index]= id;
  4. irq_handler = handler;
  5. return0;
  6. }
              3  在类中实现一个静态方法,id为实例对象指针。前面说过静态方法可以通过对象名间接调用实例方法
  1. void IRQ::irq_handler(uint32_t id)
  2. {
  3. IRQ *handler =(IRQ*)id;// 指向回调函数地址
  4. handler->pirq.call();// 调用回调函数
  5. }
              4   在初始化的时候,将静态方法地址,和实例地址分别送入
  1. exti_irq_init(13,(&IRQ::irq_handler),(uint32_t)this);
               绑定完毕之后,我们就可以在中断中调用了
  1. void EXTI4_15_IRQHandler(void)
  2. {
  3. if(LL_EXTI_IsActiveFlag_0_31(LL_EXTI_LINE_13)!= RESET)
  4. {
  5. LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_13);
  6. /* Manage code in main.c.*/
  7. irq_handler(exti_irq_ids[13]);
  8. }
  9. }
             假设我们创建了类IRQ的实例  A, 那么中断的调用过程就是
           中断服务-->IRQ::irq_handler(&A)-->A->pirq.call() 。也就是最终访问的是实例对象A中的变量pirq.  然后通过调用perq的call()方法执行回调函数。
            以上是对非类成员方法作为回调函数的绑定和调用过程。 如果类成员方法做为回调函数,过程一致,只是我们在类里声明函数指针的时候,因为不知到具体回调的是哪个类的实例,无法定义该变量。所以用到了模版。模版的用途就是定义了一个通用的函数指针,我们在对该指针初始化的时候传入的是什么类型,就是什么类型
  1. /** A class for storing and calling a pointer to a static or member function 用来保存静态或成员函数的指针类
  2. */
  3. // R-返回值类型 A1-参数类型
  4. template<typename R,typename A1>
  5. classFunctionPointerArg1{
  6. public:
  7. /** Create a FunctionPointer, attaching a static function 创建函数指针
  8. *
  9. * @param function The static function to attach (default is none) 附加静态函数,默认为void
  10. */
  11. FunctionPointerArg1(R (*function)(A1)=0){
  12. attach(function);
  13. }
  14. /** Create a FunctionPointer, attaching a member function
  15. * 附加成员函数,object 成员函数的对象的指针。 成员函数
  16. * @param object The object pointer to invoke the member function on (i.e. the this pointer)
  17. * @param function The address of the member function to attach
  18. */
  19. template<typename T>
  20. FunctionPointerArg1(T *object, R (T::*member)(A1)){
  21. attach(object, member);
  22. }
  23. /** Attach a static function
  24. * 附件静态函数
  25. * @param function The static function to attach (default is none)
  26. */
  27. void attach(R (*function)(A1)){
  28. _p.function = function;
  29. _membercaller =0;
  30. }
  31. /** Attach a member function
  32. * 附件成员函数
  33. * @param object The object pointer to invoke the member function on (i.e. the this pointer)
  34. * @param function The address of the member function to attach
  35. */
  36. template<typename T>
  37. void attach(T *object, R (T::*member)(A1)){
  38. _p.object =static_cast<void*>(object);// 将对象转换成void* 类型
  39. *reinterpret_cast<R (T::**)(A1)>(_member)= member;
  40. _membercaller =&FunctionPointerArg1::membercaller<T>;//注册成员函数地址
  41. }
  42. /** Call the attached static or member function
  43. */
  44. R call(A1 a){
  45. if(_membercaller ==0&& _p.function){
  46. return _p.function(a);
  47. }elseif(_membercaller && _p.object){
  48. return _membercaller(_p.object, _member, a);
  49. }
  50. return(R)0;
  51. }
  52. /** Get registered static function
  53. */
  54. R(*get_function(A1))(){
  55. return _membercaller ?(R(*)(A1))0:(R(*)(A1))_p.function;
  56. }
  57. #ifdef MBED_OPERATORS
  58. R operator()(A1 a){
  59. return call(a);
  60. }
  61. operatorbool(void)const{
  62. return(_membercaller != NULL ? _p.object :(void*)_p.function)!= NULL;
  63. }
  64. #endif
  65. private:
  66. template<typename T>//对象类型
  67. // 调用成员 对象,成员函数
  68. static R membercaller(void*object,uintptr_t*member, A1 a){
  69. T* o =static_cast<T*>(object);//类型转换
  70. R (T::**m)(A1)=reinterpret_cast<R (T::**)(A1)>(member);
  71. return(o->**m)(a);
  72. }
  73. union{
  74. R (*function)(A1);// static function pointer 静态函数指针
  75. void*object;// object this pointer 对象指针
  76. } _p;// 用联合体保存指针,静态函数或者对象,只能保存其中一种
  77. uintptr_t _member[4];// aligned raw member function pointer storage - converted back by registered _membercaller
  78. // 函数指针
  79. R (*_membercaller)(void*,uintptr_t*, A1);// registered membercaller function to convert back and call _m.member on _object
  80. };
           总结,中断回调的关键有两点
           1   如何在类未实例化之前访问类成员--静态成员函数
           2   如何在允许挂在中断回调函数的类里声明指针变量,以用来指向回调函数 -- 模版
           所以只要理解了静态成员和模版就能够理解ebox中中断结构以及实现方法
        
          
      
 

eBox(stm32) 之中断结构的更多相关文章

  1. (二)stm32之中断配置

    一.stm32的中断和异常 Cortex拥有强大的异常响应系统,它能够打断当前代码执行流程事件分为异常和中断,它们用一个表管理起来,编号为0~15为内核异常,16以上的为外部中断,这个表就是中断向量表 ...

  2. STM32外部中断具体解释

      一.基本概念 ARM Coetex-M3内核共支持256个中断,当中16个内部中断,240个外部中断和可编程的256级中断优先级的设置.STM32眼下支持的中断共84个(16个内部+68个外部), ...

  3. stm32之中断配置

    一.stm32的中断和异常 Cortex拥有强大的异常响应系统,它能够打断当前代码执行流程事件分为异常和中断,它们用一个表管理起来,编号为0~15为内核异常,16以上的为外部中断,这个表就是中断向量表 ...

  4. STM32的中断系统

    STM32的中断系统 STM32具有十分强大的中断系统,将中断分为了两个类型:内核异常和外部中断.并将所有中断通过一个表编排起来,下面是stm32中断向量表的部分内容: 上图-3到6这个区域被标黑了, ...

  5. 转载:STM32之中断与事件---中断与事件的区别

    这张图是一条外部中断线或外部事件线的示意图,图中信号线上划有一条斜线,旁边标志19字样的注释,表示这样的线路共有19套.图中的蓝色虚线箭头,标出了外部中断信号的传输路径,首先外部信号从编号1的芯片管脚 ...

  6. STM32之中断与事件---中断与事件的区别

    STM32之中断与事件---中断与事件的区别  http://blog.csdn.net/flydream0/article/details/8208463 这张图是一条外部中断线或外部事件线的示意图 ...

  7. STM32外部中断初理解

    PA0,PB0...PG0--->EXTI0 PA1,PB1...PG1--->EXTI1 ....... PA15,PB15...PG15--->EXTI15 以上为GPIO和中断 ...

  8. STM32之中断

    在STM32(Cortex-M3)中没有显示的代码拷贝,只有启动代码进行了向量的初始化,一直以为是编译器在程序影像中自己完成了相关向量的拷贝,即,拷贝到固定的NVIC区,事实上并不是这样,cortex ...

  9. STM32串口中断实例二

    int main(void) { uint8_t a=;//LED高低电压控制 /* System Clocks Configuration */ RCC_Configuration(); //系统时 ...

随机推荐

  1. 常用SQL脚本操作

    SQL 脚本创建数据库.表及简单查询 --------------------------------------------------------------------------------- ...

  2. 错误Batch update returned unexpected row count from update [0]; actual row count: 0;

    参考:http://blog.csdn.net/ssyan/article/details/7471343 也是出现类似问题,在前台页面的隐藏域中判断id是否为null,而没有去判断是否为空字符串. ...

  3. AD Local Domain groups, Global groups and Universal groups

    http://ss64.com/nt/syntax-groups.html Rules that govern when a group can be added to another group ( ...

  4. php进程占用大量cpu优化

    使用TOP 命令发现php进程占用大量的cpu,达到100%,需要优化. 1 ll /proc/6264/fd 查看进程正在使用的资源 2 strace -p 6264 追踪进程正在做的事情 引用 h ...

  5. C#.NET中数组、ArrayList和List三者的区别

    数组在C#.NET中是最早出现的,在内存中是顺序连续存储的,所以它的索引速度非常快,赋值与修改元素也很简单:但是,也正因为数组是顺序连续存储的,在两个数据间插入数据是很不方便的,而且在声明数组的时候必 ...

  6. JAVA(IO流)文件复制

    package com.am; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOEx ...

  7. OpenGL中实现双缓冲技术

    在OpenGL中实现双缓冲技术的一种简单方法: 1.在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | G ...

  8. magento事件(event)的dispatchEvent(分发)和catchEvent(获取)

    当你需要扩展Magento的核心的功能时有两个选择: (1)重写(override)Magento的core classes (2)使用Magento的event-driven 机制 由于你只能重写一 ...

  9. Web测试的常用测试用例与知识

    1. Web测试中关于登录的测试 2. 搜索功能测试用例设计 3. 翻页功能测试用例 4. 输入框的测试 5. Web测试的常用的检查点 6. 用户及权限管理功能常规测试方法 7. Web测试之兼容性 ...

  10. Win2008R2+java+tomcat安装

    Win2008R2+java+tomcat安装 准备软件: jdk-7u25-windows-x64.exe apache-tomcat-7.0.42-windows-x64.zip 一.安装java ...