Exercices I2C ************* Programme N°2a : ---------------- 'En branchant un potentiomètre de 10K lin sur l'entrée AD1 du K8000 (voir 'shémas ci-dessous), écrivez un programme qui change la vitesse du chenillard 'en fonction de la position du potentiomètre. ' 5V ------------\ ' / ' \<---------AD1 ' / ' \ ' GND(AD1)-------/ '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 ' IC20 : PCF8591 ADDA chip 1001 0 0 0 X = 144+X 'Comme le PCF8591 est un circuit convertisseur AD et DA sur 8 bits, nous 'suposerons que la lecture du potentiomètre se fera entre 0 et 255. 'La position "zéro" définira la vitesse la plus lente 'Comme pour l'exercice précédent, nous allons écrire une petite ' liste de tâches à éffectuer. 'Début de boucle infinie ' Initialisation de la variable d'affichage ' Début de boucle d'affichage ' Lecture du pot ' Calcul de la tempo ' Allumage de la led définie au compteur ' Attendre la tempo ' Eteindre la led définie au compteur ' Incrémentation du compteur ' Fin de la boucle d'affichage 'Fin de 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 ******************************************************************************* Structure 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 Temps AS Word 'Temporisation (Vitesse de défilement) 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 ' Programme Principal ' ******************* DO WHILE k=k 'Début de la boucle "infinie" LET L = 0 'Reset de la boucle de chenillard DO WHILE L < 16 'Boucle de chenillard sur 16 pas LET i2cadr = i2cad3RD 'Adresse du circuit PCF8591 GOSUB READBYTE 'Lecture du premier convertisseur LET temps = (255-i2cio) * 8 + 100 'Temps entre 2140 ms et 100 ms IF L < 8 'Test pour envoi vers le 1er PCF8574 LET i2cio = 2 ^ L 'Valeur pour allumer une led LET i2cadr = i2cad1WR 'Adresse du premier PCF8574 GOSUB WRITEBYTE 'Envoi vers le bus I2C PAUSE temps 'Pause avant d'éteindre la led LET i2cio = 0 'Valeur pour éteindre la led LET i2cadr = i2cad1WR 'Adresse du premier PCF8574 GOSUB WRITEBYTE 'Envoi vers le bus I2C ELSE 'Sinon envoi vers le 2ème PCF8574 LET i2cio = 2 ^ (L - 8) 'Valeur pour allumer une led LET i2cadr = i2cad2WR 'Adresse du deuxième PCF8574 GOSUB WRITEBYTE 'Envoi vers le bus I2C PAUSE temps 'Pause avant d'éteindre la led LET i2cio = 0 'Valeur pour éteindre la led LET i2cadr = i2cad2WR 'Adresse du deuxième PCF8574 GOSUB WRITEBYTE 'Envoi vers le bus I2C ENDIF LET L = L + 1 'Comptage pour le chenillard ENDDO 'Fin de la boucle de chenillard ENDDO 'Fin ?? de la boucle "infinie" END ' 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 'Définitions des subroutines I2C (suite) '*************************************** ' 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 ***************************************************************************** 'Listing du programme pour le STAMP2 '******************************************************************* '* Exercice 5-2a : Réaliser un chenillard avec 16 voies avec K8000 * '* La vitesse du chenillard varie avec la position * '* d'un Pot branché sur l'entrée AD1 du K8000 * '******************************************************************* ' '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 'Les remaques données pour les deux PCF8574A dans l'exercice 'précédent (5-1) sont identiques. 'En ce qui concerne l'utilsation du PCF8491, il faut noter 'ici que dans le cadre de notre exercice nous allons y faire 'une lecture uniquement. Dans ce cas, il ne faut pas écrire 'de "control byte", et la lecture se passe selon les modalités 'décrites à la page 10 du datasheet Philips. Notez encore que 'dans la description du protocole de lecture décrit dans le 'datasheet, l'"ACK" est ici envoyé par le stamp et sert à 'prévenir le PCF8491 qu'il peut envoyer les données. 'Lors de l'écriture du programme, nous nous rendons compte 'que nous avons fait preuve d'un optimisme débordant lors de 'l'écriture du programme en structurée. En effet, si nous utilisons 'la formule utilisée pour calculer le temps, nous aurrons un 'clignotement beaucoup trop lent. Et, à force de test, nous finirons 'par mettre pour le temps la valeur lue. Et comme il suffit de 'retourner le pot pour qu'il agisse à l'inverse, nous pourrons 'utiliser la relation Temps=i2cio 'Pour terminer avec les remarques, nous verrons aussi qu'une lecture 'du pot à chaque cycle de 16 pas est beaucoup trop lent lors 'des vitesses les plus lentes. Donc, nous éffectuerons une 'lecture du pot après chaque pas, et nou modifierons la 'structurée en conséquence. '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 '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 'Definition des autres variables Temps var byte 'Temps de pause pour le chenillard 'Debut du programme principal '**************************** 'initialisation de IC17 et IC18 i2cio = 255 'Valeur pour "éteindre" les leds de IC17 et IC18 GOSUB ecr17 'Extinction des leds de IC17 GOSUB ecr18 'Extinction des leds de IC18 'Première lecture du POT GOSUB lec20 'Lecture de la valeur dans le PCF8591 Temps = i2cio 'Mise à jour de la variable tempo deb: FOR I=0 TO 15 'Comptage en boucle de 0 à 15 IF I > 7 THEN s1 'Test inversé pour l'écriture dans IC17 i2cio=255-(1< 8 THEN s2 'Test de la première valeur de IC18 pour i2cio = 255 'éteindre IC17 GOSUB ecr17 'Extinction de IC17 s2: i2cio=255-(1<<(I-8)) 'Calcul de l'octet à écrire dans IC18 GOSUB ecr18 'Ecriture de l'octet dans IC18 s3: GOSUB lec20 'Lecture de la valeur du POT Temps = i2cio 'Mise a jour de la tempo PAUSE temps 'Pause pour la "vitesse" du chenillard NEXT 'Bouclage pour les 16 pas i2cio = 255 'Valeur à écrire GOSUB ecr18 'pour éteindre les leds de IC18 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" 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 '**************************************************************************