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.

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)

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 :)