我的目标是创建两个类LED
和PWM
,目的是每个LED
对象都创建一个本地PWM
对象来控制亮度。这样的想法是,用户可以创建LED
对象,而不必设置PWM
对象,同时保留为电动机速度控制等单独创建PWM
对象的选项。< / p>
当我实例化PWM
对象内的LED
对象时,就会出现问题。代码编译没有错误;但是,结果是PWM
对象的构造函数完成后,LED
对象就消失了。
(当我触发相应的任务时,与PWM模块相关的事件均未发生。具体来说,pwm.stop
和pwm.start
函数使用空的while
循环来等待特定的事件这些事件会在任务完成时发出信号,并且在循环完成事件发生时,循环快捷方式会自动启动任务。触发适当的任务时,这些事件都不会发生。数据表警告:“请注意,必须启用外设在使用任务和事件之前。”这使我相信pwm.enable()
尚未运行。)
ohlemacher谈到constructors inside constructors:
“ ...它只是不执行您想要的操作。内部构造函数将构造一个临时本地对象,一旦外部构造函数返回,该本地对象将被删除。”
是否有更好的方法在创建PWM
对象时自动生成LED
对象?是否可以在不使PWM
对象成为LED
对象的成员的情况下做我想做的事情?
pwm.h
#ifndef rav_nrf52840_pwm_h
#define rav_nrf52840_pwm_h
#include "rav_nrf52840_baseConst.h"
typedef enum {DIV1,DIV2,DIV4,DIV8,DIV16,DIV32,DIV64,DIV128} prescaler;
typedef enum {PWM0,PWM1,PWM2,PWM3} pwmModule;
typedef enum {COMMON,GROUPED,INDIVIDUAL,WAVEFORM} decoderLoad;
class PWM {
private:
unsigned int base_address;
void enable_pwm (bool en);
bool start_pwm (void);
void stop_pwm (void);
public:
PWM ();
PWM (pwmModule module, bool looping, bool mode, int count, prescaler scale);
void init (decoderLoad load, bool decoder_mode, int loop_count);
void sequence (int seq_number, unsigned int *pointer, int count, int refresh, int enddelay);
void pinSelect (int channel, int port, int pin, bool disconnect);
void enable (void);
void disable (void);
bool start (void);
void stop (void);
};
#endif
pwm.cpp
#include "rav_nrf52840_pwm.h"
#include <cstdint>
PWM::PWM (){
#ifndef rav_nrf52840_pwm_pwm3
#define rav_nrf52840_pwm_pwm3
pwmModule module = PWM3;
#else
#ifndef rav_nrf52840_pwm_pwm2
#define rav_nrf52840_pwm_pwm2
pwmModule module = PWM2;
#else
#ifndef rav_nrf52840_pwm_pwm1
#define rav_nrf52840_pwm_pwm1
pwmModule module = PWM1;
#else
#ifndef rav_nrf52840_pwm_pwm0
#define rav_nrf52840_pwm_pwm0
pwmModule module = PWM0;
#endif
#endif
#endif
#endif
bool looping = true;
bool mode = 0;
int count = 0x7FFF;
prescaler scale = DIV4;
switch (module){
default:
;
break;
case PWM0:
base_address = BASE_ADDRESS_PWM0;
break;
case PWM1:
base_address = BASE_ADDRESS_PWM1;
break;
case PWM2:
base_address = BASE_ADDRESS_PWM2;
break;
case PWM3:
base_address = BASE_ADDRESS_PWM3;
break;
}
unsigned int * pwm_mode_reg = (unsigned int *)(base_address + REGISTER_OFFSET_PWM_MODE);
unsigned int * countertop_reg = (unsigned int *)(base_address + REGISTER_OFFSET_COUNTERTOP);
unsigned int * prescaler_reg = (unsigned int *)(base_address + REGISTER_OFFSET_PRESCALER);
unsigned int * shortcut_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SHORTS);
*pwm_mode_reg = mode;
*countertop_reg = count;
*prescaler_reg = scale;
if (looping){
*shortcut_reg = 0x04; // Enable looping
}
}
PWM::PWM (pwmModule module, bool looping, bool mode, int count, prescaler scale){
switch (module){
default:
;
break;
case PWM0:
base_address = BASE_ADDRESS_PWM0;
break;
case PWM1:
base_address = BASE_ADDRESS_PWM1;
break;
case PWM2:
base_address = BASE_ADDRESS_PWM2;
break;
case PWM3:
base_address = BASE_ADDRESS_PWM3;
break;
}
unsigned int * pwm_mode_reg = (unsigned int *)(base_address + REGISTER_OFFSET_PWM_MODE);
unsigned int * countertop_reg = (unsigned int *)(base_address + REGISTER_OFFSET_COUNTERTOP);
unsigned int * prescaler_reg = (unsigned int *)(base_address + REGISTER_OFFSET_PRESCALER);
unsigned int * shortcut_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SHORTS);
*pwm_mode_reg = mode;
*countertop_reg = count;
*prescaler_reg = scale;
if (looping){
*shortcut_reg = 0x04; // Enable looping
}
}
// PRIVATE
void PWM::enable_pwm (bool en){
unsigned int * pwm_enable_reg = (unsigned int *)(base_address + REGISTER_OFFSET_ENABLE);
*pwm_enable_reg = en;
}
bool PWM::start_pwm (void){
unsigned int * start_seq0_task = (unsigned int *)(base_address + TASK_OFFSET_SEQSTART_0);
volatile unsigned int * seq0_started_event = (unsigned int *)(base_address + EVENT_OFFSET_SEQSTARTED_0);
*start_seq0_task = true;
while(!*seq0_started_event){}
*seq0_started_event = false;
return 1;
}
void PWM::stop_pwm (void){
unsigned int * pwm_stop_task = (unsigned int *)(base_address + TASK_OFFSET_PWM_STOP);
volatile unsigned int * pwm_stopped_event = (unsigned int *)(base_address + EVENT_OFFSET_STOPPED);
*pwm_stop_task = true;
while(!*pwm_stopped_event){}
*pwm_stopped_event = false;
}
// PUBLIC
void PWM::init (decoderLoad load, bool decoder_mode, int loop_count){
unsigned int * decoder_reg = (unsigned int *)(base_address + REGISTER_OFFSET_DECODER);
unsigned int * loop_reg = (unsigned int *)(base_address + REGISTER_OFFSET_LOOP);
*decoder_reg = load;
if (decoder_mode){
*decoder_reg |= 0x100;
}
*loop_reg = loop_count;
}
void PWM::sequence (int seq_number, unsigned int *pointer, int count, int refresh, int enddelay){
unsigned int * seq_pointer_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SEQ_0_PTR + (MODIFIER_SEQ * seq_number));
unsigned int * seq_count_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SEQ_0_CNT + (MODIFIER_SEQ * seq_number));
unsigned int * seq_refresh_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SEQ_0_REFRESH + (MODIFIER_SEQ * seq_number));
unsigned int * seq_enddelay_reg = (unsigned int *)(base_address + REGISTER_OFFSET_SEQ_0_ENDDELAY + (MODIFIER_SEQ * seq_number));
*seq_pointer_reg = reinterpret_cast<std::uintptr_t>(pointer);
*seq_count_reg = count;
*seq_refresh_reg = refresh;
*seq_enddelay_reg = enddelay;
}
void PWM::pinSelect (int channel, int port, int pin, bool disconnect){
unsigned int * pin_select_reg = (unsigned int *)(base_address + REGISTER_OFFSET_PSEL_OUT_0 + (MODIFIER_PSEL_OUT * channel));
*pin_select_reg = ((disconnect << 31) | (port << 5) | pin);
}
void PWM::enable (void){
enable_pwm(true);
}
void PWM::disable (void){
enable_pwm(false);
}
bool PWM::start (void){
bool pwm_seq_started = start_pwm();
return pwm_seq_started;
}
void PWM::stop (void){
stop_pwm();
}
led.h
#ifndef rav_nrf52840_led_h
#define rav_nrf52840_led_h
#include "rav_nrf52840_macros.h"
#include "rav_nrf52840_pwm.h"
typedef enum {RED = 1,GREEN = 2,YELLOW = 3,BLUE = 4,MAGENTA = 5,CYAN = 6,WHITE = 7} ledState;
class LED {
private:
PWM pwm;
bool pwm_sequence_started_flag;
bool LED_activeLow_flag;
bool LED_RGB_flag;
int LED_portNumber[3];
int LED_pinNumber[3];
int LED_color;
int LED_intensity;
unsigned int sequence_0[4];
public:
LED (bool activeLow,int portNumber[3],int pinNumber[3]); // Use this format for RGB LEDs. Port and pin numbers must be listed in order: red, green, then blue.
LED (bool activeLow,int portNumber,int pinNumber); // Use this format for single color LEDs
void on (ledState color, int brightness); // Do not use this format with single color LEDs. Valid options for brightness are 0 - 100(%)
void off (void);
};
#endif
led.cpp
#include "rav_nrf52840_led.h"
LED::LED (bool activeLow,int portNumber[3],int pinNumber[3]) : pwm(){
LED_RGB_flag = true;
LED_activeLow_flag = activeLow;
LED_portNumber[0] = portNumber[0];
LED_portNumber[1] = portNumber[1];
LED_portNumber[2] = portNumber[2];
LED_pinNumber[0] = pinNumber[0];
LED_pinNumber[1] = pinNumber[1];
LED_pinNumber[2] = pinNumber[2];
pwm.init(INDIVIDUAL,0,0xFFFF);
pwm.sequence(0,sequence_0,4,0,0);
pwm.pinSelect(0,LED_portNumber[0],LED_pinNumber[0],false);
pwm.pinSelect(1,LED_portNumber[1],LED_pinNumber[1],false);
pwm.pinSelect(2,LED_portNumber[2],LED_pinNumber[2],false);
pwm.enable();
}
LED::LED (bool activeLow,int portNumber,int pinNumber) : pwm(){
LED_RGB_flag = false;
LED_activeLow_flag = activeLow;
LED_portNumber[0] = portNumber;
LED_pinNumber[0] = pinNumber;
pwm.init(INDIVIDUAL,0,0xFFFF);
pwm.sequence(0,sequence_0,4,0,0);
pwm.pinSelect(0,LED_portNumber[0],LED_pinNumber[0],false);
pwm.enable();
}
// PRIVATE
int LED_color = RED; // Default value for LED_color is RED.
int LED_intensity = 0xFFFF; // Default value for LED_intensity is 0xFFFF.
// PUBLIC
void LED::on (ledState color, int brightness){
LED_intensity = brightness;//(scale(brightness,0,100,0x8000,0xFFFF));
if (pwm_sequence_started_flag){
pwm.stop();
pwm_sequence_started_flag = false;
}
if (LED_RGB_flag){
LED_color = color;
if (brightness >= 0xFFFF){//100){
LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 0:1) : writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 1:0);
LED_activeLow_flag ? writePin(LED_portNumber[1],LED_pinNumber[1],readBit(LED_color,1) ? 0:1) : writePin(LED_portNumber[1],LED_pinNumber[1],readBit(LED_color,1) ? 1:0);
LED_activeLow_flag ? writePin(LED_portNumber[2],LED_pinNumber[2],readBit(LED_color,2) ? 0:1) : writePin(LED_portNumber[2],LED_pinNumber[2],readBit(LED_color,2) ? 1:0);
}
else{
sequence_0[0] = LED_intensity;
sequence_0[1] = LED_intensity;
sequence_0[2] = LED_intensity;
pwm_sequence_started_flag = pwm.start();
}
}
else{
if (brightness >= 100){
LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 0:1) : writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 1:0);
}
}
}
void LED::off (void){
if (LED_RGB_flag){
LED_activeLow_flag ? writePin(LED_portNumber[1],LED_pinNumber[1],1) : writePin(LED_portNumber[1],LED_pinNumber[1],0);
LED_activeLow_flag ? writePin(LED_portNumber[2],LED_pinNumber[2],1) : writePin(LED_portNumber[2],LED_pinNumber[2],0);
}
LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],1) : writePin(LED_portNumber[0],LED_pinNumber[0],0);
}
main.cpp
#include "rav_nrf52840_base.h"
#include "rav_nrf52840_led.h"
int main(void){ // TX
setupClock (HF_64MHz_XTAL, START);
setupClock (LF_32_768kHz_XTAL, START);
setupPin (0, 3,INPUT);
pullPin (0, 3,PULLUP);
setupPin (0,18,INPUT); // External (? Ohm) pullup resistor.
setupPin (0,22,OUTPUT);
writePin (0,22,HIGH);
setupPin (0,23,OUTPUT);
writePin (0,23,HIGH);
setupPin (0,24,OUTPUT);
writePin (0,24,HIGH);
int my_led_ports[3] = {0,0,0};
int my_led_pins[3] = {23,22,24}; // RED, GREEN, BLUE
LED led(true,my_led_ports,my_led_pins);
for(;;){
if (readPin(0,3)){
;
}
else{
led.on(RED,0xFFFF);
}
if (readPin(0,18)){
;
}
else{
led.on(RED,0xF000);
}
}
return -1;
}
为进行比较,下面是可以使用的旧版本代码(没有PWM
的{{1}}成员)。文件LED
和pwm.h
与新版本中的文件相同。
led.h -旧(工作)版本
pwm.cpp
led.cpp -旧(工作)版本
#ifndef rav_nrf52840_led_h
#define rav_nrf52840_led_h
#include "rav_nrf52840_macros.h"
typedef enum {RED = 1,GREEN = 2,YELLOW = 3,BLUE = 4,MAGENTA = 5,CYAN = 6,WHITE = 7} ledState;
class LED {
private:
bool LED_activeLow_flag;
bool LED_RGB_flag;
int LED_portNumber[3];
int LED_pinNumber[3];
int LED_color;
int LED_intensity;
public:
LED (bool activeLow,int portNumber[3],int pinNumber[3]); // Use this format for RGB LEDs. Port and pin numbers must be listed in order: red, green, then blue.
LED (bool activeLow,int portNumber,int pinNumber); // Use this format for single color LEDs
void on (ledState color, int brightness); // Do not use this format with single color LEDs. Valid options for brightness are 0 - 100(%)
void off (void);
};
#endif
main.cpp -旧(工作)版本
#include "rav_nrf52840_led.h"
LED::LED (bool activeLow,int portNumber[3],int pinNumber[3]){
LED_RGB_flag = true;
LED_activeLow_flag = activeLow;
LED_portNumber[0] = portNumber[0];
LED_portNumber[1] = portNumber[1];
LED_portNumber[2] = portNumber[2];
LED_pinNumber[0] = pinNumber[0];
LED_pinNumber[1] = pinNumber[1];
LED_pinNumber[2] = pinNumber[2];
}
LED::LED (bool activeLow,int portNumber,int pinNumber){
LED_RGB_flag = false;
LED_activeLow_flag = activeLow;
LED_portNumber[0] = portNumber;
LED_pinNumber[0] = pinNumber;
}
// PRIVATE
bool LED_activeLow_flag;
bool LED_RGB_flag;
int LED_portNumber[3];
int LED_pinNumber[3];
int LED_color = RED; // Default value is RED.
int LED_intensity = 0xFFFF; // Default value is 0xFFFF.
// PUBLIC
void LED::on (ledState color, int brightness){
LED_intensity = brightness;//(scale(brightness,0,100,0x8000,0xFFFF));
if (LED_RGB_flag){
LED_color = color;
if (brightness >= 0xFFFF){//100){
LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 0:1) : writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 1:0);
LED_activeLow_flag ? writePin(LED_portNumber[1],LED_pinNumber[1],readBit(LED_color,1) ? 0:1) : writePin(LED_portNumber[1],LED_pinNumber[1],readBit(LED_color,1) ? 1:0);
LED_activeLow_flag ? writePin(LED_portNumber[2],LED_pinNumber[2],readBit(LED_color,2) ? 0:1) : writePin(LED_portNumber[2],LED_pinNumber[2],readBit(LED_color,2) ? 1:0);
}
}
else{
if (brightness >= 0xFFFF){//100){
LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 0:1) : writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 1:0);
}
}
}
void LED::off (void){
if (LED_RGB_flag){
LED_activeLow_flag ? writePin(LED_portNumber[1],LED_pinNumber[1],1) : writePin(LED_portNumber[1],LED_pinNumber[1],0);
LED_activeLow_flag ? writePin(LED_portNumber[2],LED_pinNumber[2],1) : writePin(LED_portNumber[2],LED_pinNumber[2],0);
}
LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],1) : writePin(LED_portNumber[0],LED_pinNumber[0],0);
}
答案 0 :(得分:1)
新旧代码之间存在逻辑上的区别。罪魁祸首是其中之一。另外,您可以摆脱一些无用的代码。最后,似乎您误解了奥勒玛查赫对另一个问题的回答。
我看到的新旧版本之间最明显的逻辑差异是,新版本默认构造PWM
对象,而旧版本使用参数化构造函数。通过使用旧的工作版本并将行PWM pwm(PWM0,true,0,0x7FFF,DIV4);
更改为PWM pwm{};
,可以查看这是否是导致问题的原因。您可以通过更改两个LED
构造函数来为包含的PWM
对象指定参数来修复新版本。将: pwm(){
更改为: pwm(PWM0,true,0,0x7FFF,DIV4){
。
另一个逻辑差异是旧版本称为led.off()
,而新版本称为led.on(RED,0xF000);
。由于off()
函数未更新,因此在此处协调逻辑并不像将调用更改为LED::off()
那样简单。要检查这种差异,请注释掉旧的LED::off()
函数中的所有代码。修复新版本需要更多的精力。由于我怀疑选择PWM
构造函数是真正的罪魁祸首,所以我现在将跳过该操作。
其他逻辑上的差异似乎不太可能引起您的症状,但是无论如何我都会列出它们。旧版本不会为频道1和2调用PWM::pinSelect
,而新版本会。旧版本将pwm_sequence_started_flag
初始化为0
(隐式转换为false
),而新版本对此标志没有显式初始化。
在led.cpp
的新旧版本中,都有一个标记为“ // PRIVATE
”的部分什么都没有完成。本节定义一些(全局)变量,它们与LED
类的成员具有相同的名称。您的LED
成员函数不引用这些变量;当LED::on()
设置LED_intensity
时,它将设置成员this->LED_intensity
,而不是全局::LED_intensity
。另外,您的其他源文件不太可能引用这些全局变量,因为它们未在led.h
中声明。删除这些未使用的声明。
虽然不是严格没用,但您也可以摆脱void
的某些用途。在C ++(而不是C)中,可以使用bool start_pwm ();
而不是bool start_pwm (void);
来声明不带参数的函数。跳过“ void
”意味着专门用于阅读代码的Smidgen较少的脑力,因此,对于理解代码的Smidgen则具有较大的脑力。 Smidgens可以加起来。
使用typedef
为枚举命名的过程也看起来像是C ++中引入的C-ism。尝试使用enum pwmModule {PWM0,PWM1,PWM2,PWM3};
代替typedef enum {PWM0,PWM1,PWM2,PWM3} pwmModule;
。再次,更少的代码需要阅读。
关于简化代码的主题,行
LED_activeLow_flag ? writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 0:1) : writePin(LED_portNumber[0],LED_pinNumber[0],readBit(LED_color,0) ? 1:0);
是一个粗读。如果您从对writePin()
的调用中分离出最后一个参数的计算,则将更容易看到发生了什么。逻辑上等效(假设参数为int
)
int foo = readBit(LED_color,0) ? (LED_activeLow_flag ? 0 : 1) : (LED_activeLow_flag ? 1 : 0);
writePin(LED_portNumber[0], LED_pinNumber[0], foo);
这清楚表明,无论条件如何,都将调用writePin()
,并且前两个参数也与条件无关。这只是可以改变的最终参数。
我们继续前进到ohlemacher's answer。声称“它只是做不到您想要的事情”是指在构造函数主体内为类调用构造函数。也就是说,给定class A
,编写类似A::A(bool) { A(); }
的内容。在构造函数主体内创建一个对象,该对象自然会在构造函数返回时被销毁。
此外,ohlemacher回答的问题是关于为构造函数调用与构造函数相同的类(也称为C ++ 11中引入的“委托构造函数”)。您所关心的情况是调用数据成员的构造函数。对于数据成员来说,自从该语言标准化以来,member initializer lists就可以使用了。
答案 1 :(得分:0)
最简单的方法是使用智能指针。使LED
对象包含一个std::shared_ptr<PWM>
对象,可以在构造函数或成员函数中随时使用std :: make_shared创建该对象。这样,LED
死亡时,您既可以自动清除对象,又可以将PWM
对象复制到其他位置,以便在LED
被破坏时持久存在。
这样,您可以使任何类按需包含另一个类,并且仍然能够轻松清除。