La réalisation
Premièrement pour ceux qui ne posséderaient pas un PicKit 1 voici le schéma de l'application:
Le schéma ci-dessus nous montre la mise en place des différents composants destinés à cette application, nous repérons bien évidemment le Pic16f684 et le Max232 que nous avons déjà présenté. Le barregraph est représenté au travers des 5 leds, car après tout ce composant n’est rien d’autre qu’un support qui accroche 5 leds rectangulaire. Chacune de ces leds sont en séries avec une résistance de 330ohms. Comme la chute sur la led est de 1.5Volt, nous avons donc 3.5Volt de chute sur la résistance, ce qui donnera un courant de 3.5V/330Ohms soit environ 10ma. Ce qui est suffisant pour allumer une led. Comme convenu dans l’énoncé, la tension variable est connectée à l’entrée AN7. Le connecteur SUBD-9, connecteur standard pour la communication rs232 est relié au max par les broches 2 et 3 (transmission et réception) et 5 pour la masse. Nous ne nous servirons que de l’émission dans cette application.
Le programme du Pic
Le schéma ci-dessous nous donne en simplifier le fonctionnement du programme, d’une part nous avons à gauche la tâche principale qui tourne en boucle dans l’attente de nouvelle donnée à envoyer, d’une autre part nous avons à droite la source d’interruption qui s’occupe d’envoyer à la tâche principale une nouvelle valeur à traiter toutes les 100ms. Voyons maintenant plus en détail chaque bloc de ce programme :
L’initialisation :
L’initialisation va configurer les différents registres du pic afin d’avoir d’une part une entrée analogique sur AN7, et des sortie pour pouvoir allumer 5 leds, ainsi que d’une sortie supplémentaire pour pouvoir envoyer des informations à l’ordinateur.
TRISC = 0b00001000;
TRISA = 0b00001101;
TX=1; // TX à 1 au départ
T1CON=1;
ANSEL = 0b10000001; // Select AN7
ADCON0 = 29; // AN7 entrée analogique, VDD en ref, module powerup
TMR0 = 0x3C; // set Timer0
OPTION = TMRPRESCALE;
T0IE = SET; //Timer0 Overflow Interrupt Enabled
T0IF = CLEAR; //Clear Timer0 Overflow Interrupt Flag
PEIE = SET; // Active l'interruption des périphérique
ADIE = SET; // Active l'interruption des conversion AD
send = 0;
GIE = SET; // Enable All Interrupts
Dans un premier temps, nous configurons TRISC comme ayant toutes ses broches en sortie sauf la broche RA3 sur laquelle est connectée l’entrée analogique AN7. Le porta quant à lui est configuré de telle manière à avoir le bit 1 (tx) et les bits 4 et 5 (leds) en sortie. Les autres bits sont mis à l’état HiZ.
Nous mettons ensuite TX (alias RA1) au niveau logique 1 soit nous mettons la ligne rs232 à l’état de repos. Il est à noter que lors de la mise sous tension la carte peut envoyer une valeur à l’ordinateur qui sera souvent 0 (lors du démarrage du pic, un niveau bas peut très bien apparaître ce qui marquerait le début d’une communication, il est donc vital lors d’une application industriel de ne pas commander le démarrage d’un moteur avec un seule instruction sans vérifier qu’il ne s’agit pas d’un envoie parasite).
Via le registre ANSEL nous allons activer le bloc convertisseur. Nous mettons ANS7 et ANS0 comme entrée analogique. Pourquoi ANS0 ??? Car le circuit analogique tel que gravé sur le board pickit1 est sur ANS0. Pour éviter tout problème je le place en entrée analogique et je court-circuite les deux entrées. Le registre ADCON0 nous permet d’allumer le bloc analogique, de préciser que l’entrée à acquérir est l’entrée AN7, d’indiquer la référence comme étant l’alimentation du pic et de préciser l’ordre des bits dans les deux registres de résultat (nous y reviendrons plus tard).
Via le registre OPTION, nous configurons le prescaler du timer0 à 1:256, soit une incrémentation tous les 256µs. En plaçant 0x3c dans le timer0, nous avons un débordement toutes les 50ms.
Ensuite nous activons les interruptions du timer0, des périphériques et du convertisseur analogique.
La variable send, à une certaine importance dans le programme. C’est elle qui indique si y’a une nouvelle valeur à envoyer. Dans ce cas sa valeur passe à 1.
La boucle principale :
while(1){ //Loop Forever
if (send){…} }
Dans un premier temps la boucle regarde s’il y à une nouvelle donnée à envoyer. Si c’est le cas la première étape est de mettre à jour l’état du bargraph. Vu que la valeur reçue variera entre 0 et 5 volt, que nous ne garderons que les 8 bits de poids fort, nous aurons donc 1 volt toutes les 51 unités. La variable out va prendre les valeurs des trois premiers bits de portc afin d’éviter de mettre plein de ligne de code inutile je mets l’attribution du portc en une seule affectation ce qui rend aussi le code plus clair. Les bits RA4 et RA5 donnant les 4 et 5 Volt sont attribués un à un.
if (valeur>51) out=1 ;
else out=0;
if (valeur>102) out=3;
if (valeur>153) out=7;
PORTC=out;
if (valeur>204) RA4=1;
else RA4=0;
if (valeur==255) RA5=1;
else RA5=0;
La deuxième partie du code va transformer les 3 chiffres constituant la valeur de l’acquisition en trois caractères qui seront envoyé à l’ordinateur. Pour ça nous nous servirons de la propriété très simple du code ASCII qui veut qu’en ajoutant 0x30 nous obtenons le code ASCII correspondant au chiffre désiré. Vu que l’on ne sait pas comment le compilateur C va gérer la division ni les nombres flottants et que pour un processeur 8bits, travailler avec une virgule ce n’est pas vraiment l’idéal. Pour séparer les trois chiffres j’y ai donc été d’un diviseur software simple :
for (i=0;i<3;i++){
if (valeur>=100) {
dec++;
valeur-=100;}
else break;}
putchr(dec+0x30);
dec=0;
for (i=0;i<10;i++){
if (valeur>=10) {
dec++;
valeur-=10;}
else break;}
putchr(dec+0x30);
putchr(valeur+0x30);
putchr(0x0D);
putchr(0x0A);
send=0;
L’algorithme va simplement décrémenter la valeur de 100 pour compter le nombre de centaines qu’il y a dedans, puis de 10 et la valeur qui restera représentera les unités. La fonction putchr permet d’envoyer le caractère à l’ordinateur nous l'avons déjà présentée dans les articles précédent, après l’envoie des trois caractères nous envoyons un carrier return qui indiquera au programme d’interface que la transmission a été effectuée et qu’il doit lire cette ligne. En remettant send à 0 nous remettons le pic en attente d’une nouvelle valeur à envoyer.
Les interruptions :
La première source d’interruption est le timer0, comme nous l’avons vu dans l’initialisation, celui-ci déborde toutes les 50ms, or dans notre cas, il faut une conversion toutes les 100ms, nous attendrons donc deux débordements avant de relancer une nouvelle acquisition
La deuxième source d’interruption marque la fin de la conversion analogique, nous pouvons alors récupérer les 8 bits de poids fort contenu dans ADRESH (nous avons configuré dans l’initialisation de telle manière que les 8 bits de poids fort se retrouve dans le même registre). Une fois la valeur recopiée, nous envoyons un message à la boucle principale via la variable globale send pour lui indiqué qu’une nouvelle valeur est contenue dans la variable globale « valeur ».
void interrupt Isr(){
static int centmilli = 0;
if ( (T0IE & T0IF) == SET) { //If A Timer0 Interrupt, Then
TMR0 = 0x3C;
centmilli ^=1;
if (centmilli) GODONE = SET;
T0IF = 0;}
if ( (ADIE & ADIF) == SET) { //If A A/D Converter Interrupt
valeur = ADRESH;
send=1;
ADIF = 0; }
return;}
L’interface PC :
Le C# est un langage de programmation créé par Microsoft qui permet d’exploiter l’entièreté du framework DotNet. Dans notre application, le C# apporte l’avantage de présenter une interface de développement RAD (rapide application design), ce qui nous permet de créé rapidement une interface communicant avec un projet électronique. De plus C# est muni de base d’un objet pour communiquer avec le port com :
Nous pouvons d’une part configurer les différents paramètres de la configuration, et d’autre en deux trois cliques créer un événement qui va traiter l’information quand celle-ci arrivera dans le buffer d’entrée de l’ordinateur :
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string texte = serialPort1.ReadLine();
int i;
double volte, valeur;
char[] tab = texte.ToCharArray();
valeur = 0;
texte = "";
for (i = 0; i < tab.Length; i++)
{
if (CharIsNumeric(tab[i]))
{
texte += Convert.ToString(tab[i]);
}
}
if (texte != "")
{
valeur = Convert.ToInt32(texte);
volte = (5.0 * valeur / 255);
texte = Convert.ToString(volte);
texte = texte.Substring(0, texte.IndexOf(",") + 2);
SetText(texte, valeur);
}
}
Dans un premier temps on lit la ligne reçue, rappellons nous, que nous envoyons à chaque fois un CRLF qui indique une fin de ligne, ce qui est très utile dans notre cas. La chaine reçue est alors transformée en un tableau de caractere afin de pouvoir permettre sa conversion.
Pour obtenir la tension envoyé il faut traduire cette valeur en tension, pour cela : nous savons que 255 est la résolution de fond d’échelle, donc en divisant la valeur par 255 ça revient à connaître le pourcentage de fond d’échelle que la valeur reçue représente, il suffit alors de la multiplier par 5 pour avoir la valeur réel.
De son coté, le voltmètre affiche 2.73V, voilà donc un programme qui fonctionne. Vous trouverez ci-dessous le code source des programmes en téléchargement.
Attention vous aurez besoins de Visual C# express disponible gratuitement sur le site de Microsoft