For i2c communication (smbus, wire.h) between Arduino and raspberry pi, refer to the overseas forum raspberrypi.org. Did. I will omit the introduction of i2c for raspberry pi.
main.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import smbus
import time
import os
import json
#Obtaining an I2C bus
bus = smbus.SMBus(1)
#arduino address
SLAVE_ADDRESS = 0x04
#End of config
CONFIG_END = 0x00
#For config confirmation 0x1*
REQUEST_CONFIG = 0x10
#For sleep time
GET_INO_SLEEP = 0x11
#For waiting time when shutting down Raspberry Pi
GET_PI_SHUT = 0x12
#For waiting time until Raspberry Pi starts
GET_PI_ISW_TIME = 0x13
#Config setting 0x2X
CONFIG_SET = 0x20
#For sleep time
SET_INO_SLEEP = 0x21
#For waiting time when shutting down Raspberry Pi
SET_PI_SHUT = 0x22
#For waiting time after starting Raspberry Pi
#When returning when ACC is off
#Raspberry Pi startup time when returning with the watchdog timer
SET_PI_ISW_SLEEP = 0x23
#Maximum number of trials when connecting to I2C
I2C_TRY = 5
#Read config from config file
def read_conf():
with open('conf.json', 'r') as f:
file = f.read()
return file
#Read the current config from Raspberry Pi
def get_config(ino_add, name):
TRY = I2C_TRY
while TRY:
try:
tmp_conf = bus.read_byte_data(ino_add, name)
return tmp_conf
except IOError as e:
print "get config IO error"
TRY -= 1
except:
print "get config error"
raise
if not TRY:
raise
#Write config
def set_config(ino_add, cmd1, cmd2, cmd3, cmd4):
TRY = I2C_TRY
while TRY:
try:
bus.write_i2c_block_data(ino_add, cmd1, [cmd2, cmd3, cmd4])
time.sleep(4.0)
except IOError as e:
print "set config IO error"
TRY -= 1
except:
print "set config error"
raise
if not TRY:
raise
#For checking the input status of ACC
def check_state(ino_add):
TRY = I2C_TRY
while TRY:
try:
reading = int(bus.read_byte_data(ino_add, 0x50))
print(reading)
if reading == 5:
os.system("sudo /sbin/shutdown -h now")
except IOError as e:
print "check data IO error"
TRY -= 1
except:
print "check data Unexcepted error"
if __name__ == '__main__':
#Load config
config = json.loads(read_conf())
set_ino_sleep = int(config["config"]["arduino"]["sleep"])
set_pi_shut = int(config["config"]["pi"]["shut_wait"])
set_pi_sleep = int(config["config"]["pi"]["on_sleep_wakeup_time"])
#Check the current setting status
config_ino_sleep = get_config(SLAVE_ADDRESS, GET_INO_SLEEP)
config_pi_shut = get_config(SLAVE_ADDRESS, GET_PI_SHUT)
config_pi_sleep = get_config(SLAVE_ADDRESS, GET_PI_ISW_TIME)
#Change the config if there is a change
if (config_ino_sleep != set_ino_sleep):
set_config(SLAVE_ADDRESS, SET_INO_SLEEP, set_ino_sleep, 0x00, 0x00)
print "set conf set_ino_sleep"
if (config_pi_sleep != set_pi_sleep):
set_config(SLAVE_ADDRESS, SET_PI_ISW_SLEEP, set_pi_sleep, 0x00, 0x00)
print "set conf set_pi_sleep"
if (config_pi_shut != set_pi_shut):
set_config(SLAVE_ADDRESS, SET_PI_SHUT, set_pi_shut, 0x00, 0x00)
print "set conf set_pi_shut"
#Main loop
while True:
check_state(SLAVE_ADDRESS)
time.sleep(1.0)
serial_sleep.ino
#include <avr/wdt.h> //Watchdog timer library
#include <avr/sleep.h> //Sleep library
#include <Wire.h> //I2C library
#include <EEPROM.h> //EEPROM library address is 0 to 511(512)
#define LED_PIN (13) //For LED pins
#define ACC_IN (2) //For interrupt pins
#define PI_POWER (12) //For power ON relay of Raspberry Pi
const int SLAVE_ADDRESS = 0x04; //I2C address
const int CONFIG_END=0x00; //For normal state
//The following settings are common to Raspberry Pi
//For config confirmation 0x1*
const int REQUEST_CONFIG=0x10;
//For sleep time
const int GET_INO_SLEEP=0x11;
//For waiting time when shutting down Raspberry Pi
const int GET_PI_SHUT=0x12;
//Waiting time until the power can be turned off after starting Raspberry Pi
const int GET_PI_ISW_TIME=0x13;
//Config setting 0x2X
const int CONFIG_SET=0x20;
//For sleep time
const int SET_INO_SLEEP=0x21;
//For waiting time when shutting down Raspberry Pi
const int SET_PI_SHUT=0x22;
//For waiting time after starting Raspberry Pi
//When returning when ACC is off
//Raspberry Pi startup time when returning with the watchdog timer
const int SET_PI_ISW_SLEEP=0x23;
//Interval flag during sleep
volatile bool slp_interval_flg;
//Sleep mode flag
volatile bool slp_counter_flg=false;
//Sleep loop flag
volatile bool slp_loop_flg=false;
//Sleep interval counter
volatile int interval_counter;
//Value for sending ACC status to Raspberry Pi
volatile int pi_acc_state;
//For holding messages for the received mode
volatile int message_state;
//For maintaining the state of arduino
volatile int ino_state;
//For EEPROM address
//Sleep time recording address
const int ino_sleep_addr=0;
//Address for specifying sleep time
const int pi_sleep_wakeup_addr=1;
//Raspberry Pi shutdown wait time address
const int pi_shut_addr=2;
//Basically, the timer sleeps for 4 seconds x the specified number of times.
//4 seconds of the timer is done in the watchdog timer setting part
//4 seconds if the following is specified as 15.* 15 =60 seconds
const int count_max=15;
//If the above is specified by 15, it can be specified every minute.
//For the following three items, the value recorded in EEPROM has priority.
//Specify the initial state (minutes) of sleep time below
volatile int wait_minutes=1;
//Initial setting of shutdown waiting time (10 seconds unit) of Raspberry Pi
volatile int pi_shut_time=3;
//Specify the waiting time (in minutes) after starting Raspberry Pi
volatile int pi_osw_time=1;
//Variable for saving wait release time after starting Raspberry Pi
volatile long onslp_max_time;
//Variable for saving time after starting Raspberry Pi
volatile long onslp_past_time;
// onslp_max_time overflow
volatile bool counter_switch=false;
//Status reset
void init_value()
{
slp_interval_flg=false;
message_state=0x00;
slp_counter_flg=false;
}
//Pin set
void init_pins()
{
pinMode(LED_PIN,OUTPUT);
pinMode(PI_POWER,OUTPUT);
pinMode(ACC_IN, INPUT);
}
//Check the ACC status at startup
void init_state()
{
if (digitalRead(ACC_IN))
{
ino_state=0x00;
slp_interval_flg=false;
}else
{
ino_state=0x03;
//ACC status change
pi_acc_state=0x05;
}
}
//Read config from EEPROM
void read_rom_config()
{
wait_minutes=EEPROM.read(ino_sleep_addr);
if( (wait_minutes <= 0) || (wait_minutes > 250) )
{
wait_minutes=1;
}
pi_shut_time=EEPROM.read(pi_shut_addr);
if( (pi_shut_time <= 0) || ( pi_shut_time >250) )
{
pi_shut_time=1;
}
pi_osw_time=EEPROM.read(pi_sleep_wakeup_addr);
if( (pi_osw_time <= 0 ) || (pi_osw_time > 250) )
{
pi_osw_time=1;
}
}
//Write config to EEPROM
//Specify address and value
void set_config(int addr, byte data)
{
noInterrupts();
EEPROM.write(addr,data);
interrupts();
}
//Watchdog timer settings
void wdt_set()
{
wdt_reset();
cli();
MCUSR = 0;
//Set WDCE WDE
WDTCSR |= 0b00011000;
//WDIE settings Specify WDIF in 4 second increments
WDTCSR = 0b01000000 | 0b100000;
sei();
}
//Unset watchdog timer
void wdt_unset()
{
wdt_reset();
cli();
MCUSR = 0;
//WDCE WDE settings
WDTCSR |= 0b00011000;
//State initialization
WDTCSR = 0b00000000;
sei();
}
//Called on return by watchdog timer
//This is a watchdog timer
ISR(WDT_vect)
{
//Check the sleep counter flag
if(slp_counter_flg)
{
//Increase the interval counter
interval_counter++;
//Ends sleep if the interval counter reaches the specified number of times
//Called every 4 seconds if specified every 4 seconds in the watchdog timer settings
// count_max is 15 and wait_If minutes is 1, it ends if you stand for 1 minute
if( interval_counter >= (count_max * wait_minutes) )
{
//End of sleep
slp_counter_flg = false;
}
}
}
//Change the flag and activate it when there is an ACC interrupt
void wakeUp()
{
slp_counter_flg = false;
}
//arduino sleep
void sleep()
{
interval_counter = 0;
//Watchdog timer set
wdt_set();
//Sleep mode settings
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
//ACC interrupt settings
//If there is an ACC interrupt, change the flag and force it to start
attachInterrupt(0,wakeUp, RISING);
//Set of sleep counter flags
slp_counter_flg=true;
//Loop until the sleep counter flag is cleared
//ISR with watchdog timer(WDT_vect)Is called, so until there is a change or interrupt
while(slp_counter_flg)
{
noInterrupts(); //cli();
sleep_enable();
interrupts(); //sei();
sleep_cpu(); //cpu sleep
sleep_disable();
}
//Unset watchdog timer
wdt_unset();
//Canceling the ACC interrupt setting
detachInterrupt(0);
}
//Receive messages from Raspberry Pi via I2C
void get_message(int n){
int cmd[4];
int x = 0;
while(Wire.available()) {
cmd[x] = Wire.read();
x++;
}
if ((cmd[0] >= 16) && (cmd[0] < 32)) // 0x10~0x1F get config
{
message_state = cmd[0];
}
else if((cmd[0] >= 32) && (cmd[0] < 47)) //0x20~0x2F set config
{
switch (cmd[0])
{
case 0x21: //ino_sleep_time (minutes)
set_config(ino_sleep_addr, cmd[1]);
read_rom_config(); //reload config
break;
case 0x22: //pi shutdown wait time
set_config(pi_shut_addr, cmd[1]);
read_rom_config(); //reload config
break;
case 0x23: //pi in sleep wakeup time
set_config(pi_sleep_wakeup_addr, cmd[1]);
read_rom_config(); //reload config
break;
}
}
else if ((cmd[0]==0) && (cmd[3]==120))
{
toggle();
}
else
{
}
if(cmd[0] == 0x50){
message_state = cmd[0];
}
}
//Send a message to Raspberry Pi
void send_message(){
//when get cmd switch
switch (message_state) {
case 0x11: //ino_sleep_time (minutes)
Wire.write(wait_minutes);
break;
case 0x12: //pi shutdown wait time
Wire.write(pi_shut_time);
break;
case 0x13: //pi in sleep wakeup time
Wire.write(pi_osw_time);
break;
case 0x50: //
Wire.write(pi_acc_state); //send
break;
}
}
//Wait timer function (standby in seconds)
void wait_time(int t)
{
volatile unsigned long now = millis();
volatile unsigned long out_time = (now + 1000* (unsigned long)t);
if(now < out_time){
while(millis()< out_time){}
}
//Counter overflow measures
else
{
while(millis() > now){}
while(millis() < out_time){}
}
}
//Raspberry Pi power ON function
void pi_wakeup()
{
digitalWrite(PI_POWER,HIGH);
digitalWrite(LED_PIN,HIGH);
}
//Check sleep time
void read_time_slp()
{
onslp_max_time = ( millis()+ 60000 * pi_osw_time );
onslp_past_time = millis();
//If it overflows, the process will be changed, so set the switch flag.
if (onslp_max_time > onslp_past_time)
{
counter_switch=true;
}
else
{
counter_switch=false;
}
}
//test
boolean LEDON = false;
void toggle(){
LEDON = !LEDON; //true and false change
digitalWrite(LED_PIN, LEDON);
}
//setup
void setup()
{
//Initialization
init_value();
//Pin initialization
init_pins();
//I2C start
Wire.begin(SLAVE_ADDRESS);
//Receive message
Wire.onReceive(get_message);
//Send message
Wire.onRequest(send_message);
//Reading config from EEPROM
read_rom_config();
//State initialization, sleep without ACC connection
init_state();
//Wait a little
delay(1000);
}
//Main loop
void loop()
{
//Check the status of ACC every time
int acc = digitalRead(ACC_IN);
switch(ino_state)
{
//initial state
//Record the activation of Raspberry Pi and ACC status, transition to normal status
case 0x00:
pi_wakeup();
pi_acc_state=0x01;
ino_state++;
break;
//Normal condition
case 0x01:
//ACC is off, sleep interval flag is not set
if( (acc==0) && (!slp_interval_flg) )
{
//To shut down Raspberry Pi
ino_state++;
}
//Sleep interval flag only
// case 0x04:When ACC is off, the sleep interval flag is set.
else if(slp_interval_flg)
{
//Check the switch flag on the counter
if(counter_switch)
{
//Normal processing
//Current time onslp_max_More than time or overflowed onslp_past_If it is less than or equal to time, the interval flag is cleared.
if((millis() > onslp_max_time) || (millis() < onslp_past_time))
{
slp_interval_flg = false;
}
}
//Post-overflow processing
//Current time onslp_past_less than time and onslp_max_If it is time or more, the interval flag is canceled.
else
{
if( (millis() < onslp_past_time) && (millis() > onslp_max_time) )
{
slp_interval_flg = false;
}
}
}
break;
//Raspberry Pi Shutdown
case 0x02:
ino_state++;
//Change the value of the ACC state variable
pi_acc_state=0x05;
//Wait for the shutdown command to be executed
wait_time(pi_shut_time * 10);
//Raspberry Pi power off
digitalWrite(PI_POWER,LOW);
digitalWrite(LED_PIN,LOW);
//After turning off the relay, let the Raspberry Pi wait properly until the power becomes zero.
wait_time(pi_shut_time * 10);
break;
//arduino sleep
case 0x03:
sleep();
ino_state++;
break;
//After waking up from sleep
//Check sleep interval and check ACC status
case 0x04:
slp_interval_flg=true;
//Read if ACC is off_time_slp();To make the Raspberry Pi wait for the specified time without shutting it down
if(acc==0)
{
read_time_slp();
}
//If ACC is ON, return as usual
else
{
slp_interval_flg=false;
}
//Initial arduino state
ino_state=0x00;
break;
}
}
conf.json
{"config": {"pi": {"shut_wait": "3", "on_sleep_wakeup_time": "1"}, "arduino": {"sleep": "1"}}}
Recommended Posts