我有一种情况,我在单片机上有一个处理脉宽调制的类。极为简化的例子:
class MotorDriver
{
int pin_;
public:
MotorDriver(int pin);
void init();
void start();
void stop();
void changeDutyCycle(int dc);
};它具有初始化、启动、停止和改变pwm的功能。如果我将4个马达连接到微控制器,我将创建该类的4个实例,并将它们放入一个数组中,然后调用以下函数
motors[0].changeDutyCycle(50);
motors[1].changeDutyCycle(40);
....出现问题是因为没有在所述微控制器上配置定时器的通用方法。例如,一个电机必须使用Timer3,而另一个电机必须使用Timer4。不同的计时器有不同的位大小,寄存器,通道,引脚,.我希望能够为每个定时器编写自定义函数,但仍然能够将所有对象放入相同的数组中,并调用它们上的函数。
class MotorDriver
{
void changeDutyCycle(int dc) = 0;
};
class MotorDriver1 : public MotorDriver
{
void changeDutyCycle(int dc)
{
TIM3->CCR2 = dc;
}
};
class MotorDriver2 : public MotorDriver
{
void changeDutyCycle(int dc)
{
TIM4->CCR1 = dc;
}
};
MotorDriver1 md1();
MotorDriver2 md2();
MotorDriver* mds[] = { &md1, &md2 };
int main()
{
mds[0]->changeDutyCycle(10);
mds[1]->changeDutyCycle(20);
}我知道我可以用虚拟函数实现我想要的东西。这个函数很短,而且经常被调用,所以虚拟函数的价格很高。在这种情况下是否有办法避免这种情况或不同的设计模式?目标是拥有易于在外部使用的可重用代码。在数组中拥有我所需要的一切会使许多事情变得容易得多。
编辑:我知道这篇文章的Avoiding virtual functions,但答案与我需要的内容有关:
如果您所处的情况是每个调用周期都很重要,也就是说,您在函数调用中所做的工作非常少,并且在性能关键的应用程序中从内部循环调用它,那么您可能需要一种完全不同的方法。
发布于 2017-01-05 07:36:22
定时器之间的差别通常很小,特别是在配置实际输出宽度时--初始化可能不同,但是可以有虚拟函数。只需在类中存储对基本TIM寄存器和通道索引的引用,这似乎就是您要做的所有事情。如果您使用诸如“互补”通道之类的东西,那么您可以将它们存储为负面索引。
检查这段代码-这是为了一个非常相似的目的(驱动步进电机)在STM32F4上,但应该给你一个想法。
namespace
{
/// array with all CCR registers
const decltype(&TIM_TypeDef::CCR1) ccrs[]
{
&TIM_TypeDef::CCR1,
&TIM_TypeDef::CCR2,
&TIM_TypeDef::CCR3,
&TIM_TypeDef::CCR4
};
constexpr bool isAdvancedControlTimer(const TIM_TypeDef& tim)
{
return &tim == TIM1 || &tim == TIM8;
}
} // namespace
TIM_TypeDef& HardwareTimer::getTim() const
{
// "timBase_" is "uintptr_t timBase_;"
// initialized with TIM1_BASE, TIM2_BASE, ...
return *reinterpret_cast<TIM_TypeDef*>(timBase_);
}
int HardwareTimer::start(const int8_t channel, const uint16_t compare) const
{
if (channel == 0)
return EINVAL;
const auto complementaryChannel = channel < 0;
const auto channelShift = (complementaryChannel == true ? -channel : channel) - 1;
if (channelShift >= 4)
return EINVAL;
auto& tim = getTim();
const auto advancedControlTimer = isAdvancedControlTimer(tim);
if (complementaryChannel == true && advancedControlTimer == false)
return EINVAL;
tim.*ccrs[channelShift] = compare;
if (advancedControlTimer == true)
tim.BDTR |= TIM_BDTR_MOE;
tim.CR1 |= TIM_CR1_CEN | TIM_CR1_URS;
return 0;
}不要太担心性能-在现实中,微控制器是非常快的,仅仅使用适当的架构(如RTOS或事件驱动)将使他们在80%-90%的时间里感到无聊!
如果您实现了简单的代码,它实际上会导致您的应用程序太慢,那么--假设您无法改进算法或总体架构--只需预先计算构造函数中start()中的大多数值,并可能删除错误检查(或者将其移到其他地方,从循环中移出)。
或者仅仅使用虚拟函数,间接调用的影响通常可以忽略不计。
发布于 2017-01-05 21:03:07
您可以使用单个定时器中断所有的,这样你就不会被限制为计时器的数量。与其改变定时器的占空比设置,你只需改变变量,也就是说,每一个X都会勾选/设置/重置与此马达对应的引脚。在计时器例程中,您只需创建简单的for循环,迭代等于连接的电机数,并检查每一个,即模块操作,如果现在是更换引脚的时间。在这种情况下,使用定时器中断的软件PWM是很好的选择。
https://stackoverflow.com/questions/41476286
复制相似问题