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