Software Specification
Pixace40X2 Code:
The PICAXE40X2 is responsible for reading data sent by the laptop along the serial line and transmitting it to the ATMEGA644P via I2C.
init: hi2csetup i2cmaster, %00000011, i2cslow_8, i2cbyte main: serrxd b0 hi2cout (b0) goto main
ATMEGA644P Code:
The ATMEGA644P receives the serial data from the PICAXE40X2 via I2C. The init_i2c(address) method initiates the appropriate registers so the chip listens to the I2C data whenever its address is requested(which is always because it is the only slave on the I2C bus). This allows in future revisions for multiple devices to be added to the I2C bus such as SRAM. The init_devices() method sets up the pins that have peripherals connected to them. There are a total of 4 peripherals used in this revision(2 block unit relays, 1 unit relay, and one status light unit). The “block unit relays” control one power strip and have a green and red led that are used to signal turning on and off behavior respectively. The “unit relays” have two 3 unit power strips and have a green led put in series with the relay. Therefore, when a unit relay is on, the status green led turns on. Lastly, the status light unit is two independent lights. One is a green cold cathode pair of lights and the other is an orange status light.
#include <avr/interrupt.h> #include <avr/io.h> #include <util/delay.h> volatile unsigned char command; #define CMD_BLOCKUNITRELAY0_OFF 0x41 #define CMD_BLOCKUNITRELAY0_ON 0x42 #define CMD_BLOCKUNITRELAY1_OFF 0x43 #define CMD_BLOCKUNITRELAY1_ON 0x44 #define CMD_UNITRELAY0_OFF 0x45 #define CMD_UNITRELAY0_ON 0x46 #define CMD_UNITRELAY1_OFF 0x47 #define CMD_UNITRELAY1_ON 0x48 #define CMD_SLIGHT0_OFF 0x49 #define CMD_SLIGHT0_ON 0x50 #define CMD_SLIGHT1_OFF 0x51 #define CMD_SLIGHT1_ON 0x52 void delay(char ds) { char counter = 0; while(counter < (ds*10)) { _delay_ms(10); counter++; } } void init_I2C(char address) { TWAR = (address << 1) | (1 << TWGCE); TWCR = (1 << TWEA) | (1 << TWEN) | (1 << TWIE); } ISR(TWI_vect) { command = TWDR; TWCR |= (1 << TWINT) | (1 << TWEA); } void init_devices() { MCUCR = (1 << PUD); DDRA = (1 << DDA1) | (1 << DDA3) | (1 << DDA4) | (1 << DDA5) | (1 << DDA6) | (1 << DDA7); } int main(void) { char temp = 0; init_I2C(0x01); init_devices(); sei(); for(;;) { switch (command) { case CMD_BLOCKUNITRELAY0_OFF: { temp = 0; PORTA &= ~(1 << PA0); //since PUD is set we just need to switch DDRA to go from low to HIGH-Z while(temp < 10) //on and off 5 times in 5 sec { DDRA ^= (1 << DDA0); delay(5); temp++; } DDRA &= ~(1 << DDA0); //make port output again PORTA &= ~((1 << PA0) | (1 << PA1)); //turn off relay and led break; } case CMD_BLOCKUNITRELAY0_ON: { temp = 0; DDRA |= (1 << DDA0); PORTA |= (1 << PA0); //since PUD is set we just need to switch DDRA to go from high to HIGH-Z while(temp < 10) //on and off 5 times in 5 sec { DDRA ^= (1 << DDA0); delay(5); temp++; } PORTA |= (1 << PA0) | (1 << PA1); //turn on relay and green led break; } case CMD_BLOCKUNITRELAY1_OFF: { temp = 0; PORTA &= ~(1 << PA2); //since PUD is set we just need to switch DDRA to go from low to HIGH-Z while(temp < 10) //on and off 5 times in 5 sec { DDRA ^= (1 << DDA2); delay(5); temp++; } DDRA &= ~(1 << DDA2); //make port output again PORTA &= ~((1 << PA2) | (1 << PA3)); //turn off relay and led break; } case CMD_BLOCKUNITRELAY1_ON: { temp = 0; DDRA |= (1 << DDA2); PORTA |= (1 << PA2); //since PUD is set we just need to switch DDRA to go from high to HIGH-Z while(temp < 10) //on and off 5 times in 5 sec { DDRA ^= (1 << DDA2); delay(5); temp++; } DDRA |= (1 << DDA2); //make port output again PORTA |= (1 << PA2) | (1 << PA3); //turn on relay and green led break; } case CMD_UNITRELAY0_OFF: { PORTA &= ~(1 << PA4); break; } case CMD_UNITRELAY0_ON: { PORTA |= (1 << PA4); break; } case CMD_UNITRELAY1_OFF : { PORTA &= ~(1 << PA5); break; } case CMD_UNITRELAY1_ON: { PORTA |= (1 << PA5); break; } case CMD_SLIGHT0_OFF: { PORTA &= ~(1 << PA6); break; } case CMD_SLIGHT0_ON: { PORTA &= ~(1 << PA7); PORTA |= (1 << PA6); break; } case CMD_SLIGHT1_OFF: { PORTA &= ~(1 << PA7); break; } case CMD_SLIGHT1_ON: { PORTA &= ~(1 << PA6); PORTA |= (1 << PA7); break; } } } }
Laptop Code:
The laptop is responsible for fetching commands from the MySQL database, updating the database when the commands are completed, and updating the appropriate pins on the microcontroller. Any command less than 3 signals that no current action is needed. A 2 is used to show a device is currently on while a 1 signifies a device is currently off. A 3 is used to signal to the laptop that a device should be turned off while a 4 signals the laptop to turn the device on.
#include <errno.h> #include <fcntl.h> #include <mysql.h> #include <stdio.h> #include <stdlib.h> #include <string> #include <string.h> #include <termios.h> #include <unistd.h> using namespace std; int init_serial() { int fd; struct termios options; fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NDELAY); if(fd == -1) { perror("Could not initialize serial connection"); exit(1); } tcgetattr(fd, &options); tcflush(fd, TCIFLUSH); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; options.c_cflag |= (CLOCAL | CREAD); tcsetattr(fd, TCSANOW, &options); return fd; } MYSQL* init_mysql(MYSQL* mysql_server) { mysql_server = mysql_init(NULL); if (!mysql_real_connect(mysql_server,"mysql server","top secret username","top secret password","my database", 0,NULL,0)) { perror("Could not connect to the MYSQL server"); exit(1); } return mysql_server; } int main() { int fd,key,command; bool exit = false;; MYSQL *mysql_server; MYSQL_RES *res; MYSQL_ROW row; string query; mysql_server = init_mysql(mysql_server); fd = init_serial(); while(true) //loop forever { mysql_query(mysql_server, "SELECT * FROM room_status"); res = mysql_use_result(mysql_server); command = 0x41; exit = false; while (!exit && (row = mysql_fetch_row(res)) != NULL) //go over all the devices { query = ""; if(!strcmp(row[2],"3") || !strcmp(row[2],"4")) //if the device needs to be updated { query = "UPDATE room_status SET Status = "; if(!strcmp(row[2],"3")) //if port needs to be turned off { query += "1"; write(fd,(const char*)&command,1); sleep(1); command += 2; } else //if port needs to be turned on { query += "2"; command += 1; write(fd,(const char*)&command,1); sleep(1); command += 1; } query += " WHERE ID = "; query += row[0]; mysql_free_result(res); mysql_query(mysql_server,query.c_str()); exit = true; break; } else { command += 2; } } } mysql_close(mysql_server); close(fd); }
COGITO Control:
The website used to control the project can be found here. The central code is found in the following php script:
if(is_user_logged_in()) { $connection=mysql_connect("mysql server","username","password") or die ("Could not connect to MySQL Database"); mysql_select_db("secret database") or die("Could not open up the room's database"); if(isset($_POST["submit"])) { $result = mysql_query("SELECT * from room_status"); $number = 0; while($number < mysql_num_rows($result)) { $row = @mysql_fetch_array($result); $old[$number] = $row["Status"]; $number += 1; } $peripherals = $_POST["peripherals"]; $number = 0; if($peripherals == NULL) { while($number < mysql_num_rows($result)) { if($old[$number] == 2) { mysql_query("UPDATE room_status SET Status = '3' WHERE ID='" . $number . "'"); } $number += 1; } } else { while($number < mysql_num_rows($result)) { if(in_array($number,$peripherals)) { if($old[$number] == 1) { mysql_query("UPDATE room_status SET Status = '4' WHERE ID='" . $number . "'"); } } else { if($old[$number] == 2) { mysql_query("UPDATE room_status SET Status = '3' WHERE ID='" . $number . "'"); } } $number += 1; } } } echo '<form action="http://www.thecogitoproject.brentstrysko.com/room-status/" method="post">'; $number = 0; $result = mysql_query("SELECT * from room_status"); while($number < mysql_num_rows($result)) { $row = @mysql_fetch_array($result); $checked = ($row['Status']==2 || $row['Status']==4)?"checked":""; echo "<input type='checkbox' name='peripherals[]' value='" . $number . "' " . $checked . "/>" . $row['Device'] . "<br />"; $number += 1; } echo "<u>_____________________</u>"; echo "<input type='submit' name='submit' value='Update Room' /> </form>"; } else { echo "You must Log In to change room settings"; }