Kategorien
Node Red

Arduino – Node Red – MCP42010 – Steuerung des digitalen Potentiometers

Arduino – Node Red – MCP42010 – Beispiel Steuerung des digitalen Potentiometers

Im Beitrag Arduino – steuern und Test Digital Potentiometer MCP42010 auf Steckbrett habe ich dargestellt wie der MCP42010 über den seriellen Monitor der Arduino IDE gesteuert werden kann.
Jetzt will ich dieses etwas komfortabler zu tun.
Die Bedienung sollte aus dem Browser heraus erfolgen, optisch sehr ansprechend aussehen und auch mit dem Smartphone möglich sein.

Warum mit Node Red?

Node Red ist in der Standard Installation der Raspberry Pi enthalten, kostenlos und intuitiv bedienbar.
Durch die Möglichkeit den Programm Flow per drag and drop zusammen zu stellen, kommt man sehr schnell zu einem guten Ergebnis.
Für Prototypen und auch IOT Anwendungen eine echt tolle Sache.
Wo Licht ist, ist auch Schatten: Es verbraucht recht viel Ressourcen.
Dennoch kommt die Raspberry Pi 2 spielend damit zurecht und die Pi 3 logischerweise noch viel besser.

benötigte Funktionen des Flows

Der Flow soll die Eingaben, die ich im Experiment Arduino – steuern und Test Digital Potentiometer MCP42010 auf Steckbrett per Hand gemacht habe übernehmen.
Der Flow soll die Rückgabe – Werte in einem Gauge Chart darstellen.

Eingabe:
1:Wert von 0-255 -> setzt Potentiometer1 auf den Wert und gibt die Spannung an A0 zurück
2:Wert von 0-255 -> setzt Potentiometer2 auf den Wert und gibt die Spannung an A1 zurück

Der Flow

  • einfach den folgenden Flow kopieren und unter Menü (rechts oben) -> Import – Clipboard einfügen
[{"id":"ebf0e947.110038","type":"ui_slider","z":"8ec3bd3.cce4dc","tab":"147200e2.b8e19f","name":"Slider","topic":"","group":"Pot1","order":1,"min":0,"max":"255","x":225.5,"y":125,"wires":[["25bd2695.9acaf2"]]},{"id":"b755b484.2bd75","type":"ui_text","z":"8ec3bd3.cce4dc","tab":"147200e2.b8e19f","name":"Wert","group":"Pot1","order":1,"format":"{{msg.payload}}","x":636.5,"y":102,"wires":[]},{"id":"ed9f01b2.dfae38","type":"ui_gauge","z":"8ec3bd3.cce4dc","tab":"147200e2.b8e19f","name":"Spannung in V an A0","group":"Pot1","order":1,"format":"{{value}}","min":0,"max":"5","x":681.5,"y":322,"wires":[]},{"id":"25bd2695.9acaf2","type":"function","z":"8ec3bd3.cce4dc","name":"Value to Command","func":"var msg1 = { payload:\"1:\" + msg.payload +\"\\n\"};\nreturn [msg, msg1];","outputs":"2","noerr":0,"x":440.5,"y":125,"wires":[["b755b484.2bd75"],["134514.6c0042ed"]]},{"id":"134514.6c0042ed","type":"serial out","z":"8ec3bd3.cce4dc","name":"/dev/ttyUSB0","serial":"d535ccdc.123838","x":658.5,"y":148,"wires":[]},{"id":"13db30d1.da3c67","type":"serial in","z":"8ec3bd3.cce4dc","name":"/dev/ttyUSB0","serial":"43aa993f.185738","x":186.5,"y":345,"wires":[["f39416bc.0495"]]},{"id":"f39416bc.0495","type":"function","z":"8ec3bd3.cce4dc","name":"Response to value","func":"//find A0 or A1\nvar value;\nif (msg.payload.indexOf(\"A0\") != -1) {\n    value = msg.payload.split(\"A0: \");\n    value = value[1].replace(\" Volt\", \"\");\n    msg.payload = value;\n    return [msg, null];\n} else {\n    value = msg.payload.split(\"A1: \");\n    value = value[1].replace(\" Volt\", \"\");\n    msg.payload = value;\n    return [null , msg];\n}","outputs":"2","noerr":0,"x":431.5,"y":345,"wires":[["ed9f01b2.dfae38"],["ddbfff6.2bdb3"]]},{"id":"8a48ef7d.33ba9","type":"ui_slider","z":"8ec3bd3.cce4dc","tab":"147200e2.b8e19f","name":"Slider","topic":"","group":"Pot2","order":1,"min":0,"max":"255","x":224,"y":227,"wires":[["127d632d.c0419d"]]},{"id":"5a58be54.e6b8d8","type":"ui_text","z":"8ec3bd3.cce4dc","tab":"147200e2.b8e19f","name":"Wert","group":"Pot2","order":1,"format":"{{msg.payload}}","x":635,"y":204,"wires":[]},{"id":"127d632d.c0419d","type":"function","z":"8ec3bd3.cce4dc","name":"Value to Command","func":"var msg1 = { payload:\"2:\" + msg.payload +\"\\n\"};\nreturn [msg, msg1];","outputs":"2","noerr":0,"x":439,"y":227,"wires":[["5a58be54.e6b8d8"],["ee1b0407.9fbca"]]},{"id":"ee1b0407.9fbca","type":"serial out","z":"8ec3bd3.cce4dc","name":"/dev/ttyUSB0","serial":"43aa993f.185738","x":657,"y":250,"wires":[]},{"id":"ddbfff6.2bdb3","type":"ui_gauge","z":"8ec3bd3.cce4dc","tab":"147200e2.b8e19f","name":"Spannung in V an A1","group":"Pot2","order":1,"format":"{{value}}","min":0,"max":"5","x":681,"y":370,"wires":[]},{"id":"147200e2.b8e19f","type":"ui_tab","z":"","name":"Test MCP42010","icon":"dashboard","order":"1"},{"id":"d535ccdc.123838","type":"serial-port","z":"","serialport":"/dev/ttyUSB0","serialbaud":"9600","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false},{"id":"43aa993f.185738","type":"serial-port","z":"","serialport":"/dev/ttyUSB0","serialbaud":"9600","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false}]

Video Ansteuerung MCP42010 mit Node Red

Kategorien
Arduino

Arduino MCP42010 – Steuerung und Test des Digital Potentiometers

Arduino MCP42010 – auf einem Steckbrett austesten

Es gibt viele Anleitungen digitale Potentiometer mit einer Arduino anzusteuern.
Meine Suche im Internet nach dem MCP42010 in Verbindung mit Arduino war sehr vielversprechend, führte aber erst nach einigen Versuchen zum Erfolg.
Viele Seiten und Foreneinträge diskutieren das Thema, beschreiben aber keine funktionierende Lösung.

Die Idee ist die beiden digitalen 10 Kiloohm Potentiometer an den Enden zwischen 5 Volt und Masse zu schalten und die Mitte des Potis auf jeweils einen analogen Eingang zu legen.
Je nach dem was jetzt für ein Widerstand (angesteuert) wird, wird die Spannung an den analogen Eingängen steigen oder fallen. Und das lässt sich auswerten.

Ich beschreibe, wie ich vorgegangen bin.

Zum Einsatz kam ein Arduino Nano Nachbau, der schon für etwas über 3,50 Euro zu haben ist und ein digitales Potentiometer MCP42010 (Datenblatt), was ich für ca. 2 Euro bei www.reichelt.de bestellt habe. Ich habe den Aufbau auch mit einer Arduino Uno getestet mit den selben IO Pins. Erfolgreich :-)

Wie in der folgenden Fritzing Grafik und dem Eagle Schaltplan zu erkennen, habe ich folgendermaßen verdrahtet.
Pin Belegung MCP42010MCP42010:
Pin 1 -> D10 Arduino, Pin2 -> D13 Arduino, Pin3 -> D11 Arduino, Pin4 -> Masse, Pin5 -> Masse, Pin6 -> A1 -> Arduino, Pin7 -> +5V, Pin8 -> + 5V, Pin9 -> A0 Arduino, Pin10 -> Masse, Pin11 -> +5V, Pin12 -> 5V, Pin13 – frei, Pin14 -> 5V

Arduino: Außer den Anschlüssen unter MCP42010 nur noch 5 Volt und Masse, um die Arduino mit Strom zu versorgen.

Ansteuerung des MCP42010

Auszug Datenblatt MCP42010Wie im Datenblatt auf Seite 18 zu sehen, muss CS (PIN 10) für die Dauer der Übertragung auf Low gesetzt werden.
Für die Übertragung werden 2 Bytes gesendet.
Als erstes ein Steuerbyte, in dem die Operation (Schreiben) und der Pot (das gewünschte der beiden Potentiometer) angegeben wird.
Schreiben in Potentiometer 1 -> B00010001 und in Potentiometer 2 -> B00010010
Als zweites Byte wird der Wert übertragen, den das ausgewählte Potentiometer annehmen soll.
Anbei ein Minimal Beispiel, wie in das Potentiometer 1 (Pot0) der Wert 127, also ca. Mittelstellung geladen wird.

//minimal Example to set the Pot0 of a MCP42010 to the value 127 
#include 
void setup() {
  // take the CS pin low to select the chip:
  digitalWrite(10,LOW);
  //  send in the address and value via SPI:
  SPI.transfer(B00010001);
  // write out the value 127
  SPI.transfer(127);
  // take the CS pin high to de-select the chip:
  digitalWrite(10,HIGH);
}
 
void loop() {
 
}

Das Programm zur ‚komfortablen‘ Ansteuerung der 2 Potentiometer des MCP42010

Die Bedienung ist sehr einfach gehalten, wie auch schon im Video oben zu sehen war. Ich übergebe Werte an das digitale Potentiometer und werte die resultierende Spannung an den analogen Eingängen A0 und A1 aus.
Für die Dateneingabe und -Ausgabe nutze ich den Seriellen Monitor der Arduino IDE.

Eingabe:
1:Wert von 0-255 -> setzt Potentiometer1 auf den Wert und gibt die Spannung an A0 zurück
2:Wert von 0-255 -> setzt Potentiometer2 auf den Wert und gibt die Spannung an A1 zurück
s -> gibt Werte beide Potentiometer und die Spannungen an A0 und A1 zurück

// inslude the SPI library:
#include 
 
// set pin 10 as the slave select for the digital pot:
const int slave_Select_Pin  = 10;
const int analogInPin0      = A0; 
const int analogInPin1      = A1; 
String    inputString       = "";         // a string to hold incoming data
boolean   stringComplete    = false;      // whether the string is complete
int       level1            = 0;
int       level2            = 0;
 
void setup() {
     inputString.reserve(100);
     // set the slaveSelectPin as an output:
     pinMode (slave_Select_Pin, OUTPUT);
     Serial.begin(9600);
 
     // initialize SPI:
     SPI.begin();
     MSP42010PotWrite(slave_Select_Pin, B00010001, level1);
     MSP42010PotWrite(slave_Select_Pin, B00010010, level2);
}
 
void loop() {
  if (stringComplete) {
    //check ob R1:
    if (inputString.substring(0, 2) == "1:") {
      level1 = inputString.substring(2).toInt();
      MSP42010PotWrite(slave_Select_Pin, B00010001, level1);     
      printValues(level1, analogInPin0);
    }
    //check ob R2:
    if (inputString.substring(0, 2) == "2:") {
      level2 = inputString.substring(2).toInt();
      MSP42010PotWrite(slave_Select_Pin, B00010010, level2); //Datasheet Page 18
      printValues(level2, analogInPin1);
    }
    //check ob s
    if (inputString.substring(0, 1) == "s") {
      printValues(level1, analogInPin0);
      printValues(level2, analogInPin1);
    }
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}
 
void MSP42010PotWrite(int slaveSelectPin, byte address, int value) {
     // take the SS pin low to select the chip:
     digitalWrite(slaveSelectPin,LOW);
     //  send in the address and value via SPI:
     SPI.transfer(address);
     SPI.transfer(value);
     // take the SS pin high to de-select the chip:
     digitalWrite(slaveSelectPin,HIGH);
}
void printValues(int level, int aPin) {
      delay(5);
      int pot = 0;
      if (aPin == 15) {
        pot = 1;
      }
      Serial.print("level Pot");
      Serial.print(pot);
      Serial.print(": ");
      Serial.print(level);
      Serial.print(" Spannung an A");
      Serial.print(pot);
      Serial.print(": ");
      double sl = analogRead(aPin);
      sl = sl * 5 / 1024; 
      Serial.print(sl);
      Serial.println(" Volt");  
}
/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */
void serialEvent() {
  while (Serial.available()) {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    } else {
      inputString += inChar;
    }
  }
}
Kategorien
Raspberry Pi

Raspberry Pi – Serielle Schnittstelle (RS232) nutzen

Die Raspberry Pi ist mit vielen Schnittstellen ausgestattet.
Mit dem USB Port lassen sich die Möglichkeiten diesbezüglich mehr als potenzieren.
Um mit meinen AVR Mikrocontrollern zu kommunizieren ist am besten eine serielle Schnittstelle geeignet.

Natürlich hat die Raspberry Pi Eine, aber leider nur als Pins auf der GPIO Steckerleiste.
Die benötigten Pins könnten theoretisch direkt mit dem Mikrocontroller z.B. ATMega8 verbunden werden.
Das würde aber voraussetzen, dass der Mikrocontroller mit 3,3 Volt arbeitet.
Mein Pollin Evaluationsboard arbeitet aber mit 5 Volt, bringt aber eine fertige RS232 Schnittstelle zur Kommunikation mit PC’s oder sonstigen Gerätschaften mit.
Am einfachsten wäre es, die Pi hätte ebenso eine RS232 Schnittstelle.
Beim Googlen habe ich dann die Seite Serial Port Add On gefunden.
Das dort beschriebene Serial Port to TTL Digital Converter Module, habe ich mir bei Ebay gekauft.

GPIO Header Pins
RaspberryPI_GPIO_serielle_Schnittstelle
2 4 6 8 10 12 14 16 18 20 22 24 26
1 3 5 7 9 11 13 15 17 19 21 23 25
1= 3.3V, 9= GND, 8= TX, 10= RX

Die Jumper Kabel zum Anschluss an die Raspberry Pi wurden mitgeliefert.
Ich habe das Modul, wie im Bild dargestellt mit der Pi verbunden.

Um die serielle Schnittstelle ans Laufen zu bekommen müssen noch die /etc/inittab und die /boot/cmdline.txt angepasst werden.

/etc/inittab

  • Auskommentieren der Zeile ‚T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100‘
#Spawn a getty on Raspberry Pi serial line
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

/boot/cmdline.txt

  • Löschen von: dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait
dwc_otg.lpm_enable=0 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait

Bilder meiner PI inklusive ’serieller Schnittstelle‘

RaspberryPI_mit_serieller_Schnittstelle_VS RaspberryPI_GPIO_serielle_Schnittstelle1_VS RaspberryPI_GPIO_serielle_Schnittstelle2_VS RaspberryPI_GPIO_serielle_Schnittstelle3_VS RaspberryPI_GPIO_serielle_Schnittstelle4_VS

Video, zur Demonstration

Das Video kommt bereits bei meinem ‚Hello World Beispiel‘ im ATMega8 Bereich meiner Webseite zum Einsatz.
Ich habe dafür ein kleines Perl Script geschrieben.
Sicherlich wäre es auch mit Programmen wie minicom gegangen, aber da hätte ich mich auch erst mal wieder einarbeiten müssen.
Das Script ging schneller und ist am Ende des Tages flexibler.

Kategorien
ATMega8

ATMega8 – Registerinhalte auf dem Mikrocontroller über serielle Schnittstelle steuern

Pollin_Board_klein
Wie im Beispiel Hello World über serielle Schnittstelle senden und im Beispiel LED’s des Pollin Evaluationboards über die serielle Schnittstelle steuern dargestellt, ist es recht einfach möglich Buchstaben oder Bytes zu einem PC zu übertragen und auch anders herum vom PC aus Schaltzustände zu verändern.
Die neue Herausforderung ist es nun Registerinhalte via serieller Schnittstelle zu füllen und Diese wieder auszulesen.

Gedacht ist die Übung als Vorbereitung für eine interne Systemuhr auf dem ATMega8, die von einem PC oder z.B. auch der Raspberry Pi gestellt und abgelesen werden kann.

PollinBoard_ATMega8_Registerinhalte_per_UART_steuern_und_ausgeben_Ablaufplan_VSWie im Ablaufplan (Bild links) dargestellt, habe ich das Programm so strukturiert, dass

  • im Hauptprogramm die Variablen initialisiert werden und der Interrupt sobald ein Byte über RX/UART empfangen wird, aktiviert ist
  • Das Unterprogramm IncommingByte entscheidet, ob es sich um ein Aktives, oder Neues Unterprogramm handelt und ruft ein weiteres Unterprogramm FunctionCall auf, was an das aktive oder gewählte Unterprogramm weiterleitet.
  • Das Unterprogramm StelleUhr, wird durch das Senden eines Bytes mit dem Inhalt 1 aufgerufen und erwartet das danach 3 weitere Bytes als Inhalt für die Register Stunde, Minute und Sekunde via RX/UART übergeben werden. Diese werden in den Registern gespeichert.
  • Das Unterprogramm Sende Uhrzeit, wird mit einem Byte mit Inhalt 2 aufgerufen und sendet 3 Byte mit den Inhalten Stunde, Minute und Sekunde zurück an den PC.

Der hier abgebildete Assemblercode ist mit vielen Kommentaren versehen.

Quellcode des Assemblerprogramms:

; avrdude -p m8 -c stk500v2 -P /dev/ttyACM0 -U flash:w:Registerinhalte_via_UART_steuern_und_ausgeben.hex
; 13.9.2013 Das Programm soll Registerinhalte per serielle Datenübertragung manipulieren können und diese auch wieder ausgeben
.NOLIST
;.INCLUDE "/home/henry/Dokumente/Mikrocontroller/AVR-Assembler/AVR_Definitionsfiles/m8def.inc"
.INCLUDE "m8def.inc"
.LIST
;
.def Sekunde                = R2
.def Minute                 = R3
.def Stunde                 = R4
;--------------------------------
.def temp                   = R16               ; Register 16 der Variable temp zuweisen 
.def ByteNummer             = R17               ; Enthält die Nummer des aktuell übertragenen Bytes innerhalb eine Unterprogramms
.def aktivesUnterprogramm   = R19               ; Enthält die numerische ID des aktuell aktiven Unterprogamms
.def EmpfRXByte             = R20               ; Enthält das zuletzt via. UART empfangene Byte 
 
.equ F_CPU = 16000000                           ; Systemtakt in Hz
.equ BAUD  = 9600                               ; Baudrate
 
; Berechnungen
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     ; Reale Baudrate
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
 
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
.endif
 
; Startvektoren 
.org 0x00
    rjmp main
.org URXCaddr                                   ; Interruptvektor für UART-Empfang
    rjmp IncommingByte
 
; --------------------------------Hauptprogramm--------------------------------------
main:
 
    ; Stackpointer initialisieren
    ldi     temp, HIGH(RAMEND)
    out     SPH, temp
    ldi     temp, LOW(RAMEND)
    out     SPL, temp
 
    ; Baudrate einstellen
    ldi     temp, HIGH(UBRR_VAL)
    out     UBRRH, temp
    ldi     temp, LOW(UBRR_VAL)
    out     UBRRL, temp
 
    ; Frame-Format: 8 Bit
    ldi     temp, (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0)     out     UCSRC, temp     sbi     UCSRB, RXCIE                        ; Interrupt bei Empfang     sbi     UCSRB, RXEN                         ; RX (Empfang) aktivieren          sei                                         ; Interrupts global aktivieren loop:     rjmp    loop                                ; Endlosschleife / idle mode ; ---------------------------ENDE Hauptprogramm-------------------------------------- ; ---------------------------IncommingByte------------------------------------------- ; Interruptroutine: wird ausgeführt sobald ein Byte über das UART empfangen wurde IncommingByte:     in      EmpfRXByte, UDR                     ; empfangenes Byte lesen,                                                 ; dadurch wird auch der Interrupt gelöscht     cpi     aktivesUnterprogramm, 1             ; vergleich aktivesUnterprogramm mit 1     brge    UPAufruf                            ; ist aktivesUnterprogramm > 0, springe zu UPAufruf
    mov     aktivesUnterprogramm, EmpfRXByte    ; kopiere EmpfRXByte in aktivesUnterprogramm
    clr     ByteNummer                          ; setze ByteNummer aud 0
 
UPAufruf:
    rcall   FunctionCall                        ; rufe Unterprogramm FunctionCall auf
EndIncommingByte:
    reti                                        ; Interrupt beenden
; ----------------------Ende-IncommingByte-------------------------------------------
 
; ---------------------------FunctionCall--------------------------------------------
; Abfrage aktivesUnterprogramm und Aufruf der entsprechenden Unterprogramme
FunctionCall:
    cpi     aktivesUnterprogramm, 1
    breq    Byte1                               ; Wenn eine 1 übertragen wurde zu Byte1 springen 
    cpi     aktivesUnterprogramm, 2
    breq    Byte2                               ; Wenn eine 2 übertragen wurde zu Byte2 springen 
    rjmp    EndFunctionCall                     ; zum Unterprogramm - Ende (Es wurde kein Wert der einem gültigem Unterprogarmm entspricht übertragen.)
 
Byte1:
    rcall   StelleUhr                           ; StelleUhr aufrufen
    rjmp    EndFunctionCall                     ; zum Unterprogramm - Ende
Byte2:
    rcall   SendeUhrzeit                        ; SendeUhrzeit aufrufen
    rjmp    EndFunctionCall                     ; zum Unterprogramm - Ende
EndFunctionCall:
    ret                                         ; Ende - zurück springen
; ----------------------Ende-FunctionCall--------------------------------------------
 
; ---------------------------StelleUhr-----------------------------------------------
StelleUhr:
    cpi     ByteNummer, 1                       ; vergleich ByteNummer mit 1
    breq    StelleSekunde                       ; ist ByteNummer = 1, springe zu StelleSekunde
 
    cpi     ByteNummer, 2                       ; vergleich ByteNummer mit 2
    breq    StelleMinute                        ; ist ByteNummer = 2, springe zu StelleMinute
 
    cpi     ByteNummer, 3                       ; vergleich ByteNummer mit 3
    breq    StelleStunde                        ; ist ByteNummer = 3, springe zu StelleStunde
 
    rjmp    ErhoeheByteNummer                   ; springe zu ErhoeheByteNummer
 
StelleSekunde:
    mov     Sekunde, EmpfRXByte                 ; Kopiere EmpfRXByte in Sekunde
    rjmp    ErhoeheByteNummer                   ; spinge zu ErhoeheByteNummer
 
StelleMinute:
    mov     Minute, EmpfRXByte                  ; Kopiere EmpfRXByte in Minute
    rjmp    ErhoeheByteNummer                   ; spinge zu ErhoeheByteNummer
 
StelleStunde:
    mov     Stunde, EmpfRXByte                  ; Kopiere EmpfRXByte in Stunde
    clr     aktivesUnterprogramm                ; setze aktivesUnterprogramm auf Null, wir sind fertig mit Uhr stellen :-)
    rjmp    EndStelleUhr                        ; spinge zu EndStelleUhr
 
ErhoeheByteNummer:
    inc     ByteNummer                          ; erhöhe ByteNummer um 1
EndStelleUhr:
    ret                                         ; Ende - zurück springen
; ----------------------Ende-StelleUhr-----------------------------------------------
 
; ---------------------------SendeUhrzeit--------------------------------------------
SendeUhrzeit:
    cbi     UCSRB, RXEN                         ; RX (Empfang) deaktivieren
    sbi     UCSRB, TXEN                         ; TX (Senden) aktivieren
 
Sekunde_wait:
    sbis    UCSRA,UDRE                          ; Warten bis UDR für das nächste Byte bereit ist
    rjmp    Sekunde_wait                        ; Springe zurück zu Sekunde_wait, solange UDR noch nicht bereit ist
    out     UDR, Sekunde                        ; sende das Byte Sekunde via UART
 
Minute_wait:
    sbis    UCSRA,UDRE                          ; Warten bis UDR für das nächste Byte bereit ist
    rjmp    Minute_wait                         ; Springe zurück zu Minute_wait, solange UDR noch nicht bereit ist
    out     UDR, Minute                         ; sende das Byte Minute via UART
 
Stunde_wait:
    sbis    UCSRA,UDRE                          ; Warten bis UDR für das nächste Byte bereit ist
    rjmp    Stunde_wait                         ; Springe zurück zu Stunde_wait, solange UDR noch nicht bereit ist
    out     UDR, Stunde                         ; sebnde das Byte Stunde via UART
 
    cbi     UCSRB, TXEN                         ; TX (Senden) deaktivieren
    sbi     UCSRB, RXEN                         ; RX (Empfang) aktivieren
    clr     aktivesUnterprogramm                ; setze aktivesUnterprogramm auf Null, wir sind fertig mit Uhrzeit ausgeben :-)
EndSendeUhrzeit:
    ret                                         ; Ende - zurück springen
; ----------------------Ende-SendeUhrzeit--------------------------------------------

 

Video, zur Demonstration

 

Eigenbau Wooden Generator 1 – Experiment 2 mit Gleichrichter

Wooden Generator 1 mit Gleichrichter

Aufbauend auf Wooden Generator Experiment 1 wurde die Schaltung jetzt um einen Brückengleichrichter erweitert.

Hierfür habe ich BAT48 Schottky Dioden verwendet, da diese nur 0,2 Volt verbrauchen.
Als stabilisierendes Element kommt ein 1000 μF Elektrolytkondensator dazu.
Der puffert das ganze ein wenig und die LED sollte etwas länger und stabiler leuchten.
Mit einer kleinen LED als Verbraucher erhalte ich bei schnellen Drehzahlen einen Strom von ca. 5 mA und eine Spannung von ca. 1,7 Volt.
Errechnet ergibt das eine stolze Leistung von 8,5 Milliwatt.
Es ist also noch reichlich Luft nach oben :-)

Wooden Generator Schaltplan Experiment 2 Wooden Generator Versuchsaufbau Exeperiment 2

Das folgende Video gibt einen kurzen Eindruck von der doch recht dürftigen Ausbeute.

https://youtube.com/watch?v=SH9jxq0oGrw%26hl%3Den%26fs%3D1

Wooden Generator 1 – Experiment 1



Da nicht wie ursprünglich geplant nur eine positive Halbwelle erzeugt wird, sondern ein richtiger Wechselstrom wie unter Wooden Generator 1 bereits beschrieben, reagiere ich auf die für mich simpelste Weise darauf.
LED’s verbrauchen wenig Strom. Es kommt ja auch (noch) relativ wenig :-)
Also die positive Halbwelle bringt eine LED zum leuchten und die Negative eine entgegengesetzt Gepolte.

Schaltplan Experiment 1 Versuchsaufbau Experiment 1

Das folgende Video gibt einen Eindruck wie lang und wie stark die LED’s leuchten.

Kategorien
ATMega8

ATMega8 – LED 1 und 2 über Taster T1 und T2 schalten

Pollin_Board_kleinDie meisten elektronischen Geräte / Schaltungen / Projekte müssen in irgendeiner Form auf Eingaben reagieren.
Sei es wie hier dargestellt auch ’nur‘ auf einen Taster.
Das Pollin Board bietet mehrere Taster, LED’s, einen Piepser und weitere Hardware zum ansteuern.


In diesem Beispiel wird die LED1 und 2 über Taster 1 und 2 angesteuert.

Wie in der Grafik zu erkennen, sind alle LED’s und Taster mit dem PortD verbunden.
PollinBoard_ATMega8_Taster_LED_Beispiel_Vorschau

Für dieses Beispiel werden keine weiteren Bauteile rund um das Evaluationsboard benötigt.

Der hier abgebildete Assemblercode ist mit vielen Kommentaren versehen.
Ich habe den Source auf Grundlage dieser Beispiele von Mikrocontroller.net aufgebaut.

Quellcode des Assemblerprogramms:

; avrdude -p m8 -c stk500v2 -P /dev/ttyACM0 -U flash:w:LED1_und_2_mit_Taster1_und_2.hex
; 9.8.2013 Das Programm soll sobald der Taster1 gedrückt wurde, die LED1 an bzw. ausschalten und
; sobald der Taster2 gedrückt wurde, die LED2 an bzw. ausschalten
; Das Programm ist zum grossen Teil aus 
; http://www.mikrocontroller.net/articles/AVR-Tutorial:_IO-Grundlagen
; übernommen. Dort gibt es noch viel weitere Infos und Tipps
.NOLIST
;.INCLUDE "/home/henry/Dokumente/Mikrocontroller/AVR-Assembler/AVR_Definitionsfiles/m8def.inc"
.INCLUDE "m8def.inc"
.LIST
 
.def temp 	= R16
 
.equ Taster1 	= PD2
.equ Taster2 	= PD3
.equ LED1 	= PD5
.equ LED2 	= PD6
 
; Port D, LED Pins auf Ausgang und Taster Pins auf Eingang schalten
 
	ldi	temp, (1<<LED1) | (1<<LED2)							
	out	DDRD, temp					; LED1/2 Pollin Evaluationsboard ,, PD5/6 auf Ausgang schalten	
 
Tastenabfrage:
	sbic	PIND, Taster1
	rjmp 	LED1Schalten					; Wenn Taster1 auf High (gedrückt), dann rufe LED1Schalten
	sbic	PIND, Taster2
	rjmp 	LED2Schalten					; Wenn Taster2 auf High (gedrückt), dann rufe LED2Schalten
	rjmp	Tastenabfrage					; zurück zur Tastenabfrage
 
LED1Schalten:
T1entprellen:
	sbic	PIND, Taster1					; loope solange der Taster1 nicht wieder losgelassen wurde
	rjmp 	T1entprellen
	sbic	PORTD, LED1					; überspringe die nächste Instruktion, wenn die LED1 ausgeschaltet ist
	rjmp	LED1ausschalten
LED1einschalten:	
	sbi	PORTD, LED1					; Setze das LED1 Bit in PORTD
	rjmp	EndeLED1schalten				; springe zu EndeLED1schalten
LED1ausschalten:
	cbi	PORTD, LED1					; Lösche das LED1 Bit in PORTD
EndeLED1schalten:	 
	rjmp 	Tastenabfrage					; zurück zum Hauptprogramm
 
LED2Schalten:
T2entprellen:
	sbic	PIND, Taster2					; loope solange der Taster2 nicht wieder losgelassen wurde
	rjmp 	T2entprellen
	sbic	PORTD, LED2					; überspringe die nächste Instruktion, wenn die LED2 ausgeschaltet ist
	rjmp	LED2ausschalten
LED2einschalten:	
	sbi	PORTD, LED2					; Setze das LED2 Bit in PORTD
	rjmp	EndeLED2schalten				; springe zu EndeLED2schalten
LED2ausschalten:
	cbi	PORTD, LED2					; Lösche das LED2 Bit in PORTD
EndeLED2schalten:	 
	rjmp 	Tastenabfrage					; zurück zum Hauptprogramm

 

Video, zur Demonstration

 

Kategorien
Messen - Steuern - Regeln

Drehzahlmessung und Datenerfassung durch Videobeweis

Die Idee entstand beim Versuch zu ermitteln, was aus meinem Kreissägeblatt Scheibengenerator für eine Leistung kommen könnte.

Das Sägeblatt, also der Stator mit den Neodym – Magneten liegt auf einem Drehteller, der eigentlich unter einen Fernseher oder ähnliches gehört und wird per Hand angeschoben. Ein typischer Versuchsaufbau im Heimbereich eben.

Die Spulen für die Stromerzeugung, werden auch per Hand in die Richtung der Magneten geführt, was dafür sorgt, keine Hand mehr frei zu haben.

Ich kann nun punktgenau ablesen wie viel Spannung über einem Verbraucher (kleine Lämpchen) anliegt und wie viel Strom fließt. Daraus ist es einfach auf die abgegebene Leistung zu schließen.
Leider aber nur Pi mal Daumen.
Aussagen wie: Wenn ich schnell drehe, dann Leistung 1, wenn langsam, dann Leistung 2, sind möglich. Unbefriedigend.

Selbst wenn ich nun einen Drehzahlmesser zusätzlich ins Spiel bringe, wird es nicht einfach den Stator anzuschieben, die Spulen zu halten, die Werte punktgenau zur selben Zeit abzulesen.

Die Idee:

  • Sägeblatt an einer Stelle markieren, um eine Umdrehung gut nachvollziehen zu können.
  • Die Versuchsanordnung so aufbauen, dass eine Videokamera das Sägeblatt und die Messgeräte aufnehmen kann.

Das Video zur Idee:

Bemerkungen:

  • geeignet für Drehzahlen unter 300 U/min, da eine normale Videokamera nur 25 Bilder pro Sekunde aufnimmt.
  • Außer der Videokamera, werden nur noch 2 Vielzweckmessgeräte benötigt, die meist bereits vorhanden sind.
  • Das Ergebnis ist verblüffend. Ich kann damit direkt vergleichen, ob eine Änderung im Aufbau sich so auswirkt, wie ich es gern hätte.
  • Die Auswertung ist jederzeit wiederholbar. Habe ich erst mal das Video, kann ich es auch später auswerten.

Eigenbau Vertikalachsen Windrad – Lenz 2 Turbine – selfmade VAWT

selfmade VAWT

Auf diesen Seiten werde ich in der nächsten Zeit den Aufbau eines Vertikal Achsen Windrades dokumentieren. Bisher habe ich hier immer fleißig mitgeloggt, wenn ich daran gearbeitet habe.

Detaillierte Informationen:

Als ersten Eindruck hier mal ein Video, was das Windrad in Betrieb zeigt.

Es handelt sich um ein Vertikal – Achsen – Windrad nach dem Vorbild eines Lenz2.

Kategorien
Messen - Steuern - Regeln

002 – automatisierte Verbrauchsgenerierung und Messung

Intro:

Wie bereits im Artikel Manuelle Verbrauchsgenerierung und -Messung dargestellt, möchte ich die Menge der Energie, welche die kleine Solarzelle liefert beziffern können.

Die manuelle Messung hat sich als nicht praktikabel erwiesen. So ist es z.B. Voraussetzung vor Ort zu sein. Scheint die Sonne also stark wenn ich im Urlaub bin, schaltet der Laderegler ab und weg ist er, der Ertrag. Auch ein Grund, warum ich im sonnigen Halbjahr soviel verschenkt habe. Die bisher gemessene Leistung habe ich auf der Seite 10 Kilowattstunden in 2012 zusammengefasst.

Ein paar Bilder vom ‚Messgerät‘ und dem Aufbau der Versuchsanlage:

Video:

Zielstellung:

  • Die Batterie soll immer einen gewissen Ladezustand halten, der für Aktivitäten wie Rasen trimmen oder andere diverse Elektrogeräte in der Garage benötigt wird.
  • Die Solarzellen sollen nicht leer laufen. Das heißt, dass alles was die Sonne bringt umgesetzt werden soll und wenn es auch erst einmal nur über die 26 Watt Glühlampe verbraucht wird.
  • Die Lampe soll dementsprechend ein- oder ausgeschaltet werden, um die überschüssige Energie zu verbrauchen
  • Die Anzahl der Minuten ( 10 Minutenintervalle), die die Lampe bereits eingeschaltet war soll via. Bluetooth auf dem Handy angezeigt werden.

Ablaufschema Der entsprechenden Logik:

Quellcode meines Assemblerprogramms:

;Pollin Board Stromverbrauchsgenerator und Messeinheit mit ATMega8
;Ausgabe via UART
.NOLIST
.INCLUDE "m8def.inc"
.LIST
;
; Henry Koch 5.8.2012
;
.def vierSekunden       = r1
.def Ladewert           = r2
.def IntervallCounter   = r3
;----------------------------
.def temp               = r16                   ; Register für kleinere Arbeiten
.def zeichen            = r17                   ; in diesem Register wird das Zeichen an die
                                                ; Ausgabefunktion übergeben
.def count              = r18
.def temp1              = r19
.def temp2              = r20
.def sync1              = r21
.def sync2              = r22
;
;.def messungen  = r23
.equ Schwellwert = 212                          ; 212 entspricht ca. 13,3 Volt bei meinem Spannungsteiler
.equ F_CPU = 4000000                            ; Systemtakt in Hz
.equ BAUD  = 9600                               ; Baudrate
;
; Berechnungen
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     ; Reale Baudrate
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
;
.if ((BAUD_ERROR>10) || (BAUD_ERROR Ende
serout_string_wait:
    sbis    UCSRA,UDRE                          ; Warten bis UDR für das nächste
                                                ; Byte bereit ist
    rjmp    serout_string_wait
    out     UDR, r0
    adiw    zl:zh,1                             ; Zeiger erhöhen
    rjmp    serout_string                       ; nächstes Zeichen bearbeiten
serout_string_ende:
    ret                                         ; zurück zum Hauptprogramm
;
; Umwandlung in Dezimalzahlen
;**********************************************************************
;
; Eine 8 Bit Zahl ohne Vorzeichen ausgeben
;
; Übergabe:      Zahl im Register temp1
; veränderte Register: keine
;
lcd_number:
    push    temp1                               ; die Funktion verändert temp1 und temp2,
    push    temp2                               ; also sichern wir den Inhalt, um ihn am Ende
                                                ; wieder herstellen zu können
 
    mov     temp2, temp1                        ; das Register temp1 frei machen
                                                ; abzählen wieviele Hunderter
                                                ; in der Zahl enthalten sind
 
;** Hunderter **
    ldi     temp1, '0'-1                        ; temp1 mit ASCII '0'-1 vorladen
lcd_number_1:
    inc     temp1                               ; ASCII erhöhen (somit ist nach dem ersten
                                                ; Durchlauf eine '0' in temp1)
    subi    temp2, 100                          ; 100 abziehen
    brcc    lcd_number_1                        ; ist dadurch kein Unterlauf entstanden?
                                                ; nein, dann zurück zu lcd_number_1
    subi    temp2, -100                         ; 100 wieder dazuzählen, da die
                                                ; vorherhgehende Schleife 100 zuviel
                                                ; abgezogen hat
    rcall   lcd_data                            ; die Hunderterstelle ausgeben
;** Zehner  **
    ldi     temp1, '0'-1                        ; temp1 mit ASCII '0'-1 vorladen
lcd_number_2:
    inc     temp1                               ; ASCII erhöhen (somit ist nach dem ersten
                                                ; Durchlauf eine '0' in temp1)
    subi    temp2, 10                           ; 10 abziehen
    brcc    lcd_number_2                        ; ist dadurch kein Unterlauf enstanden?
                                                ; nein, dann zurück zu lcd_number_2
    subi    temp2, -10                          ; 10 wieder dazuzählen, da die
                                                ; vorherhgehende Schleife 10 zuviel
                                                ; abgezogen hat
           rcall lcd_data                       ; die Zehnerstelle ausgeben
 
;** Einer **
    ldi     temp1, '0'                          ; die Zahl in temp2 ist jetzt im Bereich
    add     temp1, temp2                        ; 0 bis 9. Einfach nur den ASCII Code für
    rcall   lcd_data                            ; '0' dazu addieren und wir erhalten dierekt
                                                ; den ASCII Code für die Ziffer
 
    pop     temp2                               ; den gesicherten Inhalt von temp2 und temp1
    pop     temp1                               ; wieder herstellen
    ret                                         ; und zurück
 
lcd_data:
    mov     zeichen, temp1
    loop1:
    rcall   serout                              ; Unterprogramm aufrufen
    rcall   sync
    brne    loop1                               ; solange die Null nicht erreicht ist springe zur loop
    ret
 
my_Schwellwert:     .db "ges. SchwellWert:  ",0
my_Ladewert:        .db "akt. Ladewert:  ",0
my_Intervalle:      .db "Anz. 10 Min. Int.: ",0
my_10MinIntervall:  .db "**10 Min. Int. **",10,0

Schaltplan und technische Details:

Das Pollin Board ist an der Stelle des ATMega8 Prozessors mit einem 4 MHZ Quarz bestückt.
Das ist so, weil der Stromverbrauch des Prozessors so niedriger ist und die 16 MHZ für die Anwendung absolut nicht erforderlich sind.
Das hat den Haken, dass die Baud Rate für die Kommunikation via UART nicht riesig sein kann. Aber 9600 Baud sind vollkommen ok.

Die Relaiseinheit zum schalten der 26 Watt Glühbirne und die Bluetoothkarte ist von Ebay

Die 5V Stromversorgung für das Pollin Board und die Relais Steuereinheit wurde mit einem handelsüblichen KFZ – USB Adapter realisiert.

Wünsche an eine verbesserte Version:

  • Stromzuführung für das Bluetooth Modul mit Taster des Pollin Boards steuern
  • UART Kommunikation in der Programmlogik nur aktiv betreiben, wenn das Bluetooth Modul angeschaltet ist
  • Es sollte ein Tageswechsel erkennbar sein, z.B. Start eines neuen Counters, mit jedem neuen Tag und Ausgabe einer Counterliste
  • Die 10 Minuten AUS Intervalle sind ungünstig. Möglicherweise ist der Ladezustand schon während der 10 Minuten wieder erreicht, bzw. geht so hoch, dass der Laderegler abschaltet. Habe ich am 9.8.2012 beobachtet!
  • normales Relais durch SSR tauschen und dementsprechend ansteuern
  • bessere Stabilisierung der Spannung, so dass die Messwerte nicht so sehr schwanken
  • den Spannungsteiler evtl. mit einer 10 Volt Zehnerdiode realisieren