Моя цель - создать два класса LED
и PWM
с намерением создать для каждого объекта LED
локальный объект PWM
для управления яркостью.Идея состоит в том, что пользователь может создать объект LED
без необходимости установки объекта PWM
, сохраняя при этом возможность создания объекта PWM
отдельно для управления скоростью двигателя и т. Д.
проблема возникает, когда я создаю экземпляр объекта PWM
внутри объекта LED
.Код компилируется без ошибок;однако в результате объект PWM
исчезает, как только завершается конструктор объекта LED
. (Ни одно из событий, связанных с модулем ШИМ, не происходит, когда я запускаю соответствующую задачу. В частности, функции pwm.stop
и pwm.start
используют пустой цикл while
для ожидания определенных событий, которые сигнализируют, когда задачазавершено, и ярлык цикла автоматически запускает задачу при возникновении события завершения цикла. Ни одно из этих событий не происходит, когда запускаются соответствующие задачи. В листе данных содержится предупреждение: «Обратите внимание, что периферийное устройство должно быть включено до того, как задачи и события могут бытьиспользуется. "Это приводит меня к мысли, что pwm.enable()
не работает.)
ohlemacher говорит это о конструкторах внутри конструкторов :
«... Он просто не делает то, что вы хотите. Внутренний конструктор создаст временный локальный объект, который будет удален после возвращения внешнего конструктора.»
Есть ли лучший способ для автоматическогосгенерировать объект 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
члена LED
).Файлы pwm.h
и pwm.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);
}
main.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;
}