Stability | experimental |
---|---|
Maintainer | erkokl@gmail.com |
Safe Haskell | None |
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.
- withArduino :: Bool -> FilePath -> Arduino () -> IO ()
- data Arduino a
- analog :: Word8 -> Pin
- digital :: Word8 -> Pin
- pin :: Word8 -> Pin
- data Pin
- data PinMode
- setPinMode :: Pin -> PinMode -> Arduino ()
- analogRead :: Pin -> Arduino Int
- analogWrite :: Pin -> Int -> Arduino ()
- digitalWrite :: Pin -> Bool -> Arduino ()
- digitalRead :: Pin -> Arduino Bool
- waitFor :: Pin -> Arduino Bool
- waitAny :: [Pin] -> Arduino [Bool]
- waitAnyHigh :: [Pin] -> Arduino [Bool]
- waitAnyLow :: [Pin] -> Arduino [Bool]
- pulse :: Pin -> Bool -> Int -> Maybe Int -> Arduino (Maybe Int)
- pulseIn_hostTiming :: Pin -> Bool -> Maybe Int -> Arduino (Maybe Int)
- pulseOut_hostTiming :: Pin -> Bool -> Int -> Int -> Arduino ()
- setAnalogSamplingInterval :: Int -> Arduino ()
- pullUpResistor :: Pin -> Bool -> Arduino ()
- delay :: Int -> Arduino ()
- time :: Arduino a -> Arduino (Int, a)
- timeOut :: Int -> Arduino a -> Arduino (Maybe a)
- queryFirmware :: Arduino (Word8, Word8, String)
Running the controller
:: Bool | If |
-> 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.
The Arduino monad.
Programming the Arduino
Pins
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.)
Declare an digital pin on the board. For instance, to refer to digital pin no 12
use digital
12
.
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.
The mode for a pin.
setPinMode :: Pin -> PinMode -> Arduino ()Source
Set the mode on a particular pin on the board
Analog input/output (PWM)
analogRead :: Pin -> Arduino IntSource
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 BoolSource
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 BoolSource
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
forduration
microseconds. - Waits 2 microseconds
- Waits until pin
p
has valuenot 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
isNothing
, thenpulse
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
isJust t
then,pulse
will stop if the above procedure does not complete within the given micro-seconds. In this case, the overall return value isNothing
.
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.
:: 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
time :: Arduino a -> Arduino (Int, a)Source
Time a given action, result is measured in micro-seconds.