Posts mit dem Label Modul werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Modul werden angezeigt. Alle Posts anzeigen

Sonntag, 24. April 2022

Karosseriebeleuchtung mit PCA9685


Ein Teil des Ausbaus meines FPV Crawler bestand darin, die LEDs zu montieren und entsprechend mit Energie zu versorgen. Natürlich reichte nicht ein einfaches Anschließen an die Versorgungsspannung aus. Denn die LEDs sollten je nach ihrer Aufgabe eingeschaltet werden, was zunächst einfach klingt.
Vom Gedanken bis zur Umsetzung zeigte sich ein deutliche höherer Aufwand beim Verkabeln mehrere Leitungen und beim Programmieren des PWM Moduls, als gedacht.


Benötigt

  • Arduino
  • PWM Modul PCA9685
  • LEDs und Widerstände

 

Ziel

Standlicht, Fahrlicht, Blinker und Flutlichter sollten alle individull an-steuerbar sein. Hier sollen die Lichter immer durch ein Fade-Effekt abgebildet werden.

 

Initialisieren

Für die folgenden Beispiele verwendete ich immer die gleiche Initialisierung.
 #include <Wire.h>  
 #include <Adafruit_PWMServoDriver.h>  
 Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();  
 void setup() {  
  pwm.begin();  
  pwm.setPWMFreq(1600);  
  Wire.setClock(400000);  
  // schaltet alle aus  
  for (uint8_t pwmnum=0; pwmnum < 16; pwmnum++) {  
    pwm.setPWM(pwmnum, 0, 4095);  
  }  
 }  


Fade-In und Fade-Out

Leider kann man nicht einfach einen Wert von 0 bis 256 in den Controller eingeben, um Animationsverläufe darin abzubilden. Wenn man versucht auf diese Weise die LEDs anzusteuern, dann funktioniert das schlecht oder gar nicht. Zum Glück ist bereits ein Beispiel Code in den Sourcen für das PCA9685 Modul integriert, dass genau diese Funktion darstellt.


Mit dem Adafruit Beispiel  'pwmtest' wird gezeigt, wie das Zuweisen um-gesetzt wird. Dort sieht man, dass nicht immer plus eins, sondern immer plus acht addiert wird. Das ist sicherlich auf die 12Bit pro Port zurück zu führen.

 
void loop() {  
  int stepAdd = 10;  
  int leds = 4;  
  for (uint16_t i=0; i<4096; i += stepAdd) {  
   for (uint8_t pwmnum=0; pwmnum < leds; pwmnum++) {  
    pwm.setPWM(pwmnum, 0, 4096 - i);  
   }  
  }  
  delay(1000);  
  for (uint16_t i=0; i<4096; i += stepAdd) {  
   for (uint8_t pwmnum=0; pwmnum < leds; pwmnum++) {  
    pwm.setPWM(pwmnum, 0, i);  
   }  
  }  
  delay(1000);  
 }


Asynchroner Ablauf

Für mein Ziel wird mehr als eine LED und neben dem Modul noch WS2812b RGB LEDs eingesetzt. Damit ich nicht für jede LED einen eigenen Controller benötige, muss ich sicherstellen, wie schnell etwas aus- oder eingeblendet werden soll.

 unsigned long mCurrentMillis;  
 unsigned long mLastMillis_LED_1;   
 unsigned long mLastMillis_LED_2;  
 uint16_t mValueLED_1 = 0;  
 uint16_t mValueLED_2 = 0;  
 void loop() {  
  uint16_t endValue = 4096;  
  int stepAdd = 10;  
  int leds = 4;  
  mCurrentMillis = millis();  
  if(mCurrentMillis - mLastMillis_LED_1 > 5) {  
   if(mValueLED_1 < endValue) {   
    mValueLED_1 += stepAdd;  
    pwm.setPWM(0, 0, mValueLED_1);  
   }  
   else {   
    mValueLED_1 = 0;  
   }  
   mLastMillis_LED_1 = mCurrentMillis;  
  }  
  if(mCurrentMillis - mLastMillis_LED_2 > 10) {  
   if(mValueLED_2 < endValue) {   
    mValueLED_2 += stepAdd;  
    pwm.setPWM(1, 0, mValueLED_2);  
   }  
   else {   
    mValueLED_2 = 0;   
   }   
   mLastMillis_LED_2 = mCurrentMillis;  
  }  
 }   


Blinker

Einfaches Ein- und Ausschalten ist nicht schwer zu programmieren. Mit einem schnelle Fade-In, Fade-Out war nur etwas ausprobieren nötig. Zuerst hatte ich das Problem. dass die LEDs nie ganz ausgingen, womit das Blinken selbst weniger deutlich zu sehen waren, wenn der Blinker betätigt wurde.
Im Grunde war das ein Denkfehler, weil ich die Schrittweite zum Fade-Out nicht berücksichtigt habe und, um eine Iteration zu früh den Vorgang verlassen habe.

 unsigned long mCurrentMillis;  
 unsigned long mLastMillis_LED_1;   
 unsigned long mLastMillis_LED_2;  
 uint16_t mValueLED_1 = 0;  
 bool mFlashingLED_2 = false;  
 void loop() {  
  uint16_t endValue = 4096;  
  int stepAdd = 10;  
  int leds = 4;  
  mCurrentMillis = millis();  
  if(mCurrentMillis - mLastMillis_LED_1 > 5) {  
   if(mValueLED_1 < endValue) {   
    mValueLED_1 += stepAdd;  
    pwm.setPWM(0, 0, mValueLED_1);  
   }  
   else {   
    mValueLED_1 = 0;  
   }  
   mLastMillis_LED_1 = mCurrentMillis;  
  }  
  if(mCurrentMillis - mLastMillis_LED_2 > 200) {  
   mFlashingLED_2 = !mFlashingLED_2;  
   if(mFlashingLED_2) {   
    pwm.setPWM(1, 0, 4095);  
   }  
   else {   
    pwm.setPWM(1, 0, 0);  
   }   
   mLastMillis_LED_2 = mCurrentMillis;  
  }  
 } 

 

Viel aus-probieren

Erst am Ende, wenn alles im Programmcode eingegeben ist, muss die Geschwindigkeit der Animationen eingestellt werden. Damit dies geht, sollte möglichst am Anfang diese Einstellungen zentral eingehalten werden, um das Nachjustieren zu beschleunigen.

Sonntag, 16. August 2020

Analog Digital Wandler ADS1115 einlesen (Meadow)

Meistens, wenn ich ein Modul finde, das ich noch nicht kenne, dann existiert bereits eine Bibliothek, die in C/C++ geschrieben ist.

Schaut man im .NET Umfeld, dann ist wiederum meistens nichts zu finden. Damit ist mein Interesse geweckt, etwas darüber zu schreiben und natürlich ein Beispiel-Code hier auf meinem Blog zu veröffentlichen.

Seit fast einem Jahr liegt bei mir der Meadow und läuft aktuell mit dem Beispielprogramm. Dieser Controller zielt auf ‚Internet of Things‘- Themen ab und ist der direkte Nachfolger vom Netduino. Im Gegensatz zu dem Netduino, kann mit dem Meadow in der aktuellen C# (8.0) und .NET Framework (4.7.3) Version geschrieben werden. Dies bedeutet auch, dass gegenüber dem veraltetem .NET Micro Framework vieles neu aufgebaut wurde und folglich neue Lösungen geschrieben werden können.

 Benötigt:

  • Meadow
  • Breadboard
  • Jumper Leitungen
  • Potentiometer (oder alternative ein Widerstand und ein Lichtempfindlicher Widerstand)
  • ADS1115

 

Kurzes über den AD Wandler

Bevor ich mit der Zielbeschreibung loslege, müssen einige Details zu dem AD Wandler genannt werden. Beispielsweise, wie hoch darf die Eingangsspannung sein, die auf den vier Eingängen angelegt wird?

Betriebsspannung (VDD)

2V bis 5,5V

Stromaufnahme (Continuous Mode)

150uA

Industrieschnittstelle

I²C

Adresse

0x48 (Kann geändert werden durch Pin Select)

Eingänge

4

Abtastrate

8 bis 860

Eingangsspannung

-0,3V bis +0,3V über der Betriebsspannung (VDD)

Eingangsstrom

10mA bei fortlaufender Messung, 100mA bei einzel Messung

Für manche Anwendung ist auch die Betriebstemperatur wichtig, die hier von -40°C bis +125°C sein darf.


Anforderung

An einem Potitiometer soll die anliegende Teilspannungshöhe geändert werden. Die abgeleitete Teilspannung soll am Eingang A0 eingehen. Über einen Methoden Aufruf soll der Eingang eingelesen und dessen Wert über die Output Konsole ausgegeben werden.

 

Schaltungsaufbau

Im folgendem Bild ist zu sehen, dass ich kein Potitiometer verwende (schlichtweg, weil ich keinen hatte). Alternativ verwende ich einen 10k Ohm Widerstand und einen üblichen Lichtempfindlichen Widerstand (Lichtsensor 30 - 90 KOhm).


Verwenden von bestehenden Informationen

Zuerst wollte ich den bestehenden C++ Code migrieren nach C# und .NET Framework. Das bedeutet im Grunde, dass ich die Methodennamen und die #define Direktiven mit dessen Biteinstellungen (HEX Werte) direkt übernehme. Aber nach und nach stellte ich fest, dass einige Inhalte sich auf andere Module wiederum bezogen und ich immer wieder im Datenblatt nach sehen musste, was eigentlich die einzelne Biteinstellung für das Modul bedeutet. Ein Beispiel ist die Standard Einstellung 128SPS (Samples per second) für den ADS1115 Modul, aber im Adafruit Code steht etwas von 1600SPS.

Das Gute daran ist, man erarbeitet sich selbst eine Lösung, wie die Einstellungen abgebildet werden. Das macht den Aufbau der Klasse einfacher und die Beschreibungen zielgenauer.


Programm code

Im folgenden Beispiel aus dem ‚SimpleCode‘-Branch wurde nur das übernommen, was den Standard- Einstellungen entsprach. Z.B. Bitstellungen, die mit 0 belegt sind (bzw. in HEX 0x00 Wert) mussten nicht sein, da das Anlegen der Konfiguration immer mit 0 beginnt. Der folgende Code ist aus der Klasse ‚SimpleAds1115‘ und hat für den Abruf eine öffentliche Methode ‚ReadSingleInputValue‘ zum Abruf der anliegenden Spannung. Die Parameter-Eingabe bestimmt, welcher Eingang gelesen wird.

 internal class SimpleAds1115 : App<F7Micro, SimpleAds1115>  
 {  
   private readonly II2cPeripheral _i2CPeripheral;  
   public SimpleAds1115()  
   {  
     var i2CBus = Device.CreateI2cBus();  
     this._i2CPeripheral = new I2cPeripheral(i2CBus, 0x48);  
   }  
   internal ushort ReadSingleInputValue(AdsInput input)  
   {  
     // disable the comparator  
     // Single-shot mode (default)  
     // Operational status/single-shot conversion start  
     // - Begin a single conversion  
     ushort config = 0x8103;  
     config |= (ushort)input;  
     byte[] data = new byte[] { (byte)(config >> 8), (byte)(config & 0xff) };  
     this._i2CPeripheral.WriteRegisters(0x01, data);  
     Thread.Sleep(9);  
     var result = this._i2CPeripheral.ReadRegisters(0x00, 2);  
     return (ushort)((result[0] << 8) | result[1]);  
   }  
 }  

Vollumfänglich wird später die Klasse ‚Ads1115‘, die zu dem jetzigen Zeitpunkt nicht fertig ist.


Auf den Meadow schreiben

Sobald die Anwendung über Deploy auf dem Meadow geschrieben wurde, kann über das Fenster 'Output' das Ergebnis der anliegenden Spannung gelesen werden. Mit der Static Methode ‚GetVoltage‘ wird der gelesene Wert umgerechnet in Volt. Den Wert 22610 entnahm ich bei einem Eingangssignal von 5V. An der Stelle könnt Ihr den zu kalibrierenden Wert ersetzen, wenn bei Euch mit 5V ein anderer Wert gemessen wird.

 


Vorsicht mit der maximalen Eingangsspannung

In Standard Einstellungen sind die Eingänge bis 6,144V. Bei dieser Einstellung sollte nicht mehr als 0,3V anliegen, weil dies zur einer Beschädigung des Moduls führen könnte.


Fazit

Zunächst das Offensichtliche:  wenn das eigene Projekt mehr Analog-Digital Wandler benötigt, dann ist dieses Modul genau richtig. In einem I²C Bus können bis zu vier Module adressiert werden. Doch dieses Modul hat noch weitere Funktionen, um sich auf die Bedingungen eines Projektes besser anzupassen. Die Eingänge können auf gezielte Maximal-Spannungen eingestellt werden. Die Anzahl der Messungen pro Sekunde gehen bis zu 860SPS (Samples per second). Die vier Eingänge werden durch ein Multiplex Funktion angesprochen, so das von vier Eingänge auf zwei Eingänge umgestellt werden kann. Mit dem einstellbaren Komparator kann auf spezifische Bedingung reagiert werden.

 

Meadow Code
Github – ExampleAds1115 (SimpleCode Branch)

Samstag, 13. Oktober 2018

PCA9685 PWM Driver Module mit Rasperry Pi & Win 10 Iot


Was mit dem Netduino geht, geht für gewöhnlich auch auf dem Raspberry Pi (wenn es nicht gerade um PWM Ausgänge geht). Grundsätzlich hatte ich das Modul tatsächlich für den Rasperry Pi gekauft, um die Fehlende Ausgabemöglichkeit eines PWM Signal auszugleichen. Zwar kann man einen Pin so programmieren, dass ein PWM Signal erzeugt wird, aber ich fand dieses Lösung zunächst nicht sehr ansprechend.

Benötigt:
  • Raspberry Pi 2 oder 3
  • 8GB SD Karte mit installierten Windows 10 IoT
  • Mindestens ein Servo zum Testen
  • Externe Spannungsquelle mit Maximal 6V


UWP Anwendung erstellen
Nam dem anlegen einer neuen Solution wird für den Zugriff auf die Schnittstelle I²C die Reference "Windows IoT Extensions for the UWP" hinzugefügt. Das Beispiel geht mit allen Version die für Windows 10 IoT und Raspberry Pi.


Fast identisch
Außer der Zugriff auf das Interface für I²C, ist der Aufruf gleich. Das Konfigurieren der Schnittstelle erfolgt z.B. nicht im Konstruktor, sondern in einer eigenen Initialisierungsmethode. Grund hierfür ist das abrufen der Instanz von I2cDevice das über die DeviceInformation abgeholt werden kann.

internal class Pca9685 {

private readonly byte _address = 0x40;
private readonly byte PCA9685_MODE1 = 0x00;
private readonly byte PCA9685_PRESCALE = 0xFE;
private readonly byte LED0_ON_L = 0x06;
private readonly byte LED0_ON_H = 0x07;
private readonly byte LED0_OFF_L = 0x08;
private readonly byte LED0_OFF_H = 0x09;

private I2cDevice _i2cDevice;

public Pca9685(int period) : base()
{
    this._period = period * 1000;
}

private async Task Init()
{
    var i2cSettting = new I2cConnectionSettings(this._address);
    i2cSettting.BusSpeed = I2cBusSpeed.StandardMode;

    var deviceSelector = I2cDevice.GetDeviceSelector();

    var deviceInfo = await DeviceInformation.FindAllAsync(deviceSelector);
    this._i2cDevice = await I2cDevice.FromIdAsync(deviceInfo[0].Id, i2cSettting);

    if (this._i2cDevice == null)
    {
        throw new Exception("i2cDevice is null");
    }
}
…

Zudem sind alle Methodenaufrufe Asynchron. Die Lösung ist auch in Synchron möglich, jedoch denke ich, dass die Verwendung von Async, Await und Task noch im Übersichtlichen Rahmen ist.
Allerdings muss man sich bewusst machen, obwohl die Methoden Asynchron ausgeführt werden können, müssen die Aufrufe nacheinander erfolgen. Überschneiden oder gleichzeitig ist Technisch für die Schnittstelle nicht möglich, weil die Bits nacheinander geschrieben werden können.

…
public async Task Reset()
{
    if(!this.Write(new byte[] { this.PCA9685_MODE1, 0x00 }))
    {
        throw new Exception("Can not send the reset command.");
    }

    await Task.Delay(10);
}

internal async Task Start()
{
    await this.Init();

    int hz = 1000000 / this._period;

    await this.Reset();
    await this.SetPwmFrequency(hz);
}

public async Task SetPwmFrequency(float frequency)
{
    byte prescale = this.GetPrescale(frequency);

    byte[] buffer = new byte[1] { this.PCA9685_MODE1 };

    if (!this.Read(buffer))
    {
        throw new Exception("can not read mode1");
    }

    byte oldMode = buffer[0];

    // sleep
    byte newMode = (byte)(((byte)oldMode & (byte)0x7F) | (byte)0x10);

    // go to sleep
    this.Write(new byte[] { this.PCA9685_MODE1, newMode });
    this.Write(new byte[] { this.PCA9685_PRESCALE, prescale });
    this.Write(new byte[] { this.PCA9685_MODE1, oldMode });
    await Task.Delay(5);
    this.Write(new byte[] { this.PCA9685_MODE1, (byte)(oldMode | 0x80) });

    byte[] bufferRead = new byte[] { this.PCA9685_MODE1 };
    this.Read(bufferRead);
}
        
internal void SetPwm(byte outputNumber, int on, int off)
{
    byte targetOutput_ON_L = (byte)(this.LED0_ON_L + 4 * outputNumber);
    byte targetOutput_ON_H = (byte)(this.LED0_ON_H + 4 * outputNumber);
    byte targetOutput_OFF_L = (byte)(this.LED0_OFF_L + 4 * outputNumber);
    byte targetOutput_OFF_H = (byte)(this.LED0_OFF_H + 4 * outputNumber);

    this.Write(new byte[] { targetOutput_ON_L, (byte)on });
    this.Write(new byte[] { targetOutput_ON_H, (byte)(on >> 8) });
    this.Write(new byte[] { targetOutput_OFF_L, (byte)(off) });
    this.Write(new byte[] { targetOutput_OFF_H, (byte)(off >> 8) });
}
…

Zur Vollständigkeit kommen noch die restlichen Methoden. Das Umrechnen (GetPrescale) ist hier direkt kopiert und unterscheidet sich auch nicht mal von der C++ Version die in den Sourcecode von Adafruit fand.
Das Versenden der Bytes braucht nicht mehr code als die Netduino Lösung.

…
private byte GetPrescale(float frequency)
{
    frequency *= 0.9f;
    // internal clock frequency
    float prescaleval = 25000000;
    prescaleval /= 4096;
    prescaleval /= frequency;
    prescaleval -= 1;

    return (byte)(prescaleval + 0.5);
}

private bool Write(byte[] buffer)
{
    var result = this._i2cDevice.WritePartial(buffer);

    if (result.Status != I2cTransferStatus.FullTransfer)
    {
        Debug.WriteLine(result.Status);
    }

    return result.Status == I2cTransferStatus.FullTransfer;
}

private bool Read(byte[] buffer)
{
    var result = this._i2cDevice.ReadPartial(buffer);

    if (result.Status != I2cTransferStatus.FullTransfer)
    {
        Debug.WriteLine(result.Status);
    }

    return result.Status == I2cTransferStatus.FullTransfer;
}
}

Kommt mir immer noch verdreht vor
Bereits im Blog Post für das Netduino Beispiel, hatte ich den Eindruck, dass die Ansteuerung verdreht ist. Das Verhalten ist auch hier Identisch.

Verkabeln
Vier Leitungen reichen, um das Modul Anzusteuern. Hier sind keine Besonderheiten. Damit der Angeschlossene Servo zuverlässig reagiert, sollte eine Externe Spannungsquelle angeschlossen werden.

Die Wesentlichen Technischen Infos:
PWM Signal kann in 4096 Stufen gesteuert werden (12Bit)
PWM Signal kann zwischen 24Hz bis maximal 1526Hz eingestellt werden.
Die 16 Anschlüsse für die Stromversorgung der Servos, können maximal betrieben werden in Abhängigkeit der Angeschlossenen Spannungsversorgung.
PWM Output selbst kann maximal bis 25mA verwendet werden für LEDs
Spannungsversorgung für die Steuerung über I²C darf von 2,3V bis 5,5V liegen.
16 PWM Ausgänge
Kann über einen Externen Clock betrieben werden, der maximal bis 50MHz sein darf.
Intern ist ein 25MHz Oszillator verbaut.
Kann für LEDs oder Servos verwendet werden.


Github Quellcode in C++
Datenblatt:


Sonntag, 23. September 2018

PCA9685 PWM Driver Modul mit dem Netduino


Nach etwas längerer Zeit ist eine Thema mit dem Netduino wieder dran. Diesmal ist das PWM Treiber Modul dran, den ich schon etwas länger hier liegen habe und es ist eigentlich zunächst für den Raspberry Pi gedacht, aber da fehlt mir noch eine neue Platine um einen eigenen Motor Treiber zu bauen.

Benötigt wird:
  • Netduino (sollte mit allen Versionen funktionieren)
  • PCA9685 16 Channel PWM Driver (Meins ist nicht von Adafruit)
  • Mindestens ein Servo zum Testen
  • Externe Spannunsquelle mit Maximal 6V


Neues Projekt
Für das Projekt werden die Referenzen Microsoft.SPOT.Hardware und Microsoft.SPOT.Native die für die I²C und Debug Ausgaben verwendet werden. Neben der bestehenden Program.cs Klasse wird eine eigene Klasse für den PWM Treiber hinzugefügt, die dann den Inhalt hat des hier folgenden gezeigten Code. Weitere Kommentare sind im Github Repository zu sehen.

public class Pca9685 : I2CDevice
{
    private readonly byte PCA9685_MODE1 = 0x00;
    private readonly byte PCA9685_PRESCALE = 0xFE;

    private readonly byte LED0_ON_L = 0x06;
    private readonly byte LED0_ON_H = 0x07;

    private readonly byte LED0_OFF_L = 0x08;
    private readonly byte LED0_OFF_H = 0x09;

    private readonly byte ALL_LED_ON_L = 0xFA;
    private readonly byte ALL_LED_ON_H = 0xFB;
       
    private int _period;
       
    public Pca9685(int period) : base(new Configuration(0x40, 100))
    {
        this._period = period * 1000;
    }

    public void Reset()
    {
        this.Write(new byte[]{ PCA9685_MODE1, 0x00 });
        Thread.Sleep(10);
    }

    internal void Start()
    {
        int hz = 1000000 / this._period;

        this.Reset();
        this.SetPwmFrequency(hz);
    }
        
    public void SetPwmFrequency(float frequency)
    {
        frequency *= 0.9f;
        float prescaleval = 25000000;
        prescaleval /= 4096;
        prescaleval /= frequency;
        prescaleval -= 1;

        byte prescale = (byte)(prescaleval + 0.5);

        byte[] buffer = new byte[1] { PCA9685_MODE1 };
           
        if (this.Read(buffer) != 1)
        {
            throw new Exception("can not read mode1");
        }

        byte oldMode = buffer[0];

        byte newMode = (byte)(((byte)oldMode & (byte)0x7F) | (byte)0x10);

        // go to sleep
        this.Write(new byte[] { PCA9685_MODE1, newMode });
        this.Write(new byte[] { PCA9685_PRESCALE, prescale });
        this.Write(new byte[] { PCA9685_MODE1, oldMode });
        Thread.Sleep(5);
        this.Write(new byte[] { PCA9685_MODE1, (byte)(oldMode | 0x80) });

        byte[] bufferRead = new byte[] { PCA9685_MODE1 };
        this.Read(bufferRead);
        Debug.Print("Mode now: " + bufferRead[0].ToString());
    }
       
    internal void SetPwm(byte outputNumber, int on, int off)
    {
        Debug.Print("Output: " + outputNumber.ToString() + ", ON: " + on.ToString() + ", OFF: " + off.ToString());

        byte targetOutput_ON_L = (byte)(LED0_ON_L + 4 * outputNumber);
        byte targetOutput_ON_H = (byte)(LED0_ON_H + 4 * outputNumber);
        byte targetOutput_OFF_L = (byte)(LED0_OFF_L + 4 * outputNumber);
        byte targetOutput_OFF_H = (byte)(LED0_OFF_H + 4 * outputNumber);

        this.Write(new byte[] { targetOutput_ON_L, (byte)on });
        this.Write(new byte[] { targetOutput_ON_H, (byte)(on >> 8) });
        this.Write(new byte[] { targetOutput_OFF_L, (byte)(off) });
        this.Write(new byte[] { targetOutput_OFF_H, (byte)(off >> 8) });
    }

    private int Write(byte[] buffer)
    {
        I2CTransaction[] trans = new I2CTransaction[]
        {
            CreateWriteTransaction(buffer)
        };

        return Execute(trans, 1000);
    }
       
    private int Read(byte[] buffer)
    {
        I2CTransaction[] trans = new I2CTransaction[]
        {
            CreateReadTransaction(buffer)
        };

        return Execute(trans, 1000);
    }
}

Inhalt zur Klasse
Mit der Fertigstellung der Klasse, bzw. ist diese jetzt soweit ausgeführt, dass die einzelnen PWM Ausgänge des Moduls über die I²C gesteuert werden können. Sieht man in das Datenblatt, dann ist zusehen, dass das Modul noch ein paar mehr Sachen kann. Zum einen bin ich hier nicht auf das Kaskadieren des Moduls mit mehreren nicht eingegangen. Dazu komme ich auf ein anderes mal, wenn ich mehrere Module davon besitze.
Der Programmcode selbst habe ich ursprünglich aus öffentlichen C++ Programmcode entnommen und habe deshalb auch die selben Namen für Methoden verwendet wie aus dem Adafruit Programmcode.

Vielleicht verdreht
An der Stelle für SetPwm bin ich mir noch nicht sicher ob die Ansteuerung so richtig ist. Zugegeben, ich bin noch nicht mit dem Datenblatt durch. Da ich selbst weis, wie ein PWM Signal auszusehen hat, sollte auch die Ansteuerung meiner Vorstellung entsprechen. Doch wenn ich den High Puls festlege, dann ist dieser länger als der Low Puls Länge Inherhalb der Periode. Das sollte eigentlich umgekehrt sein.

Verkabeln
Mit vier Leitungen ist das Modul vom Netduino steuerbar. Damit aber auch die Servos später versorgt sind, muss in der Mitte ebenfalls eine Spannungsquelle angeschlossen werden.


Probleme
Falls ihr die Stromversorgung in der Mitte vom Modul mit dem 5V Ausgang vom Netduino versorgt, kann es sein, dass es nicht funktioniert oder instabil reagiert. Bedeutet, kann funktionieren, muss aber nicht. Besser ist immer eine seperate Versorgung anzuschließen. Allein je nach größe des verwendeten Servos und dessen Belastung, könnte die Stromaufnahme zu groß sein (Leider konnte ich keine Information finden, wieviel Strom maximal am 5V Pin abgenommen werden kann vom Netduino).

Die Wesentlichen Technischen Infos:
PWM Signal kann in 4096 Stufen gesteuert werden (12Bit)
PWM Signal kann zwischen 24Hz bis maximal 1526Hz eingestellt werden.
Die 16 Anschlüsse für die Stromversorgung der Servos, können maximal betrieben werden in Abhängigkeit der Angeschlossenen Spannungsversorgung.
PWM Output selbst kann maximal bis 25mA verwendet werden für LEDs
Spannungsversorgung für die Steuerung über I²C darf von 2,3V bis 5,5V liegen.
16 PWM Ausgänge
Kann über einen Externen Clock betrieben werden, der maximal bis 50MHz sein darf.
Intern ist ein 25MHz Ozillator verbaut.
Kann für LEDs oder Servos verwendet werden.


Quellenangaben:
Github Quellcode in C++
Datenblatt:



Gehäuseentwurf für Signalleuchten (Part 2)

Heute morgen sah ich mir mein Druckergebnis an und dachte: Nein, das sieht nicht nach einem Kristall aus. Also im Internet gesucht und ein T...