AdSense

Sonntag, 27. Oktober 2013

Arduino-Code auf dem ATmega 1284P

(English version) Um Arduino-Code auf dem ATmega 1284P auszuführen muss man lediglich ein paar kleine Schritte durchführen. Zuerst muss das folgende Archiv heruntergeladen werden:
https://github.com/maniacbug/mighty-1284p/zipball/master
Der Inhalt wird dann nach C:\Program Files (x86)\Arduino\hardware\mighty-1284p entpackt (bzw. in den entsprechenden Ordner, je nachdem wohin die Entwicklungsumgebung installiert wurde). Anschließend startet man die Entwicklungsumgebung neu und kann unter Board auch schon den 1284 auswählen. Ich benutze Original Mighty 1284p 16MHz. Die Pin-Belegung ist nun natürlich auch anders und zwar wie folgt (Die Zahl in Klammern ist für den Arduino relevant):

                      +---\/---+
           (D 0) PB0 1|        |40 PA0 (AI 0 / D24)
           (D 1) PB1 2|        |39 PA1 (AI 1 / D25)
      INT2 (D 2) PB2 3|        |38 PA2 (AI 2 / D26)
       PWM (D 3) PB3 4|        |37 PA3 (AI 3 / D27)
    PWM/SS (D 4) PB4 5|        |36 PA4 (AI 4 / D28)
      MOSI (D 5) PB5 6|        |35 PA5 (AI 5 / D29)
  PWM/MISO (D 6) PB6 7|        |34 PA6 (AI 6 / D30)
   PWM/SCK (D 7) PB7 8|        |33 PA7 (AI 7 / D31)
                 RST 9|        |32 AREF
                VCC 10|        |31 GND
                GND 11|        |30 AVCC
              XTAL2 12|        |29 PC7 (D 23)
              XTAL1 13|        |28 PC6 (D 22)
      RX0 (D 8) PD0 14|        |27 PC5 (D 21) TDI
      TX0 (D 9) PD1 15|        |26 PC4 (D 20) TDO
RX1/INT0 (D 10) PD2 16|        |25 PC3 (D 19) TMS
TX1/INT1 (D 11) PD3 17|        |24 PC2 (D 18) TCK
     PWM (D 12) PD4 18|        |23 PC1 (D 17) SDA
     PWM (D 13) PD5 19|        |22 PC0 (D 16) SCL
     PWM (D 14) PD6 20|        |21 PD7 (D 15) PWM
                      +--------+

Donnerstag, 24. Oktober 2013

RGB-LED mit ATmega16A ansteuern

(English version) RGB-LEDs sind ziemlich interessant (z.B. in LED-Streifen oder ähnlichem). Daher möchte ich heute erklären, wie man mit einem ATmega16A eine RGB-LED ansteuert. Zuerst einmal zur RGB-LED. Ich benutze diese LED von Tayda Electronics. Diese LED besteht praktisch aus drei verschiedenen LEDs welche alle in einem Gehäuse sind. Daher gibt es 3 Pins für die verschiedenen LEDs und eine gemeinsame Kathode (-). Legt man nun PWM-Signale an diese 3 Pins, so kann man die Farbe der LED einstellen. Den ATmega16A benutze ich, da der ATmega8 nur 2 PWM-Kanäle hat, das reicht leider nicht für 3 Pins. Damit ist eigentlich auch alles geklärt, hier mal der Code von mir, welcher durch den kompletten Farbkreis läuft:

#include <avr/io.h>
#define F_CPU 16000000UL
#include <util/delay.h>

int main(void)
{
  DDRA = 0xFF;//Output
  DDRD = 0xFF;
  ICR1 = 256;
  TCCR2 = (1<<WGM20) | (1<<COM21) | (1<<CS20); // PWM, phase correct, 8 bit.
  TCCR1A = (1<<WGM10) | (1<<COM1A1) | (1<<COM1B1); // PWM, phase correct, 8 bit.
  TCCR1B = (1<<CS10);// | (1<<CS10); // Prescaler 64 = Enable counter, sets the frequency
  double rCounter = 255;
  double rMax=255;
  double bCounter = 255;
  double bMax = 180;
  double gCounter = 0;
  double gMax = 70;
  int stages = 0;
  while(1)
  {
    switch (stages)
 {
   case 0:
     bCounter --;
     if (bCounter <= 0)
  {
    stages = 1;
  }
  break;
      case 1:
     gCounter ++;
     if (gCounter >= 255)
  {
    stages = 2;
  }
  break;
   case 2:
     rCounter --;
     if (rCounter <= 0)
  {
    stages = 3;
  }
  break;
   case 3:
     bCounter ++;
     if (bCounter >= 255)
  {
    stages = 4;
  }
  break;
   case 4:
     gCounter --;
     if (gCounter <= 0)
  {
    stages = 5;
  }
  break;
   case 5:
     rCounter ++;
     if (rCounter >= 255)
  {
    stages = 0;
  }
  break;
 }
 OCR1B = (int)(bCounter*bMax*bCounter/255/255);
 OCR1A = (int)(gCounter*gMax*gCounter/255/255);
 OCR2 = (int)(rCounter*rMax*rCounter/255/255);

 _delay_ms(5);
  }

}

Dienstag, 8. Oktober 2013

C# - Alle Dateien in Ordner und Unterordnern anzeigen

(English version) Alle Dateien in einem Ordner auszulesen ist recht simpel (siehe dazu auch C# Tipps und Tricks). Will man das rekursiv machen ist das auch nicht weiter schwer. Der Code, welchen ich dafür benutze ist der folgende:

var allfiles = System.IO.Directory.GetFiles(
  @"C:\YourFolder",  
  "*.*"
  System.IO.SearchOption.AllDirectories);

foreach (string file in allfiles) {}

Um dieses Ergebnis nun weiter zu filtern kann man ein .Where hinten anhängen, im folgenden Code werden also nur Audio-Dateien zurückgegeben:

var allfiles = System.IO.Directory.GetFiles( 
  @"C:\YourFolder"
  "*.*"
  System.IO.SearchOption.AllDirectories).Where(
    s => s.EndsWith(".mp3") || 
    s.EndsWith(".wav") || 
    s.EndsWith(".wma"));  

foreach (string file in allfiles) {}

Montag, 7. Oktober 2013

LCD Display mit Arduino / ATmega

(English version) Ich habe mir dieses LCD-Modul gekauft und diesen I2C-Controller dafür. In diesem Post werde ich erklären, wie man nun Text auf das Display schreiben kann. Zuerst benötigt man die LiquidCrystal_I2C Library von hier. (Ich habe einfach die neueste Version genommen). Nun kann man auch schon direkt in der Arduino-Entwicklungsumgebung anfangen. Zuerst die Includes:

#include <Wire.h>
#include <LCD.h>
#include <LiquidCrystal_I2C.h>

Als nächstes müssen einige Sachen definiert werden, die in der Library nicht ganz für das LCD-Modul passen:

#define I2C_ADDR    0x20

#define BACKLIGHT_PIN  3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7

#define  LED_OFF  1
#define  LED_ON  0

Nun muss das Display definiert werden:

LiquidCrystal_I2C  lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

Als nächstes fängt man in der setup()-Funktion an. Zuerst sagt man dem Programm um was für ein Display es sich handelt (also die Größe, ich benutze ein 20 x 4 Zeichen Display).

  lcd.begin (20,4);
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  lcd.setBacklight(LED_ON);

Den Rest benötigt man, damit man mit lcd.backlight(); die Beleuchtung anschalten kann. Danach wird das LCD-Display resettet:

  lcd.clear();
  delay(1000);
  lcd.home();

Nun kann man Sachen auf das Display schreiben. Das geht so:

  lcd.print("Hello, world!");

Um den Cursor an eine Stelle zu setzen macht man folgendes:

  lcd.setCursor(5,1);

Damit sollten die grundsätzlichen Funktionen geklärt sein. Um alles zu löschen ruft man einfach lcd.clear(); auf.

Noch ein kleiner Hinweis, dieses Problem bereitete mir am Anfang viel Kopfzerbrechen: Programmiert man einen ATmega und steckt ihn dann direkt in ein Steckbrett, so funktioniert meistens gar nichts, der ATmega braucht einen Reset, nachdem er im Steckbrett steckt. Das liegt vermutlich daran, dass der ATmega schon losläuft auch wenn nur ein paar Pins mit dem Steckbrett verbunden sind.

Sonntag, 29. September 2013

Raspberry PI - C++ - Socket öffnen

(English version) Heute will ich einen kleinen Post zum Thema Socket öffnen in C++ schreiben. Der Grund dafür ist, dass mein Raspberry PI vieles ansteuert, ausliest, etc. Das dann alles über Dateien zu regeln ist keine so schöne Lösung, daher will ich direkt über das Netzwerk mit dem Raspberry PI reden können. Dafür muss am Raspberry PI ein Netzwerk-Socket aufgemacht werden. Vieles von dem Code habe ich einfach aus anderen Quellen übernommen, da ich ja nur das Empfangen und Senden der Nachricht benötige. Außerdem habe ich die Nachrichtenlänge auf 256 Bytes festgesetzt. Das Ganze geht folgendermaßen:

//define variables 
int sockfd, newsockfd, portno = 82; //number of port
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n; 
 
//create socket 
sockfd = socket(AF_INET, SOCK_STREAM, 0);

bzero((char *) &serv_addr, sizeof(serv_addr));

serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);

bind(sockfd, (struct sockaddr *) &serv_addr,
        sizeof(serv_addr));
listen(sockfd,5);
clilen = sizeof(cli_addr); 
 
//accept tcp clients 
while(true)
{
  //accept client 
  newsockfd = accept(sockfd, 
            (struct sockaddr *) &cli_addr, 
            &clilen); 
  bzero(buffer,256);
  //read client message into buffer
  n = read(newsockfd,buffer,256);
  //write message to client
  n = write(newsockfd,"I got your message, this should be 256 bytes long",256);

  close(newsockfd);
}
close(sockfd);

Freitag, 27. September 2013

Raspberry PI - C++ - Threads

(English version) Threads in C# zu implementieren ist total einfach. Will man jedoch auf dem Raspberry PI soetwas mit C++ haben, so muss man ein paar Kleinigkeiten beachten. Ein Thread wird folgendermaßen erzeugt und gestartet, #include <thread> muss ganz oben stehen.

std::thread networkThread (networkCommunication);
networkThread.detach();


Zum Compilieren müssen jetzt aber noch zwei Optionen angegeben werden, sonst funktioniert das nicht:

-std=c++0x
-pthread


Das ganze Programm wird dann wie folgt compiliert:

g++ ./myProgram.c++ -o outputName -std=c++0x -pthread

Damit kann mann dann auch am Raspberry PI Threads erzeugen und lustige Sachen damit machen.

Dienstag, 24. September 2013

Einfluss der Corioliskraft auf ein Scharfschützen-Projektil

(English version) Vor einiger Zeit sah ich den Film Shooter (Wikipedia). Recht am Anfang wird über einen Schuss aus 1,5 km Entfernung gesprochen. Dabei wird auch erwähnt, dass bei diesem Schuss sogar die Corioliskraft eine Rolle spielt. Das will ich heute hier durchrechnen.

Zuerst eine kurze Einführung zum Thema Corioliskraft. Die Corioliskraft zählt zu den sogenannten Scheinkräften, welche in rotierenden Bezugssystemen auftritt. Die Kraft lässt sich recht einfach herleiten, indem man die Bewegungsgleichungen eines freien Teilchens in ein rotierendes Koordinatensystem transformiert (siehe dazu auch z.B. H.-R. Trebin, Theoretische Physik 1, Mechanik). Für meine Rechnung ist dies jedoch nicht vonnöten. Anschaulich erklärt tritt die Kraft auf, weil sich die Erde unter dem Geschoss weiterdreht.

Kommen wir zur Rechnung. Um eine maximale Wirkung der Corioliskraft zu haben gehe ich davon aus, dass der Schuss entlang eines Längengrades ausgeführt wird. Geht man von einem Breitengrad von etwa 45° aus, so ist das Ziel etwa 1 km weiter von der Rotationsachse der Erde entfernt, daher bewegt sich das Ziel senkrecht zur Flugbahn etwas schneller als das Projektil. Nun will ich diese beiden Geschwindigkeiten berechnen. Der Erd-Durchmesser ist etwa 12 730 km. Im 45. Breitengrad entspricht das einem Radius von ziemlich genau 4500 km, also einem Umfang von 28274 km. Das führt bei einer Umlaufzeit von 86400 Sekunden zu einer Geschwindigkeit von 327,245 m/s. Vergrößert sich der Radius nun um 1 km, so ist der neue Umfang 28281 km und die neue Geschwindigkeit 327,326 m/s. Das macht eine Differenz von 0,081 m/s.

Im Film wird von etwa 6-10 Sekunden Flugzeit gesprochen, das würde 0,5 bis 0,8 Metern Abweichung vom Ziel entsprechen. Ich persönlich schätze die Flugzeit jedoch etwas anders, ein Geschoss mit 1000 m/s braucht für die Strecke nur 1,5 Sekunden, das macht dann immerhin 12 cm aus (was bereits über Treffer oder nicht Treffer entscheiden kann).

Real Time Clock DS1307

(English Version) Manchmal benötigt man bei Arduino-Projekten die aktuelle Uhrzeit oder das aktuelle Datum - z.B. wenn man einen Datenlogger bauen möchte. Eine Möglichkeit wäre natürlich, Arduino-intern eine softwarebasierte Uhr zu programmieren. Das hat jedoch den Nachteil, dass es Rechenzeit verbraucht. Der viel größere Nachteil ist jedoch, dass die Uhrzeit verloren ist, wenn der Arduino von der Versorgungsspannung getrennt wird. Die Uhrzeit müsste also bei jeder Inbetriebnahme neu eingestellt werden. Eine Lösung bieten hier Real-Time-Clock-Module wie das "Tiny RTC". Es arbeitet mit einem DS1307-IC und hat eine Stützbatterie, läuft also auch dann weiter, wenn der Arduino nicht mehr unter Strom steht.

Der DS1307 wird über I2C angesprochen - der Anschluss des Moduls an den Arduino ist also denkbar einfach: einfach SDA und SCL mit den entsprechenden Pins am Arduino verbinden sowie die Betriebsspannung anlegen. Wichtig ist dabei, dass die Anschlüsse auf der rechten Seite (also der Seite mit den 7 Pins) verwendet werden. Die Pins auf der anderen Seite dienen zum Anschluss des EEPROM-Chips, der ebenfalls auf dem Modul verbaut ist.
Auf der rechten Seite gibt es noch einen Pin zum Zugriff auf die Batterie-Spannung (BAT) sowie den Pin SQ. Der IC kann ein Rechtecksignal erzeugen, das hier abgegriffen werden kann. Darauf werde ich aber nicht näher eingehen. Auf dem Modul kann außerdem ein Temperatursensor vom Typ DS18B20 aufgelötet werden. Auf den Sensor könnte mit dem letzten verbleibenden Pin DS zugegriffen werden. Aber auch hierauf werde ich in diesem Beitrag nicht weiter eingehen.

Der IC kann Datum und Uhrzeit (Jahr, Monat, Tag, Wochentag, Stunde, Minute, Sekunde) ausgeben. Die Werte werden in einem SRAM-Register gespeichert und können von dort über I2C ausgelesen werden. Das Register ist wie folgt aufgebaut:
In den Bits 0 bis 6 des Registers 0 sind die Sekunden gespeichert, das Bit 7 CH gibt an, ob die Uhr aktiv ist oder nicht. Wird das Bit auf 1 gesetzt, wird der Takt angehalten und die Uhrzeit wird nicht mehr weiter gezählt. Ist das Bit gelöscht, läuft der Takt und somit auch die Uhr weiter.
Die Bits 0 bis 6 des Registers 1 enthalten die Minuten.
Die Stunden werden im Register 2 gespeichert. Ist das Bit 6 des Registers gesetzt, werden die Stunden im 12h-Format angegeben, das Bit 5 gibt dabei AM(low)/PM(high) an. Ist Bit 6 gelöscht, können die Stunden (wie für Europäer gewohnt) im 24h-Format ausgelesen werden.
Register 3 enthält den aktuellen Wochentag - dabei entspricht 1 Sonntag, 2 Montag usw.
In den Registern 4 bis 6 werden Tag, Monat und Jahr gespeichert.
Register 7 dient zur Konfiguration des Rechtecksignal-Generators. Die restlichen Register können als batteriegestützer RAM verwendet und frei beschrieben werden.

Die Zahlen werden im BCD-Format (Binary Coded Decimal) ausgegeben. Dabei geben die Bits 0 bis 3 eines Bytes die Einer und die restlichen Bits die Zehner einer Zahl aus. Die Zahl 18 wäre somit also 0001'1000, die Zahl 34 entspräche 0011'0100 und so weiter.

Der DS1307 kann über die Adresse 0x68 im I2C-Bus angesprochen werden.

Bei der ersten Inbetriebnahme des Moduls muss die Uhrzeit eingestellt werden.
#include "Wire.h"

#define DS1307_ADDRESS 0x68

void setup(){
  Wire.begin();
    
  Serial.begin(9600);
  
  byte second =      0; //0-59
  byte minute =      44; //0-59
  byte hour =        22; //0-23
  byte weekDay =     1; //1-7
  byte monthDay =    22; //1-31
  byte month =       9; //1-12
  byte year  =       13; //0-99

  Wire.beginTransmission(DS1307_ADDRESS);
    
  Wire.write(0x00); //Pointer auf Register 0
  
  Wire.write(decToBcd(second));
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));
  Wire.write(decToBcd(weekDay));
  Wire.write(decToBcd(monthDay));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));

  Wire.endTransmission();
  
}

void loop(){
}

byte decToBcd(byte val){
//Dezimal in BCD konvertieren
  return ( (val/10*16) + (val%10) );
}

In den Variablen kann die aktuelle Uhrzeit bzw. das Datum eingestellt werden. Mit dem Befehl beginTransmission() wird dann die Übertragung zum Modul gestartet. Dzu wird der Pointer auf das Register 0 (das mit den Sekunden) gesetzt. Nun können Uhrzeit und Datum übertragen werden. Dazu werden die in den Variablen gespeicherten Werte zuerst vom Dezimal- ins BCD-Format konvertiert und dann mit write() ins Register des ICs geschrieben. Nach dem write()-Befehl springt der Arduino automatisch zum nächsten Register.

Ist der IC einmal richtig eingestellt, zählt er munter bis ans Ende aller Tage (bzw. bis ans Ende der Batterie) die Zeit hoch und kann jederzeit mit folgenden Befehlen ausgelesen werden:

#include "Wire.h"
#define DS1307_ADDRESS 0x68

void setup(){
  Wire.begin();
  Serial.begin(9600);
}

void loop(){
  
  //Pointer auf Register 0 setzen
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();

  //Zeit abfragen
  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read());
  int weekDay = bcdToDec(Wire.read());
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());

  //Datum ausgeben im Format dd.mm.yy - hh:mm:ss
  Serial.print(monthDay);
  Serial.print(".");
  Serial.print(month);
  Serial.print(".");
  Serial.print(year);
  Serial.print(" - ");
  Serial.print(hour);
  Serial.print(":");
  Serial.print(minute);
  Serial.print(":");
  Serial.println(second);
  delay(1000);
}

byte bcdToDec(byte val)  {
//BCD in Dezimal konvertieren
  return ( (val/16*10) + (val%16) );
}

In der loop() wird zuerst der Pointer auf das Register 0 gesetzt (wir wollen als erstes die Sekunden auslesen), dann werden mit dem Befehl requestFrom() aus diesem und den folgenden Registern 7 Bytes angefordert. Diese werden dann mit dem read()-Befehl empfangen, vom BCD- ins Dezimal-Format konvertiert und zum Schluss über die serielle Schnittstelle ausgegeben.

Mittwoch, 18. September 2013

ATMega - Alles um den Faktor 8 langsamer?

(English version) Genau dieses Problem trat bei mir auf: Ich habe einen ATMega 1284-P welcher mit einem 16 MHz Quarz läuft. Allerdings lief alles um den Faktor 8 zu langsam. Die Fuses (Ich benutze AVR Studio 4, da sieht man nicht alles) waren alle korrekt eingestellt. Nach einiger Zeit auf Google kam ich endlich auf die Lösung: Das Fuse-Bit CKDIV8 ist 0, also wird die Clock durch 8 geteilt. Leider kann man auf dieses Fuse-Bit im AVR Studio 4 nicht direkt zugreifen, es gibt jedoch eine recht einfache Möglichkeit, den Clock Divider auszuschalten:

#include <avr/power.h> 

Und dann direkt am Anfang vom Programm:

clock_prescale_set(clock_div_1);

Damit war bei mir das Problem dann behoben.

Dienstag, 17. September 2013

Musikplayer - Handy-Fernsteuerung

(English version) Wie in diesem Post beschrieben habe ich einen eigenen Musikplayer mit C# und WPF geschrieben. Da es bei größeren Wiedergabelisten durchaus vorkommen kann, dass einem mal ein Lied nicht gefällt, gibt es Hotkeys für den PC. Was ist aber, wenn man gerade gemütlich auf dem Bett liegt und man keine Lust hat, aufzustehen? Dafür habe ich eine App geschrieben, mit welcher man die grundlegenden Hotkeys (Play/Pause, nächstes Lied, vorheriges Lied) ausführen kann. Diese App kann man hier herunterladen.

Zur Verwendung der App: Die App kann man einerseits starten und dann auf die entsprechenden Buttons klicken, es gibt jedoch auch ein Widget, welches den Klick zum App Öffnen spart. Die App bietet jedoch mehr Funktionen, sogar das suchen nach einem Lied ist möglich.

In der App muss man nun IP, Port (Der Player macht standardmäßig einen Socket auf Port 7200 auf) und Passwort (welches man im Player mit F2 festlegen kann) eingeben. Dabei kann die IP lokal sein (z.B. wenn das Handy im selben Netzwerk ist wie das Handy) oder auch eine Internet-IP. Dafür muss man jedoch am Router noch eine entsprechende Port-Weiterleitung einrichten. Das Handy kann den Player in diesem Fall unabhängig davon steuern, ob es im WLAN oder im mobilen Netzwerk ist.

Montag, 16. September 2013

Android - Anwendungsdaten schreiben

(English version) Viele Android-Apps belegen einen gewissen (meist recht geringen) Speicherplatzt für "Daten". Diese Daten sind z.B. zum Speichern von Passwörtern oder ähnlichem nützlich. Ich will nun erklären, wie man auf diese Daten zugreifen kann. Zuerst kommt das Lesen:

SharedPreferences sharedPref = this.getPreferences(Context.MODE_PRIVATE);
String defaultStringValue = "";
String stringValue = sharedPref.getString("nameOfString", defaultStringValue);


Dies ist also analog zu einem C#-Dictionary mit einem String als Key und (hier) einem String als Value. Als Value kann jedoch auch ein Integer benutzt werden, die Syntax ist analog dazu. Existiert dieser Key nicht, so wird defaultStringValue zurückgegeben.

Nun zum Schreiben:

SharedPreferences sharedPref = this.getPreferences(Context.MODE_PRIVATE);
String stringValue = "asdf";
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("
nameOfString", stringValue);
editor.commit();


Hier kann natürlich auch Int analog dazu verwendet werden. Außerdem können viele editor.put...-Befehle direkt hintereinander stehen und erst am Ende muss das editor.commit(); stehen. Damit sollte der grundlegende Zugriff auf Anwendungsdaten geklärt sein. Falls man von einem Widget aus auf Anwendungsdaten zugreifen will, muss man SharedPreferences benutzen. Was sich im Code ändert ist dann:

SharedPreferences sharedPref = this.getSharedPreferences("nameOfPreferences", 0);

Mittwoch, 11. September 2013

Pin Change Interrupt mit dem ATMega oder Arduino

(English version) Viele Microcontroller (z.B. ein ATMega 168) haben nicht nur einige externe Interrupts sondern auch sogenannte Pin Change Interrups. Diese Interrupts funktionieren auf allen Kanälen. Die Grundidee ist: Wenn sich an einem Kanal was ändert wird eine Interrupt-Funktion aufgerufen. Allerdings ist das hier nicht so bequem wie mit "normalen" Interrupts, man bekommt nämlich nicht gesagt, welcher Kanal sich verändert hat und man kann auch nicht einstellen, auf welche Flanke der Interrupt warten soll, wann immer sich etwas bei einem Kanal ändert wird die Interrupt-Funktion aufgerufen.

Ich beschreibe nun am ATMega168 wie das genau aussieht. Ich benutze die Kanäle PB0, PD5..7 als Interrupt-Kanäle. Um nun die Interrupts anzuschalten gehe ich folgendermaßen vor:

PCICR |= (1 << PCIE0)|(1 << PCIE2);

Das schaltet die Interrupts für PCINT0 und PCINT2 an, also für PORTB und PORTD. Nun muss man die Kanäle definieren, welche diese Interrupts auslösen sollen:

PCMSK0 |= (1 << PCINT0);
PCMSK2 |= (1 << PCINT23)|(1 << PCINT22)|(1 << PCINT21);


Nun muss man nur noch die Interrupts anschalten (sei();). Benutzt man die Arduino-Entwicklungsumgebung, so geschieht all dies in der setup-Funktion. Als nächstes gibt es die Funktionen, welche aufgerufen werden, wenn die Interrupts ausgelöst werden. Diese müssen folgendermaßen heißen:

ISR(PCINT2_vect)
{
}


und

ISR(PCINT0_vect)
{
}


Um nun herauszufinden, welcher Kanal einen Interrupt hatte, kann man die Kanäle auslesen und nachschauen ob sich etwas verändert hat. Oder wenn man einfach 4 Schalter über Interrupts abfragen will, so kann man auslesen welcher Schalter gedrückt wurde:

int Button0 = digitalRead(8); 
int Button1 = digitalRead(7); 
int Button2 = digitalRead(6);  
int Button3 = digitalRead(5);

Montag, 9. September 2013

Vergleich verschiedener Leuchtmittel

(English version) Heute möchte ich einige Leuchtmittel, welche als Zimmerbeleuchtung dienen könnten, vergleichen. Die Kandidaten sind:
a) Eine "alte" Halogenlampe
b) Eine spiralförmige Energiesparlampe (Link)
c) Eine COB-LED (Link)

Zuerst die Spezifikationen:
a) Leistung: 40 W
Lichtstrom: 390 Lum
Leuchtdauer: 2 000 h
Preis: 2 €

b) Leistung: 23 W
Lichtstrom: 1 550 Lum
Leuchtdauer: 10 000 h
Preis: 8 €

c) Leistung: 7 W
Lichtstrom: 560 Lum
Leuchtdauer: >10 000 h (keine Angabe auf Pollin.de, vermutlich jedoch 25 000 h)
Preis: 6 € (Mit Kühlkörper, die LED an sich nur 3 €)

Der erste Vergleichspunkt ist natürlich: Wie viel Licht bekommt man bei welcher Leistung? Ich gebe hier die Werte in Lum/W an:
a) 10
b) 67
c) 80
Dass hier die LED und die Energiesparlampe gewinnen, ist klar.

Nun aber zum nächsten Punk: Was kostet so eine Lampe überhaupt? Bzw. wie viel Licht bekommtn man pro Euro? Hier die Werte in Lum/€ an:
a) 195
b) 194
c) 95
Hier verliert die LED, da sie einfach für die erbrachte Leistung teurer ist als die anderen Lampen.

Als entscheidenden Vergleichspunkt will ich nun ein Zimmer mit den entsprechenden Lampen 5 Jahre lang beleuchten. Geht man von 5000 Lum aus und einer Brenndauer von 6 Stunden pro Tag, so sind das im Jahr ganz grob 2000 Stunden. Von den einzelnen Lampen bräuchte man etwa:
a) 13
b) 3
c) 9
Berücksichtigt man die Lebensdauer, so müssen alle Halogenlampen jedes Jahr getauscht werden, während die Energiesparlampen und die LEDs alle 5 Jahre durchstehen. Das erhöht die Kosten für die Halogenlampen um den Faktor 5. Die Anschaffungskosten für die Lampen betragen in Euro:
a) 128
b) 26
c) 53
allerdings muss bei der LED berücksichtigt werden, dass die Hälfte der Kosten für den Kühlkörper sind. Als nächstes nun der Stromverbrauch:
a) 1026 kWh
b) 148 kWh
c) 125 kWh
Geht man von 20 ct / kWh aus, so kommt man auf Kosten für 5 Jahre in Euro:
a) 205
b) 30
c) 25

Am günstigsten ist also die Energiesparlampe. Jedoch muss bei der LED beachtet werden: Die Anschaffungskosten sind eigentlich nur halb so hoch wegen den Kühlkörpern, ebenfalls hält eine LED vermutlich deutlich länger als eine Energiesparlampe, sodass auf längere Sicht die LED vorne liegt, da sie außerdem noch einen etwas geringeren Stromverbrauch hat. Dass die Halogenlampe überhaupt nicht mitreden kann sollte klar sein.

LED Zimmerbeleuchtung - selbst gemacht

(English version) Bei Pollin gibt es seit einiger zeit sogenannte COB-LEDs (Pollin). Das Tolle an diesen LEDs ist, dass sie nichts an Vorwiderständen oder ähnlichem brauchen sondern einfach eine Spannungsquelle (bei mir ist das ein Laptop-Netzteil mit 24V) und ein Kühlkörper, welchen es auch bei Pollin gibt.
Mit 560 lm ist die LED ziemlich hell, ich werde in einem separaten Post einige Leuchtquellen vergleichen. Was an LED-Leuchtquellen sehr gut ist: Sie sind effektiv und laufen lange, daher wird die Zukunft vielleicht den LED-Lampen gehören. Das einzige Problem, welches es bei dieser LED gibt ist, dass sie auf relativ kleiner Fläche sehr hell ist und daher sogar als eventuell gefährlich für das Auge gilt. Daher musste ich mir einen Lampenschirm basteln. Getan habe ich dies aus Pergamin (Butterbrotpapier). Die Bastelanleitung ist auch ganz einfach, man sollte lediglich beachten, dass b > a/2 sein muss, sonst gibt es ein Loch in der Mitte:
An den roten Kanten wird eingeschnitten. Danach an den senkrechten gestrichelten Linien um 90° geknickt, sodass das Papier einen geschlossenen Zylinder ergibt. Dann werden die Laschen oben noch umgeknickt und es ergibt sich eine Art "Eimer", welcher über die Lampe gestülpt werden kann. Das Endergebnis sieht dann so aus:

Sonntag, 8. September 2013

SD-Karten mit dem Arduino beschreiben und auslesen

Wer seinen Arduino als Datenlogger nutzt, um z.B. einen Temperaturverlauf auf zu zeichnen, steht schnell vor dem Problem, wie die erfassten Daten gespeichert werden sollen. Natürlich könnte man alle Daten irgendwie in einem Array speichern und dann per serielle Schnittstelle an den PC übertragen. Doch hier ist der Speicher begrenzt und fällt einmal der Strom aus, sind die Daten futsch. Außerdem benötigt man zusätzliche Software, um die Daten von der seriellen Schnittstelle in Empfang zu nehmen und aus zu werten. Das Problem mit dem flüchtigen Speicher könnte man umgehen, wenn man die Daten im EEPROM des Arduinos speichert - doch auch hier ist der Speicherplatz und vorallem die Zahl der Schreibzyklen begrenzt. Auch das Problem mit der Übertragung bleibt bestehen.

Am Besten speichert man seine Daten daher auf einer Speicherkarte. Hier sind die Daten auch bei Stromausfall sicher gespeichert, außerdem lässt sich die Speicherkarte direkt mit dem PC verbinden und auslesen. Wenn man die Daten im richtigen Format speichert, kann man sie auch gleich mit Excel, Matlab oder ähnlichen Programmen auswerten.

Hardware

Bei Ebay gibt es SD-Karten-Module bereits für einen Euro. Ich habe mich für das Modul von LC Technology entschieden:
Die Pinbelegung ist klar ersichtlich. Neben Pins für die Spannungsversorgung (+5V, +3,3V und GND) gibt es Pins für den SPI-Bus, mit dem auf die Speicherkarte zugegriffen werden kann. Die Pins sind zwar zweireihig angeordnet, die obere und die untere Reihe sind aber jeweils intern verbunden. SD-Karten arbeiten mit einem Spannungspegel von 3,3V. Das Modul kann wahlweise mit 3,3V oder mit 5V versorgt werden. Im letzteren Fall bringt ein eingebauter Spannungswandler die Spannung automatisch auf 3,3V. Die SPI-Pins werden allerdings NICHT gewandelt, sie dürfen also auch NICHT direkt mit dem Arduino verbunden werden - sonst wird die SD-Karte gegrillt. Hier muss also ein Pegelwandler zwischen geschaltet werden.

Der fertige Aufbau sieht so aus:



Das Modul wird über den 5V-Ausgang vom Arduino versorgt. Die SPI-Pins werden über den Pegelwandler wie folgt mit dem Arduino verbunden:
MOSI an Pin 11
MISO an Pin 12
SCK an Pin 13
CS an Pin 4

Ich habe einen bi-direktionalen Wandler genommen und lasse alle Pins über den Wandler laufen. Beides ist streng genommen nicht nötig. Theoretisch reicht auch ein Pegelwandler, der nur in eine Richtung von 5V auf 3,3V wandelt (z.B. den 74HC4050). Über diesen Wandler laufen dann nur die Pins MOSI, SCK und CS. Der MISO-Pin kann direkt mit dem Arduino verbunden werden.

Ist alles richtig verkabelt, kann die SD-Karte in das Modul gesteckt werden. Der Arduino kann mit SD-Karten im Format FAT16 und FAT32 umgehen, laut Arduino-Referenz wird FAT16 allerdings bevorzugt.

Software

Die SD-Library für Arduino liefert einige Beispiele, mit der die Funktion des Aufbaus gleich getestet werden kann. Ich habe mich für das Beispiel "Datalogger" entschieden. Im Beispiel werden die Werte der drei analogen Eingänge in einer txt-Datei auf der Karte gespeichert.

#include <SD.h>

const int chipSelect = 4;

void setup()
{
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
  
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");
}

void loop()
{
  // make a string for assembling the data to log:
  String dataString = "";

  // read three sensors and append to the string:
  for (int analogPin = 0; analogPin < 3; analogPin++) {
    int sensor = analogRead(analogPin);
    dataString += String(sensor);
    if (analogPin < 2) {
      dataString += ","; 
    }
  }

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  }  
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  } 
}

In der setup()-Funktion wird zuerst eine serielle Verbindung aufgebaut, mit dem Befehl SD.begin(chipSelect) wird dann die SD-Karte initialisiert. Als Parameter wird hier der Pin übergeben, an dem CS angeschlossen ist. War die Initialisierung erfolgreich, geht es in den loop()-Funktion weiter. Hier werden die Werte der analogen Eingänge ausgelesen und in einer String-Variable gespeichert . Mit dem Befehl SD.open() wird dann die Datei "datalog.txt" im Schreib-Modus geöffnet.  Ist das Öffnen erfolgreich, wird der Wert der String-Variable in die Datei geschrieben. Dann wird die Datei wieder geschlossen.

Ähnlich einfach ist das Auslesen von Dateien.

  dataFile = SD.open("test.txt");
  if (dataFile) {
    Serial.println("test.txt:");
    
    // read from the file until there's nothing else in it:
    while (dataFile.available()) {
     Serial.write(dataFile.read());
    }
    // close the file:
    data.close();
  } else {
   // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }

 Auch hier muss zuerst wieder die Datei mit dem open()-Befehl geöffnet werden. Wurde die Datei erfolgreich geöffnet, kann sie mit dem Befehl read() Zeile für Zeile ausgelesen werden, bis das Ende der Datei erreich wurde. Dies wird mit dem Befehl available() überprüft. Abschließend wird die Datei mit dem close()-Befehl wieder geschlossen.

Freitag, 6. September 2013

C# - Globale Hotkeys, welche wirklich global sind

(English version) Mein Musikplayer benutzt Hotkeys. Diese funktionieren auch relativ gut. Leider nur relativ. Bei einigen Spielen (z.B. League of Legends) funktionieren die Hotkeys nicht mehr und man kann z.B. kein Lied mehr weiterschalten. Um dieses Problem zu beheben habe ich nach einer neuen Möglichkeit gesucht, globale Hotkeys zu implementieren. Schlussendlich habe ich eine Implementierung von meinem Freund von http://csharp-tricks.blogspot.de/ übernommen und sie etwas weiter entwickelt. Die Hotkeys sind nun eine eigene Klasse, welche folgendermaßen benutzt wird:

KeyHook MyHook = new KeyHook(this, KeyboardHookProcedure);
MyHook.Hook(KeyHook.KeyboardHookProc);

KeyHook.KeyPressed += KeyHook_KeyPressed;
KeyHook.KeyReleased += KeyHook_KeyReleased;


Die KeyHook_KeyPressed und KeyHook_KeyReleased Funktionen sehen folgendermaßen aus:

void KeyHook_KeyPressed(int keyCode, List<int> pressedKeys)
{}


keyCode ist einfach ein Integer, welcher Wert für welche Taste steht kann man hier nachlesen. Mehr gibt es zu diesen Hotkeys nicht zu sagen, die Events für KeyPressed und KeyReleased habe ich selber eingebaut, da es davor etwas unsauber gelöst wurde. Nun noch der Code der Klasse KeyHook:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace anyNamespace
{
    public class KeyHook
    {
        public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

        //Declare hook handle as int.
        static int hHook = 0;

        //Declare keyboard hook constant.
        //For other hook types, you can obtain these values from Winuser.h in Microsoft SDK.
        const int WH_KEYBOARD_LL = 13;

        public delegate void KeyPressedEventHandler(int keyCode, List<int> pressedKeys);
        public static event KeyPressedEventHandler KeyPressed;

        public delegate void KeyReleasedEventHandler(int keyCode, List<int> pressedKeys);
        public static event KeyReleasedEventHandler KeyReleased;

        [StructLayout(LayoutKind.Sequential)]
        private class keyboardHookStruct
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }

        //Import for SetWindowsHookEx function.
        //Use this function to install thread-specific hook.
        [DllImport("user32.dll", CharSet = CharSet.Auto,
         CallingConvention = CallingConvention.StdCall)]
        private static extern int SetWindowsHookEx(int idHook, HookProc lpfn,
        IntPtr hInstance, int threadId);

        //Import for UnhookWindowsHookEx.
        //Call this function to uninstall the hook.
        [DllImport("user32.dll", CharSet = CharSet.Auto,
         CallingConvention = CallingConvention.StdCall)]
        private static extern bool UnhookWindowsHookEx(int idHook);

        //Import for CallNextHookEx.
        //Use this function to pass the hook information to next hook procedure in chain.
        [DllImport("user32.dll", CharSet = CharSet.Auto,
         CallingConvention = CallingConvention.StdCall)]
        private static extern int CallNextHookEx(int idHook, int nCode,
        IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibrary(string lpFileName);

        //static Form1 View;
        static MainWindow mainWindow;

        const int MOD_SHIFT = 0x0004;

        IntPtr LL = (IntPtr)LoadLibrary("User32");

        public KeyHook(MainWindow _mainWindow, HookProc proc)
        {
            mainWindow = _mainWindow;
            Hook(proc);

        }

        ~KeyHook()
        {
            UnHook();
        }

        HookProc _proc;
        public int Hook(HookProc proc)
        {
            _proc = proc;
            hHook = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, LL, 0);
            return hHook;
        }

        public bool UnHook()
        {
            bool ret = UnhookWindowsHookEx(hHook);
            if (ret)
                hHook = 0;
            return ret;
        }

        public static List<int> pressedKeys = new List<int>();

        public static int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode < 0)
            {
                return CallNextHookEx(hHook, nCode, wParam, lParam);
            }
            else
            {
                keyboardHookStruct MyKeyboardHookStruct = (keyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(keyboardHookStruct));
                if ((MyKeyboardHookStruct.flags & 128) == 128)
                {
                    if (pressedKeys.Contains(MyKeyboardHookStruct.vkCode))
                    {
                        pressedKeys.Remove(MyKeyboardHookStruct.vkCode);
                        if (KeyReleased != null)
                        {
                            KeyReleased(MyKeyboardHookStruct.vkCode, pressedKeys);
                        }
                    }
                }
                if ((MyKeyboardHookStruct.flags & 128) == 0)
                {
                    if (!pressedKeys.Contains(MyKeyboardHookStruct.vkCode))
                    {
                        pressedKeys.Add(MyKeyboardHookStruct.vkCode);
                        if (KeyPressed != null)
                        {
                            KeyPressed(MyKeyboardHookStruct.vkCode, pressedKeys);
                        }
                    }
                }
                return CallNextHookEx(hHook, nCode, wParam, lParam);
            }
        }
    }
}

Montag, 2. September 2013

C# WPF - Invoken

(English version) Im vorigen Post taucht das Problem auf: Ich darf auf bestimmte Grafik-Sachen nur aus dem Haupt-Thread zugreifen. Dummerweise kann es jedoch immer vorkommen, dass man auch aus einem anderen Thread etwas tun will. Die Lösung dafür heißt: Invoken. Wie das geht zeige ich nun. Zuerst ein Beispiel, wie etwas nicht funktioniert:

void threadActivity()
{
    Thread.Sleep(5000);
    TaskbarItemInfo.ProgressValue = 0.2;
}


Sobald 5 Sekunden um sind wird ein Fehler auftreten: InvalidOperationException wurde nicht behandelt. Der aufrufende Thread kann nicht auf dieses Objekt zugreifen, da sich das Objekt im Besitz eines anderen Threads befindet. Wie schon angekündigt heißt die Lösung hierfür: Invoken. Der veränderte Code sieht nun folgendermaßen aus:

void threadActivity()
{
    Thread.Sleep(5000);
    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
    {
        TaskbarItemInfo.ProgressValue = 0.2;
    }));
}


Sobald nun 5 Sekunden um sind wird sich der Fortschrittsbalken in der Taskleiste auf den Wert 0.2 einstellen. Zur Syntax: alles in den inneren geschweiften Klammern wird im Haupt-Thread ausgeführt, innerhalb der Klammern kann man auf Variablen, auf welche man außerhalb der geschweiften Klammern zugreifen kann, auch zugreifen. Auch darf ruhig deutlich mehr als nur ein Befehl darin stehen (wobei es ratsamer ist, nur möglichst kurze Code-Bausteine zu invoken).

C# WPF - Fortschrittsbalken in der Taskleiste anzeigen

(English version) Bei Downloads mit dem Firefox unter Windows 7 wird in der Taskleiste ein Fortschrittsbalken angezeigt. Das selber zu realisieren ist total einfach. In dem entsprechenden Fenster muss

<Window.TaskbarItemInfo>
    <TaskbarItemInfo/>
</Window.TaskbarItemInfo>


eingefügt werden, direkt vor dem standartmäßigen <Grid>. Damit kann man nun auf TaskbarItemInfo zugreifen. Das sieht dann z.B. folgendermaßen aus:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();


        TaskbarItemInfo.ProgressState = System.Windows.Shell.TaskbarItemProgressState.Normal;
 
        Loaded += MainWindow_Loaded;
    }

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        TaskbarItemInfo.ProgressValue = 0.5;

    }
}


Man kann nun auch verschiedene ProgressStates benutzen, dementsprechend verändert der Fortschrittsbalken seine Farbe. Ebenfalls kann man über TaskbarItemInfo auch ein Symbol in der Taskleiste festlegen.

Will man all dies jedoch aus einem anderen Thread tun, so wird es nicht funktionieren. Warum das so ist erkläre ich in diesem Post. Hier nur schnell die Lösung dafür. Statt

TaskbarItemInfo.ProgressValue = 0.2

benutzt man einfach

Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
    TaskbarItemInfo.ProgressValue = 0.2;
}));

Android - Widget "stürzt ab" bei Drehung des Bildschirmes

(English version) Die genaue Fehlerbeschreibung ist: Ich habe ein Widget, wenn ich drauf klicke, möchte ich, dass sich die entsprechende App öffnet. Das funktioniert auch meistens. Manchmal passiert aber bei einem Klick überhaupt nichts, meistens nachdem der Bildschirm gedreht wurde. Schuld daran ist, dass bei manchen Sachen (z.B. Bildschirm drehen) die onUpdate-Funktion nicht aufgerufen wird, sondern lediglich die onReceive-Funktion. Da ich in der onUpdate-Funktion folgende Zeilen drin hatte

Intent intent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

remoteViews.setOnClickPendingIntent(R.id.button, pendingIntent);


wurde normalerweise die MainActivity gestartet. Nicht aber, wenn onReceive aufgerufen wurde. Daher musste ich in die onReceive-Funktion diese drei Zeilen mit hinein nehmen (intent habe ich in localIntent umbenannt, da onReceive als Parameter bei mir Intent intent hat). Danach funktioniert alles wunderbar.

Samstag, 31. August 2013

Beschleunigungssensor MPU-6050 mit ATMega 16A auslesen

(English version) Der Beschleunigungssensor MPU-6050 ist ziemlich vielseitig, klein und billig. Er kann mit bis zu 6 V betrieben werden und liefert Beschleunigungswerte und sogar Gyroskopwerte (also Drehung in Grad pro Sekunde). So ein Sensor ist also das ideale Kernstück für einen Quadrocopter.

In diesem Post möchte ich nun auch das Auslesen mit einem ATMega zeigen, da sich der Post mit dem Raspberry PI ziemlich großer Beliebtheit erfreut (http://physudo.blogspot.de/2013/07/beschleunigungssensor-mpu-6050-mit.html). Für I2C benutze ich am ATMega diese Implementierung: http://physudo.blogspot.de/2013/07/atmega-ic-master.html.

Zuerst einmal habe ich mir zwei Funktionen gebastelt, die entweder ein Register auslesen oder in ein Register reinschreiben:

void TWIM_WriteRegister(char reg, char value)
{
    TWIM_Start(addr, TWIM_WRITE); // set device address and write mode
    TWIM_Write(reg);
    TWIM_Write(value);
    TWIM_Stop();
}

char TWIM_ReadRegister(char reg)
{
    TWIM_Start(addr, TWIM_WRITE);
    TWIM_Write(reg);
    TWIM_Stop();

    TWIM_Start(addr, TWIM_READ); // set device address and read mode
    char ret = TWIM_ReadNack();
    TWIM_Stop();
    return ret;
}


Als nächstes möchte ich die Beschleunigung bzw. die Werte des Gyrometers auslesen. Zu beachten ist, dass zuerst der Sleep Mode deaktiviert werden muss, das geschieht mit TWIM_WriteRegister(107, 0). Zum auslesen der Werte habe ich mir wieder 2 Funktionen gebaut:

double MPU6050_ReadAccel(int axis)//x = 0; y = 1; z = 2
{
  char reg = axis * 2 + 59;
  char AFS_SEL = TWIM_ReadRegister(28);
  double factor = 1<<AFS_SEL;
  factor = 16384/factor;
  int val = 0;
  double double_val = 0;
  char ret = 0;

  ret = TWIM_ReadRegister(reg);
  val = ret << 8;

  ret = TWIM_ReadRegister(reg+1);  
  val += ret;

  if (val & 1<<15)
  val -= 1<<16;


   
  double_val = val;
 
  double_val = double_val / factor;

  return double_val;
}

double MPU6050_ReadGyro(int axis)//x = 0; y = 1; z = 2
{
  char reg = axis * 2 + 67;
  char FS_SEL = TWIM_ReadRegister(27);
  double factor = 1<<FS_SEL;
  factor = 131/factor;
  int val = 0;
  double double_val = 0;
  char ret = 0;

  ret = TWIM_ReadRegister(reg);
  val = ret << 8;

  ret = TWIM_ReadRegister(reg+1);  
  val += ret;

  if (val & 1<<15)
  val -= 1<<16;


  double_val = val;

  double_val = double_val / factor;

  return double_val;
}


Die Werte sind in Grad / Sekunde für das Gyrometer und in Einheiten von g für den Beschleunigungsmesser, mehr dazu gibt es auch in der Register Map, besonders bei der Erklärung von FS_SEL und AFS_SEL: http://www.invensense.com/mems/gyro/documents/RM-MPU-6000A.pdf

Donnerstag, 29. August 2013

Tageszeitabhängige Header-Grafik

Bei einer Homepage, die ich betreue, wollte ich in der Kopfzeile eine Header-Grafik haben, die sich je nach Tageszeit ändert (tagsüber ein Bild von einem Gebäude bei Tag, in der Nacht ein entsprechendes Bild des Gebäudes bei Nacht). Das lässt sich leicht mit PHP umsetzen:

Zuerst muss die aktuelle Uhrzeit erfasst und in einer Variable gespeichert werden:

$time = date("G", time())

Die Funktion time() liefert den aktuellen UNIX-Timestamp des Servers. Der UNIX-Timestamp ist die Anzahl der Sekunden seit dem 01.01.1979 um 1 Uhr - damit kann man also recht wenig anfangen. Daher kommt noch die Funktion date() zum Einsatz. Sie wandelt den Timestamp in ein verwertbares Format. Das genaue Format wird über den ersten Parameter der Funktion gewählt. Im Beispiel wird der Paramter "G" verwendet - es werden die vollen Stunden ohne führende Null angegeben. Möglich sind aber auch noch viele andere Formate wie Wochentag, Monat und so weiter. Alle möglichen Parameter sind auf dieser Seite zu finden.

Die aktuelle volle Stunde wurde also in der Varible $time gespeichert und kann nun weiter verwendet werden. Wichtig zu wissen ist, dass die Zeit in UTC (Weltzeit) angegeben wird - für MEZ oder MESZ müssten entsprechend 1 oder 2 Stunden addiert werden.

Nun kann anhand der aktuellen Zeit die passende Header-Grafik ausgewählt werden:

if ($time > 7 && $time < 21 ) {
   $pfad = "http://hierdiedomaindeservers.de/images/header_tag.jpg";
 }

else {
    $pfad = "http://hierdiedomaindeservers.de/images/header_nacht.jpg";
}

Ist die Stundenzahl größer als 7 und kleiner als 21 (ist es also zwischen 8:00 und 20:59), dann wird der Pfad der "Tag-Grafik" in der Variable $pfad gespeichert - sonst der Pfad der "Nacht-Grafik".

Zum Schluss wird die Grafik via HTML in der Homepage eingebunden:

<img src="<?php echo $pfad; ?>" width="123" height="456" alt="" />

Mit dieser Methode können natürlich nicht nur tageszeitabhängige sondern auch beispielsweise jahreszeitabhängige oder wochentagsabhängige Grafiken erzeugt werden.

Mittwoch, 28. August 2013

Arduino-Code auf dem ATtiny

Wer meine letzten Beiträge aufmerksam verfolgt hat weiß, dass ich gerade an einer Funkfernbedienung für meinen Rolladen arbeite. Für diesen Zweck ist der "normale" ATmega8 eher nicht geeignet (zu groß, 5V Betriebsspannung, teuer). Das Projekt soll also auf einem ATtiny basieren. Trotzdem möchte ich den gewohnten Komfort und die Libraries der Arduino-Entwicklungsumgebung nutzen. Wie man die Arduino IDE nutzen kann, um einen "nackten" ATmega8 zu programmieren, habe ich in meinem ersten Gastbeitrag hier beschrieben. Hierfür waren keine weitere Schritte nötig, da Arduino den ATmega8 von Haus aus unterstützt.
Für den ATtiny gilt das nicht, allerdings lässt sich die Arduino IDE mit wenigen Schritten mit dem ATtiny "vertraut" machen. Mit der folgenden Anleitung könnt ihr ATtiny45 und ATtiny85 sowie ATtiny24, ATtiny44 und ATtiny84 zur Arduino IDE hinzufügen.

Als erstes ladet ihr diese Datei herunter und entpackt sie. Den enthaltenen Ordner "attiny" kopiert ihr dann in den Ordner "hardware" eurer Arduino-Installation. Ihr solltet dann also z.B. folgende Ordnerstruktur haben: "C:\Programme\Arduino\hardware\attiny".

Der Ordner enthält eine Datei "boards.txt". Die Datei enthält alle Infos zu den verwendeten "Boards" - in diesem Fall natürlich nur ein "nackter" ATtiny. Dazu zählen Fuse-Einstellung, Taktfrequenz usw. Nur die in dieser Datei gelisteten "Boards" erscheinen nachher auch in der IDE. Die Datei enthält allerdings nur die Einstellungen für den Betrieb mit interner Taktquelle.

Natürlich könnte man den Tiny auch mit einer externen Taktquelle und entsprechendem Takt betreiben. Dann müsste eben ein weiterer passender Eintrag eingefügt werden.

Wichtig ist aber in jedem Fall, dass die Fuses für die Taktfrequenz am ATtiny auch entsprechend richtig eingestellt sind, sonst passt das Timing nicht!

Nun muss man der IDE natürlich noch die Pin-Belegung des ATiny beibringen. Dazu ist der Ordner "variants" mit den Unterordnern "tiny8" und "tiny14" enthalten. Sie enthalten jeweils die Datei "pins_arduino.h" in der die Pin-Belegung festgelegt ist. Der Datei kann auch entnommen werden, welcher Pin des ATtiny mit welchen Arduino-Funktionen belegt ist. Beim ATtiny24/44/84 wäre das z.B.
                                          +-\/-+
                                VCC  1|    |14  GND
                      (D 10)  PB0  2|    |13  AREF (D  0)
                       (D  9)  PB1  3|    |12  PA1  (D  1)
                                 PB3  4|    |11  PA2  (D  2)
    PWM  INT0  (D  8)  PB2  5|    |10  PA3  (D  3)
       PWM        (D  7)  PA7  6|    |9   PA4  (D  4)
       PWM        (D  6)  PA6  7|    |8   PA5  (D  5)        PWM
                                          +----+
Mit (D x) sind die entsprechenden Arduino-Pins bezeichnet.

Wenn die Arduino IDE nun gestartet wird, sollten unter Tools-Board die neu eingefügten ATtinys auftauchen:


Nun kann wie gewohnt programmiert werden. Je nach Funkstionsumfang des verwendeten ATtinys kann es natürlich Einschränkungen geben, z.B. bei den Interrups. Außerdem muss zum Programmieren ein Programmer wie z.B. der USBasp verwendet werden.

Die Anleitung gilt so im Prinzip auch für alle anderen ATtinys (und auch ATmegas) - man muss lediglich die passende "pins_arduino.h" auftreiben bzw. selber erstellen.

C# WPF - DataBinding

(English version) DataBindings in WPF sind ziemlich mächtig und nützlich. Heute will ich hier die Grundlagen beschreiben. Die Grundidee dahinter ist: Ich habe ein Anzeigeelement und eine Variable (eigentlich ein Feld). Wenn ich die Variable verändere, will ich, dass sich das Anzeigeelement ändert, umgekehrt will ich aber auch, dass sich bei Veränderung des Anzeigeelements (z.B. Texteingabe) die Variable ändert. Hier nun mal ein kleines Beispiel. Zuerst die XAML-Seite:

<TextBox Name="InputText" Grid.Row="0" Text="{Binding BindingText, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></TextBox>
<TextBlock Name="OutputText" Grid.Row="1" Text="{Binding BindingText, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"></TextBlock>


Als nächstes braucht man irgendein Objekt, an welches gebindet wird. Das ist bei mir die Klasse "AnyClass", welche das Feld "BindingText" enthält, man könnte jedoch auch genausogut einfach MainWindow.xaml.cs benutzen. Um jetzt das Objekt an welches gebindet wird festzulegen geht man folgendermaßen vor:

AnyClass anyClass = new AnyClass();
InputText.DataContext = anyClass;
OutputText.DataContext = anyClass;


Man könnte auch einfach this.DataContext = anyClass; machen, was prinzipiell auch richtig ist, ich will hier aber möglichst viele Möglichkeiten zeigen. Ebenfalls könnte ich einfach in MainWindow.xaml.cs das entsprechende Feld "BindingText" erstellen und dann this.DataContext = this; aufrufen.

Nun komme ich zur Klasse AnyClass. Zuerst eine kurze Einführung zum Thema Felder. Ein Feld kann wie eine Variable verwendet werden, jedoch kann ein Feld keine Werte direkt speichern. Ein minimales Feld sieht folgendermaßen aus:

public string BindingText
{
    get { return _BindingText; }
    set { _BindingText = value; }
}
private string _BindingText = "";


Das ist also ein Feld. Im get und set Block kann man nun viele lustige Dinge tun, wie z.B. Überprüfen von Eingaben, Events werfen (also ein event, wenn das Feld abgefragt wird z.B.) und eigentlich auch alles andere denkbare.

Nun zeige ich die Klasse AnyClass, welche der letzte fehlende Baustein für das DataBinding ist:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataBindingExample
{
    public class AnyClass : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public string BindingText
        {
            get { return _BindingText; }
            set
            {
                _BindingText = value;
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged(this, new PropertyChangedEventArgs("BindingText"));
                }
            }
        }
        private string _BindingText = "<empty>";
    }
}


Indem man PropertyChanged auslöst bekommt das Anzeigeelement gesagt, dass ein neuer Variablenwert existiert und aktualisiert sich. Das sollte die Grundlagen zum Thema DataBinding abdecken, falls es Fragen gibt, beantworte ich diese gerne in den Kommentaren.

Einen Post zu diesem Thema, der auch etwas weiter greift und z.B. Converter erklärt gibt es auf C# Tipps und Tricks.