Noch ein Atom-Arduino-Blinker

English Deutsch

Beim Experimentieren mit Atom habe ich ein minimales Beispiel erstellt, um meinen alten Arduino Uno periodisch blinken zu lassen.

Obwohl es zahlreiche Beispiele gibt (einige funktionieren sogar!) wollte ich keine Abhängigkeit zu den Arduino-Bibliotheken einführen. Neben der Erschwerung des Builds (auch wenn arscons ganz nett ist) erhöht es die Objektgröße und Arduino unterstützt nur eine begrenzte Auswahl an Prozessoren. Ich brauche die Flexibilität, den Code auf Controllern wie dem ATTiny45 zu verwenden.

Die meisten Beispiele sind unkommentiert und daher für Anfänger schwer verständlich. Obwohl ich glaube, dass Atom konzeptionell deutlich einfacher zu verstehen ist als Copilot, könnte der klassische eingebettete C-Programmierer kommentierten Quellcode benötigen, um Atom vollständig zu verstehen.

Zusätzlich verwende ich die im QuasiQuotation-Beitrag beschriebene Technik, um die Lesbarkeit des eingebetteten C-Codes zu erhöhen. Außerdem habe ich Features wie Assertions und Rule Coverage deaktiviert.

Blink.hs
{-# LANGUAGE QuasiQuotes #-}
{-|
Minimalistisches Atom-Reset-Beispiel für ATMega328P.
Die LED wird auf PB5 angenommen (z.B. Arduino Uno).

Es werden keine Arduino-Bibliotheken benötigt.

Kompilationsbeispiel:
@
runghc Blink.hs
avr-gcc -o Blink.elf -Os -Wall -mmcu=atmega328p -DF_CPU=16000000L blink.c
avr-objcopy -O ihex -R .eeprom Blink.elf Blink.hex
@
-}
module Blink (main) where

import StringEmbed
import Language.Atom

-- | Unser Haupt-Atom-Programm.
--   Lässt die LED periodisch blinken
blink :: Atom ()
blink = do
    -- Deklariere eine lokale Zustandsvariable
    --  die steuert, ob die LED an oder aus ist
    on <- bool "on" True
    -- Bei jedem 50000. Aufruf von blink() ...
    period 50000 $ atom "blinkOn" $ do
        -- LED-Zustand invertieren
        on <== not_ (value on)
        -- und den neuen Zustand auf PORTB schreiben
        call "showLED"

-- | C-Code, der VOR dem Atom-Code eingefügt wird
cHeader :: String
cHeader = [embedStr|
#include <avr/io.h>
#include <util/delay.h>

static inline void showLED(void);
|]

-- | C-Code, der NACH dem Atom-Code eingefügt wird
cFooter :: String
cFooter = [embedStr|
//LED: PB5
#define LED_PIN (1<<5)

//LED setzen/zurücksetzen
static inline void showLED() {
    if(state.blink.on) {
        PORTB |= LED_PIN;
    } else {
        PORTB &= ~(LED_PIN);
    }
}

int main (void) {
    //LED-Pin auf OUTPUT setzen
    DDRB |= LED_PIN;
    while(1) {
        blink();
    }
    return 0; //Nie erreicht
}
|]

main :: IO ()
main = do
    let code _ _ _ = (cHeader, cFooter)
    let cfg = defaults {cCode = code,
                        cRuleCoverage = False,
                        cAssert = False}
    (schedule, _, _, _, _) <- compile "blink" cfg blink
    putStrLn $ reportSchedule schedule

Check out similar posts by category: Allgemein, Embedded