LED auf kleinster Stufe zu hell

Hallo,

ich habe mir einen Aquariumkontroller gebaut nach folgendem Vorbild:
http://vascoferraz.com/projects/aquarium-pwm-led-v1/

Die LEDs werden hier über einen 74HC595 über die Library ShiftPWM.h angesteuert und können damit an- und ausgeschaltet und gedimmt werden. Das funktioniert alles soweit auch.

Nachts soll schwaches Licht den Mond simulieren und den Fischen Orientierung geben. Das funktioniert alles auch so weit. Das Problem ist allerdings, dass die blauen LEDs meines 5m-Strips zu hell sind. Gehe ich auf 0 ist der Kanal aus, auf 1 ist er zu hell.

Ich habe einen 220 Ohm Widerstand zwischen MOSFET und blauen Kanal gelötet und nachts passt die Helligkeit nun; tagsüber ist das blau allerdings zu schwach, sodass das Licht grünlich wirkt.

Nun zu meiner Frage:
Kann ich die LED ohne Widerstand irgendwie noch weiter dimmen?

Vielen Dank für eure Hilfe!

Man kann doch in der ShiftPWM library die maximale Helligkeit einstellen. Vielleicht Nachts einfach die mal runterdrehen?

EDIT: Was hast du denn für einen LED-Strip? Ich kenne nur solche, wo man alle roten LEDs zusammen, alle grünen LEDs zusammen, etc. steuern kann. Wozu also das Schieberegister?

Hey,

ja, die Helligkeit der LED lässt sich regeln, das stimmt. Ich kann da einen Wert zwischen 255 und 0 festlegen, wobei bei mir 240 das Maximum ist und 0 das Minimum.
Wie gesagt, tagsüber leuchten alle farben maximal, dann (bei Sonnenuntergang) dimmen sie langsam und nachts ist die maximale Helligkeit 0 bei Rot und Grün und 1 bei Blau.
Dennoch ist das Licht immer noch zu hell.

Genau, ich habe einen Strip mit 5 Anschlüssen, es ist eine RGBW-Kette. Theoretisch geht es ohne Schieberegister; das Projekt war aber mit einem gebaut und ich habe es einfach übernommen.

Viele Grüße

PS: Hier mal der Code, welcher zeigt, wie ShiftPWM genutzt wird. Den Rest des Codes (Sonnenaufgang, Untergang, Menü etc) habe ich mal weggelassen, da zu lang.
Gibt es eine Möglichkeit, die LED in der Software noch mehr zu dimmen, als den Wert auf 1 zu setzen?

//#include <Servo.h> <-- If you include Servo.h, which uses timer1, ShiftPWM will automatically switch to timer2

// Clock and data pins are pins from the hardware SPI, you cannot choose them yourself.
// Data pin is MOSI (Uno and earlier: 11, Leonardo: ICSP 4, Mega: 51, Teensy 2.0: 2, Teensy 2.0++: 22) 
// Clock pin is SCK (Uno and earlier: 13, Leonardo: ICSP 3, Mega: 52, Teensy 2.0: 1, Teensy 2.0++: 21)

// You can choose the latch pin yourself.
const int ShiftPWM_latchPin=8;

// ** uncomment this part to NOT use the SPI port and change the pin numbers. This is 2.5x slower **
//#define SHIFTPWM_NOSPI
//const int ShiftPWM_dataPin = 11;
//const int ShiftPWM_clockPin = 13;

// If your LED's turn on if the pin is low, set this to true, otherwise set it to false.
const bool ShiftPWM_invertOutputs = false;

// You can enable the option below to shift the PWM phase of each shift register by 8 compared to the previous.
// This will slightly increase the interrupt load, but will prevent all PWM signals from becoming high at the same time.
// This will be a bit easier on your power supply, because the current peaks are distributed.
const bool ShiftPWM_balanceLoad = false;

#include <Wire.h> // I2C and TWI library
#include <LiquidCrystal.h>
#include <RTClib.h>
#include <ShiftPWM.h> // Include ShiftPWM.h after setting the data, clock and latch pins!
#include <EEPROM.h>   // The microcontroller on the Arduino board has an EEPROM: memory whose values are kept when the board is turned off
                      // (like a tiny hard drive). This library enables you to read and write those bytes.
                      // The microcontrollers on the various Arduino boards have different amounts of EEPROM: 1024 bytes on the ATmega328P,
                      // 512 bytes on the ATmega168 and ATmega8 and 4 kB (4096 bytes) on the ATmega1280 and ATmega2560. 

#define DS1307_I2C_ADDRESS 0x68 // Each I2C object has a unique bus address, the DS1307 (Real Time Clock) is 0x68

RTC_DS1307 RTC;
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

// Create custom chars
byte degree_char[8] = {
  0b01110,
  0b10001,
  0b10001,
  0b01110,
  0b00000,
  0b00000,
  0b00000,
  0b00000
};

byte upbar_char[8] = {
  0b11111,
  0b00000,
  0b00000,
  0b00000,
  0b00000,
  0b00000,
  0b00000,
  0b00000
};

// Variables used to measure the temperature
const int analogtemp=6; // This is the analog pin which is measuring the input voltage from the LM35CAZ temperature sensor
double temp=0, Vin=0, ADCvar;
unsigned int j=0, k=0;
const double Vref=1100.0;

const int ClockMode = 1;          // Pushbutton to switch between modes
unsigned char ClockModeState = 0; // Current LCD mode state
unsigned char ClockModeFlag = 0;  // Flag used for debouncing the ClockMode pushbutton
const int SetClockPlus = 2;       // Increment pushbutton to set the clock

unsigned char second, minute, hour, dayOfWeek, day, month, year;
unsigned char presunrise; // Hour when the pre-sunrise will start
unsigned char sunrise;    // Hour when the sunrise will start
unsigned char sunset;     // Hour when the sunset will start
unsigned int presunriseMemoryBank = 0; // This is the position on ATmega328P's EEPROM where the hour of the pre-sunrise is stored.
unsigned int sunriseMemoryBank = 1;    // This is the position on ATmega328P's EEPROM where the hour of the sunrise is stored.
unsigned int sunsetMemoryBank = 2;     // This is the position on ATmega328P's EEPROM where the hour of the sunset is stored.
const unsigned int settingdelay = 200; // The higher this value is, the longer it will take to increment day, month, year, hour, minute, second, pre-sunrise, sunrise and sunset variables.


// If there is no input, automatically jump to main display when gotomain = gotomaincounter. Change this time by manipulating the gotomaincouter value.
unsigned int gotomain=0;
const int gotomaincounter=400;

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val) {return ( (val/10*16) + (val%10) );}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val) {return ( (val/16*10) + (val%16) );}


// Here you set the number of brightness levels, the update frequency and the number of shift registers.
// These values affect the load of ShiftPWM.
// Choose them wisely and use the PrintInterruptLoad() function to verify your load.
unsigned int maxBrightness = 240; // Don't forget that a signed char variable range is from [-128;127] and an unsigned char from [0;255].
unsigned int brightness;          // If you want to get an higher resolution, you must set maxBrightness (here) and brightness variables as integers.
unsigned int pwmFrequency = 100;
unsigned char numRegisters = 1;
const int outputEnable = 9; // If this port is LOW, shift register(s) is (are) enable. If this port is HIGH, shift register(s) is (are) disable.

// Variables used in Copyright function
unsigned char x=0, z=0, flag=0;

// Variables used in Brightness and LED_PWM functions
int y=-1;
unsigned int percent;
unsigned char WhiteString1 = 0;
unsigned char WhiteString2 = 1;
unsigned char BlueString   = 2;
unsigned char RedString    = 3;
unsigned char Brightness_WhiteString1 = 0;
unsigned char Brightness_WhiteString2 = 0;
unsigned char Brightness_BlueString   = 0;
unsigned char Brightness_RedString    = 0;

// Variable used to change between operation modes
unsigned char operationMode = 0; // Start on normal mode


void setup ()
{
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  lcd.begin(20, 4);
  lcd.createChar(0, degree_char);
  lcd.createChar(1, upbar_char);
  analogReference(INTERNAL);
  
  pinMode(ClockMode, INPUT);      // Initialize the clock mode pushbutton as an input.
  pinMode(SetClockPlus, INPUT );  // Initialize the increment pushbutton as an input.
  pinMode(outputEnable, OUTPUT);  // Initialize the output enable shift register pin as an output.
  
  // Sets the number of 8-bit shift registers that are used.
  ShiftPWM.SetAmountOfRegisters(numRegisters); 
  // Sets the pwmFrequency and maxBrightness
  ShiftPWM.Start(pwmFrequency,maxBrightness);
  
  // This set of instructions will disable all outputs from all shift registers to prevent the random (or last saved on/off state) activation of the LEDs.
  digitalWrite(outputEnable, HIGH);
  ShiftPWM.SetAll(0);
  delay(10);
  digitalWrite(outputEnable, LOW);
  
  // following line sets the RTC to the date & time this sketch was compiled 
  //RTC.adjust(DateTime(__DATE__, __TIME__));

Ich meine diese Zeile hier:

ShiftPWM.Start(pwmFrequency,maxBrightness);

Kannst du da nicht nachts für maxBrightness 100 einstellen und tagsüber 240? Wie gesagt, ich kenne die Bibliothek nicht, aber aufgrund des Namens würde ich schätzen, dass bei einer geringeren maxBrightness der Wert 1 eine geringere Helligkeit liefert.

Du könntest einen günstigen 16 Kanal 12 Bit PWM I2C Adapter benutzen um die FETs anzusteuern.
Der Modul könnte auch mehr Zonen unterstützen mit zusätzlichen FETs.

Das würde auch deine CPU wesentlich entlasten, im Vergleich zu SoftPWM via Schieberegister denke ich.

PCA9685
PCA9685.png

Hey,

danke für die Tipps.

Nachts passiert folgendes:

    // Moonlight 1
    if (hour >= sunset+1 && hour <= 23)
    {
    Brightness_WhiteString1 = 0; 
    Brightness_WhiteString2 = 0;
    Brightness_BlueString   = 1;
    Brightness_RedString    = 0;
  
    ShiftPWM.SetOne(WhiteString1,Brightness_WhiteString1);
    ShiftPWM.SetOne(WhiteString2,Brightness_WhiteString2);
    ShiftPWM.SetOne(BlueString,Brightness_BlueString);
    ShiftPWM.SetOne(RedString,Brightness_RedString);
    }

Im Original soll der Wert sogar 18 sein, bei mir ist er nur 1. Kleiner kann ich den Wert gar nicht wählen, denn das ist ja der tiefste Wert auf den gefahren wird. Oder sehe ich das falsch? Gäbe es noch eine andere Möglichkeit? Bei 0 ist sin die LED ja aus...

Der PWM-Adapter klingt spannend. Aber dann müsste ich ja meinen ganzen Code über den Haufen werfen, oder? So viel Arbeit wollte ich mir eigentlich gar nicht machen...

Für den Chip gibt es Libraries mit denen man nur die Werte setzen muss.
Shiftregister SoftPWM erscheint mir ziemlich von hinten durch die Brust ins Auge,
auch wenn die Komplexität da vielleicht in der Library versteckt ist.

Bei Betrachtung deines Kodeausschnitts ist der Änderungsaufwand klein bis minimal.
Du benutzt sowieso schon I2C fürs LCD,
wenn es von dir geschriebener oder verstandener Kode ist,
müsstest du eine Änderung leicht hinbekommen.
Die Shiftregister werden dann natürlich überflüssig.

Ob dein Programm mit 12 Bit Auflösung überhaupt arbeiten kann, weiss ich nicht.

Wenn es nur um die Ablaufsteuerung geht, würde ich vielleicht sogar einen kleinen ESP damit betrauen,
und das Design und die Aktivierung eher einem Rechner oder einer App überlassen

Auch für Servos ist der Modul gut geeignet. :wink:

Hier steht das Datenblatt des Chips: PCA9685.

Gönn' deinen Fischen die 15 Stufen zwischen den jetzigen 0 und 1. :wink:

Danke. Ich habe den Chip gerade in meiner Bastelkiste gefunden... Vielleicht sollte ich es wirklich angehen, wenn ich schon die Hardware hier habe... Hmpf. Das wäre aber ein Kampf, denn ich bin ziemlicher Noob... aber es wäre auch eine tolle Herausforderung!

Das wird nicht so schlimm, auch die jetzige Library benutzt ja eine Schnittstelle,
da werden keine zu großen Unterschiede sein.
Beide Libraries machen PWM auf Kanälen, das wird sich weitgehend eins zu eins übertragen lassen.

Die Entwicklung kannst du ja auf einem eigenen Arduino mit LEDs zur Simulation machen,
die kannst du direkt mit dem Chip treiben (mit Widerstand natürlich).

Each LED output can be off or on (no PWM control), or set at its individual PWM controller value. The LED output driver is programmed to be either open-drain with a 25 mA current sink capability at 5 V or totem pole with a 25mA sink, 10 mA source capability at 5 V. The PCA9685 operates with a supply voltage range of 2.3 V to 5.5 V and the inputs and outputs are 5.5 V tolerant. LEDs can be directly connected to the LED output (up to 25 mA, 5.5 V) or controlled with external drivers and a minimum amount of discrete components for larger current or higher voltage LEDs.