Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在中断处理程序中访问类成员_C++_Embedded_Interrupt Handling - Fatal编程技术网

C++ 在中断处理程序中访问类成员

C++ 在中断处理程序中访问类成员,c++,embedded,interrupt-handling,C++,Embedded,Interrupt Handling,我有一个UART类,它有Fifo类的实例(目前只是一个粗略的想法),但是如果我这样做,并且在源文件中有一个中断处理程序,我就没有办法访问Fifo实例或任何其他UART成员 //uart.hpp 类Uart{ 先进先出; // ... }; //uart.cpp 无效UART\U IRQ\U处理程序(无效) { //无法访问Uart类 } 在C中,我在头中有一个 UART< /Cux.Stutt,也许在源文件中定义 FIFO < /Cuff>实例,作为源代码文件中的代码>静态< /代码>,在IR

我有一个UART类,它有
Fifo
类的实例(目前只是一个粗略的想法),但是如果我这样做,并且在源文件中有一个中断处理程序,我就没有办法访问
Fifo
实例或任何其他
UART
成员

//uart.hpp
类Uart{
先进先出;
// ...
};
//uart.cpp
无效UART\U IRQ\U处理程序(无效)
{
//无法访问Uart类
}
<>在C中,我在头中有一个<代码> UART< /Cux.Stutt,也许在源文件中定义<代码> FIFO < /Cuff>实例,作为源代码文件中的代码>静态< /代码>,在IRQ处理程序内部访问它,但不十分确信C++中的这一点,同时保持封装。
//uart.c
静态Fifo fifoRx;
无效UART\U IRQ\U处理程序(无效)
{
//可访问fifoRx
}
如果您想访问
Uart
类本身,一种方法可能是将
static
指针设置为
uartini(Uart*pUart)
函数中的实例

//uart.c
静态Uart*psUart;
无效UART\U IRQ\U处理程序(无效){
//通过psUart访问UART
}
无效UartInit(Uart*pUart){
psUart=pUart;
// ...
}

<>但是,在保持封装完好的情况下,你将怎样做类似于现代C++的事情?

< p>你可以尝试以下机制之一:
  • 引入公共静态成员Fifo fifoRx
  • //uart.h
    类Uart{
    公众:
    静态Fifo fifoRx;
    // ...
    };
    //初始化Uart类的静态成员
    Fifo Uart::fifoRx={0};
    //uart.cpp
    无效UART\U IRQ\U处理程序(无效)
    {
    //直接访问静态成员
    Uart::fifoRx。
    }
    
  • 备选案文2。引入一个私有静态成员,并使用静态getter/setter成员函数访问/修改fifoRx
  • 类Uart{ 静态Fifo fifoRx; // ... 公众: //在此处添加getter、setter静态函数 //例如:静态get\u fifo\u front(), //例如:静态添加元素到fifo(数据) //例如:静态从fifo前端移除元素 }; //uart.cpp 无效UART\U IRQ\U处理程序(无效) { //使用静态成员函数进行访问 //Uart::获取先进先出前端() } //初始化Uart类的静态成员 Fifo Uart::fifoRx={0};
    我也遇到过同样的问题,我用了一种有点肮脏和复杂的设计来解决它。我的解决方案依赖于某些硬件支持,因此它可能不适用于您的平台。我的解决方案是在STM32F1和STM32F4 uCs上开发的,它们分别使用Cortex M3和M4内核。它可能也适用于M0。此外,我的解决方案使用了一些C++17特性,但只需稍加修改即可将其转换为C++11及更高版本

    很明显,一些与硬件相关的类,如您提到的UART类,与中断处理程序紧密耦合。uC可以有这些类的多个实例。这还要求您需要多个ISR实例。因为它们不能有参数,如果必须确定中断源,那么将多个中断向量映射到同一个函数可能会导致问题

    ISR的另一个问题是,它们的名称是由供应商提供的向量表代码预先确定的,有时是用汇编编写的。由于每个向量都有一个硬编码的名称,因此如果没有一些宏暗术,就不可能编写通用代码

    首先,需要解决ISR命名问题。这是依赖于硬件支持的部分。Cortex M3和M4内核使您能够指向位于不同地址上的不同向量表。如果将向量表从闪存复制到RAM,则可以在运行时将带有
    void ISR\u func(void)
    签名的任何函数注册为ISR。M0内核具有有限的向量表重定位功能,但它们仍然提供了一种将其移动到RAM开始的方法

    我认为将ISR向量表从闪存移动到RAM的细节与这个问题的主题有点脱节,但让我们假设以下函数可用,它阻止将函数作为给定向量的ISR:

    void registerISR(IRQn_Type IRQn, void (*isr)());
    
    我们可以假设已知类实例的最大数量,因为UART硬件模块的数量已知。我们需要以下组件:

    Uart指针的静态成员数组,每个指针指向Uart的一个实例

    static constexpr unsigned MaxUarts {3};
    inline static Uart* uartList[MaxUarts] {nullptr};
    
    ISR的功能模板。这些将是静态成员函数,但最终每个实例将有自己的专用ISR:

    template <unsigned uartIndex>
    void Uart::uartIsr()
    {
        auto instance = uartList[uartIndex];
        instance->doSometing();
    }
    
    因此Uart类头应该如下所示:

    class Uart {
    public:
        Uart(/* Arguments */);
    private:
        inline static uint8_t instanceNoAssigner {0};
        
        void doSomething(); // Just a place holder
        IRQn_Type getIrqNo(); // Implementation depends on HW
    
        template <unsigned uartIndex>
            static void uartIsr();
    
        static constexpr unsigned MaxUarts {3};
        inline static Uart* uartList[MaxUarts] {nullptr};
    
        using isrPointer = void (*)();
        inline static const isrPointer uartHandlers[MaxUarts] {
            &uartIsr<0>,
            &uartIsr<1>,
            &uartIsr<2>
        }
    }
    
    template <unsigned uartIndex>
    Uart::uartIsr()
    {
        auto instance = uartList[uartIndex];
        instance->doSometing();
    }
    
    我还在RAM的开头创建了一个新的部分。对于Cortex M3和M4,向量表可以是任意位置(有一些对齐要求)。但对于Cortex M0,RAM的起始位置是唯一的替代位置,因为它们缺少VTOR寄存器

    /* Relocated ISR Vector Table */
    .isr_vector_ram 0x20000000 :
    {
      . = ALIGN(4);
      KEEP(*(.isr_vector_ram))
      . = ALIGN(4);
    } >RAM
    
    最后,这是我用于重新定位(初始化时调用一次)和注册的两个函数:

    extern uint32_t _svector;
    static constexpr size_t VectorTableSize {106}; // words
    uint32_t __attribute__((section(".isr_vector_ram"))) vectorTable[VectorTableSize];
    
    void relocateVectorTable()
    {
        // Copy IRQ vector table to RAM @ 0x20'000'000
        uint32_t *ptr = &_svector;
        for (size_t i = 0; i < VectorTableSize; ++i) {
            vectorTable[i] = ptr[i];
        }
    
        // Switch to new table
        __disable_irq();
        SCB->VTOR = 0x20'000'000ULL;
        __DSB();
        __enable_irq();
    }
    
    void registerISR(IRQn_Type IRQn, void (*isr)())
    {
        uint32_t absAdr = reinterpret_cast<uint32_t>(isr);
        __disable_irq();
        vectorTable[IRQn + 16] = absAdr;
        __DSB();
        __enable_irq();
    }
    
    extern uint32\u t\u svector;
    静态constexpr size\u t VectorTableSize{106};//话
    uint32可向量化[向量化大小];
    void relocateVectorTable()
    {
    //将IRQ矢量表复制到内存@0x20'000'000
    uint32_t*ptr=&u svector;
    对于(大小i=0;iVTOR=0x20'000'000ULL;
    __DSB();
    __启用_irq();
    }
    无效登记簿isr(IRQn类型IRQn,无效(*isr)()
    {
    uint32\u t absAdr=重新解释铸件(isr);
    __禁用_irq();
    可矢量化[IRQn+16]=absAdr;
    __DSB();
    __启用_irq();
    }
    

    <> P>不知何故,GCC足够聪明,自动生成最低位的原始函数地址1,以指示拇指指令。

    < P>您的C版本和C++版本不重新使用。
    Uart::Uart(/* Arguments, possibly the instance no */) {
        instanceNo = instanceNoAssigner++; // One can use a static counter
        uartList[instanceNo] = this;
        registerISR(this->getIrqNo(), uartHandlers[instanceNo])
    }
    
    class Uart {
    public:
        Uart(/* Arguments */);
    private:
        inline static uint8_t instanceNoAssigner {0};
        
        void doSomething(); // Just a place holder
        IRQn_Type getIrqNo(); // Implementation depends on HW
    
        template <unsigned uartIndex>
            static void uartIsr();
    
        static constexpr unsigned MaxUarts {3};
        inline static Uart* uartList[MaxUarts] {nullptr};
    
        using isrPointer = void (*)();
        inline static const isrPointer uartHandlers[MaxUarts] {
            &uartIsr<0>,
            &uartIsr<1>,
            &uartIsr<2>
        }
    }
    
    template <unsigned uartIndex>
    Uart::uartIsr()
    {
        auto instance = uartList[uartIndex];
        instance->doSometing();
    }
    
    /* The startup code into "ROM" Rom type memory */
    .isr_vector :
    {
      . = ALIGN(4);
      _svector = .;
      KEEP(*(.isr_vector)) /* Startup code */
      . = ALIGN(4);
      _evector = .;
    } >ROM
    
    /* Relocated ISR Vector Table */
    .isr_vector_ram 0x20000000 :
    {
      . = ALIGN(4);
      KEEP(*(.isr_vector_ram))
      . = ALIGN(4);
    } >RAM
    
    extern uint32_t _svector;
    static constexpr size_t VectorTableSize {106}; // words
    uint32_t __attribute__((section(".isr_vector_ram"))) vectorTable[VectorTableSize];
    
    void relocateVectorTable()
    {
        // Copy IRQ vector table to RAM @ 0x20'000'000
        uint32_t *ptr = &_svector;
        for (size_t i = 0; i < VectorTableSize; ++i) {
            vectorTable[i] = ptr[i];
        }
    
        // Switch to new table
        __disable_irq();
        SCB->VTOR = 0x20'000'000ULL;
        __DSB();
        __enable_irq();
    }
    
    void registerISR(IRQn_Type IRQn, void (*isr)())
    {
        uint32_t absAdr = reinterpret_cast<uint32_t>(isr);
        __disable_irq();
        vectorTable[IRQn + 16] = absAdr;
        __DSB();
        __enable_irq();
    }
    
    static Uart uart1 ;
    
    void UART1_IRQ_Handler(void) 
    {
       ...
       uart1.fifoRx.put( UART1_DR ) ;
       ...
    }  
    
    class Uart 
    {
        public:
          Uart( UART uart ) : m_uart(uart) { ... } ;
          void isr()
          { 
            ...
              m_fifoRx.put( m_uart.DR ) ;
            ...
          }
    
        private:
          Fifo m_fifoRx;
          UART m_uart ;
    };
    
    static Uart uart1( UART1 ) ;
    static Uart uart2( UART2 ) ;
    void UART1_IRQ_Handler(void) 
    {
        uart1.isr() ;
    }
    
    void UART2_IRQ_Handler(void) 
    {
        uart2.isr() ;
    }
    
    // uart.h
    class Uart {
          Fifo fifoRx;
          friend void UART_IRQ_Handler(void) 
          // ...
    };
    
    // uart.cpp
    void UART_IRQ_Handler(void) 
    {
       // have no way to access the Uart class
    }