Aidez nous ! Projet - Gestion domotique

Yep!

Ok pour les triacs, mais ce serait plus mieux de dimensionner le circuit de puissance en fonction des disjoncteurs, 10 A et 16 A pour les plus courants. En cas de pépin ou de surchauffe, on risque de griller le recepteur et le triac sans que les appareils de sécurité aient réagis...L'autre option est de claquer un fusible 8 A sur chaque organe de commande.

@+

Zoroastre.

Salut à tous.
Pour ceux qui veulent faire de la domotique sans ce prendre le choux, il existe DomoticHome.
C'est un projet simple qui permet de piloter avec une application via sont téléphone Androïd une platine Arduino.
Il génère même le code C pour la platine pour vous.
Les étapes :

  • Préparer votre platine avec une carte ethernet et connectés les sorties dont vous avez besoin.
  • Allez sur http://www.domotichome.net et ce créer un compte.
  • Remplier les champs.
  • Mettre le code généré dans la platine Arduino.
  • Installer l'application du Market https://market.android.com/details?id=nerdydog.domoHome, la lancer, la configurer.
    Et hop, vous avez en quelques minutes fait une application domotique sans soucis.
    Il y a même la possibilité de savoir la température.

J'ai pas pus encore essayer vus que j’attends mon module ethernet.

Brisebee:
J'ai rapidement regardé le lien concernant le montage de commande par triac, c'est un montage de base qui doit très bien fonctionner.
Après il faut voir au cas par cas en fonction de la puissance à commander et du type de commande TOR ou progressif.
Mais n'hésiste pas Osaka (on se tutoie) à me solliciter pour toute question liée au hard.

Merci Bribri :), vu ton expérience dans le domaine je sais que je peux te faire confiance à 100% .
J'attend avec impatience la suite de tes solutions. $)

zoroastre:
L'autre option est de claquer un fusible 8 A sur chaque organe de commande.

Je pense que c'est le mieux, fusible dédié et au plus près du "risque" d'échauffement sans trop perturbé le reste ?
N'hésite pas à donner tes idées et solutions également.

jplaville:
Pour ceux qui veulent faire de la domotique sans ce prendre le choux, il existe DomoticHome.

Solution intéressante pour ne pas se prendre le choux effectivement :grin:, mais bon ici le but est (de ce prendre le choux :P) d'avoir une solution 100% personnalisée (différente solutions ici donc plus une entre aide) sans dépendre d'un système ou application limité à une technologie (androïd,tel capteurs, ...).
(Et j'aime mettre mes mains dans le cambouis :D)
Par contre une fois que tu l'auras testé, je te recommande d'ouvrir un post dédié car ça doit surement intéressé du monde. :wink:

osaka:
Solution intéressante pour ne pas se prendre le choux effectivement :grin:, mais bon ici le but est (de ce prendre le choux :P) d'avoir une solution 100% personnalisée (différente solutions ici donc plus une entre aide) sans dépendre d'un système ou application limité à une technologie (androïd,tel capteurs, ...).
(Et j'aime mettre mes mains dans le cambouis :D)
Par contre une fois que tu l'auras testé, je te recommande d'ouvrir un post dédié car ça doit surement intéressé du monde. :wink:

Je comprends, moi aussi je suis pour mettre les mains dans le cambouis, mais ça peut être approche intéressante pour débuter et arriver rapidement à quelque chose.
De plus, je débute sur Arduino mais c'est nettement plus facile de programmer une platine Arduino que de programmer un mobile Androïd.
Je suis actuellement des cours de développement Java Androïd et je sais te quoi je parle, je te souhaite bonne chance si tu veux te lancer là dedans et faire un programme (potable) pour piloter ta platine.
Surtout si t'as jamais fait de Java.
De plus, le code Arduino est généré automatiquement mais rien ne t'empêche de le modifier ensuite.
Mais tu as raison, c'est limité à certains périphériques.
Pour la température par exemple, c'est un certain MCP9700A qui est utilisé et rien d'autre.
Pour les sorties par contre tu peux piloter ce que tu veux, tu mets à HIGH ou LOW quelque soit le type de sortie.
Mais ça vas ce développer surement.
A suivre donc... je vais dès que j'aurais testé ouvrir un nouveau sujet.

jplaville:
mais c'est nettement plus facile de programmer une platine Arduino que de programmer un mobile Androïd.

Si on ce contente du core arduino je dirais moui,par contre si on veux quelque chose d'optimal c'est genre registre et c only.

jplaville:
Je suis actuellement des cours de développement Java Androïd et je sais te quoi je parle, je te souhaite bonne chance si tu veux te lancer là dedans et faire un programme (potable) pour piloter ta platine.

Je suis dev "java" inactif pour le moment (longue histoire). :grin:
Niveau portabilité je suis plutôt pour un client léger (web plus simple) surtout en ce qui concerne l'interface, ici on est quand même dépendant du sdk androïd.
Pour l'interface justement je compte plutôt continuer sur ma solution http://arduino.cc/forum/index.php/topic,72035.0.html .

jplaville:
Surtout si t'as jamais fait de Java.

Le titre de mon projet de fin d'études (graduat) était "Application modulaire serveur de domotique en Java". (j'avais déjà la domo en tête :grin:) :open_mouth:
Donc c'est un peux pour tout ça que je peux me "permettre" de mettre les mains dans le cambouis, mon études sur le sujet (domotique) date et est suivis d'une longue réflexion, recherche, ...

jplaville:
De plus, le code Arduino est généré automatiquement mais rien ne t'empêche de le modifier ensuite.

Le code des autres et généré automatique est souvent difficile à comprendre et à reprendre. :~

jplaville:
Mais tu as raison, c'est limité à certains périphériques.
Pour la température par exemple, c'est un certain MCP9700A qui est utilisé et rien d'autre.
Pour les sorties par contre tu peux piloter ce que tu veux, tu mets à HIGH ou LOW quelque soit le type de sortie.
Mais ça vas ce développer surement.

Le plus gros défaut =(

jplaville:
A suivre donc... je vais dès que j'aurais testé ouvrir un nouveau sujet.

Je suis certain que ça intéressera du monde. :wink:

#include <util/crc16.h>
#include <util/delay.h>
#include <avr/wdt.h>

#define DATA_LENGTH 6
#define ADDRESS 0x10
#define RECEIVER 0x11
#define RE_DE_ON PORTD|=4
#define RE_DE_OFF PORTD&=~(4)
#define RE_DE_REG DDRD |= 4
#define BAUD 115200

#define _WAIT(_pres) _delay_us(_pres)
#define SERIAL_BUFFER_SIZE 16

struct ring_buffer
{
  uint8_t buffer[SERIAL_BUFFER_SIZE];
  volatile uint8_t head;
  volatile uint8_t tail;
};

volatile uint8_t listener = 0;
volatile uint32_t delayWD = 0;
ring_buffer rx_buffer  =  { { 0 }, 0, 0 };

uint8_t bufferBusTx[DATA_LENGTH] = {0}; 

uint32_t delayS = 0;
uint32_t _micros = 0;

volatile uint8_t ack = 0;
uint8_t err = 0;

const uint32_t pres = 69120000/BAUD; //temps de maintien RE_DE
const uint32_t maxRec = 14000000/BAUD; //temps max en reception
const uint32_t maxTrans = (32640000/(BAUD/100))+((ADDRESS*(pres*2))); //temps max de transaction+ temps different entre module selon l'adresse

volatile uint8_t* registreR[3] = {&PINB, &PINC, &PIND}; //tableau pour la gestion semi dynamique des registres (&DDR = &PIN+1, &P0RT= &PIN+2)

uint8_t stateB = 0;
uint32_t delayB = 0;

inline void store_char(uint8_t c, struct ring_buffer *buffer) //gestion des donnees entrantent dans le buffer (circulaire)
{
  uint8_t i = (uint8_t)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

  if (i != buffer->tail) {
    buffer->buffer[buffer->head] = c;
    buffer->head = i;
  }
}

ISR(USART_RX_vect)
{
  if((UCSR0B & (1<<RXB80))) // si bit9 à 1 = adresse
  {
    listener = UDR0;
    if(listener == ADDRESS || listener == 0x80 || (ack && listener == 0x81)) //s'il sagit de son adresse ou adresse controleur = 0x80 ou si une transaction en cours&& adresse de ack = 0x81  on active l'ecoute
    {
      UCSR0A &= ~(1<<MPCM0);
    }
    else //sinon toute donnees transitant sur le bus seront ignore
    {
      UCSR0A |= (1<<MPCM0);
    }
    
    delayWD = micros()+maxTrans; //on active un delay max d'occupation du bus quelque soit l'emeteur ou ecouteur
  }
  else
  {
    store_char(UDR0, &rx_buffer); //si mode écoute entrante, on enregistre les donnees
  }
}

////////////////////////////////////////////////////////////////////////////

void setup()
{
  RE_DE_REG; //pin RE_DE en sortie
  DDRB |= 56; //debug
  
  DDRD &= ~(64); // button de test en entree
  DDRD |= 56; //debug
  
  begin(BAUD); //init
  PORTB |= 56;
  _delay_ms(100);
  PORTB &= ~(56); //debug reset
  wdt_enable(WDTO_2S); //activation watch dog, temps max 2 sec
}

void loop()
{
  _micros = micros();
  wdt_reset();// watch remise a 0 a chaque passage
  
  if(available()) //si donnees entrente
  {
    readData();
  }
  else //sinon on verifie s'il y a des donnee a transmettre dans le buffer
  {
    sendData();
  }
  
  if(PIND&64 && _micros >= delayB) // code de teste en temps que contrôleur distant, remplissage du buffer
  {
      if(!stateB)
      {
        bufferBusTx[0] = 0x05; //taille des donnees
        bufferBusTx[1] = RECEIVER; //destinataire
        bufferBusTx[2] = ADDRESS; //emeteur
        bufferBusTx[3] = 0x01; //cmd
        bufferBusTx[4] = 0x02;  //param: registre
        bufferBusTx[5] = 0x20; // param: bit

      }
      else
      { 
        bufferBusTx[0] = 0x05;
        bufferBusTx[1] = RECEIVER;
        bufferBusTx[2] = ADDRESS;
        bufferBusTx[3] = 0x00;
        bufferBusTx[4] = 0x02;
        bufferBusTx[5] = 0x20;
      } 
      delayB = _micros+250000;
  }
  
  if(listener != 0) //debug
  {
    PORTD |= 8;
  }
  else
  {
    PORTD &= ~(8);
  }
  PORTB &= ~(56);// debug
  PORTD &= ~(31);//debug
}

uint8_t sendData()
{
  if(bufferBusTx[2] && !listener) // si données à transmettre et que le bus est libre (=0)
  {
    PORTB |= 8; //debug
    _WAIT(pres); //petite pause de sécurité car même en cas de liberation '0', RE_DE peux encore être maintenu de l'autre côté
    writeData(bufferBusTx); //on envois les données
    ack = 1; //
  }
  
  if(listener && _micros >= delayWD) // si delay de transaction max est dépasse donc erreur, collision, etc
  {
    listener = 0x00;
    ack = 0;
  }
}

void readData() // reception
{
    if(read() == 0x02) //debut de trame
    {
      delayS = _micros+(maxRec*2); //definition d'un delay max pour la lecture 
      while(!available()) //temps qu'il n'y a pas de suite ...
      {
        if(micros() >= delayS) // si delay depasse on arrête et on retourne une erreur
        {
          PORTD |= 16;
          ackError(0x01);
          break;
        }
      } 

      uint8_t sizeD = read(); // recuperation de la taille des donnees
      uint8_t data[sizeD+4];
      data[0] = sizeD;
      delayS = _micros+(maxRec*(sizeD+4)); //definition d'un delay max pour la lecture
      
      uint8_t i = 1;
      while(i < data[0]+4) //temps qu'on a pas reçu toute la trame
      {
        if(micros() >= delayS) // si delay depasse on arrête et on retourne une erreur
        {
          PORTD |= 16;
          ackError(0x01);
          break;
        }
        
        if(available()) // si donnée(s)
        {
          data[i] = read();
          ++i;
        }
      }

      if(data[data[0]+3] == 0x03) //fin de trame
      {
        if(checkData(data)) //crc ok, on envoie la commande
        {
          action(data, 0);
        }
        else //sinon on retourne directement un message d'erreur crc à l'envoyeur
        {
          ackError(0x02);
        }
      }
      else //sinon on retourne directement un message d'erreur general de reception
      {
        (0x01);
      }
    }
    RXflush();   
}

void action(uint8_t* data, uint8_t local)
{
  if(data[3] < 0xFE) //s'il sagit d'une cmd
  {
    if(data[3]==0x00) // test off
    {
      *(registreR[data[4]]+2) &= ~(data[5]); //PORT &= ~(bit)
    }
    else if(data[3]==0x01) //test on
    {
      *(registreR[data[4]]+2) |= data[5];
    }
    
    data[5] = ((*registreR[data[4]])&(data[5])); // pour ack : PIN&BIT
    
    if(local) //s'il sagit d'une commande local on rempli le buffer de transmition
    {
      bufferBusTx[0] = 0x05;
      bufferBusTx[1] = 0x80;
      bufferBusTx[2] = ADDRESS;
      bufferBusTx[3] = 0xFD;
      bufferBusTx[4] = data[4];
      bufferBusTx[5] = data[5];
    }
    else //sinon on retourne directement un ack de confirmation 
    {
      data[1] = 0x80;
      data[2] = ADDRESS;
      data[3] = 0xFF;
      _WAIT(pres);
      writeData(data); 
    } 
  }
  
  if(ack && data[3] >= 0xFE && (bufferBusTx[1] == data[2])) //si transaction en cours et cmd >= FE
  {
    if(data[3] == 0xFF || err == 2) // ack positif ou plus de 3 échec, on libère le bus
    {
      bufferBusTx[2] = 0;
      _WAIT(pres);
      RE_DE_ON;
      write(0x00, 1);
      _WAIT(pres);
      RE_DE_OFF;
      ack = 0;
      err = 0;
      if(data[3] == 0xFF) //s'il sagit d'un ack positif on enregistre le resultat
      {
        stateB = data[5];
      }
    }    
    else //si un ack d'erreur on retante directement
    {
      ++err;
      _WAIT(pres);
      writeData(bufferBusTx);
    }
  }
}

void writeData(uint8_t* data)
{
  //calcul du crc en premier
  uint16_t crc = 0xFFFF;
  
  for(uint8_t i=0; i <= data[0]; i++)
  {
    crc = _crc16_update(crc, data[i]);
  }
  
  //active le mode transmition
  RE_DE_ON;
  
  write(data[1], 1); //adressage
  write(0x02, 0); //debut de trame
  for(uint8_t i=0; i <= data[0]; i++) //donnees (suivant la taille specifiée)
  {
    write(data[i], 0);
  }
  
  write(((crc & 0xFF00) >> 8), 0); //crc MSB
  write((crc & 0x00FF), 0); //crc LSB
  write(0x03, 0); //fin de trame
  _WAIT(pres); //delay de maintien 
  RE_DE_OFF; // on desacive le mode de transmition
}

uint8_t checkData(uint8_t* data) //controle crc
{
  uint16_t crc = 0xFFFF;
  uint16_t _crc = (data[data[0]+1]<<8);
  _crc += data[data[0]+2];
  for(uint8_t i=0; i <= data[0]; i++)
  {
    crc = _crc16_update(crc, data[i]);
  }
  
  if(crc == _crc)
  {
    return 1;
  }
  
  return 0;
}

void ackError(uint8_t ErrorNo)
{
  uint8_t data[5] = {0};
  data[0] = 0x04; 
  data[1] = 0x81;
  data[2] = ADDRESS;
  data[3] = 0xFE;
  data[4] = ErrorNo;
  _WAIT(pres);
  writeData(data);
}
//////////////////////////////////////////////////////////////////////////////////////////////////

void write(uint8_t data, uint8_t txb8)
{
  while (!((UCSR0A) & (1 << UDRE0)))
    ; 
  if(txb8)
  {
    UCSR0B |= (1<<TXB80);
  }
  else
  {   
    UCSR0B &= ~(1<<TXB80);
  }
  UDR0 = data;
}

uint8_t available(void)
{
  return (uint8_t)(SERIAL_BUFFER_SIZE + rx_buffer.head - rx_buffer.tail) % SERIAL_BUFFER_SIZE;
}

uint8_t read(void)
{
  if (rx_buffer.head == rx_buffer.tail) 
  {
    return -1;
  } 
  else 
  {
    uint8_t c = rx_buffer.buffer[rx_buffer.tail];
    rx_buffer.tail = (uint8_t)(rx_buffer.tail + 1) % SERIAL_BUFFER_SIZE;
    return c;
  }
}

void RXflush()
{
  rx_buffer.head = rx_buffer.tail;
}

void begin(unsigned long baud)
{
  uint16_t baud_setting;

  UCSR0A = 0;
  baud_setting = (F_CPU / 8 / baud - 1) / 2;

  UBRR0H = baud_setting >> 8;
  UBRR0L = baud_setting;
    
  UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0)|(1<<UCSZ02);
  UCSR0C = (3<<UCSZ00);
  
  UCSR0A |= (1<<MPCM0);
}

Com poste suivant:

Suite:
Histoire de montré où j'en suis dans mes tests je met mon code brouillons actuel avec quelque commentaires.
Comme c'est là chaque module est contrôleur et récepteur en même temps (pour le brouillons), il n'y a pas de maître du bus, la gestion des collision , erreurs, etc se fait par des délais.
Les délais doivent encore être mieux réglé et défini d'après la longeur max d'une trame (je pense mettre à 32 max).
Tout fonctionne correctement avec trois arduino mini contrôleur et récepteur en même temps, tout les trois tester dans les deux modes simultanément :astonished: (au final ça sera pas ainsi mais là c'est le stress test :grin:), avec des transactions de plus ou moin 50ms à 9600baut et 4ms à 115200baut pour une trame de 10 octet (commande simple sur registre I/O).

Il y a encore du boulot mais le plus gros est fait je pense, si quelqu'un a des idées, suggestions ou questions ? :sweat_smile: :*

Yep!

Super, j'ai commencé à regarder ton code XD
Je pense partir sur quelque chose de plus épuré dans un premier temps, on voit que tu as bien appronfondi le sujet :wink:

J'ai pourtant deux questions qui me passe là :

First, quelle est la taille (utilisation mem) de la bibliothèque crc16 ???
Second, pourquoi avoir utilisé un watchdog ? On risque pas le reset complet du programme ?? Alternative : timer, interruption ???

J'ai reçu il y a peu mes SN75176 et quelques tiny2313, si l'on part sur des commandes simples avec retour vers le maitre par echo, je pense qu'il faudra parier sur un uC plus simpliste que le 328 ou 644 (dip')

@+

Zoroastre.

zoroastre:
J'ai pourtant deux questions qui me passe là :

First, quelle est la taille (utilisation mem) de la bibliothèque crc16 ???
Second, pourquoi avoir utilisé un watchdog ? On risque pas le reset complet du programme ?? Alternative : timer, interruption ???

pour la taille de la biblio crc16 (de la lib avr) je sais pas trop mais je ferais le teste une fois , pour l'instant le tout pèse +- 2,5ko en mémoire programme (donc avec les 450octet rajouter pas le core arduino et les divers chose utile pour debug, etc ).
Le watchdog pour l'instant c'est juste dans mes testes brouillons, je découvre. :grin:, mais j'ai fais au maximum pour ne pas avoir de code bloquant comme pour la partie envoi "sendData();" juste au passage dans loop ou le timer "delayS" (boucle sécurisée) à la réception par ex.

zoroastre:
J'ai reçu il y a peu mes SN75176 et quelques tiny2313, si l'on part sur des commandes simples avec retour vers le maitre par echo, je pense qu'il faudra parier sur un uC plus simpliste que le 328 ou 644 (dip')

J'utilise les mini (168) pour l'instant comme c'était le plus minimaliste et simple pour moi qui suis amateur dans le domaine des uC et l'électronique en général :sweat_smile:, mais les ATtiny m’intéresse donc s'il y a moyen de faire encore plus minimaliste (conso, taille, etc) je reste ouvert à toute propositions (et surtout aide :grin:) :open_mouth:
Enfin pour l'instant ça reste du prototypage. :wink:

Yop yop,
Ai fais le test pour la fonction de la lib crc16 et elle pèse 52octet en mémoire programme.

J'ai également testé et adapté le code pour un module version tiny et j’obtiens 1388 octet, pas testé mais fonctionnel sur mini (1684octet) .

#include <util/crc16.h>
#include <util/delay.h>
#include <avr/wdt.h>

#define DATA_LENGTH 6
#define ADDRESS 0x11
#define RECEIVER 0x12
#define RE_DE_ON PORTD|=4
#define RE_DE_OFF PORTD&=~(4)
#define RE_DE_REG DDRD |= 4
#define BAUD 115200

#define _WAIT(_pres) _delay_us(_pres)

#define SERIAL_BUFFER_SIZE 10
volatile uint8_t pos = 0;
volatile uint8_t bufferBusRx[SERIAL_BUFFER_SIZE];

volatile uint8_t listener = 0;
volatile uint32_t delayWD = 0;

uint8_t bufferBusTx[DATA_LENGTH] = {0}; 

volatile uint8_t ack = 0;
uint8_t err = 0;

const uint32_t pres = 69120000/BAUD; //temps de maintien RE_DE
const uint32_t maxRec = 14000000/BAUD; //temps max en reception
const uint32_t maxTrans = (32640000/(BAUD/100))+((ADDRESS*(pres*2))); //temps max de transaction+ temps different entre module selon l'adresse

volatile uint8_t* registreR[3] = {&PINA, &PINB, &PIND}; //tableau pour la gestion semi dynamique des registres (&DDR = &PIN+1, &P0RT= &PIN+2)

uint8_t stateB = 0;
uint32_t delayB = 0;

ISR(USART_RX_vect)
{
  if((UCSRB & (1<<RXB8))) // si bit9 à 1 = adresse
  {
    listener = UDR;
    if(listener == ADDRESS) //s'il sagit de son adresse ou adresse controleur = 0x80 ou si une transaction en cours&& adresse de ack = 0x81  on active l'ecoute
    {
      UCSRA &= ~(1<<MPCM);
      pos = 0;
    }
    else //sinon toute donnees transitant sur le bus seront ignore
    {
      UCSRA |= (1<<MPCM);
    }
    
    delayWD = micros()+maxTrans; //on active un delay max d'occupation du bus quelque soit l'emeteur ou ecouteur
  }
  else //si mode écoute entrante, on enregistre les donnees
  {
    if(pos <= 9)
    {
      bufferBusRx[pos] = UDR;
      ++pos;
    }
    else
    {
      pos = 0;
    }
  }
}


////////////////////////////////////////////////////////////////////////////

void setup()
{
  RE_DE_REG; //pin RE_DE en sortie
  DDRD |= 63;
  begin(BAUD); //init
}

void loop()
{ 
  if(pos == 9) //si donnees entrente
  {
    readData();
    pos = 0;
  }
  else //sinon on verifie s'il y a des donnee a transmettre dans le buffer
  {
    sendData();
  }
  

  PORTD &= ~(31);
}

uint8_t sendData()
{
  if(bufferBusTx[2] && !listener) // si données à transmettre et que le bus est libre (=0)
  {
    _WAIT(pres); //petite pause de sécurité car même en cas de liberation '0', RE_DE peux encore être maintenu de l'autre côté
    writeData(bufferBusTx); //on envois les données
    ack = 1; //
  }
  
  if(listener && micros() >= delayWD) // si delay de transaction max est dépasse donc erreur, collision, etc
  {
    listener = 0x00;
    ack = 0;
  }
}

void readData() // reception
{
    if(bufferBusRx[0] == 0x02 && bufferBusRx[9] == 0x03) //debut de trame
    {
        if(checkData()) //crc ok, on envoie la commande
        {
          action(0);
        }
        else //sinon on retourne directement un message d'erreur crc à l'envoyeur
        {
          
          ackError(0x02);
        }
    }
    else //sinon on retourne directement un message d'erreur general de reception
    {
      ackError(0x01);
    }
     
}

void action(uint8_t local)
{
    if(bufferBusRx[4]==0x00) // test off
    {
      *(registreR[bufferBusRx[5]]+2) &= ~(bufferBusRx[6]); //PORT &= ~(bit)
    }
    else if(bufferBusRx[4]==0x01) //test on
    {
      *(registreR[bufferBusRx[5]]+2) |= bufferBusRx[6];
    }
    
    uint8_t val = ((*registreR[bufferBusRx[5]])&(bufferBusRx[6])); // pour ack : PIN&BIT
    
    if(local) //s'il sagit d'une commande local on rempli le buffer de transmition
    {
      bufferBusTx[0] = 0x05;
      bufferBusTx[1] = 0x80;
      bufferBusTx[2] = ADDRESS;
      bufferBusTx[3] = 0xFD;
      bufferBusTx[4] = bufferBusRx[5];
      bufferBusTx[5] = val;
    }
    else //sinon on retourne directement un ack de confirmation 
    {
      uint8_t data[6];
      
      data[0] = 0x05;
      data[1] = 0x80;
      data[2] = ADDRESS;
      data[3] = 0xFF;
      data[4] = bufferBusRx[5];
      data[5] = val;
      _WAIT(pres);
      writeData(data); 
    } 
}

void writeData(uint8_t* data)
{
  //calcul du crc en premier
  uint16_t crc = 0xFFFF;
  
  for(uint8_t i=0; i <= data[0]; i++)
  {
    crc = _crc16_update(crc, data[i]);
  }
  
  //active le mode transmition
  RE_DE_ON;
  
  write(data[1], 1); //adressage
  write(0x02, 0); //debut de trame
  for(uint8_t i=0; i <= data[0]; i++) //donnees (suivant la taille specifiée)
  {
    write(data[i], 0);
  }
  
  write(((crc & 0xFF00) >> 8), 0); //crc MSB
  write((crc & 0x00FF), 0); //crc LSB
  write(0x03, 0); //fin de trame
  _WAIT(pres); //delay de maintien 
  RE_DE_OFF; // on desacive le mode de transmition
}

uint8_t checkData() //controle crc
{
  uint16_t crc = 0xFFFF;
  
  uint16_t _crc = (bufferBusRx[7]<<8);
  _crc += bufferBusRx[8];
  
  for(uint8_t i=1; i <= bufferBusRx[1]+1; i++)
  {
    crc = _crc16_update(crc, bufferBusRx[i]);    
  }

  if(crc == _crc)
  {
    return 1;
  }
  
  return 0;
}

void ackError(uint8_t ErrorNo)
{
  uint8_t data[5] = {0};
  data[0] = 0x04; 
  data[1] = 0x81;
  data[2] = ADDRESS;
  data[3] = 0xFE;
  data[4] = ErrorNo;
  _WAIT(pres);
  writeData(data);
}


void write(uint8_t data, uint8_t txb8)
{
  while (!((UCSRA) & (1 << UDRE)))
    ; 
  if(txb8)
  {
    UCSRB |= (1<<TXB8);
  }
  else
  {   
    UCSRB &= ~(1<<TXB8);
  }
  UDR = data;
}

void begin(unsigned long baud)
{
  uint16_t baud_setting;

  UCSRA = 0;
  baud_setting = (F_CPU / 8 / baud - 1) / 2;

  UBRRH = baud_setting >> 8;
  UBRRL = baud_setting;
    
  UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<UCSZ2);
  UCSRC = (3<<UCSZ0);
  
  UCSRA |= (1<<MPCM);
}

Yep!

1418 octets pour un tiny2313 (8Mhz). Le transfert Isp se déroule correctement :wink:

Par contre, je ne peux pas tester plus avant le code, mon uC est sur un proto de 5x3 cm pour effectuer des tests Pwm pour le taff.
Je suis en train de dessiner sur kicad un autre proto avec 1 Atmega644, 1 ou 2 Attiny2313, des SN75176, I2C et SPI. J'ai besoin d'experimenter les conversations sur plusieurs protocoles, principalement sur l'I2C car je compte m'inspirer des automates modernes (1 tache rapide + 1 tache lente) pour créer un carte biproc à base d'ATmega644.

Merci pour ton code trés bien écrit, il me sera certainement utile :wink:

Tu en es où de tes experimentations du Rs485 sur le terrain ?

@+

Zoroastre.

Yop yop, sorry pour la réponse tardive je me choppe une petite grippe depuis hier. =(

zoroastre:
J'ai besoin d'experimenter les conversations sur plusieurs protocoles, principalement sur l'I2C car je compte m'inspirer des automates modernes (1 tache rapide + 1 tache lente) pour créer un carte biproc à base d'ATmega644.

J'aimerai connaître le résultat de tes expérimentations :open_mouth:, compte rendu obligatoire :grin:.

zoroastre:
Merci pour ton code trés bien écrit, il me sera certainement utile :wink:

C'est encore un peux brouillon mais je m'approche de la solution final.

zoroastre:
Tu en es où de tes experimentations du Rs485 sur le terrain ?

Je suis retourné en half duplex classique, comme ici la communication ne peut être simultanée de toute façons.
Par contre toujours en breadboard et bout de fils pendents :*, pas encore testé sur longue distance ou autre, il serait temps que je m'offre un petit fer et composants standard tel que trans, condo, diode, moc, etc, pour aller plus loin.

Par contre tu pourras peut être me renseigné sur la réel différence entre les tiny et atmega, avantage, inconvénient ?
Par exemple ici j'aimerais des module simple e/s, 8 entrées (commande locale par bp ou autre) et 8 sorties correspondante (1 en + pour le bus ce qui fait 17 e/s) donc théoriquement avec mes mini 168 (23 I/O - (2 pour l'uart) - (2 crystal)) ça devrait aller ?
En fait dans les descriptions première des µc je vois 20 I/O (attiny 2313) par exemple (youpie), sauf que 2 pour l'uart, 2 pour le chrystal, etc ... et donc je n'arrive pas à faire au plus juste (ni trop, ni trop peux) ?

J'ai modifier l'image histoire de voir la correspondance registre et non arduino, il n'y a que le bit7 du registre C (pc7 ?) que je ne trouve pas dans le sommaire de la doc.

Entre () je comprend un peux mieux la team arduino d'avoir fais des tableaux de correspondance afin d'avoir un ordre plus "naturel" et instinctif de correspondance pin/registre vu que certain ne comprennent pas automatiquement 8 bit ou utilisé par l'orloge, l'uart, etc, ...
Pour cette dernière raison je vais abandonné la trame cmd/registre/bit mais plutôt dcmd/sortie_n° .

Yep!

osaka:
Par contre tu pourras peut être me renseigné sur la réel différence entre les tiny et atmega, avantage, inconvénient ?

ATtiny2313, 2048 bytes, DIP20
ATtiny4313, 4096 bytes, DIP20
ATTiny25/45/85 2048, 4096, 8168 bytes, DIP8

Cà c'est pour ceux que je connais. Il y a aussi des modèles CAN bus.

Naturellement, on ne retrouvera pas toutes les fonctionnalités des mega, principalement du côté des ports analogiques, sur les tiny, je n'en connais pas. L'I2C est aussi sacrifié, mais il demeure le TWI, avec donc, des possibilité quand même.
Pour le tiny2313, 18 i/o brutes dont Rx/Tx, 4 Pwm, l'horloge, etc. Quand on fait les comptes, il demeure grosso modo 10/12 i/o. C'est déjà pas mal.

Le principal inconvénient, c'est bien entendu l'absence de port analogique. Pour inclure des capteurs de cette famille, pas le choix faut serialiser à travers un chip ou bidouillé sur les temps de charge/decharge d'une capa.

En ce qui concerne les tiny25/45/85, peut de i/o à la base mais on peut compenser avec des shifts register.

osaka:
J'aimerai connaître le résultat de tes expérimentations , compte rendu obligatoire

Pas de souci, par contre faudra être patient, j'ai un truc sur le feu pour l'instant XD

Pour détailler un peu, je compte mettre un afficheur tactile et l'ethernet sur un chip mega644 (taches lentes), quant au second 644, les tâches courantes, gestion des évenements capteurs et envoie des commandes asservies. Le tout en intercommunication.
J'espère avec cette configuration obtenir plus de réactivité sur les interfaces IHM.
Le protocole I2C est utilisé dans des projets tels que core2duino ou core3duino.

Je n'ai pas encore fixé mon choix sur le chip des modules de commandes, l'attiny2313 a ma préference pour l'instant, mais il va falloir que je m'affranchisse de l'analogique et que je palie ce problème.

Je suis plutôt satisfait de ma solution actuelle à base de mega1280 + afficheur tactile + ds18b20 + relais piloté en rs485.
Je crains pourtant en ajoutant l'ethernet et des sondes supplémentaires d'être rapidement saturé en i/o et en vitesse de calcul.
Les avantages que j'entrevois dans ma solution est d'obtenir théoriquement deux fois plus d'entrée/sortie avec la même taille mémoire. (robotique ???)
Le plus chaud sera de partager les tâches équitablement. (l'option du clustering n'est pas loin!)

L'idée de déporter les modules de commandes me plait de plus en plus :wink:

@+

Zoroastre.

Merci, je vois mieux la différence entre les deux maintenant.

zoroastre:

osaka:
J'aimerai connaître le résultat de tes expérimentations , compte rendu obligatoire

Pas de souci, par contre faudra être patient, j'ai un truc sur le feu pour l'instant XD

Pour détailler un peu, je compte mettre un afficheur tactile et l'ethernet sur un chip mega644 (taches lentes), quant au second 644, les tâches courantes, gestion des évenements capteurs et envoie des commandes asservies. Le tout en intercommunication.
J'espère avec cette configuration obtenir plus de réactivité sur les interfaces IHM.

figure toi que si j'ai bien compris, c'est exactement ce à quoi je pense, séparé contrôleur IHM (affichage, eth, ...) et contrôleur événementiel (temp, lum, horaire, ...)
(C'est pour celà que j'ai une adresse spécifique contrôleurs" 0x80" pour les retour et ack des modules, si cette adresse spécifiée, tout les contrôleur écoute c'est qu'il s'agit d'un retour d'état que la commande soit distante ou locale au module).

zoroastre:
Je n'ai pas encore fixé mon choix sur le chip des modules de commandes, l'attiny2313 a ma préference pour l'instant, mais il va falloir que je m'affranchisse de l'analogique et que je palie ce problème.

Je suis plutôt satisfait de ma solution actuelle à base de mega1280 + afficheur tactile + ds18b20 + relais piloté en rs485.
Je crains pourtant en ajoutant l'ethernet et des sondes supplémentaires d'être rapidement saturé en i/o et en vitesse de calcul.
Les avantages que j'entrevois dans ma solution est d'obtenir théoriquement deux fois plus d'entrée/sortie avec la même taille mémoire. (robotique ???)
Le plus chaud sera de partager les tâches équitablement. (l'option du clustering n'est pas loin!)

L'idée de déporter les modules de commandes me plait de plus en plus :wink:

La conception modulaire me conforte dans l'idée de n'avoir presque aucune limites. :open_mouth:

Yep!

osaka:
figure toi que si j'ai bien compris, c'est exactement ce à quoi je pense, séparé contrôleur IHM (affichage, eth, ...) et contrôleur événementiel (temp, lum, horaire, ...)

Ouép, on travaille dans la même direction.
C'est aussi une des raisons pour lesquels, je m'interesse beaucoup à tes dernières experimentations :wink:

Le protocole I2C est donné pour être plus rapide (100 à 400 khz) que le rs485, certes sur une distance beaucoup beaucoup moins importante. Mais l'essentiel est que ce sont tout deux des protocoles solides avec chacun une mission, celle au voisinage, celle au lointain.

Le proto que je dessine en ce moment réunit la puissance de 2 atmega644 afin de résoudre la séquentialisation des données.
En effet, comment donner la priorité à tel ou tel tâche si le cerveau est unique, l'algorithme devient complexe.
Si on décuple les cerveaux et on leur attribuent des tâches spécifiques mais conjointent, on commence à parler buffer de process, pipe et on aboutit à un système neuronal proche du clustering, avec un algorithme plus simple, un algorithme de fourmie travailleuse. :wink:

@+

Zoroastre.

Yop yop,
J'avais pensé à l'I2C (même au spi, can, ...), mais quelque chose me dérangeais c'est la communication maitre esclaves, pour laisser la parole à chaque esclave il est obligé de les interrogé l'un à la suite de l'autre, c'est un peux faire du "token ring" ?
J'ai vu qu'il y avait moyen de faire du multi-maître et d'entamé une conversation et transaction à la libération de la ligne sur sdl et sca ?
Enfin finalement je me suis dit que j'allais le réservé pour d'autre choses (par ex: le module rtc 1307, ...), que le rs485 permettait la longue distance, le "Multi-processor Communication Mode" que j'avais envie de testouiller, etc , donc j'ai pas approfondi le bus i2c. (et donc ça tombe bien que tu t'y intéresses :grin:).
Concernant la vitesse tout dépend également de ses exigences (à 4ms la transaction ça me donne quand même 250 transaction par sec ) et du code qui traine derrière , comme j'ai eu le cas avec l'ethernet (pourtant à 10Mbps théorique) et les sockets, on pourrais ce dire que ça rox, be finalement les différents chipotages,traitements (byte->json, etc) et intermédiaires (php qui clôture la transaction à la simple vue d'un 0 ]:slight_smile: ) donnent un résultat catastrophique comparé à ce que j’espérais pour une tel vitesse. (enfin ici c'est les différents chipotage pour rendre le tout compatible qui fout le boxon, faudrait que je remette mon shield, j'ai quelques idée pour pallier ça qui me trotte en tête). =(
Dans tout les cas la seule façon d'avoir le meilleur choix c'est de testé et comparé (je compte sur toi :grin:).
Ca me fait pensé qu'il faudrait testé ma solution sans la gestion du crc voir si ça en vaut la peine ?

zoroastre:
Le proto que je dessine en ce moment réunit la puissance de 2 atmega644 afin de résoudre la séquentialisation des données.
En effet, comment donner la priorité à tel ou tel tâche si le cerveau est unique, l'algorithme devient complexe.
Si on décuple les cerveaux et on leur attribuent des tâches spécifiques mais conjointent, on commence à parler buffer de process, pipe et on aboutit à un système neuronal proche du clustering, avec un algorithme plus simple, un algorithme de fourmie travailleuse. :wink:

On peux ajouter que la mort ou destruction d'un neurone n'empêche pas le cerveau de fonctionné (Je n'y vois que des avantages quand je lis ta description). :open_mouth:

zoroastre:
un algorithme de fourmie travailleuse

Tien ça me donne idée de nom (s'il faut le nommé :P) au système, "antsDomo" la fourmilière au service de votre maison. XD

Premier post pour vous dire...
...
..
.
que vous êtes de grands malades! XD

Continuez, personnellement je suis vos avancées avec attention! :wink:

Yep!

osaka:
J'avais pensé à l'I2C (même au spi, can, ...), ...
J'ai vu qu'il y avait moyen de faire du multi-maître et d'entamé une conversation et transaction à la libération de la ligne sur sdl et sca ?

Je suis passé par ces étapes de reflexion également, et effectivement le mode multi-maitre fait partie du protocole I2C. Lors de mes recherches, j'ai entrevus quelques solutions arduino et je pense sincèrement que cela est possible.
Les ressources ne sont pourtant pas trés nombreuses et plutôt légères. Il n'y aura, bien sûr, que la pratique qui pourra valider ou pas mes hypothèses. L'experience me tente fortement.

osaka:
Ca me fait pensé qu'il faudrait testé ma solution sans la gestion du crc voir si ça en vaut la peine ?

Je m'attendais à ce que le crc soit plus lourd en fait. J'avais regardé les differents algo de contrôle et certain me semblait fort alambiqué. Il faut effectivement voir ce qu'il apporte réellement.

osaka:
"antsDomo"

:grin:

Pour le proto, la mise en place des composants ne sera pas trop compliqué, j'ai surtout des problèmes d'esthétique en fait, je travaille sur une seule couche (compo dips uniquement) et j'essaie d'eviter autant que possible les straps.
Je suis déjà à mon second shema, le premier sur un seul plan, le second sur deux (principe du shield).
Je vais encore tatillonner quelques jours/semaines avant de choisir une solution. J'ai déjà l'essentiel des composants, et j'aimerais autant que possible que le proto soit plus qu'un proto, donc une plateforme pre et/ou définitive.
Le processeur IHM sera donc pourvu de l'ethernet de facto (ENC28J), d'un bus rs232 et rs485. Le processeur evenementiel sera doté de deux bus rs485. Une liaison I2C liera les deux processeurs, une eeprom au milieu.

Je travaille depuis peu avec les registres, cette méthode me parle plus en fait, je suis technicien de maintenance et l'automatisme est mon dada. J'ai par contre tout à apprendre du c++, mais je voyage depuis quelques années d'un language à un autre au grés de mes besoins.

Levaillant:
vous êtes de grands malades!

Et c'est que le début XD

@+

Zoroastre.

zoroastre:

osaka:
Ca me fait pensé qu'il faudrait testé ma solution sans la gestion du crc voir si ça en vaut la peine ?

Je m'attendais à ce que le crc soit plus lourd en fait. J'avais regardé les differents algo de contrôle et certain me semblait fort alambiqué. Il faut effectivement voir ce qu'il apporte réellement.

Je m'attendais également à une certaine lourdeur, jusqu'a ce que je tombe lors d'une de mes explorations sur le crc16.h de la lib avr.

static __inline__ uint16_t
_crc16_update(uint16_t __crc, uint8_t __data)
{
	uint8_t __tmp;
	uint16_t __ret;

	__asm__ __volatile__ (
		"eor %A0,%2" "\n\t"
		"mov %1,%A0" "\n\t"
		"swap %1" "\n\t"
		"eor %1,%A0" "\n\t"
		"mov __tmp_reg__,%1" "\n\t"
		"lsr %1" "\n\t"
		"lsr %1" "\n\t"
		"eor %1,__tmp_reg__" "\n\t"
		"mov __tmp_reg__,%1" "\n\t"
		"lsr %1" "\n\t"
		"eor %1,__tmp_reg__" "\n\t"
		"andi %1,0x07" "\n\t"
		"mov __tmp_reg__,%A0" "\n\t"
		"mov %A0,%B0" "\n\t"
		"lsr %1" "\n\t"
		"ror __tmp_reg__" "\n\t"
		"ror %1" "\n\t"
		"mov %B0,__tmp_reg__" "\n\t"
		"eor %A0,%1" "\n\t"
		"lsr __tmp_reg__" "\n\t"
		"ror %1" "\n\t"
		"eor %B0,__tmp_reg__" "\n\t"
		"eor %A0,%1"
		: "=r" (__ret), "=d" (__tmp)
		: "r" (__data), "0" (__crc)
		: "r0"
	);
	return __ret;
}

Ca m'étonne d'ailleurs que ce code ne soit pas plus utilisé, pour le 1wire par exemple ... alors que ...

_crc_ibutton_update(uint8_t __crc, uint8_t __data)

zoroastre:
Pour le proto, la mise en place des composants ne sera pas trop compliqué, j'ai surtout des problèmes d'esthétique en fait, je travaille sur une seule couche (compo dips uniquement) et j'essaie d'eviter autant que possible les straps.
Je suis déjà à mon second shema, le premier sur un seul plan, le second sur deux (principe du shield).

Pour le module I/O (8/8) je partais sur le principe du 2 couche (shield mais avec mini qui vient ce "broché" par dessus) vu ça taille (30X17) , sinon pour les autre où le mini ne serait pas adapté ça sera comme toi simple couche et dip ,pas question de uno, mega, ... ou la place est loin d'être optimisé à l'utilisation qu'on en ferais (je suppose que c'est également ton but, d'ailleurs il y a des chance que je te copie :grin:) .

zoroastre:
Je travaille depuis peu avec les registres, cette méthode me parle plus en fait, je suis technicien de maintenance et l'automatisme est mon dada. J'ai par contre tout à apprendre du c++, mais je voyage depuis quelques années d'un language à un autre au grés de mes besoins.

En effet la logique semble plus intuitive pour quelqu'un ayant l'habitude de l'automatisme, l'electropneumatique, hydrau, etc, industrielle.
Mes premières études (secondaire = college/lycees) étaient dans l'électromécanique (tout du moin avant que je me fasse mettre à la porte de l'école :.), puis la construction mécanique et métallique et mon meilleur amis qui étais avec moi au cours est technicien de maintenance maintenant (kraft be).
Finalement je regrette d'avoir choisie la voie de l'informatique (dev) ...
Enfin cette voie je l'ai pas vraiment choisie , c'est suite à une reconversion (graduat= bac+3) après une accident de tuture qui ma foutu les bras en l'air.
Maintenant j'hésite à faire une "petite" formation d'automaticien ou électromécanicien pour quitté le monde des fauteuils de bureau qui ne veulent pas de moi de toute façons. :grin:
Pour l'instant je me réfugie sur les µc et la domo des fourmis.

Levaillant:
vous êtes de grands malades!

C'est pas le début de la fin, c'est la fin du commencement (vers la follie). :grin:

Je suis également vos échanges que je trouve très intéressants, mais pour le moment mes préoccupations sont bien plus basiques.

J’espère seulement être en mesure de suivre et contribuer à vos échanges un de ces jours (même lointain).

L’idée d’utiliser plusieurs processeurs pour diverses tâches, peut-être très intéressante, et peut apporter un niveau de sécurité supplémentaire, car un processeur peut de temps en temps surveiller l’autre et réagir en cas de dysfonctionnement.