Webteo : Explication du programme PicBasic
Transcription
Webteo : Explication du programme PicBasic
Explication du programme du PicBasic Projet Webteo 2009/2010 '***************************************************************** ' DECLARATION DES CONSTANTES '***************************************************************** const BYTE k_array=(0,'A','I','O','T','C') 'Liste des variables Const CL_MSB_Adr = &H0FFE Const CL_LSB_Adr = &H0FFF Const BDS = 50 'Vitesse de transmission (103=9600bds/50=19200bds) Const RXD = 8 Const TXD = 9 Const Const Const Const SDA SCL CTRL_R CTRL_W Const Const Const Const O0 O1 O2 O3 = = = = 'Avant dernier emplacement mémoire 'Dernier emplacement mémoire 'Broche utilisée pour réception série=I/O8 'Broche utilisée pour émission série=I/O9 = = = = 10 11 &b10100001 &b10100000 12 13 14 15 'Broche donnée I2C=I/O10 'Broche horloge I2C=I/O11 'Octet de contrôle lecture 'Octet de controle ecriture 'Sortie 'Sortie 'Sortie 'Sortie O0=I/O12 O1=I/O13 O2=I/O14 O3=I/O15 '***************************************************************** ' DECLARATION DES VARIABLES '***************************************************************** DIM Adr AS INTEGER 'Pointeur Adressage eeprom DIM V AS INTEGER 'Valeur analogique DIM u AS INTEGER 'Unité valeur analogique DIM d AS INTEGER 'Dizaine valeur analogique DIM c AS INTEGER 'Dixième valeur analogique DIM CL AS INTEGER 'Content-Length DIM i AS BYTE 'Divers DIM j AS BYTE 'Divers DIM k AS BYTE 'Divers DIM l AS BYTE 'Divers DIM pos_T AS BYTE 'Position du texte LCD DIM Cpt AS INTEGER 'Compteur de connexion DIM GETHTTP(50) AS BYTE 'Requête HTTP Cette première partie de code déclare les constantes puis les variables. Les constantes étant déclarées par « CONST » et les variables par « DIM ». La toute première constante est un tableau contenant une liste de variables. Les variables et constantes peuvent prendre divers types de valeurs. Cela joue sur la capacité de mémoire alloué à la variable et donc, les valeurs extrêmes qu'elle peut prendre. Voici un tableau récapitulant les différents types de données possibles : Type de donnée Taille Valeurs possibles (Minimum .. Maximum) byte 8-bit 0 .. 255 char 8-bit 0 .. 255 word 16-bit 0 .. 65535 short 8-bit -128 .. 127 integer 16-bit -32768 .. 32767 longint 32-bit -2147483648 .. 2147483647 Noter aussi la présence des commentaires par l'apostrophe qui les précède. Ces commentaires améliorent la compréhension du programme ; la lecture du code tel quel n'étant pas une chose aisée, pour un développeur reprenant le programme, par exemple. ' INITIALISATIONS '=========================================================================== Cpt=0 'Initialisation du compteur de connexions INIT: ' Initialisation des sorties '-----------------------------------------------OUT O0,0 OUT O1,0 OUT O2,1 OUT O3,0 ' Initialisation de l'afficheur LCD '----------------------------------------SET PICBUS HIGH LCDINIT CLS LOCATE 0,0 : PRINT "Station meteo" LOCATE 5,1 : PRINT "WEBTEO" ' Calcul du Content-Length -------------------------------------------------CL=EEREAD(CL_MSB_Adr) CL=CL*256 i=EEREAD(CL_LSB_Adr) CL=CL+i 'RAZ 'RAZ 'RAZ 'RAZ O0 O1 O2 O3 'PICBUS à 19200bds 'Initialisation LCD 'Efface LCD 'Message d'accueil Ligne 1 'Message d'accueil Ligne 2 'Lecture MSB CL 'Calcul CL 'lecture LSB CL 'Calcul CL Cette nouvelle partie de programme à pour but d'initialiser le comportement du PicBasic. Tout d'abord, le compteur de connexions ( visible sur la page HTML du Picbasic ) est mis à zéro. Ensuite, on place un marqueur « INIT: » qui définit la ligne à partir de laquelle il faudrait reprendre l'initialisation ( instruction « GOTO INIT » ). Puis, les 4 sorties sont mises à zéro ( état bas ). L'écran est à sont tour initialisé. On l'efface puis on écrit le message d'accueil : Station meteo WEBTEO Enfin, on utilisant l'instruction « EEREAD(ADR) ». Cette instruction permet de récupérer une donnée à l'adresse (Adr) dans la mémoire FLASH du"PICBASIC". Ici, on lit le Bit de poids fort contenu à l'avant dernier emplacement mémoire ( &H0FFE ) , puis le Bit de poids faible au dernier emplacement mémoire ( &H0FF ). Ceci afin de calculer le Content-Length ( L'en-tête Content-Length permet au serveur d'indiquer au client la taille exacte du corps du message, ce qui permet au client de déterminer exactement quand celui-ci a été entièrement transmis ). ' MISE A JOUR DES SORTIES DE LA CARTE ET DE L'ECRAN LCD '========================================================================== DEBUT: 'Attente connexion client http '-------------------------------------------SERIN RXD,BDS,0,1000,DEBUT,[UNTIL(13),GETHTTP(0)~49] 'Enregistrement des caractères reçus dans la variable GETHTTP 'tant que caractère <> retour chariot (=13) 'Redirection vers sous programme de programmation eeprom '------------------------------------------------------------IF GETHTTP(0)="P" THEN 'Si 3 premiers caractères = "PRG" IF GETHTTP(1)="R" AND GETHTTP(2)="G" THEN GOTO PRG 'enregistre les caractères suivants dans l'eeprom (page HTML) END IF ' 'Incrémentation du compteur de connexions '-------------------------------------------Cpt=Cpt+1 SEROUT TXD,BDS,0,0,["HTTP/1.0 200 OK",13,10] 'Accusé de réception requête accomplie correctement 'Lecture des données contenues dans l'adresse html '---------------------------------------------------j=0 ' FOR i=0 TO 49 'Lecture variable tableau GETHTTP IF GETHTTP(i)="?" THEN j=i+3 'Si "?" détecté => mémorisation dans j position début texte NEXT i IF j>0 THEN 'Si j>0 'Mise à jour des sorties ------------------------------------------------IF GETHTTP(j)="1" THEN OUT O0,1 ELSE OUT O0,0 j=j+1 IF GETHTTP(j)="1" THEN OUT O1,1 ELSE OUT O1,0 j=j+1 IF GETHTTP(j)="1" THEN OUT O2,1 ELSE OUT O2,0 j=j+1 IF GETHTTP(j)="1" THEN OUT O3,1 ELSE OUT O3,0 'Affichage du texte sur l'écran LCD '-------------------------------------j=j+4 pos_T=j k=j+32 LOCATE 0,0 l=j+16 CLS FOR i=j TO k IF GETHTTP(i)="+" THEN GETHTTP(i)=32 IF i=l THEN LOCATE 0,1 PRINT GETHTTP(i) NEXT i END IF 'mise à ' 'mise à ' 'mise à ' 'mise à jour sortie O0 jour sortie O1 jour sortie O2 jour sortie O3 'Position début texte 'Mémorisation position 'Position fin du texte 'Position curseur ' ' ' 'Remplace le + par un espace 'Passage 2ème ligne afficheur 'Affichage caractère sur LCD ' On retrouve tout d'abord le marqueur « DEBUT » fonctionnant à l'identique du marqueur « INIT » que j'ai expliqué précédemment. Ensuite, on récupère les caractères reçus dans la variable GETHTTP, c'est à dire les données qui suivent l'adresse web. La chaine de caractères de l'adresse est lue du premier caractère (0) au cinquantième (49), mais si le caractère lu est un retour chariot, la chaine est considérée comme terminée, donc la lecture s'arrête. Ensuite viens la séquence servant au stockage de la page HTML dans l'EEPROM. Si les 3 première lettres de la variable GETHTTP sont « PRG » alors la séquence de stoskage peut être exécutée, et le programme va directement au marqueur « PRG » situé plus loin (j'y reviendrait par la suite ). Si ces caractères diffèrent de « PRG » la séquence n'aura pas lieu. Puis le compteur de connexion est incrémenté de 1, et le PicBasic renvoie un accusé de réception informant le client que la requête s'est accomplie correctement. Enfin, la dernière partie de ce morceau de code est longue mais simple. Le Picbasic lit une nouvelle fois la requête GETHTTP et en ressort l'état des 4 sorties et le texte à afficher sur l'écran LCD, demandés par le client. ' ENVOI DE LA PAGE HTML AU CLIENT HTTP '================================================================ 'Envoi de l'entête http '--------------------------------------------------SEROUT TXD,BDS,0,0,["Content-Type: text/html",13,10] 'Type de contenu : html=text/html (si wap=text/vnd.wap.wml) SEROUT TXD,BDS,0,0,["Content-Length: ",DEC(CL),13,10] 'Longueur du corps de la réponse SEROUT TXD,BDS,0,0,[13,10] 'Ligne vierge 'Envoi du code html '--------------------------------------------------GOSUB I2C_START 'Condition de START SHIFTOUT SCL,SDA,2,CTRL_W,8 'Octet de controle ECRITURE SHIFTOUT SCL,SDA,2,0,8 'Adresse du 1er octet à lire (MSByte) SHIFTOUT SCL,SDA,2,0,8 'Adresse du 1er octet à lire (LSByte) GOSUB I2C_START 'Condition de START SHIFTOUT SCL,SDA,2,CTRL_R,8 'Octet de controle LECTURE Cette partie du programme crée et envoie la page HTML au client. Tout d'abord, il y a l'en tête de la page qui signale au navigateur du client qu'il s'agit s'une page HTML et qui lui définit la longueur du Content-Length. Puis saute une ligne. Ensuite le Picbasic démarre la lecture de la page HTML dans l'EEPROM ( je reviendrai plus en détail sur ceci par la suite ). SUITE_RAZ: i=0:j=0:k=0 'initialisation des variables SUITE: j=SHIFTIN(SCL,SDA,1,8) IF j=26 THEN GOTO I2C_NOACK ELSE GOSUB I2C_ACK 'Lecture de la donnée 'Envoi acknowledge ON k GOTO 100,1,2,3,4,5 'branche sur une 'ligne en fonction de la valeur de k (ex: si k=1 branche sur la ligne 1) Ici, les variables i, j et k sont mises à 0 puis le PicBasic lit un octet dans l'EEPROM. Puis envoie un bit d'« acknoledge » à l'EEPROM signifiant que la lecture s'est correctement accomplie. La dernière instruction envoie à un certain marqueur en fonction de la valeur de k : si k=0 envoi au marqueur 100, si k=1 envoi au marqueur 1, … 'LECTURE ANALOGIQUE '-------------------------------------------------------1 j=j-48 V=ADIN(j) 'Lecture donnée analogique GOSUB CONV 'SP conversion mesure SEROUT TXD,BDS,0,0,[u,",",d,c] 'Envoi valeur mesurée u,dc GOTO SUITE_RAZ 'Branche sur l'étiquette SUITE_RAZ Il s'agit ici de la séquence associée au marqueur 1. La lecture de la broche j (variable) est lue puis convertie d'une tension en ASCII. Puis envoyée au navigateur du client. Puis retourne au marqueur « SUITE_RAZ ». 'LECTURE NUMERIQUE DES ENTREES '--------------------------------------------2 j=j-48 'ASCII -> DECIMAL j=j+17 'n° entrée concernée j=IN(j) 'Lecture état entrée j=j+48 'DECIMAL -> ASCII SEROUT TXD,BDS,0,0,[j] 'Envoi état entrée GOTO SUITE_RAZ 'Branche sur l'étiquette SUITE_RAZ Cette séquence associée au marqueur 2, lit l'état de l'entrée numérique j , puis la convertie de tension en ASCII et l'envoie au navigateur du client. Enfin le programme retourne au marqueur « SUITE_RAZ ». 'LECTURE NUMERIQUE DES SORTIES '--------------------------------------------3 j=j-48 'ASCII -> DECIMAL j=j+12 'n° sortie concernée j=OUTSTAT(j) 'Lecture état sortie j=j+48 'DECIMAL -> ASCII SEROUT TXD,BDS,0,0,[j] 'Envoi état sortie GOTO SUITE_RAZ 'Branche sur l'étiquette SUITE_RAZ Cette séquence associée au marqueur 3, lit l'état de la sortie numérique j , puis la convertie de tension en ASCII et l'envoie au navigateur du client. Enfin le programme retourne au marqueur « SUITE_RAZ ». 'ECRAN LCD '----------------------------------------------------------------4 IF pos_T>0 THEN 'Si texte modifié depuis RAZ serveur l=pos_T+32 'Borne sup (32 caractères) FOR j=pos_T TO l ' SEROUT TXD,BDS,0,0,[GETHTTP(j)] 'Envoi des 32 caractères NEXT j ' ELSE ' SEROUT TXD,BDS,0,0,["WEBTEO "] 'Texte par défaut END IF ' GOTO SUITE_RAZ 'Branche sur l'étiquette SUITE_RAZ Ici, la séquence associée au marqueur 4 écrit sur l'écran LCD le nouveau message ( envoyé par le client ), s'il y en a un, ou écrit sur l'écran LCD : WEBTEO Puis le programme retourne à « SUITE_RAZ ». 'COMPTEUR DE CONNEXIONS '---------------------------------------------------5 IF j="P" THEN SEROUT TXD,BDS,0,0,[DEC(Cpt)] 'Envoi donnée compteur GOTO SUITE_RAZ 'Branche sur l'étiquette SUITE_RAZ Cette séquence dont le marqueur est 5, envoie au navigateur du client la variable contenant le nombre de connexions effectues sur le PicBasic depuis la dernière remise à zéro. Enfin le programme retourne à « SUITE_RAZ ». 100 IF i="$" THEN FOR k=1 TO 5 IF k_array(k)=j THEN GOTO SUITE NEXT k END IF ' 'si caractère n-1 = $ ' ' ' ' IF j<>"$" THEN SEROUT TXD,BDS,0,0,[j] 'Envoi resultat sur port série i=j 'Caractère n-1 = caractère n GOTO SUITE 'Branche sur étiquette SUITE => Lecture donnée suivante Cette séquence associée au marqueur 100, si i a la valeur du caractère $, le programme attribue une valeur à k et défini le type de variable à envoyer ( utilisation du tableau « k_array » : $A0,$A1,$A2,$A3 $I0,$I1,$I2,$I3 $O0,$O0,$O0,$O0 $T0 $CP -> -> -> -> -> entrées analogiques entrées logiques sorties logiques texte sur écran LCD compteur de connexions depuis dernier RESET ). Sinon, le programme envoie la valeur de j et retourne à « SUITE ». Voici à présent les sous-programmes : Les sous-programmes sont appelées par « GOSUB » et retournent au programme appelant à la fin de leur execution « RETURN ». Pour comprendre pleinement ces sous programmes, il est recommandé de se reporter aux documents sur le protocole I²C. 'I2C : ECRITURE 1 octet '============================================================================ I2C_WRITE_BYTE: GOSUB I2C_START 'Condition de START SHIFTOUT SCL,SDA,2,CTRL_W,8 'Octet de contrôle LECTURE i=Adr/256 'Octet de poids fort SHIFTOUT SCL,SDA,2,i,8 'Adresse début écriture (MSByte) i=Adr 'Octet de poids faible SHIFTOUT SCL,SDA,2,i,8 'Adresse début écriture (LSByte) SHIFTOUT SCL,SDA,2,j,8 'Ecriture en eeprom de j Adr=Adr+1 'Incrementation pointeur adresse DELAY 5 'Tempo 5ms GOSUB I2C_STOP 'Condition de STOP DELAY 5 'Tempo 5ms RETURN Ce sous-programme, exécute la procédure d'écriture d'un octet dans l'EEPROM. Il démarre la discussion en prenant le contrôle de la ligne puis signale sa volonté d'écrire des données dans l'EEPROM. Puis il écrit l'octet à écrire puis arrète la transmission en libérant le contrôle de la ligne (au cas où il y aurait plusieurs maitres voulant prendre le contrôme de la ligne). 'I2C : START '============================================================================ I2C_START: OUT SCL,0 'SCL=0 OUT SDA,1 'SDA=1 OUT SCL,1 'SCL=1 OUT SDA,0 'SDA=0 OUT SCL,0 'SCL=0 RETURN 'I2C : STOP '============================================================================ I2C_STOP: OUT SCL,0 'SCL=0 OUT SDA,0 'SDA=0 OUT SCL,1 'SCL=1 OUT SDA,1 'SDA=1 OUT SCL,0 'SCL=0 RETURN 'I2C : ACKNOWLEDGE (émis par le PicBasic) '============================================================================ I2C_ACK: OUT SCL,0 'SCL=0 OUT SDA,0 'SDA=0 OUT SCL,1 'SCL=1 OUT SCL,0 'SCL=0 RETURN 'I2C : NO ACKNOWLEDGE (émis par le PicBasic) '============================================================================ I2C_NOACK: OUT SCL,0 'SCL=0 OUT SCL,1 'SCL=1 OUT SCL,0 'SCL=0 GOSUB I2C_STOP 'Condition de STOP GOTO DEBUT 'Retour au début du programme Ces sous-programmes correspondent aux séquences I²C de début de transmission (I2C_START), de fin de transmission (I2C_STOP), d'acquittement (I2C_ACK), et de non-acquittement (I2C_NOACK) dans quel cas le comportement à adopter est l'arret de la transmission. 'Conversion DECIMAL -> TENSION -> ASCII : x,xx '============================================================================ CONV: V=V/4 'Résolution 10 bits -> 8 bits V=(100*V)/51 'Calcul tension nombre entier u=V/100 'Calcul unité c=100*u d=(V-c)/10 'Calcul dixième c=c+(10*d) c=V-c 'Calcul centième u=u+48 'Unité -> CODE ASCII d=d+48 'Dixième -> CODE ASCII c=c+48 'Centième -> CODE ASCII RETURN Dans ce sous-programme, la valeur (en Volts) de l'entrée analogique (mais en numérique pour le moment) est convertie de 10 bits à 8 bits en divisant la valeur par 2² soit 4. Le nombre de volts (en 8 bits ) est alors convertie en une valeur analogique en multipliant la valeur numérique par le quantum qui est de 1/51 . Plus précisément: q = 5V/(2^8) = 5/256 = 1/51,2 = 19,5mV Mais ici la valeur du quantum appliquée est 1/51 afin de simplifier les résultats. Ensuite la valeur analogique est alors répartie dans 3 variables : une contient les unités (u), un autre les dixièmes (d) et une dernière les centièmes (c). Il n'y a pas de dizaines car l'entrée analogique ne peut dépasser 5V. Enfin on ajoute 48 à u, c et d pour les transformer en valeurs ASCII. En effet : Caractère Valeur décimale ASCII 0 0 + 48 = 48 1 1 + 48 = 49 2 2 + 48 = 50 3 3 + 48 = 51 4 4 + 48 = 52 5 5 + 48 = 53 6 6 + 48 = 54 7 7 + 48 = 55 8 8 + 48 = 56 9 9 + 48 = 57