La domotique

Vaste domaine

Des projets pour la maison...

Télécommande lumières extérieurs RF433 (A faire)
La bobineuse

La régulation

Un projet pour en construire d'autres...Cette réalisation est nécessaire pour réaliser des moteurs ou générateurs Brushless maison.
Je suis peut-être allé trop loin, mais ça vas me servir réguilèrement.
Soit un total de 7.97 € hors impression 3d

Le Câblage


Le PCB proto


La configuration

Première étape, appuyer sur le bouton au démarrage.
L'écran se met à clignoter, relâcher le bouton. Vous êtes dans le mode configuration.

Le point en bas à droite indique le digit en cours de modification.
Un appuis court incrémente la valeur, un appuis long change de digit.
Attention, la valeur est multipliée par 10, la limite est donc de 999 tours.
Lorsque vous arrivez au bout, l'écran clignote de nouveau pour vous indiquer la fin de modification.

Le Fils

Pour bobiner du fil de cuivre, il faut absolument du fil emaillé.
Ø mm
hors isolant
SWGsection
mm²
Ω/mI à 4 A/mm²
mA
spires jointives
pour 10mm de long
tr/cm
1.516-171.770.0107,16,5
1.25181.230.0154,98
1.0190.780.0233,110
0.8210.500.0362,012
0.7220.380.0472,014
0.56240.250.0731,017
0.5250.200.0920,820
0.4270.130.1430,524
0.315300.080.2310,331
0.25330.050.3670,238
0.235-360.030.5730,148
Pour un bobinage, en entrée le nombre de tour, et en sortie la longueur de fil.
Diviseur de vitesse du processeur
Diam tambour mm
Largeur du tambour mm
Diamètre du filmm
Nombre d'enroulements 
Nombre de bobines 
Distance entre bobinesmm

Le programme

Fichier 1 hex pour flash
Fichier 1 hex pour eeprom

Bon bobinage

Sam
Niveau d'eau dans le puits

Plan de l'EEPROM :

 
  0 1 2 3 4 5 6 7 8 9 A B C D E F
0 
1 
2 
3 
4 
5120h de sauvegarde soit 4j
6 
7 
8 
9 
A 
B 
C 
DNon utilisé
E 
FADR FLASHADR EEPROM
  0 1 2 3 4 5 6 7 8 9 A B C D E F


Le registre X contient la valeur de la mesure
Le registre Y pointe la valeur dans l'EEPROM
Le registre Z pointe la valeur dans la mémoire FLASH

Organisaion de la mémoire FLASH ROM

Plan de la mémoire Flash :

Adresse pour la Table Flash. Le programme commence de 0x0000 à 0x01FF
La table de donnée commence donc de 0x0200 à 0x07FF

0000Programme
0200192 Données 
02C0192 Données 
0380192 Données 
0440192 Données 
0500192 Données1546 Données
05C0192 Données 
0680192 Données 
0740192 Données 
0800fin

WDTCR – Watchdog Timer Control Register

Bit76543210
WDTCRWDIFWDIEWP3WDCEWDEWDP2WDP1WDP0
Exemple01001111

WDEWDIEWatchdog Timer State Action on Time-out
00Stopped None
01Running Interrupt
10Running Reset
11Running Interrupt

Watchdog Timer Prescale Select

WDP3WDP2WDP1WDP0Number of WDT Oscillator
Cycles
Typical Time-out at
VCC = 5.0V
00002K (2048) cycles16 ms
00014K (4096) cycles32 ms
00108K (8192) cycles64 ms
001116K (16384) cycles0.125 s
010032K (32764) cycles0.25 s
010164K (65536) cycles0.5 s
0110128K (131072) cycles1.0 s
0111256K (262144) cycles2.0 s
1000512K (524288) cycles4.0 s
10011024K (1048576) cycles8.0 s
Programme principal en assembleur
Gestion watchdog
Gestion EEPROM
Une alarme Sécurisé ma maison, ce n'est pas juste contre le vol, mais également en cas d'incendie, et l'assainissement d'air.
Alarme, Capteur Présence, monoxyde de carbone, Température, Hygrométrie
  • Objectif :Mesurer et transmettre différentes mesures.
  • Moyen:
    • Utilisation d'un processeur principal ATmega328P sur Arduino Nano
    • Processeur esclave Attiny "One Wire" <8mA
    • Énergie utilisée : Transformateur 230V/5V
    • Mesures : Capteurs
      • AM2320 Capteur d'humidité et de température I²C - single-bus
        • Alimentation: 3,1 à 5,5 Vcc
        • Consommation maxi: 1,5 mA ; En Stand-by : 950μA
        • Plage de mesure:
          • température: -40 à +80°C
          • humidité: 0 à 99,9% HR
        • Précision:
          • température: ± 0,5°C
          • humidité: ± 3% HR
        • Dimensions: 15 x 12,1 x 4,5 mm
      • GPL, de CO (Monoxide de carbone) ou de fumées
        • MQ-2
        • Consommation maxi: 160 mA
        • Penser à refaire une calibration périodiquement à l'air pure (Je ne sais pas encore combien)
      • Module détecteur de Mouvement infrarouge pyroelectrique PIR
      • Un Buzzer actif Ø10mm 25mA à 35mA
      • DS3231 AT24C32 Module I2C Horloge de précision
    • Communication : One Wire
    • Sauvegarde des données? : Periode ?? temps ?? Où?

Les détecteurs "one wire"

Composés de d'un Attiny (adresse entre 0x10 et 0x50), PIR 1 bit, d'un MQ-2 (GPL, CO, fumées ) 2 Octets, d'un AM2320 (détecteur de température et d'humidité) 2 Octets+2 Octets, et enfin d'un Buzzer.. Le tout alimenté sous forme filaire

Les règles de fonctionnement

Il est nécessaire de prévoir un balayage et un stockage des données :

Les commandes

0x55 : MATCH ROM COMMAND
0x4E : WRITE SCRATCHPAD Juste pour écrire $R_O$ en RAM (2 octets)
0x48 : WRITE DATA TO RAM
    0x17 : ALARME BUZZER ACTIVE
  • Paramètre 0x00 : Alarme inactive par défaut 1
  • Paramètre 0x01 : Alarme uniquement ce TinyAL sans ordre 0, il continue de sonner
  • Paramètre 0x02 : Alarme tous les TinyAL sans ordre 0, il continue de sonner
  • Paramètre 0x03 : Surveillance2 si 0 pas de d'alarme présence (par défaut), sinon 1 alarme présence
  • Paramètre 0x04 : Alarme température supérieure à 50°C

1En cas d'alarme fumées, le paramètre d'alarme passe automatiquement à 0x02 sur le TinyAL et l'information est donnée au Master, qui diffuse l'information
2En cas d'alarme présence et Paramètre à 0x03(1), l'alarme passe automatiquement à 0x01 sur le TinyAL et l'information est donnée au Master, qui diffuse l'information.


Calibration du capteur MQ-2

Attention pour calibrer le capteur MQ-2, il est nécessaire de le mettre dans un lieu à environs 20°C avec de l'air pur durant environs 48h.
Il est donc nécessaire d'utiliser une procédure pour récupérer la valeur de $R_O$.

Lire les données

0xBE : Load data to RAM : READ SCRATCHPAD Renvoyer la table de données suivante :
Table des données transmises par esclave TinyAL
AdresseDonnéeExemple
0x00Valeur analogique brute MQ-2 GPL, de CO (Monoxyde de carbone) ou de fumées (High byte)0x96
0x01Valeur analogique brute MQ-2 GPL, de CO (Monoxyde de carbone) ou de fumées (Low byte)0x14
0x02AM2320 (high humidity bytes)0x01
0x03AM2320 (low humidity bytes)0xF4
0x04AM2320 (high temperature bytes)0x00
0x05AM2320 (low temperature bytes)0xFA
0x06PIR état 0/1 0x01
0x07ALARME 0, 1, 2, 3 et 40x01
0x08Version 010x01
0x09Révision 030x03
0x0AFAMILYCODE0x28
0x0BDEVICE ID (N°TinyAL)0x10
0x0CValeur analogique brute MQ-2 $R_O$ high0x96
0x0DValeur analogique brute MQ-2 $R_O$ high0x14
0x0ECRC 8bits "one-wire"

Les composants

- Sur l'esclave:

AM2320

Branchement I²CBranchement "single bus"
;
;single_bus.inc
;
;single_bus.as
;______________________________________
;           GESTION Single-Bus
; Matériel :     ATtiny 85 16MHz 5V
; (c) sammy76.free.fr 23/09/2018
;V1.0 
;                          ATtiny85
;                         +-\/-+
;                    PB5 1|-  -|8  Vcc
;DTH22/AM2320 SDA    PB3 2|-  -|7  PB2
;                    PB4 3|-  -|6  PB1 
;                    GND 4|-  -|5  PB0 
;                         +----+
;______________________________________
;FUSE H:FE, E:DD, L:E1
;w lfuse 0 0xe1
;w hfuse 0 0xdd
;w efuse 0 0xfe
;.CSEG
;.include "tn85def.inc"
;.def   A       =r16    ; GENERAL PURPOSE ACCUMULATOR
;.def   tmp1    =r2 ;pour Single-bus
.def    timeL   =r4
.def    timeH   =r5

.equ    timeout =(F_CPU*1000)/(9000000)        ;nombre de cycle pour timeout
.equ    bSDA    = PB3    ;* SDA Port B, PB1 Pin 6
.equ    mSDA    = (1<<bSDA);Calculate binary value corresponding to I/O port bit for masking
                ;   MIN     TYP     MAX     UNIT
.equ    Tbe =10 ;   0.8     1       20      ms
.equ    Tgo =40 ;   20      30      200     us
.equ    Tre =80 ;   75      80      85      us
;.equ   TLOW=50 ;   48      50      55      us
;.equ   TH0 =26 ;   22      26      30      us
;.equ   TH1 =70 ;   68      70      75      us
;.equ   Ten =50 ;   45      50      55      us
        

read_single:
push    ZH
push    ZL

;Go into high impedence state to let pull-up raise data line level and
;start the reading process.
cbi     DDRB,bSDA    ; SDA en entrée
sbi     PORTB,bSDA   ; HIGH avec Résistance de pullup
ldi     A,250
rcall   WaitMiliseconds

;Host the start signal down time
;First set data line low for Tbe milliseconds.
sbi     DDRB,bSDA    ; SDA en sortie
cbi     PORTB,bSDA   ; LOW 
ldi     A,Tbe
rcall   WaitMiliseconds
cli     ;clear interrupt

;Bus master has released time Tgo
sbi     PORTB,bSDA    ; HIGH
;End the start signal by setting data line high for 40 microseconds.
ldi     XH,HIGH(C4PUS*Tgo) ;Tgo 
ldi     XL,LOW(C4PUS*Tgo)
rcall   Wait4xCycles    ;Wait Tbe us

cbi     DDRB,bSDA    ; SDA en entrée, 
sbi     PORTB,bSDA   ; pull-up activé
nop
rcall   expectPulseLOW    ;(4 cycles) Trel

rcall   expectPulseHIGH    ;(4 cycles) Treh


ldi     A,5                 ;5x8 bits=40 bits   ;1 cy
mov     tmp1,A                                  ;1 cy
bc_octets:
    ldi     A,8             ;8 bits             ;1 cy
    clr     DATA                                ;1 cy
    bc_8bits:
        rcall   expectPulseLOW                  ;4 cy
        mov     timeH,XH                        ;1 cy    
        mov     timeL,XL                        ;1 cy
        adiw    XH:XL,10                        ;Rattrapage du décalage
        rcall   expectPulseHIGH                 ;4 cy
        lsl     DATA                            ;1 cy
        cp      XL,timeL                        ; Compare low byte ; 1 cy
        cpc     XH,timeH                        ; Compare high byte ; 1 cy
        brlo    bitZero                         ; HIGHT<LOW  1 cy false 2 cy true
        ori     DATA,1                          ;1 cy
        bitZero:
        dec     A
        brne    bc_8bits                        ; <  1 cy false 2 cy true
        st        Z+,DATA                       ;1 cy
    dec    tmp1                                 ;1 cy
    brne bc_octets                              ; <  1 cy false 2 cy true
    pop    ZL
    pop ZH
; verif CRC 
    ldi     ZL, low(AllData)            ;RAM    les 5 octets
    ldi     ZH, high(AllData)
    ldi     A,4       ;4 données
    mov     tmp1,A
    clr     A
whitoutCRC:
    ld      DATA,Z+        
    add     A,DATA
    dec     tmp1
    brne    whitoutCRC
    ld      DATA,Z
    cp      A,DATA                    ;Si = pas d'erreur, sinon erreur, BRNE -> ERREUR
    ret    

expectPulseLOW:
    ;compte le temps ou SDA et à 0
    clr    XL                           ;1 cy x=0
    clr XH    ;count                    ;1 cy
    push timeL
    push timeH
    push A
    ldi     A,HIGH(timeout)
    mov     timeH,A
    ldi     A,LOW(timeout)
    mov     timeL,A
    bc_expectPulseLOW:
        sbic    PINB,bSDA               ; if SDA clear, skip increment
                                        ; false (1 cycle)/true (2cycles)
        rjmp fin_expectPulseLOW         ; 2 cy
        adiw    XH:XL, 1                ; x++ (2 cycles)    9cycles par boucles    
        ;compare tmp avec 1ms
        ;si tmp>1ms -> Erreur timeout
        ;sinon valeur de tmp
        cp        XL,timeL              ; Compare low byte ; 1 cy
        cpc        XH,timeH             ; Compare high byte ; 1 cy
        brsh    fin_expectPulseLOW      ; >timeout false (1 cycle)/true (2cycles)
        rjmp bc_expectPulseLOW          ;jump if not zero (2 cycles)
    fin_expectPulseLOW:
    pop    A
    pop timeH
    pop timeL
    ret                                 ; (4 cycles)

expectPulseHIGH:
    ;compte le temps ou SDA et à 1
    clr    XL                           ;(1 cycle) x=0
    clr XH    ;count                    ;(1 cycle)
    push timeL
    push timeH
    push A
    ldi     A,HIGH(timeout)
    mov     timeH,A
    ldi     A,LOW(timeout)
    mov     timeL,A
    bc_expectPulseHIGH:
        sbis    PINB,bSDA               ; if SDA set, skip increment
        rjmp fin_expectPulseHIGH
        adiw    XH:XL, 1                ; x++ (2 cycles)    9cycles par boucles
        ;compare tmp avec 1ms
        ;si tmp>1ms -> Erreur timeout
        ;sinon valeur de tmp
        cp        XL,timeL              ; Compare low byte ; 1 cy
        cpc        XH,timeH             ; Compare high byte ; 1 cy
        brsh    fin_expectPulseHIGH     ; >timeout false (1 cycle)/true (2cycles)
        rjmp bc_expectPulseHIGH
    fin_expectPulseHIGH:
    pop    A
    pop timeH
    pop timeL
    ret
    

MQ2

Le capteur de gaz MQ2 est utilisé pour la détection des fuites de gaz pour les équipements des marchés de grandes consommations et industriel.
Ce capteur est conçu pour détecter le LPG, i-butane, propane, méthane ,alcool, hydrogene et la fumée.
Il a une grande sensibilité et un temps de réponse rapide. Sa sensibilité peut d'ailleurs être ajustée par potentiomètre.
Le MQ2 doit être alimenté en 5V pour le capteur physico-chimique puisse atteindre sa température de fonctionnement. Il faut par ailleurs attendre 24 heures de préchauffage pour améliorer la précision des mesures.
Il dispose d’une sortie analogique et d’un réglage de la sensibilité par potentiomètre.
Consommation <800mW soit environ 160mA.

Attention : le MQ2 ne peut être utilisé que pour des expérimentations et pas pour des dispositifs de sécurité car il n’est pas homologué pour cela.

Cependant, je l'utilise pour mon système qui de toutes façons ne sera pas homologué.

Principe de lecture du capteur

RS/Ro
$log_{10}1,6=0,2$
$log_{10}0,26=-0.6$
PPM
$log_{10}200=2,3$
$log_{10}10000=4$
Pente de la droite :
$\dfrac{X_B-X_A}{Y_B-Y_A}=\dfrac{-0,6-0,2}{4-2,3}=\dfrac{-0,8}{1,7}=-0,24$

$pente = -0,47 = \dfrac{log_{10} (RS/R0) – 0,2}{ log_{10}(ppm) -2.3}$

donc $log_{10} (ppm) = 2,3 + \dfrac{log_{10} (RS/R0) – 0,2}{–0,47}$
soit $ppm = 10^{2,3 + \dfrac{log_{10} (RS/R0) – 0,2}{–0,47}}$

RS/Ro
$log_{10}5=0,2$
$log_{10}1,5=-0.6$
PPM
$log_{10}200=2,3$
$log_{10}10000=4$
Pente de la droite :
$\dfrac{X_B-X_A}{Y_B-Y_A}=\dfrac{-0,6-0,2}{4-2,3}=\dfrac{-0,8}{1,7}=-0,47$

$pente = -0,47 = \dfrac{log_{10} (RS/R0) – 0,2}{ log_{10}(ppm) -2.3}$

donc $log_{10} (ppm) = 2,3 + \dfrac{log_{10} (RS/R0) – 0,2}{–0,47}$
soit $ppm = 10^{2,3 + \dfrac{log_{10} (RS/R0) – 0,2}{–0,47}}$

RS/Ro
$log_{10}1,6=0,2$
$log_{10}0,26=-0.6$
PPM
$log_{10}200=2,3$
$log_{10}10000=4$
Pente de la droite :
$\dfrac{X_B-X_A}{Y_B-Y_A}=\dfrac{-0,6-0,2}{4-2,3}=\dfrac{-0,8}{1,7}=-0,47$

$pente = -0,47 = \dfrac{log_{10} (RS/R0) – 0,2}{ log_{10}(ppm) -2.3}$

donc $log_{10} (ppm) = 2,3 + \dfrac{log_{10} (RS/R0) – 0,2}{–0,47}$
soit $ppm = 10^{2,3 + \dfrac{log_{10} (RS/R0) – 0,2}{–0,47}}$

Lire l'article de pharduino

Le programme qui vas me permettre de convertir les données sur le maitre, étalonner le capteur, récupérer $R_0$,…

    /*******************Demo for MQ-2 Gas Sensor Module V1.0*****************************
Support:  Tiequan Shao: support[at]sandboxelectronics.com

Lisence: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)

Note:    Ce morceau de code source est censé être utilisé comme démonstration UNIQUEMENT.
Un étalonnage plus sophistiqué est requis pour les applications industrielles. 

                                                    Sandbox Electronics    2011-04-25
************************************************************************************/

/************************Hardware Related Macros************************************/
#define         MQ_PIN                       (0)     //définir le canal d'entrée analogique que vous allez utiliser
#define         RL_VALUE                     (5)     //définir la résistance de charge sur la carte, en kilo ohms
#define         RO_CLEAN_AIR_FACTOR          (9.83)  //RO_CLEAR_AIR_FACTOR = (résistance du capteur en air propre) / RO, 
                           //dérivée du tableau de la fiche technique

/***********************Software Related Macros************************************/
#define         CALIBARAION_SAMPLE_TIMES     (50)    //définir combien d'échantillons vous allez prendre dans la phase d'étalonnage
#define         CALIBRATION_SAMPLE_INTERVAL  (500)   //définir l'intervalle de temps (en milliseconde) entre chaque échantillon dans la phase de cablibration
#define         READ_SAMPLE_INTERVAL         (50)    //définir combien d'échantillons vous allez prendre en fonctionnement normal
#define         READ_SAMPLE_TIMES            (5)     //définir l'intervalle de temps (en milliseconde) entre chaque échantillon en fonctionnement normal

/**********************Application Related Macros**********************************/
#define         GAS_LPG                      (0)
#define         GAS_CO                       (1)
#define         GAS_SMOKE                    (2)

/*****************************Globals***********************************************/
float           LPGCurve[3]  =  {2.3,0.21,-0.47};   //deux points sont pris de la courbe avec ces deux points, 
                          //une ligne est formée qui est "approximativement équivalente" à la courbe originale.
                                                    //data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59) 
float           COCurve[3]  =  {2.3,0.72,-0.34};    //deux points sont pris de la courbe avec ces deux points, 
                          //une ligne est formée qui est "approximativement équivalente" à la courbe originale.
                                                    //data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000,  0.15) 
float           SmokeCurve[3] ={2.3,0.53,-0.44};    //deux points sont pris de la courbe avec ces deux points, 
                          //une ligne est formée qui est "approximativement équivalente" à la courbe originale.
                                                    //data format:{ x, y, slope}; point1: (lg200, 0.53), point2: (lg10000,  -0.22)                                                     
float           Ro           =  10;                 //Ro est initialisé à 10 kilo ohms

void setup()
{
  Serial.begin(9600);                               //UART setup, baudrate = 9600bps
  Serial.print("Calibrating...\n");                
  Ro = MQCalibration(MQ_PIN);                       //Calibrage du capteur.
                          //Assurez-vous que le capteur est à l’air pur lorsque vous effectuez l’étalonnage
  Serial.print("Calibration is done...\n"); 
  Serial.print("Ro=");
  Serial.print(Ro);
  Serial.print("kohm");
  Serial.print("\n");
}

void loop()
{
   Serial.print("LPG:"); 
   Serial.print(MQGetGasPercentage(MQRead(MQ_PIN)/Ro,GAS_LPG) );
   Serial.print( "ppm" );
   Serial.print("    ");   
   Serial.print("CO:"); 
   Serial.print(MQGetGasPercentage(MQRead(MQ_PIN)/Ro,GAS_CO) );
   Serial.print( "ppm" );
   Serial.print("    ");   
   Serial.print("SMOKE:"); 
   Serial.print(MQGetGasPercentage(MQRead(MQ_PIN)/Ro,GAS_SMOKE) );
   Serial.print( "ppm" );
   Serial.print("\n");
   delay(200);
}

/****************** MQResistanceCalculation ****************************************
Input:   raw_adc - valeur brute lue à partir de adc, qui représente la tension
Output:  la résistance du capteur calculée
Remarks: Le capteur et la résistance de charge forment un diviseur de tension. 
     Compte tenu de la tension aux bornes de la résistance de charge et de sa résistance,
     la résistance du capteur pourrait être déduite.
************************************************************************************/ 
float MQResistanceCalculation(int raw_adc)
{
  return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc));
}

/***************************** MQCalibration ****************************************
Input:   mq_pin - canal analogique
Output:  Ro du capteur
Remarks: Cette fonction suppose que le capteur est à l'air pur. 
     Il utilise MQResistanceCalculation pour calculer la résistance du capteur à l'air pur 
     et la divise ensuite avec RO_CLEAN_AIR_FACTOR. 
     RO_CLEAN_AIR_FACTOR est d'environ 10, ce qui diffère légèrement entre les différents capteurs.
************************************************************************************/ 
float MQCalibration(int mq_pin)
{
  int i;
  float val=0;

  for (i=0;i<CALIBARAION_SAMPLE_TIMES;i++) {            //prendre plusieurs échantillons
    val += MQResistanceCalculation(analogRead(mq_pin));
    delay(CALIBRATION_SAMPLE_INTERVAL);
  }
  val = val/CALIBARAION_SAMPLE_TIMES;                   //calculer la valeur moyenne

  val = val/RO_CLEAN_AIR_FACTOR;                        //divisé par RO_CLEAN_AIR_FACTOR 
                            //donne le Ro selon le tableau de la fiche technique 

  return val; 
}
/*****************************  MQRead *********************************************
Input:   mq_pin - analog channel
Output:  Rs du capteur
Remarks: Cette fonction utilise MQResistanceCalculation pour calculer la résistance du capteur (Rs).
         Le Rs change à mesure que le capteur se trouve dans la concentration différente du gaz cible. 
     Les temps d'échantillonnage et l'intervalle de temps entre les échantillons 
     peuvent être configurés en modifiant la définition des macros.
************************************************************************************/ 
float MQRead(int mq_pin)
{
  int i;
  float rs=0;

  for (i=0;i<READ_SAMPLE_TIMES;i++) {
    rs += MQResistanceCalculation(analogRead(mq_pin));
    delay(READ_SAMPLE_INTERVAL);
  }

  rs = rs/READ_SAMPLE_TIMES;

  return rs;  
}

/*****************************  MQGetGasPercentage **********************************
Input:   rs_ro_ratio - Rs divisé par Ro
         gas_id      - type de gaz cible
Output:  ppm du gaz cible
Remarks: Cette fonction transmet différentes courbes à la fonction MQGetPercentage 
     qui calcule les ppm (parties par million) du gaz cible.
************************************************************************************/ 
int MQGetGasPercentage(float rs_ro_ratio, int gas_id)
{
  if ( gas_id == GAS_LPG ) {
     return MQGetPercentage(rs_ro_ratio,LPGCurve);
  } else if ( gas_id == GAS_CO ) {
     return MQGetPercentage(rs_ro_ratio,COCurve);
  } else if ( gas_id == GAS_SMOKE ) {
     return MQGetPercentage(rs_ro_ratio,SmokeCurve);
  }    

  return 0;
}

/*****************************  MQGetPercentage **********************************
Input:   rs_ro_ratio - Rs divisé par Ro
         pcurve      - pointeur sur la courbe du gaz cible
Output:  ppm du gaz cible
Remarks: En utilisant la pente et un point de la ligne.
     Le x (valeur logarithmique de ppm) de la ligne pourrait être dérivé si y (rs_ro_ratio) est fourni.
     Comme il s'agit d'une coordonnée logarithmique, la puissance de 10 est utilisée pour convertir le résultat en valeur non logarithmique
************************************************************************************/ 
int  MQGetPercentage(float rs_ro_ratio, float *pcurve)
{
  return (pow(10,( ((log(rs_ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0])));
}
    

$10^{\dfrac{log_{10}(Ro)-pt_1}{pt_2}+pt_0}$

HC SR501 PIR Analogique

    Capteur de type HC SR501
  • Tension de fonctionnement : 5V à 20V continu (DC).
  • Consommation statique de 65 micro Ampères
  • Niveaux de sortie : High 3.3 V, Low 0 V.
  • Temps de délai ajustable de 0.3 secondes à 18 secondes.
  • Temps mort 0.2 secondes.
  • Déclenchement : L sans répétition , H répétition possible, valeur H par défaut.
  • Portée de détection : angle de moins de 120°, 7 mètres.
  • Température de fonctionnement de -15°C à +70 °C.
  • Dimensions du PCB 32x24 mm
  • Ecart entre les trous de 28mm, diamètre de vis du capteur de 2 mm
  • Capteur de 23 mm de diamètre.
    
init_PIR:    
    cbi   DDRB,PIR  ;Broche en entrée, attendre 30s pour initialisation, 
    ldi A,29    ;30s
    rcall waitseconds
    ret
    
load_PIR:
    sbis    PINB,PIR     ;skip si PIR haut
    rjmp    PIRLOW
PIRHIGHT:
    cp      pirState,zero
    brne    endloadPIR
    inc     pirState
    rjmp    PIRHIGHTLOW

PIRLOW:
    cp      pirState,zero
    breq    endloadPIR
    clr     pirState
PIRHIGHTLOW:
    st       Y+,pirState
    ldi      A,200    ;200ms
    rcall    WaitMiliseconds

endloadPIR:
    ret
     

BUZZER Actif

Continous Sound Beep Continuously Alarm
Material: ABS
Color: Black
Rated Current (MAX): 30 mA
Min Sound Output at 10cm: 85 dB
Resonant Frequency: 2300±300 Hz
Operating Temperature: -27°C ~ +70°C
Storage Temperature: -30°C ~ +105°C
Weight : 2g
- Sur le maitre:

DS3231 AT24C32 I²c

    DS3231 AT24C32 Module I2C precision Horloge en temps reel
  • DS3231 : 0xC0
  • Générateur d'horloge en temps réel, minutes, heures, jour, date, mois et année, et valable jusqu'à l'an 2100
  • Alimentation: 3,3 à 5,5 Vcc
  • Réveil calendrier avec deux sortie d'onde carrée programmable
  • Le capteur de température précision de ± 3° C
  • mémoire: AT24C32 (capacité de stockage 32kbits soit 8koctets) 0x57
  • Communication : I2C maximale de 400KHz
  • Adresse modifiable, par défaut est 0x57
  • Dimensions: 38 x 22 x 14mm
  • Masse : 8 g

Lecteur micro SD SPI

Stockage des données sur le maitre

Soit 11 données par composants, mais que faire de ces données.

Les valeurs de MQ-2

Elles vont être décomposées par calcul en fonction de $R_o$ en 3 valeurs GPL,CO, fumées sur 16 bits puis stockées.
Et enfin comparé au valeur admissible (A définir).

La valeur de AM2320

Les valeurs de température et hygrométrie sur 16 bits vont être stockées.
Et enfin comparé au valeur admissible (A définir).

La valeur du PIR

Juste mémorisé

table de stockage maitre

AdresseDonnée
0x00NO TinyAL + bit haut PIR
0x01MQ-2 - GPL (High byte)
0x02MQ-2 - GPL (Low byte)
0x03MQ-2 - CO (High byte)
0x04MQ-2 - CO (Low byte)
0x05MQ-2 - fumées (High byte)
0x06MQ-2 - fumées (Low byte)
0x07AM2320 - Humidité (High bytes)
0x08AM2320 - Humidité (Low byte)
0x09AM2320 - température (High bytes)
0x0AAM2320 - température (Low byte)
0x0BHeure du jour
0x0CMinute du jour
Soit 13 octets, si il y a 5 TinyAL cela fait donc 65 octets par sauvegarde.
La sauvegarde se fera toute les 30s dans un premier temps sur l'EEPROM de l'AT24C32
Durant 1h cela représente 120 sauvegardes soit 7800 octets sur un EEPROM de 8ko.

Ensuite, toute les heures la sauvegarde s'effectuera de l'EEPROM vers une carte micro SD de 16Go
Une carte SD formater en FAT32!!!
Un fichier à chaque fin d'une heure nommé YYMMJJHH.TAL, donc avec Année, mois, jour, heure précédente
avec une fichier qui aura une taille en fonction de la taille des clusters soit 8192 octets.
Ce qui vas représenté un maximum d'environs 2097152 heures soit 12483 semaines, ou 240.1 années , ce qui est plus que correct, mais sans utilité.
Il faudrait par contre qu'à partir du moment ou une alarme se déclenche, les données soient sauvegardées.
Si je me base sur une semaine de sauvegarde, j'ai besoin de 1279.6875 ko

Le DS3231 permettra de sauvegarder à heure fixe.
Télécommande lumières extérieurs Bluetooth Soit un total maximale de 18.36 €, hors téléphone et boitier, bien entendu.

Le principe

Soit un circuit électrique d'éclairage

A partir de celui-ci je souhaite ajouter une commande Bluetooth (Pour l'instant Android).

La transmission asynchrone

Le choix du protocole série asynchrone.

La vitesse de transmission

Temps de bit : Ce temps est lié au débit binaire en bits par seconde ( bit/s ou bauds )de la transmission.
$Débit~binaire = \dfrac{1}{T}$. Par exemple, si $T = 1~ms$, la transmission se fait à $1000 bit/s$. Vitesse de transmission “standard” en bauds (bits par secondes) 1200, 2400, 4800, 9600, 19200, 38400, 57600, et 115200.
Un bit de stop, et pas de bit de parité "none"
Je choisirai celui qui correspond au HC-06 soit 9600 bauds

Un bit de "start", un bit de "stop" et pas de parité "none"


bitStartb0b1b2b3b4b5b6b7Stop
Valeur0101010101

Le bit de départ a un niveau logique "0" tandis que le bit d'arrêt est de niveau logique "1".
Le bit de donnée de poids faible est envoyé en premier suivi des autres.
Tout d'abords, je vais déterminer le temps de transmission de chaque bit, et de chaque octet en fonction de la vitesse de mon processeur.

Pour la réception


Pour prendre l'information au plus vraie, je la prend au milieu du bit, soit 1.5bit après le premier front descendant du bit de "start".

Diviseur de vitesse du processeur
Fréquence du processeurMHz
Vitesse de transmission en bauds

Le programme

Solution 6, et dernière

L'ajout de bouton poussoir augmenterai l'utilisation des ports, j'utiliserai donc un Arduino Nano (Sniff, je m'éclate plus en assembleur sur Attiny85).
Le seul inconvénient de ce système est l'obligation de remplacer un interrupteur par un bouton poussoir, et de refaire son câblage en 5V.
Ce pendant, je retiens cette solution!, c’est une installation dans le bâtiment extérieurs de mon ami Nicolas, on verra ensemble, si cette solution lui convient!


Pour l'emission Bluetooth du l'HC-06, l'entrée est sur 3,3V, je calcul un petit diviseur de tension :
$V_s=\dfrac{R_2}{R_1+R_2}\cdot V_{cc}$ avec $V_s=3,3V$ et $V_{cc}=5V$ alors $\dfrac{R_2}{R_1+R_2}=\dfrac{V_s}{V_{cc}}=\dfrac{3,3}{5}$
$5\times R_2=3,3\times(R_1+R2)$ soit $R_2=\dfrac{33}{17}\times R_1$ pour $R_1=1k\Omega$, $R_2=1,94k\Omega$, vue mon stock ce sera $1,7k\Omega$.
Je vérifie la tension :
$V_s=\dfrac{1,7}{1+1,7}\times 5=3,15 V$ pour 3,3V, c'est bon ça!

Synthèse des branchements

Le schéma est un principe, le programme est réalisé avec les consignes suivantes.
Utilisation par ports:
BrocheDésignationFonctionZone
Pin D2PD2/INT0Interruption externe, Tx du HC-06, Rx de l'arduino
Pin D3PD3/INT1Interruption externe, Tous les Boutons poussoir
Pin D4PD4Rx du HC-06, Tx de l'arduino
Pin D8PB0Sortie Relay 0Portail (1 relais 10A)
Pin D9PB1Sortie Relay 1Bassin 4 lampes (10A max)
Pin D10PB2Sortie Relay 2Terasse (10A max)
Pin D11PB4Sortie Relay 3Entrée 6 lampes (10A max)
Pin D12PB3Sortie Relay 4Plus (10A max)
Pin A0PC0Entrée BP 0
Pin A1PC1Entrée BP 1
Pin A2PC2Entrée BP 2
Pin A3PC3Entrée BP 3
Pin A4PC4Entrée BP 4
Attention: pour le portail, une seule impulsion de 200cs paramétrable par l'administrateur
Option du programme Une option qui me paraît intéressante, si la lumière reste allumé un temps important (comme 2.5h par exemple, paramétrable par l'administrateur), alors la lumière s'éteint toute seule.
Le branchement étant défini, je passe à la programmation.

main.asm +

AM.inc +

Wait.inc +

eeprom_V5.inc +


Sur Android


Il est possible de paramétrer l'application, attention cependant, il faut penser aux restrictions admin/non admin.

Reste

Il reste effectivement plusieurs choses à voir :
Information boite aux lettre

Principe

Ma boite aux lettres est placer à l'ombre, (à peu près) à labrit du vent. Elle vas donc pouvoir me donner la température et l'hygrométrie extérieure.
Mais au départ, je voulais juste savoir si j'avais du courrier, mais c'est un peu trop simple. Elle vas me transmettre plusieurs information

Comme la distance entre la maison et la boite aux lettres est relativement importante (environs 20m), j'opte pour un petit composant pas chère et à faible consommation en RF (Radio Fréquence)
Le FS1000A pour l'émission, avec ces 28mA pour la transmission de données, c'est plutôt pas mal!

En parlant de consommation.

L'énergie

Attention en fonction de l'alimentation, la fréquence de l'horloge diminue, je vais donc faire une petit montage et un petit programme pour vérifier la fréquence réelle de mon processeur à 3,7V, histoire de voir si cette tension est suffisante et fiable pour répondre à mes exigences.

Je profite du watchdog de l'attiny85, avec un temps de 8s, cela me permet de consommer 5μA en mode veille.
Donc les informations sont envoyées dans la nature toutes les 8 secondes. Soit 431 relevés/heure, c'est un peu trop non!
Pour une BAL (boîte aux lettres, je pense qu'une fois par minutes c'est suffisant!
Le watch dog vas se lancer 60/8=7.5 je prendrai 8*8=64secondes. Durant la partie récupération des informations, le temps de fonctionnement de l'AM2320 est d'environs 350ms.
Xx64+0,35*X=3600
X=$\dfrac{3600}{64,35}=55,94$ cycles de fonctionnement par heure On vas pas chipoter, cela fait 60 cycles par heure.

ComposantActif"standby"Total par heure
TempsCourantTempsCourantmAh
AM2320$350ms\times 60$
=21s
1,5mA8s soit $3600-21$
3579s
950μA0,953
FS1000A$0,4ms\times 60$
=24s
28mA$3600-24$
3576s
0A0,187
Attiny85$350.4ms\times 60$
=21s
8mA$3600-21$
3579s
5μA0,052
78L05-1mA3600s1mA1,000
Un total cumulé de 2,192mAh
Si j'utilise une alimentation de 3,7V, alors j'économise l'énergie du 78L05, donc 1mAh. De plus la consommation vas baissée
Récapitulatif
Batteries 3.7V 1200mAh$1200mAh/1,192mAh=1.006,711$ heures, 42 jours
2 batteries 18650 3.7V 9800mAh $9800mAh/2,192mAh=4.470,803$ heures, 186 jours
1 batteries 18650 3.7V 9800mAh $9800mAh/1,192mAh=8.221,477$ heures, 343 jours

La transmission asynchrone

Le choix du protocole série asynchrone.

La vitesse de transmission

Temps de bit : Ce temps est lié au débit binaire en bits par seconde ( bit/s ou bauds )de la transmission.
$Débit~binaire = \dfrac{1}{T}$. Par exemple, si $T = 1~ms$, la transmission se fait à $1000 bit/s$. Vitesse de transmission “standard” en bauds (bits par secondes) 1200, 2400, 4800, 9600, 19200, 38400, 57600, et 115200.
Un bit de stop, et pas de bit de parité "none"
Je choisirai celui qui correspond le mieux au FS1000A au vue de la distance soit 2400 bauds

Un bit de "start", un bit de "stop" et pas de parité "none"


bitStartb0b1b2b3b4b5b6b7Stop
Valeur0101010101

Le bit de départ a un niveau logique "0" tandis que le bit d'arrêt est de niveau logique "1".
Le bit de donnée de poids faible est envoyé en premier suivi des autres.
Tout d'abords, je vais déterminer le temps de transmission de chaque bit, et de chaque octet en fonction de la vitesse de mon processeur.

Pour la réception


Pour prendre l'information au plus vraie, je la prend au milieu du bit, soit 1.5bit après le premier front descendant du bit de "start".

Diviseur de vitesse du processeur
Fréquence du processeurMHz
Vitesse de transmission en bauds

Le programme et sous-programmes d'émission

main.asm

    ;
; BAL.asm
;
; Created: 26/01/2019 10:26:12
; Author : samuel.dupre
;
;           GESTION BAL (Boite aux lettres)
; Matériel : 	ATtiny 85 16MHz 5V
; (c) sammy76.free.fr 26/01/2019
;V1.0 OK problème de parasite réception
;V2.0 Manchester + niveau batterie
;						 ATtiny85
;			              +-\/-+
;					 PB5 1|-  -|8  Vcc
;				Tx	 PB3 2|-  -|7  PB2	Capteur BAL ouverte/INT0
;	LED(DEBUG)		 PB4 3|-  -|6  PB1	Bouton Reset BAL/PCINT1
;					 GND 4|-  -|5  PB0	DTH22/AM2320 SDA +R
;				          +----+
;______________________________________
;FUSE H:FE, E:DD, L:E1
;w lfuse 0 0xe1
;w hfuse 0 0xdd
;w efuse 0 0xfe
;ATtinyX5.menu.clock.internal16.bootloader.low_fuses=0xf1
;ATtinyX5.menu.clock.internal16.bootloader.high_fuses=0xdf
;ATtinyX5.menu.clock.internal16.bootloader.extended_fuses=0xff
;Segment   Begin    End      Code   Data   Used    Size   Use%
;---------------------------------------------------------------
;[.cseg] 0x000000 0x0002c4    626     82    708    8192   8.6%
;[.dseg] 0x000060 0x0000b2      0     82     82     512  16.0%
;[.eseg] 0x000000 0x000000      0      0      0     512   0.0%
;cd C:\Users\samuel.dupre\Documents\Atmel Studio\7.0\BAL\BAL\
;set AVRDUDECONF="C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf"
;avrdude -C %AVRDUDECONF% -c avrisp -P COM7 -b 19200 -p t85 -U eeprom:r:eprom_t85.hex:i
.CSEG
.include "tn85def.inc"
#define F_CPU 16000000 ;8MHz pour Attiny85
#define BAUD_RATE 1200  ;2400bauds
#define DEBUG

;#define F_CPU 16500000 ;16.5MHz pour Digispark
.def	loopC	=R22	;delay countdown and loop registers
;.def	regB	=R17	;temporary registers
.def	regA	=R16
.def     zero =r10
;.equ	Rx	=PB4
.equ	Tx	=PB3
#if defined(DEBUG)
.equ	LED=PB4
#endif 
;************************************************
;* Interrupt Vectors				      *
;************************************************

	rjmp	ON_RESET	;Reset Handler
	rjmp	MYINT0		; External Interrupt 0
	rjmp	INT1		; Pin change Interrupt Request 0
	reti		; Timer/Counter1 Compare Match 1A
	reti		; Timer/Counter1 Overflow
	reti		; Timer/Counter0 Overflow
	reti		; EEPROM Ready
	reti		; Analog comparator
	reti		; ADC Conversion ready
	reti		; Timer/Counter1 Compare Match B
	reti		; Timer/Counter0 Compare Match A
	reti		; Timer/Counter0 Compare Match B
	rjmp WDTinterrupt		; Watchdog Time-out
	reti		; USI START
	reti		; USI Overflow
;______________________________________
;           SETUP
;______________________________________
ON_RESET:
	clr zero
	ldi regA, LOW(RAMEND)            ;Setup of stack pointer 0x15F t45/0x25F t85
    out SPL, regA
    ldi regA, HIGH(RAMEND)
    out SPH, regA
    ;Eteint le CAN
    cbi    ADCSRA, ADEN        ;switch Analog to Digitalconverter OFF, ADC uses ~320uA

    cli
    ldi regA,(1<<CLKPCE)
    out CLKPR,regA        ;Par logiciel sur 16 MHz, modification de la version de pré-calcule (CLKPR – Clock Prescale Register- CLKPCE: Clock Prescaler Change Enable)
    clr regA
    out CLKPR,regA        ;Réglez le précalcul à 1 (000)    Clock Division Factor=1
	;
	;Initialise le changement d'interruption sur PCINT4
	ldi	regA,( 1 << PCIE | 1<<INT0)	;modification de l'interruption active
	out GIMSK,regA
	ldi	regA,( 1 << PCINT1)	;interruption de changement de broche activée pour PCINT1
	out PCMSK,regA
    /*
    ISC01 ISC00 Description
    0       0   The low level of INT0 generates an interrupt request.
    0       1   Any logical change on INT0 generates an interrupt request.
    1       0   The falling edge of INT0 generates an interrupt request.
    1       1   The rising edge of INT0 generates an interrupt request.
    */
	ldi		regA,(1<<ISC01 | 0<<ISC00)	;
	out		MCUCR, regA
	sei;	  // activer les interruptions
	#if defined(DEBUG)
	sbi	DDRB,LED
	cbi	PORTB,LED
	#endif 
;-------------------------------------------------------------------------	
	;initialize serial tx pin 
	sbi	DDRB,Tx		;Tx output for serial out
	;sbi	PORTB,Tx	;Tx initially high
	cbi	PORTB,Tx	;Tx initially low for manchester
	;initialize serial rx pin 
;	cbi	DDRB,Rx		;Rx input for serial in
;	cbi	PORTB,Rx	;Rx no internal pullup
;-------------------------------------------------------------------------

	 ;Get data from FLASH to RAM
    ldi     ZL, low(AllDataFlash<<1)
    ldi     ZH, high(AllDataFlash<<1)
    ldi     XL, low(Message)            ;RAM    
    ldi     XH, high(Message)
    clr     regA
    rjmp    forflash

;Récupération des informations de la FLASH -> RAM
Recup:               
   lpm   tmp,Z+        ;
   st    X+,tmp        ;
forflash:                ; rjmp
   cpi   XL,low(0x60+((finAlldata-AllDataFlash)<<1))    ; X octets
   cpc   XH,zero
   brne  Recup
;-------------------------------------------------------------------------
loop:
	
	ldi		YL,low(Capteur) 
	ldi		YH,high(Capteur) 
	rcall	read_single

	ldi		YL,low(Batterie) 
	ldi		YH,high(Batterie) 	
	rcall	readbattery
	ldi		YL,low(Capteur) 
	ldi		YH,high(Capteur) 
	ld		rBin1H,Y+
	ld		rBin1L,Y+
	
	ldi		ZL,low(Hygro)
	ldi		ZH,high(Hygro) 
	rcall	Bin2ToAsc5	; Conversion DCB de 0x1F4 -> 500
						; Conversion température de 500 50.0

	ld		rBin1H,Y+
	ld		rBin1L,Y+
	ldi		ZL,low(Tempe)
	ldi		ZH,high(Tempe)
	rcall	Bin2ToAsc5	; Conversion DCB de 250 -> 25.0°C
	ldi		ZL,low(Bat)
	ldi		ZH,high(Bat)
	ldi		YL,low(Batterie) 
	ldi		YH,high(Batterie) 
	rcall	hextodcb
	ldi     ZL, low(Message)
    ldi     ZH, high(Message)
	rcall	txmanchester
	/*
transmet:
	;Transmission du message
	ld		regA,Z+
	tst		regA
	breq	fin
	rcall	txchar
	rjmp	transmet
	fin:
	*/
;	ldi		temp,8	;8x8s=64s
	ldi		temp,1	;1x8s=8s for test

blcwait:
;Pause du watchdog (8s)
	rcall	WDT_on			; Watchdog on
	ldi		regA,(1<<SE | 0<<ISC01 | 1<<ISC00)	; Enable sleep mode , Any logical change on INT0 generates an interrupt request.
	out		MCUCR, regA
	//sei						; Interrupt enable
	sleep					; On dort et on attend le watchdog
	//cli						; Interrupt disable
	ldi		regA,(0<<SE | 0<<ISC01 | 1<<ISC00)    ; Disable sleep mode
	out		MCUCR, regA
	dec		temp
	brne	blcwait
rjmp	loop

hextodcb:
	ld		rBin1H,Y+
	ld		rBin1L,Y+
	mov		regA,rBin1H ;regA=0xH1L1
	swap	regA        ;regA=0xL1H1
	andi	regA,0x0F   ;regA=0xH1
	rcall	conv1H      ;Sauve Z+, asc(hex H1)
	mov		regA,rBin1H 
	andi	regA,0x0F   ;regA=0xL1
	rcall	conv1H      ;Sauve Z+, asc(hex L1)
	mov		regA,rBin1L ;regA=0xH2L2
	swap	regA        ;regA=0xL2H2
	andi	regA,0x0F   ;regA=0xH2
	rcall	conv1H      ;Sauve Z+, asc(hex H2)
	mov		regA,rBin1L
	andi	regA,0x0F   ;regA=0xL2
	rcall	conv1H      ;Sauve Z+, asc(hex L2)
	ret
conv1H:
	cpi		regA,0x0A   ;compare RegA avec 10
	BRLT	numH1       ;regA<0x0A ->numH1
	subi	regA,0xC9  ;regA+(65-10) RegA+55 ->'A'
	rjmp	saveH1	    
numH1:
	ori		regA,0x30	
saveH1:
	st		Z+,regA
	ret


MYINT0:
	push	regA        ;Met le courrier à yes
	ldi		regA,'Y'
endint:
	sts		bal,regA
	pop		regA
	reti

INT1:
	push	regA        ;button réinitialise courrier à no
	ldi		regA,'N'
	rjmp	endint


;.include "Fakewait.inc"
.include "wait.inc"
.include "manchester.inc"
.include "single_bus.inc"
.include "watchdog.inc"
.include "bintoasc.inc"
.include "batterie.inc"

AllDataFlash:
.db 13,10,"Temperature +--.-°C",13,10,"Hygrometrie  --.-%Hg",13,10,"Courrier -",13,10,"Batterie ----",13,10,0,0
.db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
finAlldata:

.DSEG ; Start data segment
Message:
.db 13,10,"Temperature "
Tempe:
.db "+--.-°C",13,10
.db "Hygrometrie "
Hygro:
.db " --.-%Hg",13,10
.db "Courrier "
Bal:
.db "Y",13,10,"Batterie "
Bat:
.db "----",13,10,0,0


Capteur: ;Les 5 bits
AMHg:
.byte 2 ; AM2320 Humidité
AMtemp:
.byte 2 ; AM2320 Température 
AMCRC:
.byte 2 ; AM2320 CRC
Batterie:
.byte 2 ; Batterie

.ESEG
.org 0xc0
buildtime:
.db "sammy76.free.fr "
.db "V2.00:%DAY%.%MONTH%.%YEAR% %HOUR%:%MINUTE%"
    

manchester.inc

    ;Transmission avec le protocol Manchester
;
;						 ATtiny85
;			              +*\/-+
;					 PB5 1|-  -|8  Vcc
;				Tx	 PB3 2|-  -|7  PB2
;					 PB4 3|-  -|6  PB1
;					 GND 4|-  -|5  PB0
;.equ	Tx	=PB3
;--------------------
;ZH:ZL pointe le message
;	.def	regA	=R16
;.def	loopC	=R22	;delay countdown and loop registers
.def	regB	=R17	;temporary registers
#ifndef F_CPU
	#define F_CPU 16000000 ;16MHz
	#error "F_CPU must be defined!"
#endif
#ifndef BAUD_RATE
	#define BAUD_RATE 2400 ;57600 bauds maxi OK
	#error "BAUD_RATE must be defined!"
#endif
#ifndef BAUD_RATE
	#define C4PUS (F_CPU/4000000) ;/4 nombre de périodes par us attention aux approximation
	#error "C4PUS must be defined!"
#endif
;  Base delay | bauds | factor
#define timebit (921600/BAUD_RATE)*C4PUS ;2400bps 4 cycles pour Wait4xCycles 16MHz

	;il est commun de mettre à zéro une chaîne ou de transmettre de petits nombres comportant beaucoup de zéros
	;ces zéros peuvent être confondus avec un modèle d'apprentissage, ce qui crée de la confusion chez le récepteur 
	;et entraîne une perte de paquets importante,
	;donc on "xor" les données avec masque de découplage aléatoire
#define DECOUPLING_MASK 0b11001010
txmanchester:
#if defined(DEBUG)
	sbi		PORTB,LED
#endif 
;Transmit RegA
	ldi	    loopC,14		;send capture pulses
initT:
	rcall	sendzero		;end of capture pulses 0b10 x14
	dec		loopC
	brne	initT
	rcall	sendone			;start data pulse 0b01

transmetmessage:
	;Transmission du message
	ld		regA,Z+
	tst		regA
	breq	finmessage
	;regA	data
	ldi		loopC,8		;8 bits
loopallbit:
	;ldi		regB,DECOUPLING_MASK
	ror		regA		;rotate right bit0 into carry
	brcs	bitatone	;branch if bit right high (carry set)
	rcall	sendzero
	rjmp	transmetsuite
bitatone:	
	rcall	sendone

transmetsuite:
	dec		loopC
	brne	loopallbit
	rjmp	transmetmessage
finmessage:
	; Send terminating 0 to correctly terminate the previous bit and to turn the transmitter off
	rcall	sendzero
	rcall	sendzero
	#if defined(DEBUG)
	cbi		PORTB,LED
	#endif
	ret

sendzero:
	sbi	    PORTB,Tx			;HIGH  
	ldi		XH,HIGH(timebit)	
	ldi		XL,LOW(timebit)		
	rcall	Wait4xCycles			 
	cbi	    PORTB,Tx			;LOW 
	ldi		XH,HIGH(timebit)
	ldi		XL,LOW(timebit) 
	rcall	Wait4xCycles	
	ret

sendone:
	cbi	    PORTB,Tx			;LOW  
	ldi		XH,HIGH(timebit)	
	ldi		XL,LOW(timebit)		
	rcall	Wait4xCycles		
	sbi	    PORTB,Tx			;HIGH 
	ldi		XH,HIGH(timebit)
	ldi		XL,LOW(timebit) 
	rcall	Wait4xCycles	
	ret    

Wait.inc

    ;______________________________________
;         MODULE Wait
; Matériel : 	ATtiny 45/85 4MHz à 20Mhz 5V
; (c) sammy76.free.fr
;	V1.0 2016/11/06
;______________________________________

#ifndef F_CPU
	#define F_CPU 16500000 ;16.5MHz
	#error "F_CPU must be defined!"
#endif


#if F_CPU < 4000000
	#message "Processeur beaucoup trop lent"
	#warning "F_CPU too low, possible wrong delay"
#endif

#define CYCLES_PER_US (F_CPU/1000000) ;Nombre de cycles par us
#define C4PUS (F_CPU/4000000) ;/4 nombre de périodes par us attention aux approximation
#define FOR1MS 1000;us par ms 

;.define DVUS(x) (C4PUS*x)

;------------------------------------------------------------------------------
; Input : XH:XL - number of CPU cycles to wait (divided by four)
;------------------------------------------------------------------------------
Wait4xCycles: ;(rcall 3cycle)
	sbiw	XH:XL, 1		; x-- (2 cycles)
	brne	Wait4xCycles	; jump if not zero (2 cycles)
	ret		;(4 cycles )

;------------------------------------------------------------------------------
; Input : A - number of milliseconds to wait
;------------------------------------------------------------------------------
;Attention:
;Approximation pour 1ms = 4*1000*4cyc*1000rep*3mult/16.5E6 soit 0.969ms 
;donc avec les répétitions on cumul l'erreur
;
WaitMiliseconds:
	push	regA
WaitMsLoop:	
	ldi		XH,HIGH(C4PUS*FOR1MS) ;1000us soit 1ms en fait avec 16.5MHz mettre X=0x10D0 4304d 
	ldi		XL,LOW(C4PUS*FOR1MS)  ;à 16Mhz mettre X=0xFA0 4000d
	rcall	Wait4xCycles
	dec		regA
	brne	WaitMsLoop
	pop		regA
	ret
/*
;------------------------------------------------------------------------------
; Input : A - number of centiseconds to wait
;------------------------------------------------------------------------------
;Attention:
;Approximation pour 1ms = 4*1000*4cyc*1000rep*3mult/16.5E6 soit 0.969ms 
;donc avec les répétitions on cumul l'erreur
;
Waitcentiseconds:
	push	regA
	push	XL
	push	XH

waitcenti:
		push 	regA
		waitcs:
			ldi 	regA,10	;0,01s soit 1 centisecond
			rcall  WaitMiliseconds
			brne   waitcs
		pop		regA
		dec    regA
		brne   waitcenti
	pop		XH
	pop		XL
	pop    regA
	ret

;------------------------------------------------------------------------------
;Input : A - number of seconds to wait
;------------------------------------------------------------------------------
waitseconds:
	push	regA
	push	YL
	push	YH
	push	XL
	push	XH

waitsec:
		ldi		YL,10	;1s
		push 	regA
		waitms:
			ldi 	regA,100	;0,1s
			rcall  WaitMiliseconds
			dec	YL
			brne   waitms
		pop		regA
		dec    regA
		brne   waitsec
	pop		XH
	pop		XL
	pop		YH
	pop		YL
	pop    regA
ret
;------------------------------------------------------------------------------
;Input : A - number of minutes to wait
;------------------------------------------------------------------------------
waitminute:
	push	regA
	ldi		regA,60
onesecond:
	rcall	waitseconds
	pop		regA
	dec		regA
	brne	waitminute
	ret
*/    

single_bus.inc

    ;
;single_bus.inc
;______________________________________
;           GESTION Single-Bus
; Matériel : 	ATtiny 85 16MHz 5V
; (c) sammy76.free.fr 2018/09/23
;V1.0 
;V1.1 Attention aux interruptions, à voir, actuellement cli et sei!
;			 ATtiny85
;		      +-\/-+
;		 PB5 1|-  -|8  Vcc
;		 PB3 2|-  -|7  PB2
;		 PB4 3|-  -|6  PB1 
;		 GND 4|-  -|5  PB0 DTH22/AM2320 SDA +R
;		      +----+
;______________________________________
;FUSE H:FE, E:DD, L:E1
;w lfuse 0 0xe1
;w hfuse 0 0xdd
;w efuse 0 0xfe
;.CSEG
;.include "tn85def.inc"
;.def 	regA 		=r16			; GENERAL PURPOSE ACCUMULATOR
.def 	DATA 	=r18			;all DATA
.def 	tmp 	=r3				;pour Single-bus
.def	timeL	=r8	
.def	timeH	=r9
.equ	bSDA		= PB0	;* SDA Port B, PB0 Pin 5
.equ	mSDA		= (1<<bSDA);Calculate binary value corresponding to I/O port bit for masking
.equ	timeout		=(F_CPU*1000)/(9000000)		;nombre de cycle pour timeout 9cyl/boucle
							;	MIN		TYP		MAX		UNIT
.equ	Tbe			=10		;	0.8 	1 		20 		ms
.equ	Tgo			=40		;	20		30		200		us
		

read_single:
push	YH
push	YL

;Go into high impedence state to let pull-up raise data line level and
;start the reading process.
cbi		DDRB,bSDA	; SDA en entrée
sbi		PORTB,bSDA	; HIGH avec Résistance de pullup
ldi		regA,250
rcall 	WaitMiliseconds	;250ms

;Host the start signal down time
;First set data line low for Tbe milliseconds.
sbi		DDRB,bSDA	; SDA en sortie
cbi		PORTB,bSDA	; LOW 
ldi		regA,Tbe
rcall 	WaitMiliseconds

;cli		;clear interrupt
;Bus master has released time Tgo
sbi		PORTB,bSDA	; HIGH
;End the start signal by setting data line high for 40 microseconds.
ldi		XH,HIGH(C4PUS*Tgo) ;Tgo 
ldi		XL,LOW(C4PUS*Tgo)
rcall 	Wait4xCycles	;Wait Tbe us

cbi		DDRB,bSDA	; SDA en entrée, 
sbi		PORTB,bSDA	; pull-up activé
nop
rcall 	expectPulseLOW		;4 cy Trel
rcall 	expectPulseHIGH		;4 cy Treh

ldi		regA,5			;5x8 bits=40 bits	;1 cy
mov		tmp,regA							;1 cy
bc_octets:
	ldi		regA,8			;8 bits		;1 cy
	clr		DATA					;1 cy
	bc_8bits:
		rcall 	expectPulseLOW		;4 cy
		mov		timeH,XH			;1 cy	
		mov		timeL,XL			;1 cy
		adiw	XH:XL,10			;2 cy Rattrapage du décalage
		rcall 	expectPulseHIGH		;4 cy
		lsl		DATA				;1 cy
		cp		XL,timeL			;1 cy Compare low byte 
		cpc		XH,timeH			;1 cy Compare high byte
		brlo	bitZero				; HIGHT<LOW  1 cy false 2 cy true
		ori		DATA,1				;1 cy
		bitZero:
		dec		regA
		brne 	bc_8bits			; <  1 cy false 2 cy true
		st		Y+,DATA				;1 cy
	dec	tmp							;1 cy
	brne bc_octets					; <  1 cy false 2 cy true
	pop	YL
	pop YH

	ret	
expectPulseLOW:
	;compte le temps ou SDA et à 0
	clr	XL						;1 cy x=0
	clr XH	;count				;1 cy
	push timeL
	push timeH
	push regA
	ldi	 regA,HIGH(timeout)
	mov	 timeH,regA
	ldi	 regA,LOW(timeout)
	mov	 timeL,regA
	bc_expectPulseLOW:
		sbic	PINB,bSDA		; if SDA clear, skip increment
								; false (1 cycle)/true (2cycles)
		rjmp fin_expectPulseLOW	; 2 cy
		adiw	XH:XL, 1		; x++ (2 cycles)	9cycles par boucles	
		;compare tmp avec 1ms
		;si tmp>1ms -> Erreur timeout
		;sinon valeur de tmp
		cp		XL,timeL			;1 cy Compare low byte 
		cpc		XH,timeH			;1 cy Compare high byte
		brsh	fin_expectPulseLOW	; >=timeout false (1 cycle)/true (2cycles)
		rjmp bc_expectPulseLOW		;2 cy jump if not zero
	fin_expectPulseLOW:
	pop	regA
	pop timeH
	pop timeL
	ret							;4 cy

expectPulseHIGH:
	;compte le temps ou SDA et à 1
	clr	XL						;1 cy x=0
	clr XH	;count				;1 cy
	push timeL
	push timeH
	push regA
	ldi	 regA,HIGH(timeout)
	mov	 timeH,regA
	ldi	 regA,LOW(timeout)
	mov	 timeL,regA
	bc_expectPulseHIGH:
		sbis	PINB,bSDA		; if SDA set, skip increment
		rjmp fin_expectPulseHIGH
		adiw	XH:XL, 1		; x++ (2 cycles)	9cycles par boucles
		;compare tmp avec 1ms
		;si tmp>1ms -> Erreur timeout
		;sinon valeur de tmp
		cp		XL,timeL			; Compare low byte ; 1 cy
		cpc		XH,timeH			; Compare high byte ; 1 cy
		brsh	fin_expectPulseHIGH	; >=timeout false (1 cycle)/true (2cycles)
		rjmp bc_expectPulseHIGH
	fin_expectPulseHIGH:
	pop	regA
	pop timeH
	pop timeL
	ret    

Watchdog.inc

    ;______________________________________
;           GESTION WATCHDOG
; Matériel : 	ATtiny 45/85 4MHz 5V
; 				
; (c) sammy76.free.fr
;	V1.0 2016/06/01 Juin 2016
;______________________________________


; Enclenche le watchdog
WDT_on:
	ldi	regA,0b01101001		;met le timeout a 8 sec et set le wtachdog interrupt
;	ldi	regA,0b01101000		;met le timeout a 4 sec et set le wtachdog interrupt
;	ldi	regA,0b01001111		;met le timeout a 2 sec et set le wtachdog interrupt
;	ldi	regA,0b01001110		;met le timeout a 1 sec et set le wtachdog interrupt
;	ldi	regA,0b01001101		;met le timeout a 0,5 sec et set le wtachdog interrupt
;	ldi	regA,0b01001100		;met le timeout a 0,25 sec et set le wtachdog interrupt
;	ldi	regA,0b01001011		;met le timeout a 0,125 sec et set le wtachdog interrupt
;	ldi	regA,0b01001010		;met le timeout a 64 ms et set le wtachdog interrupt
;	ldi	regA,0b01001001		;met le timeout a 32 ms et set le wtachdog interrupt
;	ldi	regA,0b01001000		;met le timeout a 16 ms et set le wtachdog interrupt
	out	WDTCR,regA
	ret
;______________________________________

; Éteint le watchdog
WDT_off:
	WDR
; Clear WDRF in MCUSR
	ldi regA, (0<<WDRF)
	out MCUSR, regA
; Write logical one to WDCE and WDE
; Keep old prescaler setting to prevent unintentional Watchdog Reset
	in  regA, WDTCR
	ori regA, (1<<WDCE)|(1<<WDE)
	out WDTCR, regA
; Turn off WDT
	ldi regA, (0<<WDE)
	out WDTCR, regA
	ret
;______________________________________
; Interruption du timeout du watchdog. On retourne simplement juste après le "sleep" !
WDTinterrupt:
	reti    

bintoasc.inc

    ;--------------
;
;
; 2 DIGITS TO ASCII
; Bintoasc.asm
;
; Created: 29/01/21/019
; Author : samuel.dupre
;
;           Conversop,
; Matériel : 	ATtiny 85 16MHz 5V
; (c) sammy76.free.fr 29/01/21/019
;V1.0 
;.CSEG
;.include "../includes/tn45def.inc"
.def	rBin1L		= r4	;
.def	rBin1H		= r5	;
;.def	regA		= r16	;
.def	temp		= r19	;

; In: 16-bit-binary in rBin1H:L
;  Z points to current BCD digit
; Out: Result in Z
Bin2ToAsc5:
	mov		temp,rBin1H
	or		temp,temp
	brmi	dcbneg
	ldi		regA,' '
	rjmp	sgndcb
dcbneg:
	ldi		regA,'-'
	ldi		temp,0x7F
	and		rBin1H,temp
sgndcb:
	st		Z+,regA
	ldi		temp,100
	rcall	todcb
	cp		regA,zero
	brne	chifdcb
	ldi		regA,' '
	rjmp	nochifdcb
chifdcb:
	ori		regA,0x30
nochifdcb:
	st		Z+,regA
	ldi		temp,10
	rcall	todcb
	ori		regA,0x30
	st		Z+,regA
	ldi		regA,'.'
	st		Z+,regA
	mov		regA,rBin1L
	ori		regA,0x30
	st		Z+,regA
	ret

todcb:
    clr     regA
todcb1:
    sub		rBin1L,temp
	sbc		rBin1H,zero
	brmi	todcb2
	inc		regA
	rjmp	todcb1
todcb2:
	add		rBin1L,temp
	adc		rBin1H,zero
	ret     
Détecteur de fumées

Principe

Le principe est toujours le même, une lumière est émise, et le récepteur ne reçoit rien!

Lorsqu'il y a de la fumée, le rayon est détourné, en effet la fumée agit comme un écran et reflète la lumière. A ce moment là, le capteur génère de l'électricité.
Mais la poussière aussi fera réagir le système, alors attention aux particules.

Régulateur VMC double flux Ventilation mécanique controlée. Le principe du double flux est le suivant :
Le taux de renouvellement d'air sur la période hivernale entre 0,3 et 0,7 volumes/heures.
Si la sous ventilation peut poser des problèmes de qualité de l’air liée à une insuffisance de ventilation, la sur ventilation poser le problème d’assécher l’air (avec tous les problèmes de santé liés à cela).

Débits d’air

Minimum dans les pièces de service

Nombre pièces
principales
Cuisine
mini/max*
Salle de
bains
WC
unique
WC
si plusieurs
Autres
pièces d’eau
Débit total
mini
120 / 7515 15151535
230 / 9015 15151560
345 / 10530 15151575
445 / 1203030151590
545 / 13530301515105
645 / 13530301515120
745 / 13530301515135
* Pour la cuisine, l’arrêté du 24 mars 1982 introduit le principe d’une ventilation qui sera soit continue à 90 m3/h, soit modulée avec un débit de base et un débit de pointe pendant l’usage de la cuisine.

Minimum dans les pièces de vie

Pour évaluer comment ventiler les pièces de vie, nous pourrons utiliser l’une des 2 règles suivantes :

Projet

La VMC est composée de deux moteurs 230V, faible consommation 15W pour environs 90m3/h.
information sur le régulateur : DIMMER
Relai temporisé avec détecteur de présence et luminosité
Câblage
/*Allumage d'une lampe en fonction de la luminosité
-Une photo résistance brancher sur 5V avec une photo-résistance
de retour de 10Kohm entre la broche A0 et GND.
-Un relai relié à la broche D8.
-Le signal PIR sur la broche D7
 */
unsigned long time;

int photocellPin = 0; // A0
int photocellReading; // the analog reading from the analog resistor divider

int calibrationTime = 30;
int ledPin = 13;  //Sortie LED de la carte
int inputPin = 7;  // Entrée PIR
int pirState = LOW;
int val = 0;

int luxstate = LOW;

int relay1 = 8; //Sortie Permier relai
int relayState = HIGH;

void setup(void) {
  time = millis(); //Reprend le temps
  if (mode_debug==1){
    Serial.begin(9600);
  }
  pinMode(relay1, OUTPUT);
  digitalWrite(relay1, HIGH);//Eteindre le relai
  
  pinMode(inputPin, INPUT);
  pinMode(ledPin, OUTPUT); 
  Serial.print("Etalonnage capteur PIR ");
  for (int i = 0; i < calibrationTime; i++) {
    Serial.print(".");
    digitalWrite(ledPin, HIGH);
    delay(500);
    digitalWrite(ledPin, LOW);
    delay(500);
  }
}

void loop(void) {
//Partie PIR
 val = digitalRead(inputPin);  //lire la valeur d'entrée
 if (val == HIGH) { // vérifier si l'entrée est HIGH
    digitalWrite(ledPin, HIGH);  // passer LED ON
//    delay(150);

    if (pirState == LOW) {
      time = millis(); //Reprend le temps
      pirState = HIGH;
      //Serial.println("Un mouvement detecte!");
    }
  } else {
    digitalWrite(ledPin, LOW); // passer LED OFF
 //   delay(300);
    if (pirState == HIGH) {
      pirState = LOW;
      //Serial.println("Pas ou plus de mouvement!");
    }
  }

  //Partie Photorésistance
  photocellReading = analogRead(photocellPin);
  Serial.print("Analog reading = "),Serial.println(photocellReading);
if (photocellReading < 250) {
    //Serial.println("Sombre, Allume le relai");
    luxstate = LOW;
  } else {
    //Serial.println("Lumineux, Eteind le relai");
    luxstate = HIGH;
  }

//Gestion du temps
if (luxstate==LOW && pirState == HIGH){
    relayState = LOW; //Allume le relai si présence et pas suffisamment de lumière
}



//Gestion du relai
  if (relayState == LOW){
    digitalWrite(relay1, LOW); //Allume le relai, y'a pas d'erreur.
     Serial.println("Allume!");
     if((millis() - time) > 180000){ //3 minutes
        Serial.println("Fin tempo");
        relayState = HIGH;
      }
  }
  else{
    digitalWrite(relay1, HIGH); //etein le relai
    Serial.println("Eteint!");
  }
  Serial.print("Temps="),Serial.println(millis() - time);
  delay(3000); /*Toute les 3 secondes */
}
Auto Power Off pour TTL (A faire)

Schéma de conception

A faire

Programme de boot

A faire
Câblage
Afficheur 7 segments géant

Principe

A partir d'un modèle 3d, 7 segments, afficher segment par segment. Voir Modèle initiale
Ce modèle est réalisé sur arduino nano, pourquoi pas, mais pour afficher l'heure, il me faut plus d'élement exemple avec un récepteur DCF77.