在另一个对象 B 中创建对象 A 时,对象 A 是否是对象 B 的本地对象,对象 A 是否会存在于对象 B 的实例化之外?



我的目标是创建两个类,LEDPWM,目的是每个LED对象创建一个本地PWM对象来控制亮度。这个想法是用户可以创建一个LED对象,而无需设置PWM对象,同时保留单独创建PWM对象以进行电机速度控制等的选项。

当我在LED对象中实例化PWM对象时,问题就来了。代码编译时没有错误;但是,结果就像PWM对象的构造函数完成后LED对象立即消失。(触发相应任务时,不会发生与PWM模块相关的任何事件。具体来说,pwm.stoppwm.start函数使用空while循环来等待任务完成时发出信号的特定事件,循环快捷方式会在循环完成事件发生时自动启动任务。触发相应任务时,这些事件都不会发生。数据手册警告:"请注意,必须先启用外设,然后才能使用任务和事件。这让我相信pwm.enable()没有运行。

Ohlemacher 这样描述构造函数内部的构造函数:

"...它只是不做你想做的事。内部构造函数将构造一个临时本地对象,一旦外部构造函数返回,该对象就会被删除。

有没有更好的方法可以在创建LED对象时自动生成PWM对象?是否可以在不使PWM对象成为LED对象的成员的情况下执行我想做的事?

普姆·

#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

噗嗤.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();
}

莱德·

#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

领导.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);
}

主.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;
}

为了进行比较,这里是可以工作的旧版本的代码(没有LEDPWM成员)。pwm.hpwm.cpp的文件与新版本中的文件相同。

led.h-- 旧(工作)版本

#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

led.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);
}

主.cpp-- 旧(工作)版本

#include "rav_nrf52840_base.h"
#include "rav_nrf52840_led.h"
#include "rav_nrf52840_pwm.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);
bool pwm_sequence_started_flag = 0;
int  LED_portNumber[3] = {0,0,0};
int  LED_pinNumber[3] = {23,22,24};
unsigned int sequence_0[4];
PWM pwm(PWM0,true,0,0x7FFF,DIV4);
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();

for(;;){
if (readPin(0,3)){
;
}
else{
if (pwm_sequence_started_flag){
pwm.stop();
pwm_sequence_started_flag = false;
}
led.on(RED,0xFFFF);
}
if (readPin(0,18)){
;
}
else{
led.off();
if (pwm_sequence_started_flag){
pwm.stop();
pwm_sequence_started_flag = false;
}
int LED_intensity = 0xF000;
sequence_0[0] = LED_intensity;
sequence_0[1] = LED_intensity;
sequence_0[2] = LED_intensity;
pwm_sequence_started_flag = pwm.start();
}
}
return -1;
}

旧代码和新代码之间存在一些逻辑差异。最有可能的是,其中之一是罪魁祸首。此外,您还可以摆脱一些无用的代码。最后,你似乎误解了ohlemacher对另一个问题的回答。


我在旧版本和新版本之间看到的最显着的逻辑差异是新版本默认构造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"意味着用于阅读代码的脑力减少一点点,所以理解代码的脑力多一点。斯密根可以加起来。

使用typedef为枚举命名也看起来像是C++引入的C主义。尝试使用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的答案。声明"它只是不做你想要的"是指为构造函数主体中的类调用构造函数。也就是说,给定class A,写类似A::A(bool) { A(); }的东西。在构造函数主体中创建一个对象,当构造函数返回时,该对象自然会被销毁。

此外,ohlemacher 回答的问题是关于调用与构造函数相同的类的构造函数(也称为 C++11 中引入的"委托构造函数")。您关心的情况是调用数据成员的构造函数。对于数据成员,成员初始值设定项列表自语言标准化以来一直可用。

最简单的方法是使用智能指针。让LED对象包含一个std::shared_ptr<PWM>对象,该对象可以随时使用 std::make_shared 在构造函数或成员函数中创建。这样,您既可以在LED死亡时自动清理对象,也可以将PWM对象复制到其他位置,以便在LED被破坏时保留。

这样,您可以根据需要让任何类包含另一个类,并且仍然能够轻松清理。

最新更新