#include <Arduino.h> |
#include <TimerThree.h> |
// variables that can be concurrently updated should be marked volatile |
// so the compiler will not optimize them. |
|
volatile uint8_t state = 0; // the LED state 0 LOW or 1 HIGH |
|
#define LED 12 |
|
void tick() { |
// this procedure is called on each timer period expire |
state = !state; |
digitalWrite(LED, state); |
} |
|
long int tick_period = 500000; |
|
void setup() |
{ Serial.begin( 9600 ); |
Serial.println("Starting"); |
|
Timer3.initialize(); |
|
pinMode(LED, OUTPUT); |
|
// tick will occur every 500000 uS, i.e. 1/2 second. |
Timer3.attachInterrupt(tick, tick_period); |
} |
|
void loop() { |
|
Serial.print("x"); |
delay(3000); |
|
} |
#include <Arduino.h> |
#include <TimerThree.h> |
|
// n beats against m |
|
#define LED1 11 |
#define LED2 12 |
|
// 1/2 of the period of each of the lights, in milliseconds |
// the light is on for half and off for half |
int half_period1; |
int half_period2; |
|
// the number of ticks since the last light change |
int nticks1 = 0; |
int nticks2 = 0; |
|
// the current state of the light |
int state1 = 0; |
int state2 = 0; |
|
// the clock ticks once every millisecond |
void tick() { |
// this procedure is called 1000 times per second |
|
// if exceeded the period, change state of output value and reset |
if ( nticks1 >= half_period1 ) { |
state1 = ! state1; |
digitalWrite(LED1, state1); |
nticks1 = 0; |
} else { |
nticks1++; |
} |
|
// if exceeded the period, change state of output value and reset |
if ( nticks2 >= half_period2 ) { |
state2 = ! state2; |
digitalWrite(LED2, state2); |
nticks2 = 0; |
} else { |
nticks2++; |
} |
|
} |
|
void setup() |
{ Serial.begin( 9600 ); |
Serial.println("Starting"); |
|
Timer3.initialize(); |
|
pinMode(LED1, OUTPUT); |
pinMode(LED2, OUTPUT); |
|
// tick will occur at 1000 Hz |
Timer3.attachInterrupt(tick, 1000); |
|
half_period1 = 300; |
half_period2 = 200; |
} |
|
void loop() { |
|
// do something boring |
Serial.print("x"); |
delay(50); |
|
|
} |
#include <Arduino.h> |
#include <TimerThree.h> |
|
// Example of incorrect critical section handling |
|
#define LED1 11 |
#define LED2 12 |
|
/* interrupts can be manipulated with |
noInterrupts(); |
interrupts(); |
we can protect critical sections with noInterrups - interupts pairs. |
We have to make sure any concurrent accesses are protected, not just |
modifying ones. |
*/ |
|
|
long int tick_period = 1000; |
const int list_len = 32; |
volatile int list[list_len]; |
|
// add 1 to each element of list l |
void inc_list(volatile int * l, int len) { |
int i; |
for (i=0; i<len; i++) { l[i] = l[i] + 1; } |
} |
|
// check that l is in increasing order by increment 1, |
// return true of so, false if not |
int list_ok(volatile int * l, int len) { |
int i; |
for (i=0; i<len-1; i++) { |
if ( l[i+1] != l[i] + 1 ) { |
return 0; |
} |
} |
return 1; |
} |
|
// the clock ticks once every timer expire |
void tick() { |
inc_list(list, list_len); |
} |
|
void setup() |
{ Serial.begin( 9600 ); |
Serial.println("Starting"); |
|
Timer3.initialize(); |
|
pinMode(LED1, OUTPUT); |
pinMode(LED2, OUTPUT); |
|
// initialize the list |
for (int i=0; i < list_len; i++) { |
list[i] = i; |
} |
|
// tick is called 10^6/tick_period times per second |
Timer3.attachInterrupt(tick, tick_period); |
|
} |
|
long int step_num = 0; |
void loop() { |
step_num++; |
|
// noInterrupts(); |
inc_list(list, list_len); |
// interrupts(); |
|
if ( ! list_ok(list, list_len) ) { |
Serial.print(step_num); |
Serial.println(" List is broken"); |
} |
delay(50); |
} |
// the external LED is attached to this pin. |
// onboard LED is attached to pin 13, |
byte ledPin = 13; |
byte pressPin = 11; |
|
/* interrupt information |
|
Most Arduino boards have two external interrupts: |
0 (on digital pin 2) |
1 (on digital pin 3) |
The Arduino Mega has an additional four: |
2 (pin 21) |
3 (pin 20) |
4 (pin 19) |
5 (pin 18). |
*/ |
|
// the pushbutton is attached to this digital input pin |
int buttonPin = 21; |
int buttonInterrupt = 2; |
|
// state of the button: 0 is up, 1 is pushed |
// volatile because altered in an interrupt service routine |
|
volatile byte buttonState = 0; |
|
void buttonPress() { |
|
if ( buttonState == 0 ) { |
buttonState = 1; |
digitalWrite(pressPin, HIGH); |
/* |
Normally you should not do I/O like this in a handler. |
The only reason it works here is that interrupts are not |
required for output to the on-chip serial ports. So this |
works. Interrupts are needed for reading, so you should not |
do a read inside a handler. |
*/ |
|
Serial.println("*"); |
} |
} |
|
void buttonHandled() { |
// indicate that the button interrupt has been handled and |
// we are ready for more |
|
digitalWrite(pressPin, LOW); |
/* since the only other code that could set the button state |
is in the interrupt handler, and buttonState is a single byte, |
then this operation is safe. buttonState changes in one |
instruction. |
*/ |
buttonState = 0; |
} |
|
void setup() { |
Serial.begin( 9600 ); |
Serial.println("Starting"); |
|
// configure ledPin to be a digital output |
pinMode(ledPin, OUTPUT); |
pinMode(pressPin, OUTPUT); |
|
digitalWrite(pressPin, LOW); |
|
// set buttonPin to INPUT and |
// turn on internal pull up resistor |
pinMode(buttonPin, INPUT); |
digitalWrite(buttonPin, HIGH); |
|
// establish interrupts on button transitions |
|
// FALLING means create an interrupt on a HIGH to LOW change |
attachInterrupt(buttonInterrupt, buttonPress, FALLING); |
|
// LOW means create an interrupt as long as LOW is present |
// attachInterrupt(buttonInterrupt, buttonPress, LOW); |
|
Serial.println("OK"); |
} |
|
void loop() { |
|
Serial.println(buttonState, DEC); |
// see if button was pressed at some point |
if ( buttonState == 1 ) { |
Serial.println("TaDa"); |
delay(75); |
buttonHandled(); |
} |
|
|
delay(200); |
|
} |
|
#include <Arduino.h> |
|
/* Debouncing demonstration program. |
|
The purpose of this program is to show how the debouncing of an input |
translates to a well-defined digital signal. It simply monitors a digital |
input and passes through the state to a digital output. |
|
If we monitor the raw input signal and the digital output, we can show |
how the Schmidt triggers clean up the input signal. |
|
*/ |
|
const uint8_t button_pin = 10; |
const uint8_t output_pin = 13; |
|
void setup() { |
Serial.begin(9600); |
// set button_pin to INPUT and |
pinMode(button_pin, INPUT); |
// turn on internal pull up resistor |
digitalWrite(button_pin, HIGH); |
|
// set output_pin to OUTPUT |
pinMode(output_pin, OUTPUT); |
|
} |
|
void loop() { |
uint8_t state = digitalRead(button_pin); |
digitalWrite(output_pin, state); |
} |
#include "assert13.h" |
#include "ll.h" |
|
// the external LED is attached to this pin. |
// onboard LED is attached to pin 13, |
byte ledPin = 13; |
byte pressPin = 11; |
|
/* interrupt information |
|
Most Arduino boards have two external interrupts: |
0 (on digital pin 2) |
1 (on digital pin 3) |
The Arduino Mega has an additional four: |
2 (pin 21) |
3 (pin 20) |
4 (pin 19) |
5 (pin 18). |
*/ |
|
// The pushbutton is attached to this digital input pin |
// and ground. With the pullup resistor turned on this |
// creates a falling signal when the button is pushed. |
// To create many interrupts, just rub the two wires |
// together. |
int buttonPin = 21; |
int buttonInterrupt = 2; |
|
/* button press event */ |
typedef struct { |
unsigned long time; |
int data; |
} intr_event; |
|
// a list of interrupt events |
// volatile because altered in an interrupt service routine |
volatile linked_list intr_list; |
|
void buttonPress() { |
// Serial.println("Push"); |
// return; |
|
/* add this button press event to the processing queue */ |
intr_event * event; |
|
// these must be freed when removed from list! |
event = (intr_event *) malloc(sizeof(intr_event)); |
assert13(event != 0, 1); |
|
event->time = micros(); |
event->data = 1; |
|
addElement(intr_list, event); |
|
} |
|
|
void setup() { |
Serial.begin( 9600 ); |
Serial.println("Starting"); |
|
// configure ledPin to be a digital output |
pinMode(ledPin, OUTPUT); |
pinMode(pressPin, OUTPUT); |
|
digitalWrite(pressPin, LOW); |
|
// set buttonPin to INPUT and |
// turn on internal pull up resistor |
pinMode(buttonPin, INPUT); |
digitalWrite(buttonPin, HIGH); |
|
intr_list = initList(); |
// establish interrupts on button transitions |
|
// FALLING means create an interrupt on a HIGH to LOW change |
attachInterrupt(buttonInterrupt, buttonPress, FALLING); |
|
Serial.println("OK"); |
} |
|
void loop() { |
intr_event * event; |
|
// get the next event from the queue and display it. |
|
noInterrupts(); // begin critical section wrt intr_list |
event = (intr_event *) removeElement(intr_list); |
interrupts(); // end critical section |
|
if ( event != 0 ) { |
Serial.print(event->time, DEC); |
Serial.print(":"); |
Serial.println(event->data); |
free(event); |
} |
|
delay(100); |
} |
#include <Arduino.h> |
#include "assert13.h" |
// create a busy-loop delay, since timers are off |
int hard_loop(unsigned long int n) { |
// this introduction of y and the Serial.print |
// are to mess with gcc's optimization of the loop |
int y = 0; |
while (n > 0) { |
y = y + n; |
n--; |
} |
Serial.print(""); |
return y; |
} |
|
#define DELAY_COUNT 1000000L |
|
/* assertion checker |
assert13(invariant, code); |
if invariant is false (i.e. 0) then fail and enter |
a hard loop with interrupts disabled and repeatedly |
sending code to the serial monitor, while blinking |
the LED on pin 13. |
|
There is a small window in which an interrupt could |
occur, and in which a failure could call assert13. |
How would we guard against this? |
*/ |
|
void assert13(int invariant, int code) { |
unsigned long int count; |
if ( invariant ) { return; } |
Serial.println("Assertion failure"); |
noInterrupts(); |
pinMode(13, OUTPUT); |
while ( 1 ) { |
Serial.println(code); |
digitalWrite(13, LOW); |
// Serial.println("LOW"); |
hard_loop( DELAY_COUNT ); |
digitalWrite(13, HIGH); |
// Serial.println("HIGH"); |
hard_loop( DELAY_COUNT ); |
} |
} |
#ifndef _ll_h |
#define _ll_h |
/* |
A linked list contains nodes which hold the information for that node |
and the pointer to the next node in the list |
*/ |
typedef struct node { |
void * val; |
node * next; |
}; |
|
/* A linked list is represented by a handle, which is a |
pointer to the linked list control block. |
|
The control block maintains a pointer to the head and tail nodes |
We maintain length information so that we don't have to compute it. |
*/ |
typedef struct linked_list_cb { |
node * head; |
node * tail; |
int length; |
}; |
|
// typedef linked_list_cb * linked_list; |
typedef linked_list_cb * linked_list; |
|
// create a linked list and return the handle |
linked_list initList(); |
void addElement(linked_list list, void * val); |
void * removeElement(linked_list list); |
int getLength(linked_list list); |
#endif |
#include <stdlib.h> |
#include "assert13.h" |
#include "ll.h" |
|
// create a linked list and return the handle |
linked_list initList() { |
linked_list list; |
list = (linked_list) malloc(sizeof(linked_list_cb)); |
assert13(list != 0, 16); |
|
list->head = 0; |
list->tail = 0; |
list->length = 0; |
return list; |
} |
|
int getLength(linked_list list) { |
return list->length; |
} |
|
void addElement(linked_list list, void * val) { |
node * n = (node *) malloc(sizeof(node)); |
assert13(n != 0, 17); |
|
n->val = val; |
n->next = 0; |
if ( list->length != 0 ) { |
list->tail->next = n; |
} else { |
list->head = n; |
} |
list->tail = n; |
list->length++; |
} |
|
|
// Should not call if list->length == 0 |
void * removeElement(linked_list list) { |
if (list->length == 0) { |
// return the null pointer if the list is empty |
return 0; |
} |
|
void * rval = list->head->val; |
|
node * new_head = list->head->next; |
/* Now we can free the old head so that we don't leave unused memory |
allocated |
*/ |
|
free(list->head); |
list->head = new_head; |
if ( list->head == 0 ) { |
list->tail = 0; |
} |
|
list->length--; |
|
return rval; |
} |
|