Exercices I2C ************* Programme N°3a (bis) -------------------- 'Après avoir réalisé l'exercice n°3a, nous nous rendons compte très vite que 'lorsque l'on arrive au seuil de déclenchement, et que le mouvement est très 'lent, les allumage de leds ne sont plus très "franc" et que des clignotement 'apparaissent. Or, c'est précisement ce que l'hytérésis devait empécher!! 'La première chose qui nous vient à l'esprit à ce moment, c'est d'ajouter un 'DEBUG dans le programme stamp2 pour vérifier la lecture, et nous constatons 'que cette lecture est loin d'être stable. 'Donc, le raisonnement qui consistait à tenir compte du sens de variation est 'innaplicable dans ce cas-çi. Il nous faut donc choisir une autre voie, et au 'lieu de raisonner sur le sens de variation, il est préférable de raisonner sur 'les différents états d'éclairement. 'D'ailleurs, de manière générale, il est toujours préférable de baser le 'raisonnement d'un algorithme sur des états stables, plutôt que sur des 'variations qui, par définition, sont instables. 'Tout ceci étant dit, nous allons maintenant analyser cette nouvelle manière de 'raisonner. 'Pour rappel, nous avons les différents seuils suivants : ' 0 : Clarté ' A : Extinction lampe 1 ' B : Allumage lampe 1 ' C : Extinction lampe 2 ' D : Allumage lampe 2 ' 255 : Obscurité 'Et de plus, nous avons, pour le système, les différents états : ' S0 : Pas de lampe allumée ' S1 : Une lampe allumée ' S2 : Deux lampes allumées 'Voici ce que ca donne sous forme de graphique : 'S2 - - - - - - - - - /--<---------<----->---- ' ' v ^ ' 'S1 - - - /--<------<---->--------/ ' ' v ^ ' 'S0 ------------->--/ ' 0 A B C D 255 'Et sous forme de texte : 'Etat S0 : de 0 à B - Etat S0 ' Supérieur à B - Etat S1 'Etat S1 : Inférieur à A - Etat S0 ' de A à D - Etat S1 ' Supérieur à D - Etat S2 'Etat S2 : Inférieur à C - Etat S1 de C à 255 - Etat S2 'En pratique, nous définirons les valeurs B ,D et l'hystérésis. Les valeurs 'A et C seront en fait déduite des valeurs B et D en y retranchant la valeur 'de l'hystérésis. Pour être clair, les variables s'appelerons : "Seuil1" (B), '"Seuil2" (D) et "Hys" pour l'hystérésis. 'Nous définirons aussi la variable Etat qui définira l'état des lampes ' Etat = 0 : Les deux lampes éteintes ' Etat = 1 : Une lampe allumée ' Etat = 2 : Les deux lampes allumées 'Voici maintenant notre petite liste de tâches : 'Début de boucle "infinie" ' Lecture du Pot ' Si Etat = 0 ' Alors Si Pot <= B ' Alors Etat = 0 ' Sinon Etat = 1 ' Si Etat = 1 ' Alors Si Pot <= A ' Alors Etat = 0 ' Sinon Si Pot compris entre A et D ' Alors Etat = 1 ' Sinon Etat = 2 ' Si Etat = 2 ' Alors Si Pot <= C ' Alors Etat = 1 ' Sinon Etat = 2 ' Allumer les lampes en fonction de Etat 'Fin de la boucle "infinie" 'Liste des routines I2C '---------------------- 'I2CSTART : Mise du bus I2C dans la condition "START" 'I2CSTOP : Mise du bus I2C dans la condition "STOP" 'I2CTX : Emission d'un octet sur le bus I2C 'I2CRX : Réception d'un octet sur le bus I2C 'ACKTX : Emission d'un "ACK" sur le bus I2C 'ACKRX : Réception d'un "ACK" sur le bus I2C 'Liste des routines utilisées dans le programme '---------------------------------------------- 'WRITEBYTE : Ecriture d'un octet sur le bus 'READBYTE : Lecture d'un octet sur le bus 'LAMP0 : Extinction des deux lampes 'LAMP1 : Allumage d'une lampe 'LAMP2 : Allumage des deux lampes '******************************************************************************* ' DEBUT DU PROGRAMME ' ****************** BEGIN 'Début du programme ' Définition des variables utilisées ' ********************************** DECLARE i2cadr AS byte 'Adresse du circuit I2C DECLARE i2cio AS byte 'Valeur lue ou écrite dans le composant I2C DECLARE i2cdata AS byte 'Octet de valeur lue ou écrite sur le bus I2C DECLARE i2cack AS bit 'Bit "ACK" du bus I2C DECLARE i2csda AS nibble 'Pin du circuit qui sert de "I2C DATA" DECLARE i2cscl AS nibble 'Pin du circuit qui sert de "I2C CLOCK" DECLARE i2cad1WR AS byte 'Adresse d'écriture du premier PCF8574 DECLARE i2cad2WR AS byte 'Adresse d'écriture du deuxième PCF8574 DECLARE i2cad3RD AS byte 'Adresse de lecture du PCF8591 DECLARE Seuil1 AS byte 'Premier seuil (voir ci-dessus) DECLARE Seuil2 AS byte 'Deuxième seuil (voir ci-dessus) DECLARE Hys AS nibble 'Hystérésis (voir ci-dessus) DECLARE Pot AS byte 'Lecture de l'entrée DECLARE Etat AS nibble 'Etat des lampes (0, 1 ou 2) DECLARE I AS byte 'Variable de travail DECLARE J AS byte 'Variable de travail DECLARE K AS byte 'Variable de travail DECLARE L AS byte 'Variable de travail ' Définition des constantes ' ************************* LET i2csda = 12 LET i2cscl = 13 LET i2cad1WR = 112 LET i2cad2WR = 114 LET i2cad3RD = 145 LET Seuil1 = 120 LET Seuil2 = 150 LET Hys = 10 ' Programme Principal ' ******************* DO WHILE k=k 'Début de la boucle "infinie" LET i2cadr = i2cad3RD 'Adresse du circuit PCF8591 GOSUB READBYTE 'Lecture du premier convertisseur LET Pot = i2cio 'Mise en mémoire de la valeur du POT IF Etat = 0 'Si pas de lampes allumées (S0) IF Pot <= Seuil1 'Si pot <= seuil1 (B) LET Etat = 0 'Etat d'extinction des lampes (S0) ELSE 'Si pot > seuil1 (B) LET Etat = 1 'Etat d'allumage d'une lampe (S1) ENDIF ' ELSE ' IF Etat = 1 'Si une lampe allumée (S1) IF Pot <= Seuil1-Hys 'Si pot <= seuil1-Hys (A) LET Etat = 0 'Etat d'extinction des lampes (S0) ELSE 'Si pot > seuil1-Hys (A) IF Pot <= Seuil2 'Si pot <= seuil2 (D) LET Etat = 1 'Etat d'allumage d'une lampe (S1) ELSE 'Si pot > seuil2 (D) LET Etat = 2 'Etat d'allumage des deux lampes (S2) ENDIF ' ENDIF ' ELSE 'Si les deux lampes allumées (S2) IF Pot <= Seuil2-Hys 'Si pot <= seuil2-Hys (C) LET Etat = 1 'Etat d'allumage d'une lampe (S1) ELSE 'Si pot > seuil2-Hys (C) LET Etat = 2 'Etat d'allumage des deux lampes ENDIF ' ENDIF ' ENDIF ' IF Etat = 0 'Si Etat = 0 GOSUB Lamp0 'Extinction des lampes ELSE 'Si Etat > 0 IF Etat = 1 'Si Etat = 1 GOSUB LAMP1 'Allumage d'une lampe ELSE 'Si Etat = 2 GOSUB LAMP2 'Allumage des deux lampes ENDIF ' ENDIF ' LET Etatp = Etat 'Mise à jour de l'état précedent ENDDO 'Fin de la boucle infinie END 'Routine d'extinction des deux lampes (groupe de leds) SUB LAMP0 LET i2cio = 0 'Valeur pour éteindre les leds LET i2cadr = i2cad1WR 'Adresse du premier PCF8574 GOSUB WRITEBYTE 'Envoi vers le bus I2C LET i2cio = 0 'Valeur pour éteindre les leds LET i2cadr = i2cad2WR 'Adresse du deuxième PCF8574 GOSUB WRITEBYTE 'Envoi vers le bus I2C ENDSUB 'Routine d'allumage d'une lampe (groupe de leds) SUB LAMP1 LET i2cio = 255 'Valeur pour allumer les leds LET i2cadr = i2cad1WR 'Adresse du premier PCF8574 GOSUB WRITEBYTE 'Envoi vers le bus I2C LET i2cio = 0 'Valeur pour éteindre les leds LET i2cadr = i2cad2WR 'Adresse du deuxième PCF8574 GOSUB WRITEBYTE 'Envoi vers le bus I2C END SUB 'Routine d'allumage des deux lampes (groupe de leds) SUB LAMP2 LET i2cio = 255 'Valeur pour allumer les leds LET i2cadr = i2cad1WR 'Adresse du premier PCF8574 GOSUB WRITEBYTE 'Envoi vers le bus I2C LET i2cio = 255 'Valeur pour allumer une led LET i2cadr = i2cad2WR 'Adresse du deuxième PCF8574 GOSUB WRITEBYTE 'Envoi vers le bus I2C ENDSUB ' Routine d'écriture de i2cio à l'adresse i2cadr sur le bus I2C SUB WRITEBYTE GOSUB i2cstart 'Mise du bus en condition "START" LET i2cdata = i2cadr 'Valeur de l'adresse à écrire GOSUB i2ctx 'Ecriture de l'adresse I2C GOSUB ackrx 'Attente de l'ACK LET i2cdata = i2cio 'valeur de la donnée à écrire GOSUB i2ctx 'Ecriture de la donnée I2C GOSUB ackrx 'Attente de l'ACK GOSUB i2cstop 'Mise du bus en condition "STOP" ENDSUB ' Routine de lecture dans i2cio à l'adresse i2cadr sur le bus I2C ' Attention, cette routine ne lit qu'un seul octet, ce qui dans ' le cas du PCF8591 ne permet de lire que la valeur du premier ' convertisseur analogique-digital. (Ce qui est demandé içi) SUB READBYTE GOSUB i2cstart 'Mise du bus en condition "START" LET i2cdata = i2cadr 'Valeur de l'adresse à écrire GOSUB i2ctx 'Ecriture de l'adresse I2C GOSUB ackrx 'Attente de l'ACK GOSUB i2crx 'Lecture de la donnée I2C GOSUB acktx 'ACK du "master" LET i2cio = i2cdata 'Mise a jour de la valeur lue GOSUB i2cstop 'Mise du bus en condition "STOP" ENDSUB 'Définitions des subroutines I2C '******************************* ' I2CSTART : Mise du bus I2C dans la condition "START" SUB I2CSTART Mise à 1 de la pin définie par i2csda 'I2C data line Mise à 1 de la pin définie par i2cscl 'I2C clock line Mise à 0 de la pin définie par i2csda 'I2C data line Mise à 0 de la pin définie par i2cscl 'I2C clock line ENDSUB ' I2CSTOP : Mise du bus I2C dans la condition "STOP" SUB I2CSTOP Mise à 0 de la pin définie par i2csda 'I2C data line Mise à 1 de la pin définie par i2cscl 'I2C clock line Mise à 1 de la pin définie par i2csda 'I2C data line ENDSUB ' I2CTX : Emission d'un octet sur le bus I2C SUB I2CTX LET i = 0 DO WHILE i < 8 LET j = (i)ème bit de i2cdata Mise à la valeur j de la pin définie par i2csda Mise à 1 de la pin définie par i2cscl PAUSE 1ms Mise à 0 de la pin définie par i2cscl Mise à 0 de la pin définie par i2csda ENDDO ENDSUB ' I2CRX : Réception d'un octet sur le bus I2C SUB I2CRX LET i = 0 DO WHILE i < 8 Mise à 1 de la pin définie par i2cscl LET j = valeur lue sur la pin définie par i2csda LET (i)ème bit de i2cdata = j PAUSE 1ms Mise à 0 de la pin définie par i2cscl ENDDO ENDSUB ' ACKTX : Emission d'un "ACK" sur le bus I2C SUB ACKTX Mise à 1 de la pin définie par i2cscl Mise "haute-impédance" de la pin définie par i2csda PAUSE 1ms Mise à 0 de la pin définie par i2csda PAUSE 1ms Mise à 0 de la pin définie par i2cscl ENDSUB ' ACKRX : Réception d'un "ACK" sur le bus I2C SUB ACKRX Mise à 1 de la pin définie par i2cscl Mise "haute-impédance" de la pin définie par i2csda PAUSE 1ms Attente d'un 0 sur la pin définie par i2csda PAUSE 1ms Mise à 0 de la pin définie par i2cscl ENDSUB '****************************************************************************** 'Programme pour le STAMP '******************************************************************** '* Exercice 5-3a2 : Réaliser un allumage crépusculaire (variante). * '* Le pot simule une ldr et la variation lumineuse * '******************************************************************** ' 'Utilisation de la carte Micro-Info et le K8000 'La ligne SDA est connectée en P12 'La ligne SCL est connectée en P13 'Notez que la carte MI est allimentée par le K8000 'Description du K8000 'Circuit Type Adresse du circuit '_________________________________________Fixe_A3_A2_A1_A0__Décimal_ 'IC17 : PCF8574A n°0 IO-chip no: 0 0111 0 0 0 X = 112+X 'IC18 : PCF8574A n°1 IO-chip no: 1 0111 0 0 1 X = 114+X 'IC20 : PCF8591 ADDA chip 1001 0 0 0 X = 144+X 'Pour faciliter l'écriture de notre programme, nous utiliserons 'les routines "ECR17" et "ECR18", qui en fait seront la routine '"WRITEBYTE" de la structurée, mais avec les paramètres d'adresse 'respectivement de IC17 et IC18 du K8000. En plus, la routine '"READBYTE" sera ici remplacée par une routine "LEC20" qui 's'occupera d'écrire l'octet dans le PCF8591 'De plus, les routines Lamp0, Lamp1 et Lamp2 sont ajutées. 'Elles allumes respectivement 0, 1 ou 2 "lampes" 'Liste des routines I2C '---------------------- 'I2CSTART : Mise du bus I2C dans la condition "START" 'I2CSTOP : Mise du bus I2C dans la condition "STOP" 'I2CTX : Emission d'un octet sur le bus I2C 'I2CRX : Reception d'un octet sur le bus I2C 'ACKTX : Emission d'un "ACK" sur le bus I2C 'ACKRX : Reception d'un "ACK" sur le bus I2C 'Définition des entrées-sorties OUTPUT 0 OUTPUT 1 OUTPUT 2 OUTPUT 3 OUTPUT 4 OUTPUT 5 OUTPUT 6 OUTPUT 7 OUTPUT 8 OUTPUT 9 INPUT 10 OUTPUT 11 INPUT 12 INPUT 13 INPUT 14 INPUT 15 'Initialisation du système INS = 0 OUTS = 0 'Définition des variables de travail I VAR BYTE J VAR BYTE K VAR BYTE L VAR BYTE 'Definition des variables I2C i2caddr var byte 'Mot de l'adresse du composant I2C i2cdata var byte 'Octet de valeur lue ou ecrite sur le bus I2C i2cack var bit 'Bit "ACK" du bus I2C i2csda con 12 'Pin I2C data du Stamp2 i2cscl con 13 'Pin I2C clock du Stamp2 i2cad1WR con %01110000 'Adresse d'ecriture du 1er PCF8574A i2cad2WR con %01110010 'Adresse d'ecriture du 2eme PCF8574A i2cad3RD con %10010001 'Adresse de lecture du PCF8591 i2cio var byte 'Valeur lue ou ecrite dans le composant i2c 'Définition des autres variables pot var Byte 'Valeur de la "ldr" etat var Nib 'Etat des lampes 'Definition des constantes seuil1 con 100 'Premier seuil de lumière seuil2 con 150 'deuxième seuil de lumière hys con 30 'Valeur de l'hystérésis 'Debut du programme principal '**************************** deb: GOSUB lec20 'Lecture du Potentiomètre IF etat > 0 Then s1 'Test inverse si pas de lampe allumée IF pot > seuil1 THEN s2 'Si pot > seuil1 (B) etat = 0 'Etat d'extinction des lampes GOTO s3 'Aller à commande des lampes s2: etat = 1 'Etat d'allumage d'une lampe GOTO s3 'Aller à commande des lampes s1: IF etat > 1 THEN s4 'Test inverse si une lampe allumée IF pot > seuil1-hys THEN s5 'Si pot > seuil1-hys (A) etat = 0 'Etat d'extinction des lampes GOTO s3 'Aller à commande des lampes s5: IF pot > seuil2 THEN s6 'Si pot > seuil2 (D) etat = 1 'Etat d'allumage d'une lampe GOTO s3 'Aller à commande des lampes s6: etat = 2 'Etat d'allumage des deux lampes GOTO s3 'Aller à commande des lampes s4: IF pot > seuil2-hys THEN s7 'Si pot > seuil2-hys (C) etat = 1 'Etat d'allumage d'une lampe GOTO s3 'Aller à commande des lampes s7: etat = 2 'Etat d'allumage des deux lampes s3: IF etat > 0 THEN s8: 'Début de la commande des lampes GOSUB lamp0 'Extinction des lampes si etat = 0 GOTO deb: 'bouclage s8: IF etat > 1 THEN s9: 'Test inverse pour etat = 1 GOSUB lamp1 'Allumage d'une lampe GOTO deb: 'bouclage s9: GOSUB lamp2 'Allumage des deux lampes si etat = 2 GOTO deb: 'bouclage STOP 'ECR17 : Ecriture de la valeur contenue dans i2cio dans IC17 '*********************************************************** ecr17: GOSUB i2cstart 'Mise du bus en condition "START" i2cdata=i2cad1WR 'Valeur a envoyer = ecriture 1er PCF8574A GOSUB i2ctx 'Envoi de i2cdata sur le bus i2c GOSUB ackrx 'Attente de l'ACK i2cdata=i2cio 'Valeur a envoyer = i2cio GOSUB i2ctx 'Envoi de i2cdata sur le bus i2c GOSUB ackrx 'Attente de l'ACK GOSUB i2cstop 'Mise du bus en condition "STOP" RETURN 'ECR18 : Ecriture de la valeur contenue dans i2cio dans IC18 '*********************************************************** ecr18: GOSUB i2cstart 'Mise du bus en condition "START" i2cdata=i2cad2WR 'Valeur a envoyer = ecriture 2eme PCF8574A GOSUB i2ctx 'Envoi de i2cdata sur le bus i2c GOSUB ackrx 'Attente de l'ACK i2cdata=i2cio 'Valeur a envoyer = i2cio GOSUB i2ctx 'Envoi de i2cdata sur le bus i2c GOSUB ackrx 'Attente de l'ACK GOSUB i2cstop 'Mise du bus en condition "STOP" RETURN 'LEC20 : Lecture du premier convertisseur AD du PCF8591 : IC20 '************************************************************* LEC20: GOSUB i2cstart 'Mise du bus en condition "START" i2cdata=i2cad3RD 'Valeur a envoyer = lecture PCF8591 GOSUB i2ctx 'Envoi de i2cdata sur le bus i2c GOSUB ackrx 'Attente de l'ACK GOSUB i2crx 'lecture de l'octet i2cio=i2cdata 'Mise en mémoire de la valeur GOSUB i2cstop 'Mise du bus en condition "STOP" pot = i2cio 'Mise à jour de la valeur de POT RETURN 'LAMP0 : Extinction des deux "lampes" '************************************ lamp0: i2cio = 255 GOSUB ecr17 GOSUB ecr18 RETURN 'LAMP1 : Allumage d'une "lampe" '****************************** lamp1: i2cio = 0 GOSUB ecr17 i2cio = 255 GOSUB ecr18 RETURN 'LAMP2 : Allumage des deux "lampes" '********************************** lamp2: i2cio = 0 GOSUB ecr17 GOSUB ecr18 RETURN '************************************************************************** 'Liste des routines I2C '********************** 'I2CSTART : Mise du bus I2C dans la condition "START" '**************************************************** i2cstart: HIGH i2csda 'Mise a 1 de I2C data HIGH i2cscl 'Mise a 1 de I2C clock LOW i2csda 'Mise a 0 de I2C data RETURN 'I2CSTOP : Mise du bus I2C dans la condition "STOP" '************************************************** i2cstop: LOW i2csda 'Mise a 0 de I2C data line HIGH i2cscl 'Mise a 1 de I2C clock line HIGH i2csda 'Mise a 1 de I2C data line RETURN 'I2CTX : Emission d'un octet sur le bus I2C '****************************************** i2ctx: SHIFTOUT i2csda,i2cscl,1,[i2cdata] RETURN 'I2CRX : Reception d'un octet sur le bus I2C '******************************************* i2crx: SHIFTIN i2csda,i2cscl,0,[i2cdata] RETURN 'ACKTX : Emission d'un "ACK" sur le bus I2C '****************************************** acktx: SHIFTOUT i2csda,i2cscl,1,[%0\1] RETURN 'ACKRX : Reception d'un "ACK" sur le bus I2C '******************************************* ackrx: SHIFTIN i2csda,i2cscl,0,[i2cack\1] RETURN 'FIN DES ROUTINES I2C '**************************************************************************