LT1302 Step-Up Wandler 5V 600mA aus 2 Mignonzellen

Da Batterien auf Dauer teuer und eine ziemliche Verschwendung sind, habe ich mit neuen Akkus und einem neuen Lader vor, meinen ganzen Batteriebestand auf Akkus umzustellen. Aktuell versorge ich meine kleinen Projekte mit einer 9V Batterie und einem Linearregler der mir 5V erzeugt. Das funktioniert zwar prima, nur ist der Wirkungsgrad mit 45-55% ziemlich schlecht. Deutlich besser sind Step-Up Regler, die aus einer kleineren Spannung eine größere erzeugen. Dabei bin ich auf den LT1302 gestoßen, der aus 2-3 Mignonzellen stabile 5V mit bis 600mA erzeugt. Im Datenblatt wird auch eine SEPIC-Schaltung gezeigt, falls man z.b. 4 Akkus benutzt.

Da ich den Spannungswandler in ein neues Projekt einbauen will, habe ich mir zum Test eine eigene Platine geätzt (ähnlich wie im Referenzdesign). Die Platine auf dem Foto ist noch die alte Version, bei der die Spannungsteiler noch nicht eingeplant waren. Leider gabs bei Reichelt nur einen 330K Widerstand, mit dem ich 4.95V erhalte. Optimal wäre ein 340K Widerstand (1%) oder 330K mit 10K in Reihe. Aber mein ATmega328 gibt sich damit erstmal zufrieden.

Wer keine Platine herstellen kann, der kann sich bei Robotikhardware eine Platine bestellen. Dort gibt es auch gleich den LT1302 zu kaufen.

lt1302 675x506 LT1302 Step Up Wandler 5V 600mA aus 2 Mignonzellen

Schaltplan und Platinenlayout

lt1302 schaltplan 675x405 LT1302 Step Up Wandler 5V 600mA aus 2 Mignonzellen
lt1302 platine 675x399 LT1302 Step Up Wandler 5V 600mA aus 2 Mignonzellen

LT1302 und LT1302-5

Bei der Auswahl des ICs muss man beachten, dass es zwei Versionen gibt: LT1302 und LT1302-5. Der LT1302 kann eine variable Spannung über einen Spannunsgteiler erzeugen und der LT1302-5 erzeugt nur 5V. Bei Reichelt gibt es derzeit nur den LT1302, den ich hier auch genutzt habe.

Download

Download Platine, Schaltplan (EAGLE) und Bauteilliste
Datenblatt LT1302

Ein ganz interessantes Projekt ist Mintyboost. Das nutzt in der letzten Version auch den LT1302.

MCP23017 / MCP23S17 GPIO Port Extender

Nach einigem hin und her habe ich es geschafft, den MCP23017 GPIO Port Exender ans laufen zu bringen. Falls jemand ebenso Schwierigkeiten hat, ihn auf Anhieb zu betreiben, anbei ein paar Informationen.

Der MCP23017 hat ingesammt 16 GPIO Ports, die in 2x 8-Bit Ports unterteilt sind. Das ist GPA und GPB. Was mich anfangs ein wenig verwirrt hat, war die konfigurierbare Adressierung der Ports. Es gibt die Möglichkeit, die Register sequentiell oder in Blöcken (Banks) zu unterteilen. Welche Adressierung man wählt, wird im IOCON (I/O Configuration Register) hinterlegt. Standardmäßig ist IOCON 0×00. Beispiel:

  • IOCON.BANK = 0
    Adressierung sequentiell, d.h. IODIRA = 0×00, IODIRB, 0×01, IPOLA = 0×02, IPOLB = 0×03

  • IOCON.BANK = 1
    Adressierung in zwei Blöcken, d.h. IODIRA = 0×00, IPOLA = 0×01 – IODIRB = 0×10, IPOLB = 0×11

Da sich die ganze Adressierung der GPIO Register ändert, sollte man bei einer der beiden Optionen bleiben.

Ein nützliches Feature ist, dass man mehrere Bytes nacheinander schreiben oder lesen kann. Mit der Option IOCON.SEQOP = 0 (Default), wird der interne Pointer automatisch hochgezählt. Dadurch kann man zwei Bytes hintereinander schreiben, ohne die Adressierung zu ändern. Beispiel:

i2c_start(0x40);
i2c_write(0x12); // GPIOA
i2c_write(0xFF); // set all ports to HIGH on PORTA
i2c_write(0xFF); // set all ports to HIGH on PORTB -> GPIOA (0x12) incremented to GPIOB (0x13)
i2c_stop();

Das ist ziemlich nützlich, da man sich so ein weiteres i2c_start() spart. Voraussetzung ist, das man IOCON.BANK = 0 gesetzt hat. Aufjedenfall sollte man sich das Datenblatt ansehen, das ist in jedem Fall hilfreich.

Anschluss

mcp23017 MCP23017 / MCP23S17 GPIO Port Extender

Minimalbeschaltung:

  • VDD = 5V
  • VCC = GND
  • SCL = I2C Clock (Arduino Pin A5)
  • SDA = I2C Data (Arduino Pin A4)
  • Reset = 5V

Addresierung

Mit den Hardware Address Pins A2 bis A0 konfiguriert man die Hardware Adresse des Chips. Legt man alle drei auf GND, erhält man als Adresse 0×00, legt man alle auf HIGH, erhält man 0×07. Man kann daher is zu 8 MCP23017 adressieren. Die komplette Adresse des Chips ist 0100 + die HW Pins + R/W:

mcp23017 slave address MCP23017 / MCP23S17 GPIO Port Extender

A2 bis A0 auf GND + WRITE = 0x40
A2 bis A0 auf GND + READ = 0x41

Beispiel-Programm

Sehr nützlich ist die i2cmaster Bibliothek von Peter Fleury. Die vereinfacht den Umgang mit i2c ungemein. Für das Beispiel ist diese von nöten. Falls auf dem µC Hardware TWI vorhanden ist, einfach die “twimaster.h” in “i2cmaster.h” umbennenen.

Das Beispiel macht folgendes:

  • Schreibt das ICON-Register
  • Setzt PORTA (IODIRA) und PORTB (IODIRB) auf OUTPUT
  • Schleife: Setzt GPIOA und GPIOB auf HIGH, wartet 100ms und setzt diese wieder auf LOW
#define F_CPU 16000000
 
#include <avr/io.h>
#include <util/delay.h>
#include "i2cmaster.h"
 
#define MCP23x17_ADDR 0x40
 
// control registers
// ONLY VALID WHEN ICON.BANK = 0
#define MCP23x17_IODIRA   0x00
#define MCP23x17_IODIRB   0x01
#define MCP23x17_IOPOLA   0x02
#define MCP23x17_IOPOLB   0x03
#define MCP23x17_GPINTENA 0x04
#define MCP23x17_GPINTENB 0x05
#define MCP23x17_DEFVALA  0x06
#define MCP23x17_DEFVALB  0x07
#define MCP23x17_INTCONA  0x08
#define MCP23x17_INTCONB  0x09
#define MCP23x17_IOCON    0x0A
//#define MCP23x17_IOCON    0x0B
#define MCP23x17_GPPUA    0x0C
#define MCP23x17_GPPUB    0x0D
#define MCP23x17_INTFA    0x0E
#define MCP23x17_INTFB    0x0F
#define MCP23x17_INTCAPA  0x10
#define MCP23x17_INTCAPB  0x11
#define MCP23x17_GPIOA    0x12
#define MCP23x17_GPIOB    0x13
#define MCP23x17_OPLATA   0x14
#define MCP23x17_OPLATB   0x15
 
// IOCON register bit positions
#define MCP23x17_IOCON_BANK   7
#define MCP23x17_IOCON_MIRROR 6
#define MCP23x17_IOCON_SEQOP  5
#define MCP23x17_IOCON_DISSLW 4
#define MCP23x17_IOCON_HAEN   3
#define MCP23x17_IOCON_ODR    2
#define MCP23x17_IOCON_INTPOL 1
 
int main(void)
{
 
	// init i2c
	i2c_init();
 
	// IOCON
	// configuration register
	i2c_start(MCP23x17_ADDR + I2C_WRITE);
	i2c_write(MCP23x17_IOCON);
	i2c_write(0x00
		| (0 << MCP23x17_IOCON_BANK)
		| (0 << MCP23x17_IOCON_MIRROR)
		| (0 << MCP23x17_IOCON_SEQOP)
		| (0 << MCP23x17_IOCON_DISSLW)
		| (1 << MCP23x17_IOCON_HAEN)
		| (0 << MCP23x17_IOCON_ODR)
		| (0 << MCP23x17_IOCON_INTPOL)
	);
	i2c_stop();
 
	// IODIRA
	// set PORTA to OUTPUT
	i2c_start(MCP23x17_ADDR);
	i2c_write(MCP23x17_IODIRA);
	i2c_write(0x00);
	i2c_stop();
 
	// IODIRB
	// set PORTB to OUTPUT
	i2c_start(MCP23x17_ADDR);
	i2c_write(MCP23x17_IODIRB);
	i2c_write(0x00);
	i2c_stop();
 
	while (1) {
 
		// set GPIOA (first write) and GPIOB (second write)
		// to HIGH
		i2c_start(MCP23x17_ADDR);
		i2c_write(MCP23x17_GPIOA);
		i2c_write(0xFF);
		i2c_write(0xFF);
		i2c_stop();
 
		_delay_ms(100);
 
		// set GPIOA (first write) and GPIOB (second write)
		// to HIGH
		i2c_start(MCP23x17_ADDR);
		i2c_write(MCP23x17_GPIOA);
		i2c_write(0x00);
		i2c_write(0x00);
		i2c_stop();
 
		_delay_ms(100);
	}
 
	return 0;
}

Was beim testen hilft: Anstelle den RST/POR Pin dauerhaft auf HIGH zu setzen, kann man diesen beim initalisieren des µC toggeln. Dadurch resettet man den MCP23017 auf seine Standardwerte.

Ich hoffe die kurzen Tipps helfen!

Nützliche Links:
MCP23017 / MCP23S17 Datenblatt

ATmega328 PWM

// processor speed
#define F_CPU 16000000 // 16MHz
 
#include <avr/io.h>
 
int main(void)
{
	// timer0 register: TCCR0A, TCCR0B
	// timer0 compare register: 0CR0A, 0CR0B
 
	// set waveform generation mode
	// WGM00 - WGM02
	TCCR0A |= (1 << WGM00) | (1 << WGM01); // fast pwm
 
	// set prescaler
	// CS00 - CS02
	TCCR0B |= (1 << CS00) | (1 << CS01); // clock/64 -> F_CPU / 64 = 250kHz PWM
 
	// OC0A
	// pin 7 @ arduino
	DDRD |= (1 << DDD6);
	TCCR0A |= (1 << COM0A1); // clear on compare match
	OCR0A = 20; // 8-bit, 0 to 255
 
	while(1) {
		// ...
	}
}

Nützliche Links:
PWM Signal Generation by Using AVR Timers
ATmega Timer/Counter/Prescaler Calculator

Mein erstes AVR Programm

Es wurde vollbracht! Mittels Eclipse, den CDT-Plugins, dem AVR Eclipse Plugin und WinAVR wurde vollgender Meistercode durch avrdude auf meinen Arduino ATMega328 gebrannt:

#include <avr/io.h>
#include <util/delay.h>
 
int main (void) {
   DDRB |= (1 << DDB0);
 
   while(1) {
	   _delay_ms(1000);
	   PORTB ^= (1 << DDB0);
   }
 
   return 0;
}

Er läßt die LED des Verderbens blinken! Nun ist auch endlich der lang=”c” Parameter für mein WP-Syntax gerechtfertigt.

Buffalo Linkstation: Controlling LEDs with microapl

microapl is a wrapper script for micro_evtd, which passes the corresponding hexadecimal value for setting different values of your buffalo linkstation. In my case, debian squeeze was installed onto a Buffalo LS-Pro v1.

There are two types of controlling the leds: With “mcon”, the leds are controlled by the linkstation. With “cpu”, you can set the leds by yourself.

To get all possible settings, type in:

root@box:~ microapl
option: boot_start
boot_end
power_off
shutdown_wait
shutdown_cancel
skip_standby
delay_standby
standby
reboot
temp_get
fan_set_speed [arg]
fan_get_speed
bz_on [arg]
bz_set_freq [arg]
bz_melody tempo note ...
bz_imhere tempo note ...
int_get_switch_status [arg]
led_set_bright [arg]
led_set_cpu_mcon [arg]
led_set_on_off [arg]
led_set_blink [arg]
led_set_code_error [arg]
led_set_code_information [arg]
led_set_cpu_mcon [arg]
mcon_get_status
hdd_set_power [arg]
mcon_get_version

As you see, you can do many cool stuff, for example play a melody with bz_melody, or set and get the fan speed. Just try out.

To get the current controlling type of the leds (cpu or mcon), type in:

root@box:~ microapl -a led_set_cpu_mcon
#[microapl.led_set_cpu_mcon]
led_power=mcon
led_info=mcon
led_diag=mcon
led_link=mcon

If you want to change the diag-led (error, red) by yourself, set the the led_diag value to “cpu”:

root@box:~ microapl -a led_set_cpu_mcon diag
root@box:~ microapl -a led_set_cpu_mcon
#[microapl.led_set_cpu_mcon]
led_power=mcon
led_info=mcon
led_diag=cpu
led_link=mcon

Now the value of led_diag is changed changed to “cpu”. To light up the diag-led, type in:

root@box:~ microapl -a led_set_on_off diag
root@box:~ microapl -a led_set_on_off
#[microapl.led_set_on_off]
led_power=off
led_info=off
led_diag=on
led_link=off

To change the power, link, info and diag led to cpu and light them up, type in:

root@box:~ microapl -a led_set_cpu_mcon power info diag link
root@box:~ microapl -a led_set_on_off power info diag link

To change everything back to mcon (default), just use “off” as parameter:

root@box:~ microapl -a led_set_cpu_mcon off

Have fun!

RS232 zwischen Python and Arduino

Für ein kleines Projekt möchte ich unter Python Werte vom Arduino darstellen. In Python nutze ich hierbei das pyserial Modul, welches plattformunabhängig sehr einfach eine serielle Verbindung aufbaut.

Unter Python wird eine Anfrage gestellt, die der Arduino mit Werten definierter Größe beantwortet. Unter Arduino werden die Werte je nach Größe mit den Funktionen serial_uint8 bis serial_uint32 in einzelne Bytes (little-endian) geteilt. Auf der Gegenseite unter Python wird mit dem struct-Modul das Bytearray nach einer vorgegebenem Format wieder in einzelne Bytes entteilt.

Die Python Struct-Formate findet man hier. Die PySerial Dokumentation gibt es hier.

Python-Code:

import serial
import time
import struct
 
""" setup serial for arduino """
ser = serial.Serial()
ser.port = 2
ser.baudrate = 9600
 
""" open serial port """
ser.open()
 
while 1:
 
    """ request values from arduino """    
    ser.write("s")
 
    """ wait until all bytes were read """
    while ser.inWaiting() != 0:
 
        """ unpack format, little endian """
        unpack_fmt = "<BLbHHHH"
 
        """ read bytes as described in unpack_fmt """
        val = ser.read(size=struct.calcsize(unpack_fmt))
 
        """ display values """
        print struct.unpack(unpack_fmt, val)
 
    time.sleep(1)

Arduino-Code:

void setup() {
  Serial.begin(9600);
}
 
uint8_t serial_buffer[128];
uint8_t serial_buffer_pos = 0;
 
void serial_uint8(uint8_t val) {
  serial_buffer[serial_buffer_pos++] = (val & 0xFF);
}
 
void serial_uint16(uint16_t val) {
  serial_buffer[serial_buffer_pos++] = (val & 0xFF);
  serial_buffer[serial_buffer_pos++] = (val >> 8) & 0xFF;
}
 
void serial_uint32(uint32_t val) {
  serial_buffer[serial_buffer_pos++] = (val & 0xFF);
  serial_buffer[serial_buffer_pos++] = (val >> 8) & 0xFF;
  serial_buffer[serial_buffer_pos++] = (val >> 16) & 0xFF;
  serial_buffer[serial_buffer_pos++] = (val >> 24) & 0xFF;
}
 
void serial_init() {
  serial_buffer_pos = 0;
}
 
void serial_send() {
  for (int i = 0; i < serial_buffer_pos; i++) {
    Serial.write(serial_buffer[i]);
  }
}
 
int readByte = 0;
 
void loop() {
 
  if (Serial.available() > 0) {
 
    readByte = Serial.read();
    switch (readByte) {
      case 's':
        serial_init();
        serial_uint8(1);
        serial_uint32(millis());
        serial_uint8(100);
        serial_uint16(random(8, 2200));
        serial_uint16(random(8, 2200));
        serial_uint16(random(8, 2200));
        serial_uint16(random(8, 2200));
        serial_send();
        break;
 
      case 'r':
        serial_init();
        serial_uint8(random(0, 250));
        serial_send();
        break;
    }
  }
}

Das Ergebis sieht so aus:

(1, 1375424, 100, 1463, 927, 1220, 715)
(1, 1376425, 100, 663, 1552, 470, 308)
(1, 1377426, 100, 923, 711, 1963, 571)
(1, 1378427, 100, 732, 1259, 618, 1629)
(1, 1379428, 100, 1493, 378, 396, 80)
(1, 1380429, 100, 1115, 753, 409, 1894)
(1, 1381431, 100, 1968, 1328, 287, 413)
(1, 1382431, 100, 135, 1310, 1237, 823)
(1, 1383433, 100, 794, 1352, 1923, 439)
(1, 1384433, 100, 550, 632, 116, 175)

Split 2-byte integer into two single bytes

Python:

""" two byte integer """
val = 42131 # bin: 1010 0100 1001 0011 hex: 0xa493
print hex(val)
 
byte1 = val & 0xFF # first 8 bit
byte2 = (val >> 8) & 0xFF # last 8 bit
 
print "byte1: " + hex(byte1) # result: 0x93
print "byte2: " + hex(byte2) # result: 0xa4
 
""" merge two bytes into 2-byte integer """
val_m  = (byte1 & 0xFF)
val_m |= (byte2 & 0xFF) << 8
print hex(val_m) # result: 0xa493

Vom Breadboard zur Platine

Nach mehreren Wochen Experimentierens konnte ich nun meine erste Platine mit Hilfe des Toner-Transferverfahrens fertigstellen. Dabei nimmt man einen Laser-Drucker (günstig von eBay, z.b. HP Laserjet 1010) und druckt sein Layout auf ein geeignetes Papier (Reicheltkatalogpapier eignet sich dafür). Danach überträgt man den Toner mittels Bügeleiesen oder Laminiermaschine auf die Kupferschicht der Platine (vorher mit Aceton reinigen). Spülwasser und ein wenig rubbeln erledigen den Rest, danach ist der Toner fast krazfest auf der Platine und kann geätzt werden.

Meine Platine für den diesjährigen Pyro-Fernzünder Empfänger hat relativ gut geklappt (nach dem dritten Anlauf):
DSC00050 575x431 Vom Breadboard zur Platine
DSC00049 575x431 Vom Breadboard zur Platine

Darauf befindet sich ein Atmega 328 mit Arduino Bootloader, ein MAX232 für die Kommunikation mit einem Handy, ein 434Mhz Funkmodul und ein ULN2803A als Relaistreiber. Auf dem Foto sehen die Leiterbahnen leicht unterbrochen aus, sind aber sehr durchgängig und mit einer breite von 36mil auch relativ groß. Zum Schutz sind die Leiterbahnen mit Plastik 70 Isolierlack besprüht. Die Bohrlöcher konnte ich mit einer großen Ständerbohrmaschine problemfrei mit 0,8mm und 1mm bohren.

Zwei kleine Fehler im Layout konnte ich durch ein Kabel am Boden und einer Drahtbrücke fixen. Nur hat blöder weiße die Maße des RF-Moduls von Sparkfun nicht gepasst, so dass ich den Antennen Pin verbiegen mußte. Aber immerhin klappt nun alles und Silvester kann kommen :)