hArduino-1.1: Control your Arduino board from Haskell.

Copyright(c) Levent Erkok
LicenseBSD3
Maintainererkokl@gmail.com
Stabilityexperimental
Safe HaskellNone
LanguageHaskell2010

System.Hardware.Arduino

Contents

Description

hArduino allows Haskell programs to control Arduino boards (http://www.arduino.cc) and peripherals, using the Firmata protocol (http://firmata.org).

For details, see: http://leventerkok.github.com/hArduino.

Synopsis

Running the controller

withArduino Source

Arguments

:: Bool

If True, debugging info will be printed

-> FilePath

Path to the USB port

-> Arduino ()

The Haskell controller program to run

-> IO () 

Run the Haskell program to control the board:

  • The file path argument should point to the device file that is associated with the board. (COM1 on Windows, '/dev/cu.usbmodemFD131' on Mac, etc.)
  • The boolean argument controls verbosity. It should remain False unless you have communication issues. The print-out is typically less-than-useful, but it might point to the root cause of the problem.

See System.Hardware.Arduino.Examples.Blink for a simple example.

Programming the Arduino

Pins

analog :: Word8 -> Pin Source

Declare an analog pin on the board. For instance, to refer to analog pin no 0 simply use analog 0.

Note that analog 0 on an Arduino UNO will be appropriately adjusted internally to refer to pin 14, since UNO has 13 digital pins, while on an Arduino MEGA, it will refer to internal pin 55, since MEGA has 54 digital pins; and similarly for other boards depending on their capabilities. (Also see the note on pin for pin mappings.)

digital :: Word8 -> Pin Source

Declare an digital pin on the board. For instance, to refer to digital pin no 12 use digital 12.

pin :: Word8 -> Pin Source

Declare a pin by its index. For maximum portability, prefer digital and analog functions, which will adjust pin indexes properly based on which board the program is running on at run-time, as Arduino boards differ in their pin numbers. This function is provided for cases where a pin is used in mixed-mode, i.e., both for digital and analog purposes, as Arduino does not really distinguish pin usage. In these cases, the user has the proof obligation to make sure that the index used is supported on the board with appropriate capabilities.

data Pin Source

A pin on the Arduino, as specified by the user via pin, digital, and analog functions.

Instances

Show Pin Source

Show instance for Pin

data PinMode Source

The mode for a pin.

Constructors

INPUT

Digital input

OUTPUT

Digital output

ANALOG

Analog input

PWM

PWM (Pulse-Width-Modulation) output

SERVO

Servo Motor controller

SHIFT

Shift controller

I2C

I2C (Inter-Integrated-Circuit) connection

ONEWIRE

NB. No explicit support

STEPPER

NB. No explicit support

ENCODER

NB. No explicit support

SERIAL

NB. No explicit support

PULLUP

NB. No explicit support

UNSUPPORTED

A mode we do not understand or support

setPinMode :: Pin -> PinMode -> Arduino () Source

Set the mode on a particular pin on the board

Analog input/output (PWM)

analogRead :: Pin -> Arduino Int Source

Read the value of a pin in analog mode; this is a non-blocking call, immediately returning the last sampled value. It returns 0 if the voltage on the pin is 0V, and 1023 if it is 5V, properly scaled. (See setAnalogSamplingInterval for sampling frequency.)

analogWrite :: Pin -> Int -> Arduino () Source

Write a PWM analog value to a pin. The argument is an Int, indicating the duty cycle. 0 means off; 255 means always on. Intermediate values will create a square wave on that pin with the given duty-cycle

Digital I/O

digitalWrite :: Pin -> Bool -> Arduino () Source

Set or clear a digital pin on the board

digitalRead :: Pin -> Arduino Bool Source

Read the value of a pin in digital mode; this is a non-blocking call, returning the current value immediately. See waitFor for a version that waits for a change in the pin first.

Programming with triggers

waitFor :: Pin -> Arduino Bool Source

Wait for a change in the value of the digital input pin. Returns the new value. Note that this is a blocking call. For a non-blocking version, see digitalRead, which returns the current value of a pin immediately.

waitAny :: [Pin] -> Arduino [Bool] Source

Wait for a change in any of the given pins. Once a change is detected, all the new values are returned. Similar to waitFor, but is useful when we are watching multiple digital inputs.

waitAnyHigh :: [Pin] -> Arduino [Bool] Source

Wait for any of the given pins to go from low to high. If all of the pins are high to start with, then we first wait for one of them to go low, and then wait for one of them to go back high. Returns the new values.

waitAnyLow :: [Pin] -> Arduino [Bool] Source

Wait for any of the given pins to go from high to low. If all of the pins are low to start with, then we first wait for one of them to go high, and then wait for one of them to go back low. Returns the new values.

Receiving and sending pulses

pulse :: Pin -> Bool -> Int -> Maybe Int -> Arduino (Maybe Int) Source

Send down a pulse, and measure how long the pin reports a corresponding pulse, with a potential time-out. The call pulse p v duration mbTimeOut does the following:

  • Set the pin to value v for duration microseconds.
  • Waits 2 microseconds
  • Waits until pin p has value not v.
  • Returns, in micro-seconds, the duration the pin stayed v, counting from the 2 microsecond wait.

Time-out parameter is used as follows:

  • If mbTimeOut is Nothing, then pulse will wait until the pin attains the value required and so long as it holds it. Note that very-long time-out values are unlikely to be accurate.
  • If mbTimeOut is Just t then, pulse will stop if the above procedure does not complete within the given micro-seconds. In this case, the overall return value is Nothing.

NB. Both the time-out value and the return value are given in micro-seconds.

NB. As of March 2 2013; StandardFirmata that's distributed with the Arduino-App does not support the Pulse-In command. However, there is a patch to add this command; see: http://github.com/rwldrn/johnny-five/issues/18 for details. If you want to use hArduino's pulseIn command, then you have to install the above patch. Also see the function pulseIn_hostOnly, which works with the distributed StandardFirmata: It implements a version that is not as accurate in its timing, but might be sufficient if high precision is not required.

pulseIn_hostTiming :: Pin -> Bool -> Maybe Int -> Arduino (Maybe Int) Source

A hostOnly version of pulse-in on a digital-pin. Use this function only for cases where the precision required only matters for the host, not for the board. That is, due to the inherent delays involved in Firmata communication, the timing will not be accurate, and should not be expected to work uniformly over different boards. Similar comments apply for pulseOut_hostTiming as well. See the function pulse for a more accurate version.

pulseOut_hostTiming Source

Arguments

:: Pin

Pin to send the pulse on

-> Bool

Pulse value

-> Int

Time, in microseconds, to signal beginning of pulse; will send the opposite value for this amount

-> Int

Pulse duration, measured in microseconds

-> Arduino () 

A hostOnly version of pulse-out on a digital-pin. Use this function only for cases where the precision required only matters for the host, not for the board. That is, due to the inherent delays involved in Firmata communication, the timing will not be accurate, and should not be expected to work uniformly over different boards. Similar comments apply for pulseIn_hostTiming as well. See the function pulse for a more accurate version.

Misc utilities

setAnalogSamplingInterval :: Int -> Arduino () Source

Set the analog sampling interval, in milliseconds. Arduino uses a default of 19ms to sample analog and I2C signals, which is fine for many applications, but can be modified if needed. The argument should be a number between 10 and 16384; 10 being the minumum sampling interval supported by Arduino and 16383 being the largest value we can represent in 14 bits that this message can handle. (Note that the largest value is just about 16 seconds, which is plenty infrequent for all practical needs.)

pullUpResistor :: Pin -> Bool -> Arduino () Source

Turn on/off internal pull-up resistor on an input pin

delay :: Int -> Arduino () Source

Delay the computaton for a given number of milli-seconds

time :: Arduino a -> Arduino (Int, a) Source

Time a given action, result is measured in micro-seconds.

timeOut :: Int -> Arduino a -> Arduino (Maybe a) Source

Time-out a given action. Time-out amount is in micro-seconds.

queryFirmware :: Arduino (Word8, Word8, String) Source

Retrieve the Firmata firmware version running on the Arduino. The first component is the major, second is the minor. The final value is a human readable identifier for the particular board.