ZB1 & ZB1-LCD2 Transmit and Recieve
This program runs on a ZB1 with an ZB1-LCD2. The mainloop monitors
the state of the two pusbuttons on the ZB1-LCD2. Pressing button1
toggles the state of the LCD backlight and LED1. Pressing button2
beeps the beeper and flashes LED2.
When the state of either button changes the ZB1 uses the XBee radio
to transmit the new state to its "buddy" changing its button states.
ZB1-LCD2 Transmit and Recieve
/*
This sketch runs on a ZB1 with an ZB1-LCD2.
The mainloop monitors the state of the two pusbuttons on the
ZB1-LCD2. Pressing button1 toggles the state of the LCD backlight
and LED1. Pressing button2 beeps the beeper and flashes LED2.
When the state of either button changes the ZB1 uses the XBee radio
to transmit the new state to its "buddy" changing its button states.
(* jcl * )
*/
#include <avr/interrupt.h>
#include <avr/io.h>
#include <LCD4Bit.h>
#define OFF LOW
#define ON HIGH
// Define constants for the hardware I/O lines
// Hardware on the ZB1 board
// Pin refdes (ATmega Label)
#define STATUS_LED 7 // D4 (PD7)
// Hardware on the ZB1-LCD2
// Pin refdes (ATmega Label)
#define LED1 3 // D4 (PD3)
#define LED2 4 // D2 (PD4)
#define BUZZER 10 // SPKR1 (PB2)
#define LCD_BACKLIGHT 5 // Q1 (PD5)
#define BUTTON1 PC4 // S11 (PC4)
#define BUTTON2 PC5 // S12 (PC5)
// button interrupts
#define BUTTON1_INT PCINT12
#define BUTTON2_INT PCINT13
#define enable_int PCICR |= (1 << PCIE1)
#define disable_int PCICR &= ~(1 << PCIE1)
#define set_backlight(state) digitalWrite(LCD_BACKLIGHT, state ? HIGH : LOW)
#define set_buzzer(state) digitalWrite(BUZZER, state)
#define set_led1(state) digitalWrite(LED1, state)
#define set_led2(state) digitalWrite(LED2, state)
#define set_status_led(state) digitalWrite(STATUS_LED, state)
// This program is for a pair of radios. The source address
// of radio one needs to match the destination address of
// radio two and vice versa.
// "#if 0" for radio one
// "#if 1" for radio two
#if 0
#define XB_DESTINATION_ADDRESS "ATDH0, DL1234\r"
#define XB_MY_ADDRESS "ATMY5678\r"
#else
#define XB_DESTINATION_ADDRESS "ATDH0, DL5678\r"
#define XB_MY_ADDRESS "ATMY1234\r"
#endif
#define XB_PAN_ID "ATID1111\r"
#define XB_DATA_MODE "ATCN\r"
#define XB_CMD_MODE "+++"
LCD4Bit lcd = LCD4Bit(2);
// When a button is pressed the interrupt service
// routine will set the button_int_p[i] to 1
// (i = 0 for button 1 and i = 1 for button 2).
// The main loop will execute the appropriate actions.
// ready_p is set to 1 if the XBee initializes properly
// dest_button_change_p is set to 1 if a button on the
// other radio has changed
// button_int_p[i] is changed to 1 if a button interrupt
// has occured
// button[i] contains the state of each button
// button 1 toggles from 0 to 1 and back
// button 2 is momentary
// dest_button[i] contains the state of each button on
// the other radio
boolean ready_p = 0;
boolean dest_button_change_p = 0;
boolean volatile button_int_p[2] = {0, 0};
int button_index = 0;
char button[2] = {0, 0};
char dest_button[2] = {0, 0};
void setup() {
// configure serial communications:
// Compensating for the 12MHz XToAL
// 12800 = (16/12) * 9600
Serial.begin(12800);
lcd.init();
lcd_print("wiblock ZB1+LCD Demo\rSetup\r");
zb1_lcd2_init();
flash_status_led(3);
xbee_init();
flash_status_led(3);
// PCI1 will trigger if any enabled PCINT14..8 pin toggles
enable_int;
PCMSK1 |= (1 << BUTTON1_INT);
PCMSK1 |= (1 << BUTTON2_INT);
}
void zb1_lcd2_init() {
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(STATUS_LED, OUTPUT);
pinMode(LCD_BACKLIGHT, OUTPUT);
pinMode(BUZZER, OUTPUT);
set_buzzer(LOW);
set_led1(OFF);
set_led2(OFF);
set_backlight(OFF);
}
void xbee_init() {
long count = 0;
char in_byte = 0;
// To put the radio in command mode transmit the XB_CMD_MODE string
// and wait of the "OK\r" reply. If the wait is too long then exit
// and blink the ZB1 status LED.
lcd_print("wiblock ZB1+LCD Demo\rInitializing XBee\r");
Serial.print(XB_CMD_MODE);
while (in_byte != '\r') {
if (Serial.available() > 0) {
in_byte = Serial.read();
}
if (count++ > 100000) break;
}
if (count <= 100000) {
// Initialize the XBee to transmit and recieve
// 1. Set the destination address of the radio that will receive
// the transmissions.
// 2. Set the source address of the radio on this ZB1 board.
// 3. Set the Personal Area Network (PAN) ID. All of the radios
// in this mesh need to have the same PAN ID
// 4. Place the radio back into data mode to receve commands.
// All of the message string are defined at the top of the program
Serial.print(XB_DESTINATION_ADDRESS);
Serial.print(XB_MY_ADDRESS);
Serial.print(XB_PAN_ID);
Serial.print(XB_DATA_MODE);
lcd_print("wiblock ZB1+LCD Demo\r");
ready_p = 1;
} else {
flash_status_led(5);
lcd_print("XBee Init Failed\rCheck S2 Position\r");
}
}
void loop() {
boolean flash_led2_p;
// if the XBee initialized (ready_p == 1) then run
// otherwise loop and do nothing
if (ready_p) {
if (Serial.available() > 0) handle_serial();
// button1 toggles the backlight and led1
// button2 beeps the piezo speaker and flashes led2
// no changes to button states until the next loop
// iteration.
disable_int;
// If button 1 was pressed on this board or its
// buddy then change the state of the button 1
// and take the appropriate action.
if (button_int_p[0]) button[0] = button[0] ? 0 : 1;
if (dest_button_change_p) button[0] = dest_button[0];
if (button[0]) {
set_backlight(ON);
set_led1(ON);
} else {
set_backlight(OFF);
set_led1(OFF);
}
// If button2 was pressed on this board or its
// buddy the change set flash_led2_p to 1 and
// take appropriate actions. button2 is treated
// as momentary.
flash_led2_p = 0;
if (button_int_p[1]) flash_led2_p = 1;
if (dest_button_change_p && (dest_button[1])) flash_led2_p = 1;
if (flash_led2_p) {
button[1] = 1;
set_led2(ON);
beep(200);
set_led2(OFF);
}
// If the values of either button have changed on this
// board then update the LCD and transmit the button
// state to the buddy board.
if (button_int_p[0] || button_int_p[1]) {
serial_print_button_state();
lcd_print_button_state();
// Since button2 is treated as momentary a second value needs to
// be transmitted if it was pressed.
if (flash_led2_p) {
button[1] = 0;
dest_button[1] = 0;
serial_print_button_state();
lcd_print_button_state();
}
button_int_p[0] = 0;
button_int_p[1] = 0;
}
// If the buttons changed on the buddy board then only the LCD
// needs to be updated. No values should be transmitted.
if (dest_button_change_p) {
lcd_print_button_state();
dest_button_change_p = 0;
}
// Allow button press interrupts again.
enable_int;
}
}
//
void handle_serial() {
int in_byte = -1;
in_byte = Serial.read();
// The only bytes received should be:
// '0' for button off
// '1' for button on
// '\r' for end of string
dest_button_change_p = 0;
if (in_byte == '0' || in_byte == '1') {
// If the recieved value is different than the current value than
// set the appropriate interrupt flag and update the index.
dest_button[button_index] = in_byte == '0' ? 0 : 1;
button_index = button_index == 1 ? 0 : 1;
} else if (in_byte == '\r') {
dest_button_change_p = 1;
button_index = 0;
}
}
// beep the beeper for "n" counts
void beep(int n) {
for (int i = 0; i < n; i++) {
set_buzzer(HIGH);
delay(1);
set_buzzer(LOW);
delay(1);
}
}
// flash the status LED "n" times
void flash_status_led(int n) {
for (int i = 0; i < n; i++) {
set_status_led(ON);
delay(100);
set_status_led(OFF);
delay(100);
}
delay(200);
}
// If the state of either button has changed then set the appropriate
// interrupt flag. The interrupt flags are read and reset in the main
// loop.
ISR( PCINT1_vect )
{
if (PINC & _BV(BUTTON1)) button_int_p[0] = 1;
if (PINC & _BV(BUTTON2)) button_int_p[1] = 1;
}
// Clears the LCD and then outputs a multi-line string to the LCD.
// Each line is terminated with either a return or a newline
// character. Only the first two lines in a string are output.
void lcd_print(char str[]) {
uint8_t i;
uint8_t len;
char *p;
int line = 1;
p = &str[0];
lcd.clear();
len = strlen(str);
for (i = 0; i < len; i++) {
if (str[i] == '\r' || str[i] == '\n') {
str[i] = 0;
lcd.cursorTo(line, 0);
lcd.printIn(p);
p = &str[i+1];
line++;
}
if (line > 2) break;
}
}
// output the button state to the second line of the LCD.
void lcd_print_button_state() {
for (int i=0; i<2; i++) {
lcd.cursorTo(2, i); //line=2, x=0.
if (button[i]) lcd.printIn("1");
else lcd.printIn("0");
}
}
// output the button state to the XBee which is connected to the
// serial port.
void serial_print_button_state() {
for (int i=0; i<2; i++) {
if (button[i]) Serial.print("1");
else Serial.print("0");
}
Serial.print("\r");
}