如何从中断服务程序访问class的虚方法?
How to access class's virtual method from interrupt service routine?
我正在尝试在 C++ 中使用 Timer0 为 Atmega328P 实现 PWM。确实,我已经做到了这一点。但是,我还有另一个相关问题。
我有一个 PWM 抽象基础 class,它为 PWM 实现提供了一个接口。
// mcal_pwm_base.h
#ifndef MCAL_PWM_BASE_H_
#define MCAL_PWM_BASE_H_
namespace mcal
{
namespace pwm
{
class pwm_base
{
public:
~pwm_base() = default;
virtual bool init() noexcept = 0;
virtual void set_duty(const uint16_t duty_cycle) = 0;
virtual void pwm_ISR() noexcept = 0;
uint16_t get_duty() const noexcept { return pwm_duty_cycle; }
protected:
uint16_t pwm_duty_cycle;
pwm_base() : pwm_duty_cycle(0U) { }
pwm_base(const pwm_base&) = delete;
const pwm_base& operator=(const pwm_base&) = delete;
};
}
}
#endif /* MCAL_PWM_BASE_H_ */
我想用定时器(8 位定时器)实现 PWM。所以,我创建了另一个 class 派生自 pwm_base class.
// mcal_pwm_8.h
#ifndef MCAL_PWM_8_H_
#define MCAL_PWM_8_H_
#include "mcal_pwm_base.h"
#include "mcal_reg_access_dynamic.h"
#include <avr/interrupt.h>
namespace mcal
{
namespace pwm
{
template<const uint8_t prescalar_val = UINT8_C(0U)>
class pwm_8 : public mcal::pwm::pwm_base
{
public:
~pwm_8() = default;
virtual bool init() noexcept
{
// set pwm related things
return true;
}
virtual void set_duty(const uint16_t duty_cycle)
{
pwm_duty_cycle = duty_cycle;
}
virtual void pwm_ISR() noexcept
{
uint8_t compare_value = (pwm_duty_cycle / 100) * 255;
mcal::reg::reg_access_dynamic<uint8_t, uint8_t>::reg_set(mcal::reg::ocr0a, compare_value);
}
};
}
}
ISR(TIMER0_OVF_vect)
{
// pwm_ISR();
}
#endif /* MCAL_PWM_8_H_ */
如你所见,我想在ISR(中断服务例程)中调用pwm_ISR()成员函数。但是,我不知道该怎么做。书上写的是pwm_8class的make ISR friend函数。即使我这样做了,我将如何在 ISR 中到达 pwm_duty_cycle 的私有成员变量?在这一点上,我需要你的帮助。
最后,这是我的主要功能。
// main.h
#define F_CPU 16000000ULL
#include <avr/io.h>
#include <util/delay.h>
#include "mcal_reg.h"
#include "mcal_reg_access_static.h"
#include "mcal_port.h"
#include "mcal_led_port.h"
#include "mcal_pwm_8.h"
int main(void)
{
mcal::pwm::pwm_8<UINT8_C(5U)> myPwm;
myPwm.init();
myPwm.set_duty(250); // This will be applied when ISR called
for(;;)
{
}
return 0;
}
非常感谢。
您可以创建应注册要执行的实际操作的全局回调对象(对 ISR 可见)。
一般来说,可调用对象需要对 ISR 可见,即它需要存在于 ISR 的范围内。
noexcept
表明您使用的是 C++11 或更高版本。如果没有,您将需要回退以提升或进行更多输入...
volatile std::function<void()> pwmCallback; //even better: make it static for the PWM class
//can also by a function object...depends what you need.
ISR(TIMER0_OVF_vect)
{
if (pwmCallback) {
pwmCallback();
}
}
int main()
{
mcal::pwm::pwm_8<UINT8_C(5U)> myPwm;
pwmCallback = [&myPwm](){myPwm.pwm_ISR();}
myPwm.init();
myPwm.set_duty(250); // This will be applied when ISR called
for(;;)
{
}
return 0;
}
此外,请确保回调不会超过 pwm 对象(此处未介绍)。
另一种选择是使您的 pwm 成为全局对象。
似乎无法向 ISR
例程提供用户数据(如 void*
),因此您可以将 myPwm
设为全局变量:
示例:
头文件:
extern mcal::pwm::pwm_8<UINT8_C(5U)> myPwm;
ISR(TIMER0_OVF_vect)
{
myPwm.pwm_ISR();
}
...并且在 .cpp
文件中:
mcal::pwm::pwm_8<UINT8_C(5U)> myPwm;
您也可以在函数中隐藏全局变量以获得 lazy initialization.
头文件:
mcal::pwm::pwm_8<UINT8_C(5U)>& myPwm(); // now a function
ISR(TIMER0_OVF_vect)
{
myPwm().pwm_ISR(); // calling function to get the instance
}
...并且在 .cpp
文件中:
mcal::pwm::pwm_8<UINT8_C(5U)>& myPwm() {
static mcal::pwm::pwm_8<UINT8_C(5U)> instance;
// that returns a reference to the one instance you'll use:
return instance;
}
我正在尝试在 C++ 中使用 Timer0 为 Atmega328P 实现 PWM。确实,我已经做到了这一点。但是,我还有另一个相关问题。
我有一个 PWM 抽象基础 class,它为 PWM 实现提供了一个接口。
// mcal_pwm_base.h
#ifndef MCAL_PWM_BASE_H_
#define MCAL_PWM_BASE_H_
namespace mcal
{
namespace pwm
{
class pwm_base
{
public:
~pwm_base() = default;
virtual bool init() noexcept = 0;
virtual void set_duty(const uint16_t duty_cycle) = 0;
virtual void pwm_ISR() noexcept = 0;
uint16_t get_duty() const noexcept { return pwm_duty_cycle; }
protected:
uint16_t pwm_duty_cycle;
pwm_base() : pwm_duty_cycle(0U) { }
pwm_base(const pwm_base&) = delete;
const pwm_base& operator=(const pwm_base&) = delete;
};
}
}
#endif /* MCAL_PWM_BASE_H_ */
我想用定时器(8 位定时器)实现 PWM。所以,我创建了另一个 class 派生自 pwm_base class.
// mcal_pwm_8.h
#ifndef MCAL_PWM_8_H_
#define MCAL_PWM_8_H_
#include "mcal_pwm_base.h"
#include "mcal_reg_access_dynamic.h"
#include <avr/interrupt.h>
namespace mcal
{
namespace pwm
{
template<const uint8_t prescalar_val = UINT8_C(0U)>
class pwm_8 : public mcal::pwm::pwm_base
{
public:
~pwm_8() = default;
virtual bool init() noexcept
{
// set pwm related things
return true;
}
virtual void set_duty(const uint16_t duty_cycle)
{
pwm_duty_cycle = duty_cycle;
}
virtual void pwm_ISR() noexcept
{
uint8_t compare_value = (pwm_duty_cycle / 100) * 255;
mcal::reg::reg_access_dynamic<uint8_t, uint8_t>::reg_set(mcal::reg::ocr0a, compare_value);
}
};
}
}
ISR(TIMER0_OVF_vect)
{
// pwm_ISR();
}
#endif /* MCAL_PWM_8_H_ */
如你所见,我想在ISR(中断服务例程)中调用pwm_ISR()成员函数。但是,我不知道该怎么做。书上写的是pwm_8class的make ISR friend函数。即使我这样做了,我将如何在 ISR 中到达 pwm_duty_cycle 的私有成员变量?在这一点上,我需要你的帮助。
最后,这是我的主要功能。
// main.h
#define F_CPU 16000000ULL
#include <avr/io.h>
#include <util/delay.h>
#include "mcal_reg.h"
#include "mcal_reg_access_static.h"
#include "mcal_port.h"
#include "mcal_led_port.h"
#include "mcal_pwm_8.h"
int main(void)
{
mcal::pwm::pwm_8<UINT8_C(5U)> myPwm;
myPwm.init();
myPwm.set_duty(250); // This will be applied when ISR called
for(;;)
{
}
return 0;
}
非常感谢。
您可以创建应注册要执行的实际操作的全局回调对象(对 ISR 可见)。 一般来说,可调用对象需要对 ISR 可见,即它需要存在于 ISR 的范围内。
noexcept
表明您使用的是 C++11 或更高版本。如果没有,您将需要回退以提升或进行更多输入...
volatile std::function<void()> pwmCallback; //even better: make it static for the PWM class
//can also by a function object...depends what you need.
ISR(TIMER0_OVF_vect)
{
if (pwmCallback) {
pwmCallback();
}
}
int main()
{
mcal::pwm::pwm_8<UINT8_C(5U)> myPwm;
pwmCallback = [&myPwm](){myPwm.pwm_ISR();}
myPwm.init();
myPwm.set_duty(250); // This will be applied when ISR called
for(;;)
{
}
return 0;
}
此外,请确保回调不会超过 pwm 对象(此处未介绍)。 另一种选择是使您的 pwm 成为全局对象。
似乎无法向 ISR
例程提供用户数据(如 void*
),因此您可以将 myPwm
设为全局变量:
示例:
头文件:
extern mcal::pwm::pwm_8<UINT8_C(5U)> myPwm;
ISR(TIMER0_OVF_vect)
{
myPwm.pwm_ISR();
}
...并且在 .cpp
文件中:
mcal::pwm::pwm_8<UINT8_C(5U)> myPwm;
您也可以在函数中隐藏全局变量以获得 lazy initialization.
头文件:
mcal::pwm::pwm_8<UINT8_C(5U)>& myPwm(); // now a function
ISR(TIMER0_OVF_vect)
{
myPwm().pwm_ISR(); // calling function to get the instance
}
...并且在 .cpp
文件中:
mcal::pwm::pwm_8<UINT8_C(5U)>& myPwm() {
static mcal::pwm::pwm_8<UINT8_C(5U)> instance;
// that returns a reference to the one instance you'll use:
return instance;
}