Pour la communication i2c (smbus, wire.h) entre Arduino et raspberry pi, reportez-vous au forum outre-mer raspberrypi.org. Fait. Je vais omettre l'introduction d'i2c pour raspberry pi.
main.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import smbus
import time
import os
import json
#Obtention d'un bus I2C
bus = smbus.SMBus(1)
#adresse arduino
SLAVE_ADDRESS = 0x04
#Fin de la configuration
CONFIG_END = 0x00
#Pour la confirmation de configuration 0x1*
REQUEST_CONFIG = 0x10
#Pour le temps de sommeil
GET_INO_SLEEP = 0x11
#Pour le temps d'attente lors de l'arrêt de Raspeye
GET_PI_SHUT = 0x12
#Pour le temps d'attente jusqu'à ce que la tarte aux râpes commence
GET_PI_ISW_TIME = 0x13
#Paramètre de configuration 0x2X
CONFIG_SET = 0x20
#Pour le temps de sommeil
SET_INO_SLEEP = 0x21
#Pour le temps d'attente lors de l'arrêt de Raspeye
SET_PI_SHUT = 0x22
#Pour le temps d'attente après le démarrage de Rasppie
#Lors du retour lorsque l'ACC est désactivé
#Heure de début de la tarte Razz lors du retour avec minuterie de chien de garde
SET_PI_ISW_SLEEP = 0x23
#Nombre maximum d'essais lors de la connexion à I2C
I2C_TRY = 5
#Lecture de la configuration à partir du fichier de configuration
def read_conf():
with open('conf.json', 'r') as f:
file = f.read()
return file
#Lire la configuration actuelle de Raspeye
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
#Ecrire la configuration
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
#Pour vérifier l'état d'entrée de l'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__':
#Charger la configuration
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"])
#Vérifiez l'état actuel des paramètres
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)
#Changer la configuration s'il y a un changement
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"
#Boucle principale
while True:
check_state(SLAVE_ADDRESS)
time.sleep(1.0)
serial_sleep.ino
#include <avr/wdt.h> //Bibliothèque de minuterie Watchdog
#include <avr/sleep.h> //Bibliothèque de sommeil
#include <Wire.h> //Bibliothèque I2C
#include <EEPROM.h> //L'adresse de la bibliothèque EEPROM est comprise entre 0 et 511(512)
#define LED_PIN (13) //Pour les broches LED
#define ACC_IN (2) //Pour broche d'interruption
#define PI_POWER (12) //Pour le relais de mise sous tension de Raspeye
const int SLAVE_ADDRESS = 0x04; //Adresse I2C
const int CONFIG_END=0x00; //Pour l'état normal
//Les paramètres suivants sont communs à Razpai
//Pour la confirmation de configuration 0x1*
const int REQUEST_CONFIG=0x10;
//Pour le temps de sommeil
const int GET_INO_SLEEP=0x11;
//Pour le temps d'attente lors de l'arrêt de Raspeye
const int GET_PI_SHUT=0x12;
//Temps d'attente jusqu'à ce que l'alimentation puisse être coupée après le démarrage de Raspeye
const int GET_PI_ISW_TIME=0x13;
//Paramètre de configuration 0x2X
const int CONFIG_SET=0x20;
//Pour le temps de sommeil
const int SET_INO_SLEEP=0x21;
//Pour le temps d'attente lors de l'arrêt de Raspeye
const int SET_PI_SHUT=0x22;
//Pour le temps d'attente après le démarrage de Rasppie
//Lors du retour lorsque l'ACC est désactivé
//Heure de début de la tarte Razz lors du retour avec minuterie de chien de garde
const int SET_PI_ISW_SLEEP=0x23;
//Indicateur d'intervalle de sommeil
volatile bool slp_interval_flg;
//Indicateur de mode veille
volatile bool slp_counter_flg=false;
//Indicateur de boucle de sommeil
volatile bool slp_loop_flg=false;
//Compteur d'intervalle de sommeil
volatile int interval_counter;
//Valeur pour l'envoi du statut ACC à Raspeye
volatile int pi_acc_state;
//Pour conserver le message de mode reçu
volatile int message_state;
//Pour maintenir l'état d'arduino
volatile int ino_state;
//Pour l'adresse EEPROM
//Adresse d'enregistrement du temps de sommeil
const int ino_sleep_addr=0;
//Adresse pour spécifier l'heure de sommeil
const int pi_sleep_wakeup_addr=1;
//Adresse de temps d'attente d'arrêt de Raspeye
const int pi_shut_addr=2;
//Fondamentalement, la minuterie se met en veille pendant 4 secondes x le nombre de fois spécifié.
//4 secondes de la minuterie se font dans la partie de réglage de la minuterie du chien de garde
//4 secondes si ce qui suit est spécifié comme 15* 15 =60 secondes
const int count_max=15;
//Si ce qui précède est spécifié par 15, il peut être spécifié toutes les minutes.
//Pour les trois éléments suivants, la valeur enregistrée dans l'EEPROM est prioritaire.
//Spécifiez l'état initial (en minutes) du temps de sommeil ci-dessous
volatile int wait_minutes=1;
//Réglage initial du temps d'attente d'arrêt (unité de 10 secondes) de Raspeye
volatile int pi_shut_time=3;
//Spécifiez le temps d'attente (en minutes) après le démarrage de Raspeye
volatile int pi_osw_time=1;
//Variable pour économiser le temps d'attente après le démarrage de Raspeye
volatile long onslp_max_time;
//Variable pour gagner du temps après le démarrage de Raspeye
volatile long onslp_past_time;
// onslp_max_dépassement de temps
volatile bool counter_switch=false;
//Réinitialisation de l'état
void init_value()
{
slp_interval_flg=false;
message_state=0x00;
slp_counter_flg=false;
}
//Jeu de broches
void init_pins()
{
pinMode(LED_PIN,OUTPUT);
pinMode(PI_POWER,OUTPUT);
pinMode(ACC_IN, INPUT);
}
//Vérifiez l'état de l'ACC au démarrage
void init_state()
{
if (digitalRead(ACC_IN))
{
ino_state=0x00;
slp_interval_flg=false;
}else
{
ino_state=0x03;
//Changer le statut ACC
pi_acc_state=0x05;
}
}
//Lire la configuration depuis l'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;
}
}
//Ecrire la configuration dans l'EEPROM
//Spécifiez l'adresse et la valeur
void set_config(int addr, byte data)
{
noInterrupts();
EEPROM.write(addr,data);
interrupts();
}
//Paramètres de la minuterie de surveillance
void wdt_set()
{
wdt_reset();
cli();
MCUSR = 0;
//Définir WDCE WDE
WDTCSR |= 0b00011000;
//Paramètres WDIE Spécifiez WDIF par incréments de 4 secondes
WDTCSR = 0b01000000 | 0b100000;
sei();
}
//Annulation du réglage de la minuterie du chien de garde
void wdt_unset()
{
wdt_reset();
cli();
MCUSR = 0;
//Paramètres WDCE WDE
WDTCSR |= 0b00011000;
//Initialisation de l'état
WDTCSR = 0b00000000;
sei();
}
//Appelé au retour par le chronomètre du chien de garde
//Ceci est une minuterie de chien de garde
ISR(WDT_vect)
{
//Vérifiez l'indicateur du compteur de sommeil
if(slp_counter_flg)
{
//Augmenter le compteur d'intervalles
interval_counter++;
//Fin du sommeil si le compteur d'intervalles a atteint le nombre de fois spécifié
//Appelé toutes les 4 secondes si spécifié toutes les 4 secondes dans les paramètres de l'horloge de surveillance
// count_max est de 15 et attendez_Si les minutes sont égales à 1, cela se termine si vous restez 1 minute
if( interval_counter >= (count_max * wait_minutes) )
{
//Fin de sommeil
slp_counter_flg = false;
}
}
}
//Changer le drapeau et l'activer en cas d'interruption ACC
void wakeUp()
{
slp_counter_flg = false;
}
//sommeil arduino
void sleep()
{
interval_counter = 0;
//Jeu de minuterie pour chien de garde
wdt_set();
//Réglage du mode veille
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
//Paramètres d'interruption ACC
//S'il y a une interruption ACC, changez le drapeau et forcez-le à démarrer
attachInterrupt(0,wakeUp, RISING);
//Ensemble d'indicateurs de compteur de sommeil
slp_counter_flg=true;
//Boucle jusqu'à ce que l'indicateur du compteur de sommeil soit effacé
//ISR avec minuterie pour chien de garde(WDT_vect)Est appelé, donc jusqu'à ce qu'il y ait un changement ou une interruption
while(slp_counter_flg)
{
noInterrupts(); //cli();
sleep_enable();
interrupts(); //sei();
sleep_cpu(); //cpu sleep
sleep_disable();
}
//Annulation du réglage de la minuterie du chien de garde
wdt_unset();
//Annulation du réglage d'interruption ACC
detachInterrupt(0);
}
//Recevoir des messages de Raspeye 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];
}
}
//Envoyer un message à Raspeye
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;
}
}
//Fonction de minuterie de veille (veille en secondes)
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){}
}
//Mesures de contre-débordement
else
{
while(millis() > now){}
while(millis() < out_time){}
}
}
//Fonction Raspeye Power ON
void pi_wakeup()
{
digitalWrite(PI_POWER,HIGH);
digitalWrite(LED_PIN,HIGH);
}
//Vérifiez le temps de sommeil
void read_time_slp()
{
onslp_max_time = ( millis()+ 60000 * pi_osw_time );
onslp_past_time = millis();
//S'il déborde, le processus sera modifié, alors définissez l'indicateur de commutation.
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);
}
//installer
void setup()
{
//Initialisation
init_value();
//Initialisation des broches
init_pins();
//Démarrage I2C
Wire.begin(SLAVE_ADDRESS);
//Recevoir un message
Wire.onReceive(get_message);
//Envoyer le message
Wire.onRequest(send_message);
//Lire la configuration depuis l'EEPROM
read_rom_config();
//Initialisation de l'état, veille sans connexion ACC
init_state();
//Attendre un peu
delay(1000);
}
//Boucle principale
void loop()
{
//Vérifiez l'état de l'ACC à chaque fois
int acc = digitalRead(ACC_IN);
switch(ino_state)
{
//Etat initial
//Enregistrez l'activation et l'état ACC de Raspeye, et passez à l'état normal
case 0x00:
pi_wakeup();
pi_acc_state=0x01;
ino_state++;
break;
//Condition normale
case 0x01:
//ACC est désactivé, l'indicateur d'intervalle de sommeil n'est pas défini
if( (acc==0) && (!slp_interval_flg) )
{
//Pour arrêter la tarte aux râpes
ino_state++;
}
//Indicateur d'intervalle de sommeil uniquement
// case 0x04:Lorsque ACC est désactivé, l'indicateur d'intervalle de sommeil est activé.
else if(slp_interval_flg)
{
//Vérifiez le drapeau de commutation du compteur
if(counter_switch)
{
//Traitement normal
//Heure actuelle onslp_max_Plus que du temps ou débordé onslp_past_S'il est inférieur au temps, annulez l'indicateur d'intervalle
if((millis() > onslp_max_time) || (millis() < onslp_past_time))
{
slp_interval_flg = false;
}
}
//Traitement post-débordement
//Heure actuelle onslp_past_moins de temps et onslp_max_S'il est temps ou plus, annulez l'indicateur d'intervalle
else
{
if( (millis() < onslp_past_time) && (millis() > onslp_max_time) )
{
slp_interval_flg = false;
}
}
}
break;
//Arrêt de Rasppie
case 0x02:
ino_state++;
//Changer la valeur de la variable d'état ACC
pi_acc_state=0x05;
//Attendez que la commande d'arrêt soit exécutée
wait_time(pi_shut_time * 10);
//Rasppie hors tension
digitalWrite(PI_POWER,LOW);
digitalWrite(LED_PIN,LOW);
//Après avoir éteint le relais, laissez la tarte à la râpe attendre correctement jusqu'à ce que la puissance devienne nulle
wait_time(pi_shut_time * 10);
break;
//sommeil arduino
case 0x03:
sleep();
ino_state++;
break;
//Après s'être réveillé du sommeil
//Vérifiez l'intervalle de sommeil et vérifiez l'état de l'ACC
case 0x04:
slp_interval_flg=true;
//Lire si ACC est désactivé_time_slp();Pour faire attendre la tarte aux râpes pendant le temps spécifié sans s'arrêter
if(acc==0)
{
read_time_slp();
}
//Si ACC est activé, revenez comme d'habitude
else
{
slp_interval_flg=false;
}
//État initial de l'arduino
ino_state=0x00;
break;
}
}
conf.json
{"config": {"pi": {"shut_wait": "3", "on_sleep_wakeup_time": "1"}, "arduino": {"sleep": "1"}}}
Recommended Posts