Aidez nous ! Projet - Gestion domotique

Rebonjour a tous, mon stage d'un mois est fini et je retrouve ma petite famille. Je viens de jeter un œil sur vos derniers commentaires je vois que vous n'avez pas abandonner c'est cool.

Pendant mon stage je me suis familiariser avec l'arduino sur une guirlande de 25 leds adressables avec la librairies FastSPI . Je termine la semaine prochaine car j'ai reçu mes darlingtons pour mes dioders ikea, je vais donc souder tout cela et je reprend le projet domotique avec vous. En attendant si vous pouvez publiez vos codes et le sujet sur lequel il porte cela serait cool, certains on déjà posté du code très intéressant. Merci a tous et content d'être de retour parmi vous.

Yop Skuz,
J'ai raté ton passage, content de te revoir.
Pour mon code dès que j'aurais abouti et nettoyé je posterais.
Moi c'est le travail de Bribri que j'aimerais voir. :grin:

Bonjour à tous,

Je viens de remettre le nez dans ce projet, après quasiment deux mois de standby : ce n'était pas de l'hibernation, j'ai travaillé sur d'autres projets (sans arduino, si si ça existe !).

En fait comme je l’avais prévu, j’ai testé les différents éléments matériels, j’ai réussi à tout mettre en œuvre.
Je récapitule :
Arduino Méga 2560 avec :

  • Horloge temps réel DS1307 => OK, reste à voir le recalage de l’heure sur Internet : j’ai vu que Jean-François a posté un tuto à ce sujet, lorsque j’aurai réglé la question de la communication de l’Arduino avec le serveur web, je reverrai cette question.
  • Afficheur LCD 4x16 => OK
  • Capteur de température et d’humidité DHT11 => OK (j’en utiliserai à priori 3)
  • Capteur de température DS1820 => OK (j’en utiliserai au moins un à l’extérieur car le DHT11 est limité de 0 à 50°C => il ne mesure donc pas les températures négatives)
  • Ethernet shield W5100 => OK , mais je n’arrive pas encore à travailler de manière satisfaisante dans les deux sens, il faut que je m’intéresse très sérieusement à deux projets l’un d’Osaka sur les websockets et celui de Stantor, mais les deux ne sont pas encore à ma portée, il faut que j’en apprenne encore un peu plus sur les technologies web, (j’ai déjà un peu progressé !).

Voilà, ce que j’ai prévu de faire maintenant c’est :

  • Réécrire mon cahier des charges en détaillant les différentes fonctionnalités attendues et en mettant en face les solutions techniques retenues.
  • Réécrire tous les bouts de sketchs que j’ai glanés et utilisés pour mes essais pour en faire des éléments modulaires, que je pourrai facilement assembler dans mon application finale.
  • Puis viendra la grande question de la communication avec le serveur web et le stockage de données (plages horaires, historiques …), j’aurai certainement besoin de votre aide.

Je vous soumettrai les éléments au fur et à mesure pour que vous puissiez réagir et éventuellement prendre ce qui vous intéresse (si cela présente un intérêt pour vous !).
Bon, aller au boulot !!!

Yop Bribri content d'avoir de tes nouvelles. :open_mouth:
Je vois que tu progresses bien , si tu as besoin d'un coup de main niveau web n'hésite pas. :wink:
J'attend également tes résultats et solutions niveau hard et gestion du 220, volets, etc . :grin:
Je posterais bientôt le gros brouillons de mes résultat avec le bus rs-485.

Merci Osaka pour ta proposition d'aide pour le web, pour le moment je n'en suis pas encore là. Mais je ne manquerai pas d’appeler au secours lorsque je serai coincé, et probablement même avant pour demander des conseils pour le choix de solutions à mettre en oeuvre.

Je suis entrain de rédiger un cahier des charges très détaillé, dans lequel je vais décrire les fonctionnements attendus et les solutions techniques matérielles retenus avec schémas (testés et fonctionnels). Si au cours de ma rédaction (qui va prendre plusieurs jours, car je le fais à temps perdu) j’ai des questions (faisabilité, choix de solutions, …) je posterai sur le forum, sinon je vous livrerai mon cahier des charges une fois terminé.

Ensuite je câblerai mon système complet avant de passer à la programmation à proprement parler.
Pour la première version je n’aurai probablement pas besoin de la liaison RS 485, mais dans une version ultérieure et notamment pour gérer mes volets électriques (j’en ai 16 en plus du volet de garage) je vais surement utiliser un Arduino par étage, il va donc falloir les faire communiquer, mais ça ce sera beaucoup plus tard.

@+

Voilà, j'ai fini la première version du cahier des charges détaillé, je vous le soumets pour critiques, si vous avez le courage de le lire.
Je ne l'ai relu que très rapidement, si vous trouvez des incongruités, des incohérences ou des erreurs n'hésitez pas, c'est ainsi que j'avance.
La prochaine étape :
Câbler l’unité de gestion, puis la tester.
Je vous enverrai des schémas, des photos et les résultats de mes essais.
@+

Cahier des charges détaillé du système domotique avec interface web.pdf (437 KB)

Même si je pars sur une base 1 arduino par fonctions (contrôleur, I/O 220v, chauffage, volets, alarme, ...) ça me semble parfait et dans la même optique que moi.
Étant très amateur dans le domaine de l'électronique, concernant triac ou optotriac et 220v j'allais partir sur cette base http://www.sonelec-musique.com/electronique_realisations_interfaces_230v_001.html.
Qu'en penses-tu (vous) ?

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.
@+

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° .