-
-
//Déclaration du microcontroleur + des fichiers utilisé
-
#include <p30f2010.h>
-
#include <uart.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
-
-
//Déclaration des différents registres
-
_FOSC(CSW_FSCM_OFF & XT_PLL16); //XT with 16xPLL oscillator, Failsafe clock off
-
_FWDT(WDT_OFF); //Turn off the Watch-Dog Timer.
-
_FBORPOR(MCLR_EN & PWRT_OFF); //Enable MCLR reset pin and turn off the
-
//power-up timers.
-
_FGS(CODE_PROT_OFF); //Disable Code Protection
Maintenant que cela est fait, on peut commencer le code. Comme pour le C classique, il faut crée une procédure principale « main », et d’autres procédures et fonctions.
Commençons tout d’abord, par la déclaration des variables globale du programme.
-
//Déclaration des varaibles
-
char buffer[16]; // Tableau de 16 éléments
-
unsigned int temp0; // Valeur de 0 à 32767
-
unsigned char temp1; // Valeur de 0 à 255
-
signed char temp2; // Valeur de -128 à +128
-
-
//Déclaration des constantes
-
#define FCY 32000000 //Vitesse en MIPS
-
#define BAUDRATE 19200 //Vitesse du com serie
-
-
Voici une procédure pour perdre du temps. La fonction Delay existe aussi dans C30. Il faut pour cela charger le fichier delay.h au début du programme.
-
//----------------------------------------------------------------------------
-
// DELAY: Fonction pour perdre du temps
-
//----------------------------------------------------------------------------
-
void DelayCY(unsigned char j)
-
{
-
while(j--) { }
-
}
-
Voici la procédure d’initialisation des ports du PIC. Le registre TRIS configure les ports en entrée ou en sortie. 0 = Output et 1 = Input.
Note: que le TRISC est un registre 16bits. (Voir datasheet)
Dans la deuxième partie, vous avez la configuration du convertisseur analogique numérique. Les pattes RA0 RA1 RA2 RA3 sont configurées en analogique. Les autres sont non configurés, et comme le port A et B partage les mêmes pattes, elles sont donc configurées en numérique, par TRISB.
Un grand nombre d’option sont disponible pour le CAN. Par exemple, il est ici configuré en 10bits. Mais il peut aussi fonctionner en 12 bits.
-
//----------------------------------------------------------------------------
-
// INITIALISATION DU PIC
-
//----------------------------------------------------------------------------
-
void inipic(void)
-
{
-
OSCCON = 0b0011001101000000; //Config Oscillateur
-
TRISB = 0b11111111; //Configuration du portB en INPUT
-
TRISC = 0b101111111111111; //Configuration du port C en INPUT
-
//avec un output pour le port com
-
TRISD = 0; //met le portD et E en output
-
TRISE = 0;
-
-
// Initialisation CAN
-
ADPCFG = 0xFFF0; // Tout PORTB = Numérique; RA0 1 2 3 = Analogique
-
ADCON1 = 0x0000; // SAMP bit = 0 Pour démarrer/Arreter la conversion
-
-
ADCHS = 0x0000; // Pour se connecter à la bonne entrée analogique (ici A0)
-
ADCSSL = 0; // Skip ANx for input scan
-
ADCON3 = 0x0002; // Manual Sample, Tad = internal 2 Tcy: temps de messure
-
ADCON2 = 0;
-
ADCON1bits.ADON = 1; // turn ADC ON
-
}
Voici la configuration du PWM. Ce code va faire générer au pic, un signal créneau, a rapport cyclique variable.
Pour le faire varier, il faut simplement modifier les registres ci-dessous. Notez que le PWM3 est configuré et que c’est la patte H (high) qui va émettre le signal. Il suffit de mettre des 1 sur les registres se terminant par 3L. Le signal PWM sera identique. Mais il est possible de configurer ces registre pour que les signaux 3L et 3H soit complémentaire l’un de l’autre.
Le PWM fonctionne ici en Freemode. C'est-à-dire qu’il ne consomme pas de temps processeur pour fonctionner.
-
//----------------------------------------------------------------------------
-
// INIT PWM: PWM EN FREEMODE
-
//----------------------------------------------------------------------------
-
-
void init_pwm(void)
-
{
-
//Config PWM
-
PTCONbits.PTEN =1;
-
PTCONbits.PTSIDL =0;
-
-
PTCONbits.PTOPS =0b1111; //Postcaler 1:16 (sert a rien en freemode)
-
PTCONbits.PTCKPS =0b00; //Prescaler 1:1
-
PTCONbits.PTMOD =0b00; //Free mode runing
-
-
PTMRbits.PTDIR = 0; //Counting up
-
PTMRbits.PTMR = 5000; //Time base Count Value
-
PTPER = 300; //Time base Periode value
-
PDC3 = 350; //Duty Cycle Rapport cyclique sur PWM3
-
-
//Config PWM3 sur Port E5 (PWM3L)
-
PWMCON1bits.PEN3L =0 ;
-
PWMCON1bits.PEN3H =1 ;
-
PWMCON1bits.PMOD3 =1 ;
-
-
OVDCONbits.POVD3H =1;
-
OVDCONbits.POVD3L =0;
-
}
Pour la configuration du port série, il n’y a rien à comprendre. La seule chose importante, c’est de ne pas se tromprer lorsque l’on indique la vitesse de transfert. La valeur de baudvalue est calculée automatiquement en fonction des constantes définies en début de programme.
Note: Fcy est divisé par 16 car nous avons une PLL à 16. Ce qui importe pour UART, c’est la vitesse du quartz et non celle du PIC.
-
//----------------------------------------------------------------------------
-
// INIT PORT SERIE
-
//----------------------------------------------------------------------------
-
void init_serie(void)
-
{
-
unsigned int baudvalue;
-
unsigned int U1MODEvalue;
-
unsigned int U1STAvalue;
-
-
ConfigIntUART1(UART_RX_INT_DIS & UART_TX_INT_DIS );
-
U1MODEvalue = UART_EN & UART_IDLE_CON & UART_ALTRX_ALTTX &
-
UART_DIS_WAKE & UART_DIS_LOOPBACK &
-
UART_DIS_ABAUD & UART_NO_PAR_8BIT &
-
UART_1STOPBIT;
-
U1STAvalue = UART_INT_TX_BUF_EMPTY &
-
UART_TX_PIN_NORMAL &
-
UART_TX_ENABLE & UART_INT_RX_CHAR &
-
UART_ADR_DETECT_EN &
-
UART_RX_OVERRUN_CLEAR;
-
baudvalue = ((FCY/16)/BAUDRATE) - 1;
-
OpenUART1(U1MODEvalue, U1STAvalue, baudvalue);
-
}
-
Maintenant que le port série est configuré, il ne reste plus qu’à recevoir des données et à envoyer la réponse appropriée.
Le code ici est très simple. On regarde si l’on a un « b » dans le buffer de réception et si tel est le cas, on envoie le contenu du tableau «*data ». Nous verrons dans la procédure main, comment remplir correctement ce tableau.
-
//----------------------------------------------------------------------------
-
// COM SERIE
-
//----------------------------------------------------------------------------
-
void USART_com(char *data) // Envoi d'une chaine de caractere sur serie
-
{
-
char test;
-
-
//Receptione
-
test = 0;
-
IFS0bits.U1RXIF = 0;
-
while( DataRdyUART1())
-
{
-
test = ReadUART1(); //copie le buffer dans test
-
}
-
-
//Envoie les données
-
if (test == 98) //si on apuis sur la touche "b"
-
{
-
// Change la couleur de la diode
-
if (PORTDbits.RD1 == 0) {PORTDbits.RD1 = 1;}
-
else {PORTDbits.RD1 = 0;}
-
-
//Envoie
-
do
-
{
-
while (BusyUART1());
-
putcUART1(*data);
-
}
-
while (*data++);
-
}
-
Voici la fonction d’acquisition de valeur analogique. Le portA mesure la tension sur la patte indiqué, puis renvoie une valeur correspondante. Si il renvoi 0, alors la tension est nulle et si il renvoie 1024, alors la tension est de 5V.
Note: Il est possible de fournir au pic des tensions de références autres que 0 et 5 afin de faire une conversion plus précise. Par exemple, cela peut être utilisé si la valeur maximale renvoyée par un capteur, ne peut excéder 3.3V.
La variable Chx contient le numéro de la patte analogique à mesurer. Exemple : si Chx = 2 alors on mesure sur la patte AN2.
Grâce au registre ADCBUF, il est possible de lire les 16 dernières valeurs acquises. C’est en quelque sorte une mémoire tampon. Mais surtout, il est possible de lancer un multiple Sampling. C'est-à-dire, le PIC va prendre par exemple 16 mesures de suite, faire la moyenne, et renvoyer une seule valeur.
-
//----------------------------------------------------------------------------
-
// FONCTIONS D ACQUISITION: Renvoie une valeur sur 10bits
-
//----------------------------------------------------------------------------
-
unsigned int LectureCH (unsigned int Chx)
-
{
-
ADCHS = Chx; // Selectione la bonne entrée
-
ADCON1bits.SAMP = 1; // start sampling ...
-
DelayCY(20); // Attend un peu
-
ADCON1bits.SAMP = 0; // start Converting
-
while (!ADCON1bits.DONE); // conversion done?
-
{ }
-
return ADCBUF0; //on revoie la VALEUR
-
}
Maintenant que nous avons déclaré quelques procédures, nous allons les utiliser.
Dans le code suivant, nous allons tout d’abord initialiser le PIC, puis nous exécuterons en boucle le même code.
Ce code va tout d’abord, faire 4 CAN sur les pattes RA0-3, puis faire la somme. Si cette valeur est inférieure à 512, alors il va faire clignoter la diode de la patte RD0.
Ensuite, nous allons utiliser la procédure de communication par port série.
Dans le tableau de caractère ASCII « buffer » nous allons copier le chiffre 56 (En ASCII) puis nous allons indiquer le caractère terminal « \0 ». Une fois que buffer est rempli, on lance la procédure de com.
Elle va vérifier si le caractère « b » est présent dans le buffer d’arriver, et si tel est le cas, il enverra en réponse le chiffre 56. Il est possible de tester cela grâce à hyper terminal. Notez que la vitesse est ici de 19600. Il est possible de monter jusqu'à 1Mbps, en utilisant un module USB mais surtout en vérifiant dans la datasheet que la vitesse du quartz est compatible avec la vitesse de communication que l’on souhaite.
-
//----------------------------------------------------------------------------
-
// MAIN
-
//----------------------------------------------------------------------------
-
int main(void)
-
{
-
//Declaration des variables locales
-
char capteur[5];
-
unsigned int i;
-
-
//Initialisation
-
inipic();
-
init_serie();
-
init_pwm();
-
-
-
//Code principal
-
while (1)
-
{
-
//Lecture des 4 pattes analogiques et passage de 10bits à 8bits
-
capteur[1] = LectureCH(0x0000)/4; //AN0
-
capteur[2] = LectureCH(0x0001)/4; //AN1
-
capteur[3] = LectureCH(0x0002)/4; //AN2
-
capteur[4] = LectureCH(0x0003)/4; //AN3
-
-
temp0 = capteur[1] + capteur[2] + capteur[3] + capteur[4];
-
if (temp0 < 512)
-
{
-
// Change la couleur de la diode
-
if (PORTDbits.RD1 == 0) {PORTDbits.RD0 = 1;}
-
else {PORTDbits.RD0 = 0;}
-
}
-
-
//Comunication serie
-
buffer[0] = 5+0x30; //Rempli le buffer avec 56
-
buffer[1] = 6+0x30;
-
buffer[2] = '\0';
-
-
USART_com(buffer);
-
-
//Attend un peu
-
for (i=0;i< 20000 ;i++)
-
{
-
DelayCY(255);
-
}
-
}
-
}
Pour toutes questions: benjamin.baque AT polymtl.ca