25
Schmid Korbinian Meurant Olivier Projet Avancé Pilotage d'une carte par USB sous linux Sans un tux, un projet à l'ENSEIRB n'est pas complet Plan Introduction 1. La carte 1.1 Le matériel 1.2 Le logiciel 2. USB sous linux Conclusion

Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

Embed Size (px)

Citation preview

Page 1: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

Schmid KorbinianMeurant Olivier

Projet AvancéPilotage d'une carte par USB sous linux

Sans un tux,un projet à l'ENSEIRB n'est pas complet

Plan Introduction1. La carte

1.1 Le matériel1.2 Le logiciel

2. USB sous linuxConclusion

Page 2: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

Introduction

Le but de ce projet est de prouver qu'il est aisé de piloter des cartes faites maison sous linux.

Pour cela, on a fabriqué une carte à base d'un USBMOD3.

Un USBMOD3.

Un USBMOD3 embarque sur un support 32 broches tout ce qu'il faut pour faire fonctionner un FTDI232BM. Cette puce CMS permet de convertir des trames USB (1 ou 2) en une liaison série.

Ce module facilite l'intégration de la liaison USB sur les montages à base de microcontrôleur.

1. La carte

1.1 Le matériel

Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de base du projet du semestre 4. Il s'agissait d'utiliser un capteur de température numérique et un capteur de température analogique.

Notre carte comportera donc :• USBMOD3• PIC 16F877• un bouton poussoir de reset• un bouton poussoir en interruption• un afficheur lcd 2 lignes• une led qui clignotera sous l'action du pic• une led pour l'émission de trame• une led pour la réception de trame• un capteur de température analogique lm35• un capteur de température numérique ds1620

On y ajoutera bien sûr les éléments annexes nécessaires au fonctionnement des éléments principaux :

• résistances (contrôle du courant dans les leds, protection des circuits, tirage sur les boutons poussoirs)

• quartz (4MHz) pour la précision de l'horloge du pic• capacités (découplage, horloge du pic)• picots pour les points de tests électriques

On ajoutera aussi de nombreuses soudures sauvages, de dépôt d'étain sur les pistes car le perchlorure de fer était dans un drôle d'état lorque l'on a tirée la carte.

Page 3: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

Vue générale de la carte

1.2 Logiciel

Structure du logiciel

Le logiciel est basé sur celui du projet numérique S4. On utilise surtout les librairies qui ont été développées pour accéder aux périphériques de la carte (lcd, capteurs...).

En tâche principale le pic se charge de mettre à jour en continu la température courante venant du lm35 et du ds1620.

Il y a trois sources d'interruptions :• Le timer• Le bouton poussoir• La réception d'un caractère sur la ligne série

Le timer permet de faire clignoter la led, il pourrait permettre de faire fonctionner du multitâche.

Le bouton poussoir déclenche une interruption, cette partie de la routine d'interruption envoie deux caractères : "II" vers le PC.

La réception d'un caractère déclenche sa mise dans un buffer, puis on provoque une fonction de traitement.

Page 4: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

Commandes

Les commandes que comprend le pic sont classées par la première lettre, la lettre C désigne le lcd, la lettre M le lm35, et la lettre D le ds1620.

Commandes Description

CC Efface l'écran

CAc Affiche le caractère c à la position courante du curseur

CPxy Place le curseur à la ligne x et à la colonne y

MC Donne la température que le lm35 mesure

DC Donne la température que le ds1620 mesure

La compréhension de ces commandes par le pic nécessite la mise en place d'un automate.

Le diagramme d'état de notre automate

On l'implémente à l'aide d'une succession de switch imbriqués les uns dans les autres.

Les commandes sont stockés dans un buffer et une variable entière pointer pointe vers la case qui contiendra le prochain caractère émis.

Au début d'une commande pointer vaut toujours 0 puis il s'incrémente jusqu'à que la commande ait

Page 5: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

été correctement exécutée ou déclarée invalide.

La fonction de traitement renvoie un code pour déclarer son état, 0 pour une commande invalide, 1 pour un exécution correcte de la commande et 2 pour une commande encore incomplète.

Communication

On a établit un petit protocole de communication entre le pic et le pc pour fiabiliser la communication.

À chaque caractère reçu, le pic le renvoie : il fait un echo sur la ligne. Puis on envoie la valeur de pointer et si il est supérieur à 0 le code de retour de la fonction de traitement.

Grâce à cette petite astuce, on connaît l'état du pic et ainsi s'assurer qu'il fait bien ce qu'on lui demande.

Exemple :On envoie un commande CC (efface écran) au pic, et il répond :

C0C11C correspond à l'écho0 car le C est le premier caractère de la commande (place 0 dans le buffer)C écho1 car c'est la place 1 dans le buffer1 car la commande a été exécutée !

On envoie maintenant une commande CAb (affiche caractère b), le pic répond :

C0A12b21C écho0 place 0 dans le bufferA écho1 place 1 dans le buffer2 car la commande est incomplèteb écho2 place 2 dans le buffer1 commande exécutée !

2. USB pour linux

2.1. Le pilote du kernel

Un pilote en kernel-space est déjà écrit, le fichier spécial de périphérique se trouve sur /dev/ttyUSB0. On peut donc directement communiquer avec notre carte avec un logiciel comme kermit ou minicom. On peut également envisager de parler à notre carte en exécutant des echo -n commande > /dev/ttyUSB0.

Page 6: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

Exemple d'une communication avec le logiciel kermit.

On constate que notre carte fonctionne très bien. Passons maintenant au pilote en user-mode.

2.2. Pilotage en mode utilisateur

On peut accéder aux périphériques usb grâce à la librairie libusb. Il existe un projet libre qui met en place une librairie au-dessus de cette libusb : libftdi qui permet elle de dialoguer de façon transparente avec les puces de la famille ftdi.

Notre programme

libftdi

libusb

service du noyau

les 3 couches supérieures sont dans l'espaced'exécution utilisateur.

La communication avec les périphériques en mode utilisateur par rapport au mode noyau présente un certain nombre d'avantages :

• Un bout de code mal conçu dans l'espace du noyau peut mettre en péril le bon fonctionnement de la machine toute entière, alors qu'en espace utilisateur, il ne perturbera que son propre processus.

• La programmation est plus aisée en mode utilisateur, des outils classiques de déverminage (debug) sont à la disposition de l'utilisateur (gdb...) alors que le développement en mode kernel nécessite des redémarrage incessants de la machine.

Mais pour un périphérique classique, les interruptions ne sont pas visibles depuis l'espace utilisateur. Heureusement, nous travaillons en usb. On peut donc tout faire depuis le user-space à l'aide de la libftdi.

On peut installer cette librairie depuis les sources téléchargeables depuis le site du projet ou grâce aux paquets que fournit notre distribution préférée, dans ce cas-là, on n'oubliera pas d'installer également le paquet de développement -dev.

Page 7: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

Initialisation et ouverture de la communication

La bibliothèque ftdi propose une fonction :int ftdi_init(struct ftdi_context *ftdi);

Cette structure ftdi_context permet de régler les différents paramètres de la communication comme par exemple le baudrate (vitesse de transmission).

On utilise donc pour initialiser la structure qui servira à la communication :struct ftdi_context ftdic;ftdi_init(&ftdic);ftdic.baudrate = 9600;

Puis on utilise :int ftdi_usb_open(struct ftdi_context *ftdi, int vendor, int product);

Cette fonction permet d'ouvrir la connexion, elle prend en paramètre la structure ftdi_context préalablement initialisée par ftdi_init et deux numéros qui sont définis par la norme usb. Chaque fabriquant qui veut se lancer dans les périphériques usb se voit attribuer un numéro d'identification unique. Le fabricant se charge d'utiliser comme bon lui semble le deuxième numéro.

Avec ces 2 numéros on peut identifier de façon unique un équipement. On a décidé de ces deux numéros en programmant l'eeprom placée sur le module. On peut retrouver ces deux numéros en branchant le périphérique et en listant ceux présents sur le bus.

lsusb permet de retrouver notre montage

Notre montage a donc le couple Vendor : 0x0403 et Product : 0x6001. On pourrait obtenir plus d'informations sur le périphérique avec un lsusb -d :6001 -v.

Une fois la communication établit on peut utiliser la connexion à travers les fonctions :int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size);etint ftdi_write_data(struct ftdi_context *ftdi, unsigned char *buf, int size);pour communiquer avec le montage.

Utilitaire en ligne de commande

On a décidé de créer un utilitaire utilisable en ligne de commande, ce programme se chargera de la communication avec la carte.

Ce programme comprendra les options suivantes :

Page 8: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

• -c effacera l'écran lcd• -a "Chaîne de caractères" affichera cette chaîne de caractères sur l'écran lcd• -p PositionLignePositionColonne positionnera le curseur sur l'écran à la ligne

et à la colonne spécifiées• -m permet de récupérer la température du lm35• -d permet de récupérer la température du ds1620

Pour gérer les options, on utilisera la fonction getopt. Cette fonction s'utilise d'une façon un peu particulière, son prototype est le suivant :

int getopt (int argc, char * const argv[], const char * optstring);

Ses arguments correspondent aux argc et argv que la fonction main prend en argument, le troisième argument liste les options que la fonction va traiter, si l'option prend un argument on place un ":" derrière l'option, notre liste est donc : "a:p:cmd".

Cette fonction renvoie l'option qu'elle vient de reconnaître et place dans des variables globales les arguments qui correspondent à cette option.

On l'utilise dans une boucle while de cette façon :

while ((c = getopt (argc, argv, "a:p:cmd")) != -1) switch (c) { case 'a': tmp=0; while(optarg[tmp]!=0) { buffer_emission[pointer++]='C'; buffer_emission[pointer++]='A'; buffer_emission[pointer++]=optarg[tmp++]; } break; case 'p': buffer_emission[pointer++] = 'C'; buffer_emission[pointer++] = 'P'; buffer_emission[pointer++]=optarg[0]; buffer_emission[pointer++]=optarg[1]; break; case 'c': buffer_emission[pointer++] = 'C'; buffer_emission[pointer++] = 'C'; break; case 'm': pointer = 0; buffer_emission[pointer++]='M'; buffer_emission[pointer++]='C'; mc = 1; goto execution; break; case 'd': pointer = 0; buffer_emission[pointer++]='D'; buffer_emission[pointer++]='C'; dc = 1; goto execution; break; case '?':

Page 9: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

default: if (isprint (optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); else fprintf (stderr,"Unknown option character `\\x%x'.\n",optopt); return 1; }

A chaque fois que l'on trouve une option, on effectue le traitement qui correspond à cette option, par exemple pour afficher, à chaque caractère de optarg qui contient la chaîne de caractères en insèrant 'C', 'A' et le caractère dans le buffer_emission.

Une fois tous les traitements assurés, on envoie les commandes contenues dans le buffer_emission. La boucle while remplit ce buffer en fonction des options que l'on passe au programme puis ce buffer_emission sera utilisé par la suite du programme.

Conclusion

Comme tous les projets réalisés à l'ENSEIRB, on aurait souhaité passer plus de temps pour par exemple réaliser un pilote spécifique en mode noyau ou peaufiner notre utilitaire en ligne de commandes.

Mais ce projet reste une expérience positive puisque les objectifs primaires ont été atteints.

Annexes

Les annexes comprennent :• Le schéma électrique de la carte• Le logiciel du pic• le logiciel sous linux

Page 10: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

Code du logiciel installé sur le pic.

/**************************************************************projet.h***************************************************************/

#ifndef _H_PROJET#define _H_PROJET

#define TRUE 1#define FALSE 0

#define BUFFER_CMD_SIZE 5

#define INVALID_COMMAND -1#define COMMAND_EXEC_OK 0#define NOT_COMPLETE_COMMAND 1

struct temperature { unsigned char e; unsigned char d;};

struct temperature_courante { struct temperature lm35; struct temperature ds1620;};

void refresh_temperature_lm35(void);void refresh_temperature_ds1620(void);int interprete(char * buf, unsigned char pointer);

#endif/**************************************************************projet.c***************************************************************/

#include <pic.h>#include <pic1687x.h>#include <stdio.h>

#include "liblcd.h"#include "liblm35.h"#include "lib1620.h"#include "serie.h"#include "projet.h"#include "util.h"

#define task_led_counter_max 10 #define task_temp_counter_max 30 __CONFIG (FOSC0|BODEN|WRT|BKBUG);

/* Pour le multitasking */ /* Counter */ static bank1 unsigned int task_led_counter = 0; /* En IT */ static bank1 unsigned int task_temp_counter = 0; /* En PP */ static bank1 unsigned char Debug_mode=0;

/* allow tasks trigerred by interrupt to run in background main */ volatile unsigned char task_temp_go = FALSE; static bank1 struct temperature_courante temp_cour;

Page 11: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

static char pointer=0; // Pointe sur le caractere a ecrirestatic bank1 char buffer[BUFFER_CMD_SIZE];

void refresh_temperature_lm35(void) { unsigned short temp_e,temp_d; temp_e = 500 * lm35_readtemp(); /* 5 -> pleine echelle 100 facteur pour ramener 10 mv sur 1 V */ temp_d = 10*(temp_e % 1024)/1024; /* partie dimale */ temp_d = ( temp_d<5 ? 0 : 5); /* partie dimale soit 0 soit 5 a cause de la prision de 1/2 C */ temp_e /= 1024; /* 2^10=1024 : rolution */ temp_cour.lm35.e = temp_e; /* Mise jour structure */ temp_cour.lm35.d = temp_d;} void refresh_temperature_ds1620(void) { unsigned short temp_f; unsigned char temp_e,temp_d; temp_f = ds1620_readtemp(); /* Tempature - format float */ temp_e = (unsigned char) temp_f/2; /* Partie entie */ temp_d = (unsigned char) (10 * (temp_f/2 - ((short) temp_f/2))); /* partie dimale sur 1 digit */ temp_cour.ds1620.e = temp_e; /* Mise jour structure */ temp_cour.ds1620.d = temp_d;}

void main(void) { /* init pic */ pic_init(); pointer=0; task_temp_counter=task_temp_counter_max; task_led_counter = task_led_counter_max; while (1) { refresh_temperature_lm35(); /* lecture temp sur lm35 */ ds1620_start(); /* On lance la conversion du ds1620 */ Delays(1); /* On attend qu'elle finisse */ refresh_temperature_ds1620(); /* lecture temp sur ds1620 */ } } void task_switcher(void) { /* Task en IT */ task_led_counter ++; if (task_led_counter >= task_led_counter_max) { task_led_counter = 0; RB5 ^=1; } /* Task en PP */ task_temp_counter ++; if (task_temp_counter >= task_temp_counter_max) { task_temp_counter = 0; task_temp_go = TRUE; }}

int interprete(char * buffer,unsigned char pointer) { char buffer_temp[8]; if (pointer > BUFFER_CMD_SIZE-1) { return INVALID_COMMAND; } if (pointer == 1)

Page 12: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

return NOT_COMPLETE_COMMAND; if (pointer == 2) { switch(buffer[0]) { case 'M': switch(buffer[1]) { case 'C':/* sprintf(buffer_temp,"%d.%d",temp_cour.lm35.e,temp_cour.lm35.d); *//* buffer_temp[7]=0; // Au cas ou... *//* emission_str(buffer_temp); */ //dizaine emission(((unsigned char) temp_cour.lm35.e/10) + '0'); //unite emission((unsigned char) temp_cour.lm35.e - 10*((unsigned char) temp_cour.lm35.e/10) + '0'); //point emission('.'); //decimale emission(((unsigned char) temp_cour.lm35.d) + '0'); return COMMAND_EXEC_OK; default: return INVALID_COMMAND; } case 'C': switch (buffer[1]) { case 'C': lcd_clear(); return COMMAND_EXEC_OK; default: return NOT_COMPLETE_COMMAND; } case 'D': switch(buffer[1]) { case 'C': //dizaine emission(((unsigned char) temp_cour.ds1620.e/10) + '0'); //unite emission(temp_cour.ds1620.e - 10*((unsigned char) temp_cour.ds1620.e/10) + '0'); //point emission('.'); //decimale emission(((unsigned char) temp_cour.ds1620.d) + '0'); return COMMAND_EXEC_OK; default: return INVALID_COMMAND; } default: return INVALID_COMMAND; } }

if (pointer == 3) { switch (buffer[0]) { case 'C': switch(buffer[1]) { case 'A': lcd_putch(buffer[2]); return COMMAND_EXEC_OK; default: return NOT_COMPLETE_COMMAND; } default: return INVALID_COMMAND; }

Page 13: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

}

if (pointer==4) { switch (buffer[0]) { case 'C': switch(buffer[1]) { case 'P': lcd_pos(buffer[2]-'0',buffer[3]-'0'); return COMMAND_EXEC_OK; default: return INVALID_COMMAND; } default: return INVALID_COMMAND; } } return INVALID_COMMAND;} void it_bp(){ /*IT BP*/ tempo(0xFFFF); INTF = 0; emission('I'); emission('I');/* Debug_mode=(Debug_mode==0?1:0); *//* if (Debug_mode==1) { *//* lcd_puts("Mode Debug"); *//* } else { *//* lcd_puts("Mode normal"); *//* } */}

void it_reception(){ char car; int ret; /* IT Reception */ // Clear IT in the reception function if (reception(&car)==0) { //reemet le caractere recu emission(car); //Valeur du pointeur emission(pointer+'0'); //caractere de reset if (car=='&') pointer=0; buffer[pointer]=car; pointer ++; if (pointer!=1) { ret=interprete(buffer,pointer); //emission caractere de retour emission(ret+'1'); } else { ret=NOT_COMPLETE_COMMAND; } if (ret == COMMAND_EXEC_OK) pointer=0; if (ret == INVALID_COMMAND) pointer = 0; }}

Page 14: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

void interrupt cricri (void) { if (T0IF == 1) { /* IT Timer*/ task_switcher(); T0IF = 0; } else if (INTF == 1) { it_bp(); } else if (RCIF==1) { it_reception(); }}

/**************************************************************lib1620.h***************************************************************/

#ifndef _H_DS1620#define _H_DS1620

#define PORTA_IN TRISA=0b00100001 /* PortA en sortie sauf RA0 pour AN0 */#define PORTA_OUT TRISA=0b00000001 /* PortA en sortie sauf RA0 pour AN0 et RA5 pour DS_DQ */#define DS_RST RA1#define DS_CLK RA2#define DS_DQ RA3#define DS_RCONFIG 0xAC#define DS_REGISTER_CONFIG 0b00001011 /*CPU = 1 et 1SHOT = 1 */#define DS_WCONFIG 0x0C#define DS_STARTCONV 0xEE#define DS_READTEMP 0xAA#define DS_READCOUNTER 0xA0#define DS_READSLOPE 0xA9#define NOP asm("nop")

void ds1620_init(void);void ds1620_start(void);unsigned short ds1620_readtemp(void);unsigned char ds1620_read8(void);unsigned short ds1620_read9(void);void ds1620_write8(unsigned char data);void ds1620_write9(unsigned short data);

#endif/**************************************************************lib1620.c***************************************************************/

#include "lib1620.h"#include <pic.h>

unsigned char power2(unsigned char i){ unsigned char j,temp=1; for ( j=0; j < i ;j++) temp *= 2; return temp;}

void nop100 (void){ unsigned char i;

Page 15: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

for (i=0;i<200;i++) NOP;}

// Initialisation generale du DS1620void ds1620_init(void){ DS_RST = 1; ds1620_write8(DS_WCONFIG); /* Write config */ ds1620_write8(DS_REGISTER_CONFIG); /*CPU = 1 et 1SHOT = 1 */ DS_RST = 0; /* Reset inactif */ DS_CLK = 1; /* clk a 1 par daut */ PORTA_IN;}

// Lancement de la mesure du DS1620void ds1620_start(void){ DS_RST = 1; ds1620_write8(DS_STARTCONV); /* Start Convert */ DS_RST = 0;

}

// Lecture de la temperature du DS1620 sur 9 bitsunsigned short ds1620_readtemp(void){ float temp; unsigned short temp_read,count_per_c,count_remain;

DS_RST = 1; ds1620_write8(DS_READTEMP); /*Read temp */ temp_read = ds1620_read9(); DS_RST = 0;

DS_RST = 1; ds1620_write8(DS_READCOUNTER); /*Read counter */ count_remain = ds1620_read9(); DS_RST = 0;

DS_RST = 1; ds1620_write8(DS_READSLOPE); /*Read slope */ count_per_c = ds1620_read9(); DS_RST = 0;

temp = count_per_c - count_remain; temp /= count_per_c; temp += temp_read - 0.25; temp=temp_read;

return temp_read;}

// Lecture 8 bits DS1620unsigned char ds1620_read8(void){ unsigned char temp=0; unsigned char i; PORTA_IN; for (i = 0; i<8;i++) { DS_CLK = 0;

Page 16: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

nop100(); temp += power2(i)*DS_DQ; /* on dale sur la droite au fur et a mesure */ DS_CLK = 1; nop100(); } return temp;}

// Lecture 9 bits DS1620unsigned short ds1620_read9(void){ unsigned short temp=0; unsigned char i; PORTA_IN; for (i = 0; i<9;i++) { DS_CLK = 0; nop100(); temp += power2(i)*DS_DQ; /* on dale sur la droite au fur et a mesure */ DS_CLK = 1; nop100(); } return temp;}

// Ecriture 8 bits DS1620void ds1620_write8(unsigned char data){ unsigned char temp=data; unsigned char i; PORTA_OUT; for (i = 0; i<8;i++) { DS_CLK = 0; nop100(); DS_DQ=(temp % 2); temp >>= 1; /* on dale sur la droite au fur et a mesure */ DS_CLK = 1; nop100(); }}

// Ecriture 9 bits DS1620void ds1620_write9(unsigned short data){ unsigned short temp=data; unsigned char i; PORTA_OUT; for (i = 0; i<9;i++) { DS_CLK = 0; nop100(); DS_DQ=(temp % 2); temp /= 2; /* on dale sur la droite au fur et a mesure */ DS_CLK = 1; nop100(); }}/**************************************************************liblcd.h***************************************************************/

Page 17: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

#ifndef _H_LCD#define _H_LCD

#define XTAL_FREQ 4#define LCD_RS RB1#define LCD_RW RB2#define LCD_EN RB4#define PORT_DATA PORTD#define PORTD_IN 0b11111111#define PORTD_OUT 0b00000000#define flag_busy RD7#define LCD_STROBE LCD_EN=1;NOP;NOP;LCD_EN=0#define LCD_FUNCTIONSET 0b00111000 /* mode 8 bits - 2 lignes - 5*7 */#define LCD_DISPLAYON 0b00001100 /* Power on - cursor off - blink off */#define LCD_CLEARDISPLAY 0b00000001 /* lcd clear */#define LCD_ENTRYMODESET 0b00000110 /* increment mode - shift off */ #define LCD_SETDDRAMADRESS 0x80 /* Set DDRAM Adress */#define LCD_PREMIERELIGNE 0x00 /* adresse dut seconde ligne */#define LCD_SECONDELIGNE 0x40 /* adresse dut seconde ligne */#define LCD_RETURNHOME 0b00000010#define NOP asm("nop")

void DelayMs (unsigned int cnt);void Delays (unsigned char cnt);void Delay250Us(void);void init_lcd(void);void lcd_busy(void);void lcd_write(unsigned char c);void lcd_write_instr(unsigned char c);void lcd_putch(unsigned char c);void lcd_puts(const unsigned char * s);void lcd_pos(unsigned char ligne,unsigned char pos);void lcd_clear(void);void lcd_home(void);

#endif/**************************************************************liblcd.c***************************************************************/

#include "liblcd.h"#include <pic.h>

void Delays (unsigned char cnt){ DelayMs(1000*cnt);}

void Delay250Us(void){ TMR1L = 6; TMR1H = 0; TMR1ON = 1; while(TMR1H < 1);/* pour 250 us */ TMR1ON = 0;}

void DelayMs (unsigned int cnt){ unsigned int i; for (i=0;i < cnt;i++) { Delay250Us();

Page 18: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

Delay250Us(); Delay250Us(); Delay250Us(); }

}

/* Special pour la fonction init -- multiple call graphs */void lcd_busy_pp(void){ char temp=1; TRISD = PORTD_IN; LCD_RS = 0; LCD_RW = 1 ; while (temp) { LCD_EN=1; temp = (char) flag_busy; LCD_EN=0; }

TRISD = PORTD_OUT;}

/* Special pour la fonction init -- multiple call graphs */void lcd_write_instr_pp(unsigned char c){ LCD_RS = 0; LCD_RW = 0; PORT_DATA = c; LCD_STROBE; lcd_busy_pp();}

/* Initialisation generale du lcd en 8bits */void init_lcd(void){

/*Init timer 1 */ T1CON = 0b00000100; /* prescaler 1 postscaler 1 Timer arrete */

/*Init lcd */ TRISD = PORTD_OUT; LCD_EN = 0; /* condition initiale */

DelayMs(60);

lcd_write_instr_pp(LCD_FUNCTIONSET); /* mode 8 bits - 2 lignes - 5*7 */

lcd_write_instr_pp(LCD_DISPLAYON); /* Power on - cursor off - blink off */

lcd_write_instr_pp(LCD_CLEARDISPLAY); /* lcd clear */ lcd_write_instr_pp(LCD_ENTRYMODESET); /* increment mode - shift off */ }

void lcd_busy(void){ char temp=1; TRISD = PORTD_IN;

Page 19: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

LCD_RS = 0; LCD_RW = 1 ; while (temp) { LCD_EN=1; temp = (char) flag_busy; LCD_EN=0; }

TRISD = PORTD_OUT;}

void lcd_write(unsigned char c){ LCD_RS = 1; LCD_RW = 0; PORT_DATA = c; LCD_STROBE; lcd_busy();}

void lcd_write_instr(unsigned char c){ LCD_RS = 0; LCD_RW = 0; PORT_DATA = c; LCD_STROBE; lcd_busy();}

void lcd_putch(unsigned char c){ lcd_write(c);}

void lcd_puts(const unsigned char * s){ while (*s != 0) { lcd_putch(*s); s++; }}

void lcd_pos(unsigned char ligne,unsigned char pos){ /* ligne =1 .. 2 et pos = 1 .. 16*/ unsigned char adr=0; if (ligne ==1) adr += LCD_PREMIERELIGNE + pos-1; else adr += LCD_SECONDELIGNE + pos - 1; lcd_write_instr(LCD_SETDDRAMADRESS | adr);}

void lcd_clear(void){ lcd_write_instr(LCD_CLEARDISPLAY ); /* lcd clear */}

void lcd_home(void){ lcd_write_instr(LCD_RETURNHOME); /* lcd home */}

Page 20: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

/**************************************************************liblm35.h***************************************************************/

#ifndef _H_LM35#define _H_LM35

void lm35_init(void);unsigned short lm35_readtemp(void);

#endif/**************************************************************liblm35.c***************************************************************/

#include "liblm35.h"#include <pic.h>

void lm35_init(void){

ADCON0 = 0b00000001; /* Fclock/2 - channel 0 pour RA0 - AD ON */

ADCON1 = 0b10001110; /* Right justified - RA0 Analog input A, RAX digital input */

}

unsigned short lm35_readtemp(void){ ADGO = 1; /* lance conversion */ while (ADGO); /* attend la fin de la conversion */ return ADRESL + 256*ADRESH;}/**************************************************************serie.h***************************************************************/

#ifndef _H_SERIE#define _H_SERIE

#define SERIE_RX RC7#define SERIE_TX RC6

void init_port_serie();char emission(unsigned char n);char reception(unsigned char * n);char emission_str(char * s);

#endif/**************************************************************serie.c***************************************************************/

#include "serie.h"#include <pic.h>

void init_port_serie () {

// TRISC 1 : input 0 : output // RC7 : Input : 1 TRISC = TRISC | 0x80;

Page 21: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

// RC6 : Output : 0 TRISC = TRISC & 0xBF;

//TXSTA //8 bits transmission TX9 = 0; // Asynchronous mode SYNC = 0; // High Speed BRGH = 1;

//RCSTA //8 bits transmission RX9 = 0;

//SPBRG Baud rate 9600 -> 0.16% error -> SPBRG = 25 - page 98 de la doc table 10.4 SPBRG=25;

//Validation // Set Bit SPEN SPEN = 1; // Set Bit TXEN TXEN = 0; //Enable continuous receive CREN = 1;

//Interruption RCIE = 1; // Reception PEIE = 1; // Global - Serie UART}

char emission(unsigned char n) { // Retourne -1 si la transmission n'est pas prete, 0 si ca s'est bien pass TXEN = 1; while (TRMT == 0); TXREG = n; while (TRMT == 0); TXEN = 0; return 0;}

char reception(unsigned char * n) { //retourne -1 si la reception s'est mal passe // retourne 0 si ok, et place le caractere dans *n if ( (FERR==1) || (OERR==1) ) { // Erreur de reception //Clear Error CREN = 0; CREN = 1; return -1; } //lit et clear interruption *n = RCREG; return 0;}

char emission_str(char * s) { while (*s != 0) { emission(*s); s++; } return 0;

Page 22: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

}/**************************************************************util.h***************************************************************/

#ifndef _H_UTIL#define _H_UTIL

void tempo(unsigned int i);void pic_init (void);void return_temp(char * buf,unsigned char part_e, unsigned char part_d);

#endif/**************************************************************util.c***************************************************************/

#include <pic.h>#include <stdio.h>#include "util.h"#include "liblcd.h"#include "liblm35.h"#include "lib1620.h"#include "serie.h"

void return_temp(char * buf,unsigned char part_e, unsigned char part_d) { sprintf(buf,"%d.%d",part_e,part_d); }

void pic_init (void) { GIE = 0; /* Dalide IT globale */ /* Direction Port B */ TRISB = 0x01; /* bit 0 du port B en entree -> BP */ /* Timer 0 */ T0CS=0; /*mode timer*/ PSA=0; /*prescaler au timer*/ PS0=1; PS1=1; /*prescaler a 256 */ PS2=1; T0IE = 1; /*Valide IT*/ T0IF = 0; /*Remise 0 IT Timer*/ /* IT BP RB0 */ INTEDG = 0; /*Front descendant */ INTE = 1; /* Validation IT BP */ INTF = 0; /* Remise a 0 IT BP*/ /* Init piphiques */ RB5=1; init_lcd(); /* init lcd */ RB5 = 0; /*Initialisation led - important*/ ds1620_init(); /* init ds1620 */ DelayMs(50); /* Attente fin init */ lm35_init(); /* init lm35 */ init_port_serie();

/* On lance les IT = fin init */ GIE = 1; /* Valide IT globale */ }

Page 23: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

void tempo(unsigned int i) { /* pour l'anti rebond du poussoir */ while(i!=0) i--; }

Page 24: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

/*Utilitaire ligne de commande sous linuxA compiler avec :gcc -Wall -o meuh meuh.c -lusb -lftdi*/

#include <stdio.h>#include <unistd.h>#include <usb.h>#include <ftdi.h>#include <sys/select.h>#include <sys/time.h>#include <sys/types.h>#include <unistd.h>#include <unistd.h>#include <stdio.h>#include <string.h>#include <ctype.h>

#define BUFFERSIZE 1024

int main(int argc, char **argv){ struct ftdi_context ftdic; int f,i; struct timeval attente; int c; unsigned char buffer_emission[BUFFERSIZE]; unsigned char buffer_reception[32]; unsigned int pointer=0,tmp=0; unsigned char dc = 0, mc = 0; int pointer_reception = 0;

memset(buffer_emission,0,(size_t)BUFFERSIZE);

opterr = 0; /* a : affiche - string p : position - 2 entiers c : clear m : lm35 d : dallas1620 */

while ((c = getopt (argc, argv, "a:p:cmd")) != -1) switch (c) { case 'a': tmp=0; while(optarg[tmp]!=0) { buffer_emission[pointer++]='C'; buffer_emission[pointer++]='A'; buffer_emission[pointer++]=optarg[tmp++]; } break; case 'p': buffer_emission[pointer++] = 'C'; buffer_emission[pointer++] = 'P'; buffer_emission[pointer++]=optarg[0]; buffer_emission[pointer++]=optarg[1]; break; case 'c':

Page 25: Projet Avancé Pilotage d'une carte par USB sous linux · Pour cette carte, on utilise donc un USBMOD3 et un PIC modèle 16F877. On reprend le design de ... le pic le renvoie : il

buffer_emission[pointer++] = 'C'; buffer_emission[pointer++] = 'C'; break; case 'm': pointer = 0; buffer_emission[pointer++]='M'; buffer_emission[pointer++]='C'; mc = 1; goto execution; break; case 'd': pointer = 0; buffer_emission[pointer++]='D'; buffer_emission[pointer++]='C'; dc = 1; goto execution; break; case '?': default: if (isprint (optopt)) fprintf (stderr, "Unknown option `-%c'.\n", optopt); else fprintf (stderr,"Unknown option character `\\x%x'.\n",optopt); return 1; } execution:

ftdi_init(&ftdic); ftdic.baudrate = 9600;

f = ftdi_usb_open(&ftdic, 0x0403, 0x6001);

if(f < 0) { fprintf(stderr, "unable to open ftdi device: %d\n",f); exit(EXIT_FAILURE); }

for (i=0;i<pointer;i++) { while(ftdi_write_data(&ftdic, &buffer_emission[i],1)==0); attente.tv_sec=0; attente.tv_usec=1000; select(0,NULL,NULL,NULL,&attente); }

if ((mc == 1) || (dc == 1)) { f = ftdi_read_data(&ftdic, buffer_reception, 32); buffer_reception[f]=0; fprintf(stdout,"%s\n",buffer_reception); //Affichage température }

ftdi_usb_close(&ftdic); ftdi_deinit(&ftdic); return(EXIT_SUCCESS);}