Exercices I2C ************* Programme N°3a -------------- 'En branchant un potentiomètre comme dans l'exercice précédent, réaliser une 'fonction "allumage crépusculaire progressif" avec hytérésis. 'Le potentiomètre simule une LDR (Claire=faible valeur. Obscure = forte valeur) 'Le principe du programme est que l'on commande deux lampes (représentées 'chacune par un groupe de 8 leds, en fonction de la luminosité. Lorsque 'la luminosité commence à baisser, on allume une lampe, puis, lorsque 'la 'luminosité' a encore baissé un peu, on allume les deux lampes. 'Pour réaliser l'hystérésis, il faut que les niveaux d'allumage soient 'plus "obscures" que les niveaux d'extinction. (Sinon, on risque 'un clignotement de la lampe) 'Le K8000 est commuté en position 0 (OFF-OFF) ' Circuit Type Adresse du circuit '_________________________________________Fixe_A3_A2_A1_A0__Déc._ ' 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 ' IC19 : TDA8444 DAC chip 0100 0 0 0 X = 32+X ' IC20 : PCF8591 ADDA chip 1001 0 0 0 X = 144+X 'Dans cet exercice, il nous faudra en fait définir plusieurs seuils 'de déclanchement. En partant du principe que la clarté est définie 'par la valeur 0 et l'obscurité par la valeur 255, nous aurrons 'la suite de valeurs suivante : ' 0 : Clarté ' A : Extinction 2ème lampe ' B : Allumage 1ère lampe ' C : Extinction 1ère lampe ' D : Allumage 2ème lampe ' 255 : Obscurité 'Donc, lors d'un cycle complet, nous avons la succéssion suivante : ' en passant de la lumière à l'obscurité (augmentation de Pot) ' de 0 à B : Les deux lampes sont éteintes ' de B à D : Allumage d'une lampe ' de D à 255 : Les deux lampes sont allumées ' puis en passant de l'obscurité à la lumière (diminution de Pot) ' de 255 à C : Les deux lampes sont allumées ' de C à A : Extinction d'une lampe ' de A à 0 : Les deux lampes sont éteintes '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. 'De tout ce qui vient d'être dit, nous en concluons que le sens de variation 'est important et que nous devrons le déterminer. L'utilisation d'une variable 'supplémentaire que nous appellerons "Oldpot" mettra en mémoire la valeur 'précédente de Pot et nous permettra de connaître le sens de variation. 'Voici maintenant notre petite liste de tâches : 'Début de boucle "infinie" ' Lecture du Pot ' Si augmentation de Pot ' Alors ' Si Pot plus petit que Seuil1 ' Alors deux lampes éteintes ' Si Pot compris entre Seuil1 et Seuil2 ' Alors une lampe allumée ' Si Pot plus grand que Seuil2 ' Alors deux lampes allumées ' Sinon ' Si Pot plus grand que Seuil2-Hys ' Alors deux lampes allumées ' Si Pot compris entre Seuil2-Hys et Seuil1-Hys ' Alors une lampe allumée ' SI Pot plus petit que Seuil1-Hys ' Alors deux lampes éteintes '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 Oldpot AS byte 'Valeur antérieure de l'entrée 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 ' ******************* LET Oldpot = 0 'Initialisation de la valeur antérieure 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 Pot > Oldpot 'Augmentation de Pot IF Pot < Seuil1 'Condition "Claire" GOSUB Lamp0 'Extinction des lampes ELSE IF Pot < Seuil2 'Condition "Moyenne" GOSUB Lamp1 'Allumage d'une lampe ELSE 'Condition "Obscure" GOSUB Lamp2 'Allumage des deux lampes ENDIF ENDIF ELSE 'Diminution de Pot IF Pot > Seuil2-Hys 'Condition "Obscure" GOSUB Lamp2 'Allumage des deux lampes ELSE IF Pot > Seuil1-Hys 'Condition "Moyenne" GOSUB Lamp1 'Allumage d'une lampe ELSE 'Condition "Claire" GOSUB Lamp0 'Extinction des lampes ENDIF ENDIF ENDIF LET Oldpot = Pot 'Mise a jour de la valeur antérieure 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-3a : Réaliser un allumage crépusculaire. * '* 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" oldpot var Byte 'Valeur précédente de la "ldr" 'Definition des constantes seuil1 con 100 'Premier seuil de lumière seuil2 con 150 'deuxième seuil de lumière hys con 15 'Valeur de l'hystérésis 'Debut du programme principal '**************************** oldpot = 0 deb: GOSUB lec20 'Lecture du Potentiomètre IF pot <= oldpot THEN s1 'Saut vers diminution de POT IF pot >= seuil1 THEN s2 'Saut si pot>=seuil1 GOSUB lamp0 'lampe éteintes car pot= seuil2 THEN s3 'Saut si pot>=seuil2 GOSUB lamp1 '1 lampe allumée car pot compris GOTO s6 'entre seuil1 et seuil2 s3: GOSUB lamp2 'Les 2 lampes allumées car pot>seuil2 GOTO s6 'Saut vers bouclage s1: IF pot <= (seuil2-hys) THEN s4 'Test pour pot>seuil2-hys GOSUB lamp2 'Allumage des 2 lampes GOTO s6 'Saut vers bouclage s4: IF pot <= (seuil1-hys) THEN s5 'Test pour pot>seuil1-hys GOSUB lamp1 'Allumage d'une lampe GOTO s6 'Saut vers bouclage s5: GOSUB lamp0 'Extinction des lampes s6: oldpot = pot 'Mise à jour de Oldpot GOTO deb: 'Bouclage "infini" 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 '**************************************************************************