Bico64/Exemples de programmes
Ci-dessous, quelques exemples de programmes qui vont en se complexifiant. Pour faciliter, vous pouvez copier le programme et le coller dans ConTEXT.
Bien que les programmes soient de plus en plus compliqués, pour un débutant débutant, il est peut être plus simple de copier le 2e programme et de ne modifier que la procédure loop()
Affichage d'une image fixe (AfficheImageFixe.c)
[modifier | modifier le wikicode]Comme premier petit programme voici de quoi afficher une image fixe.
À ce stade, vous aurez forcément plein de questions sur la syntaxe du C. Le mieux est de se référer à un des nombreux cours se trouvant sur le net
//------------------------------------------------------------------------------------------
// Programme de démonstration qui affiche une image sur le Bico64
//------------------------------------------------------------------------------------------
#define __16F887
#include <pic16f887.h>
//------------------------------------------------------------------------------------------
// Configuration du PIC 16F884 selon Bico64
//------------------------------------------------------------------------------------------
__code __at _CONFIG1 unsigned int Config1 =
_INTOSCIO // I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN
& _WDT_OFF // pas de Watch Dog
& _PWRTE_ON // on attend un peu au démarrage
& _MCLRE_ON // RE3/MCLR pin function is MCLR
& _CP_OFF // Program memory code protection is disabled
& _CPD_OFF // Data memory code protection is disabled
& _BOR_OFF // BOR Disabled
& _IESO_OFF // Internal/External Switchover mode is disabled
& _FCMEN_OFF // Fail-Safe Clock Monitor is disabled
& _LVP_OFF // RB3 pin is digital I/O, HV on MCLR must be used for programming
& _DEBUG_OFF;// In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins
__code __at _CONFIG2 unsigned int Config2 =
_WRT_OFF // No prog memmory write protection
& _BOR21V; // Brown-Out Reset at 2.1V
typedef unsigned char byte;
// on donne des noms significatifs aux PORTs utilisés
#define PLIGNE PORTB
#define PVERT PORTC
#define PROUGE PORTD
//----------------------------------------------------------------------------------------
void Setup(void) {
// Initialisation
TRISB = 0x00; // PortB est en sortie
TRISC = 0x00; // PortC est en sortie
TRISD = 0x00; // PortD est en sortie
TRISA = 0xFF; // PortA est en entrée
}
byte image[16] = {
// Vert Rouge PLIGNE
0b11111111,0b00000000, // D0
0b11111110,0b00000000, // D1
0b11111100,0b00000000, // D2
0b11111000,0b00000000, // D3
0b11110000,0b00000001, // D4
0b11100000,0b00000011, // D5
0b11000000,0b00000111, // D6
0b10000000,0b00001111, // D7
};
void EffacerImage(void) {
// efface l’ensemble de l'image
short i;
for (i=0;i<16;i++){
image[i] = 0;
}
}
//----------------------------------------------------------------------------------------
void AfficherImage(byte temps) {
// affiche l'image
// le paramètre temps permet de régler le temps que va prendre cette procedure
// en répétant n fois l'affichage. C'est un moyen primaire de faire aller
// plus ou moins vite l’affichage dans les procédure qui appelle AfficherImage.
// temps =1 ==> env 5ms pour afficher
// L'image affichée se trouve dans le tableau mémoire "image"
int i,n;
byte ligne;
byte *p; //p pointe sur le premier byte du tableau image
for (n=0;n<temps;n++){
p = &image[0];
ligne = 0b11111110; // dans Ligne, on aura la ligne active à 0; on décalera le 0 pour chaque ligne
while (ligne != 0b11111111){ // tant qu’il reste un 0, on n'a pas terminé de balayer l'image
PLIGNE = 0b11111111; // pour éviter de voir des petits "phantomes" de la ligne précédente
// on ne sélectionne aucune ligne
PVERT = *p++; // on met les bits pour la couleur Rouge
PROUGE = *p++; // on met les bits pour la couleur Verte
PLIGNE = ligne; // on met la ligne (le bon bit à 0)
ligne = (ligne << 1) +1 ; // on décale le bit à 0 de un bit, comme cela met D0 à 0, on
// force D0 à 1 pour n'avoir qu'un bit à 0 (ligne active)
for (i=0;i<50;i++) {}; // on attend un peu pour avoir le temps de voir cette ligne
}
}
}
//-------------------------------------------------------------
// La boucle: on ne fait qu'afficher l'image
//-------------------------------------------------------------
void Loop(void) {
AfficherImage(1);
image[0]++; // on modifie l'image pour voir à quelle vitesse va l'affichage
}
//-------------------------------------------------------------
// Programme principal (là où le PIC va démarrer)
//-------------------------------------------------------------
void main(void) {
Setup();
while(1) {
Loop();
}
}
Quelques explications:
- la configuration du PIC: dans un premier temps inutile de comprendre: c’est comme cela qu’il faut le configurer pour le Bico64. Par contre pour les curieux (ou ceux qui veulent faire autre chose que le Bico64, on trouve les registres de config au § 14.1 et 14.2 du databook[1]. Cette section est indispensable, sans quoi le PIC sera configuré n’importe comment et risque de ne pas démarrer ou faire n’importe quoi.
- Un programme c démarre toujours dans la procédure main: Celle-ci ne fait pas grand-chose: elle appelle une fois Setup() puis elle appelle toujours la procédure Loop()
- Setup configure les Ports du PIC pour lui dire ce qui est des entrées et ce qui est des sorties (un bit à 0 dans TRISx = sortie).
- Loop ne fait que d'appeler AfficherImage qui fait le travail de scanner le tableau Image et de le mettre sur les leds
Affichage d'images variables
[modifier | modifier le wikicode]Le programme suivant permet de mettre plusieurs images et possède quelques effets comme des spirales. Ceci permet d’avoir un programme principal plus ludique puisqu'on peut enchainer plusieurs figures.
//------------------------------------------------------------------------------------------
// Programme de démonstration qui affiche une image sur le Bico64
//------------------------------------------------------------------------------------------
#define __16F887
#include <pic16f887.h>
//------------------------------------------------------------------------------------------
// Configuration du PIC 16F884 selon Bico64
//------------------------------------------------------------------------------------------
__code __at _CONFIG1 unsigned int Config1 =
_INTOSCIO // I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN
& _WDT_OFF // pas de Watch Dog
& _PWRTE_ON // on attend un peu au démarrage
& _MCLRE_ON // RE3/MCLR pin function is MCLR
& _CP_OFF // Program memory code protection is disabled
& _CPD_OFF // Data memory code protection is disabled
& _BOR_OFF // BOR Disabled
& _IESO_OFF // Internal/External Switchover mode is disabled
& _FCMEN_OFF // Fail-Safe Clock Monitor is disabled
& _LVP_OFF // RB3 pin is digital I/O, HV on MCLR must be used for programming
& _DEBUG_OFF;// In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins
__code __at _CONFIG2 unsigned int Config2 =
_WRT_OFF // No prog memmory write protection
& _BOR21V; // Brown-Out Reset at 2.1V
//-------------------------------------------------------------
// Initialisation
//-------------------------------------------------------------
// on donne des noms significatifs aux PORTs utilisés
#define byte unsigned char
#define PLIGNE PORTB
#define PVERT PORTC
#define PROUGE PORTD
void Setup(void) {
TRISB = 0x00; // PortB est en sortie
TRISC = 0x00; // PortC est en sortie
TRISD = 0x00; // PortD est en sortie
TRISA = 0xFF; // PortA est en entrée
}
byte image[16];
__code byte coeur[16] = {
// Vert Rouge PLIGNE
0b11111111,0b00000000, // D0
0b10011001,0b01100110, // D1
0b00000000,0b11111111, // D2
0b00000000,0b11111111, // D3
0b10000001,0b01111110, // D4
0b11000011,0b00111100, // D5
0b11100111,0b00011000, // D6
0b11111111,0b00000000, // D7
};
__code byte pique[16] = {
// Vert Rouge
0b00011000,0b00011000,
0b00111100,0b00111100,
0b01111110,0b01111110,
0b11111111,0b11111111,
0b11111111,0b11111111,
0b01011010,0b01011010,
0b00011000,0b00011000,
0b00111100,0b00111100,
};
__code byte rouge[16] = {
// Vert Rouge
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
};
__code byte noir[16] = {
// Vert Rouge
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
};
void CopierImage(byte *newImage){
short i;
for (i=0;i<16;i++){
image[i] = *newImage;
newImage++;
}
}
void EffacerImage(void) {
short i;
for (i=0;i<16;i++){
image[i] = 0;
}
}
#define NOIR 0
#define VERT 1
#define ROUGE 2
#define JAUNE 3
void MettrePixel(short col,short ligne, byte couleur){
byte BitCol = 0b00000001 << col;
if (couleur & VERT) {
image[ligne*2] = image[ligne*2] | BitCol;
}
else {
image[ligne*2] = image[ligne*2] & ~BitCol;
};
if (couleur & ROUGE) {
image[ligne*2+1] = image[ligne*2+1] | BitCol;
}
else {
image[ligne*2+1] = image[ligne*2+1] & ~BitCol;
}
}
void AfficherImage(byte temps) {
int i,n;
byte ligne;
byte *p; //p pointe sur le premier byte du tableau image
for (n=0;n<temps;n++){
p = &image[0];
ligne = 0b11111110; // dans Ligne, on aura la ligne active à 0; on décalera le 0 pour chaque ligne
while (ligne != 0b11111111){ // tant qu’il reste un 0, on n'a pas terminé de balayer l'image
PLIGNE = 0b11111111; // pour éviter de voir des petits "phantomes" de la ligne précédente
// on ne sélectionne aucune ligne
PVERT = *p++; // on met les bits pour la couleur Rouge
PROUGE = *p++; // on met les bits pour la couleur Verte
PLIGNE = ligne; // on met la ligne (le bon bit à 0)
ligne = (ligne << 1) +1 ; // on décale le bit à 0 de un bit, comme cela met D0 à 0, on
// force D0 à 1 pour n'avoir qu'un bit à 0 (ligne active)
for (i=0;i<50;i++) {}; // on attend un peu pour avoir le temps de voir cette ligne
}
}
}
void AfficherSpirale(byte couleur,byte temps){
//-------------------------------------------------------------
// On affiche une spirale qui tourne de manière anti-horaire de
// l'exterieur vers l'intérieur. D'une couleur donnée
//-------------------------------------------------------------
short c=0,l=0;
short rangee;
for (rangee=0;rangee<=3;rangee++) {
for (c=rangee;c<=7-rangee;c++){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
c--;
for (l=rangee+1;l<=7-rangee;l++){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
l--;
for (c=7-1-rangee;c>=rangee;c--){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
c++;
for (l=7-1-rangee;l>=rangee+1;l--){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
l++;
}
}
void AfficherBalayageGauche(byte couleur,byte temps){
//-------------------------------------------------------------
// On balaie de droite à gauche avec une couleur donnée
//-------------------------------------------------------------
short c=0,l=0;
for (c=0;c<=7;c++){
for (l=0;l<=7;l++){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
}
}
void AfficherBalayageDroite(byte couleur,byte temps){
//-------------------------------------------------------------
// On balaie de droite à gauche avec une couleur donnée
//-------------------------------------------------------------
short c=0,l=0;
for (c=7;c>=0;c--){
for (l=0;l<8;l++){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
}
}
/*
==== Pour les débutants: commencez par modifier ce bout de programme ====
.*/
void Loop(void) {
//-------------------------------------------------------------
// La boucle principale:
//-------------------------------------------------------------
int i;
byte l;
EffacerImage();
AfficherSpirale(VERT,20);
AfficherSpirale(JAUNE,20);
AfficherSpirale(ROUGE,20);
for (i=10; i<10; i++){
CopierImage(&noir[0]);
AfficherImage(25);
CopierImage(&rouge[0]);
AfficherImage(25);
}
for (l=2;l<=16;l+=2){
CopierImage(&coeur[l]);
AfficherImage(20);
}
AfficherImage(100);
for (i=0;i<5;i++){
AfficherBalayageGauche(VERT,i);
AfficherBalayageDroite(ROUGE,i);
}
AfficherSpirale(VERT,50);
AfficherSpirale(ROUGE,10);
AfficherSpirale(JAUNE,5);
AfficherSpirale(NOIR,1);
}
//-------------------------------------------------------------
// Programme principal (là où le PIC va démarrer)
//-------------------------------------------------------------
void main(void) {
Setup();
while(1) {
Loop();
}
}
Affichage d'images variables, avec utilisation d'un timer
[modifier | modifier le wikicode]Ce programme ressemble au précédent, mais fait usage d'un timer
//------------------------------------------------------------------------------------------
// Programme de démonstration qui affiche une image sur le Bico64
//------------------------------------------------------------------------------------------
#define __16F887
#include <pic16f887.h>
//------------------------------------------------------------------------------------------
// Configuration du PIC 16F884 selon Bico64
//------------------------------------------------------------------------------------------
__code __at _CONFIG1 unsigned int Config1 =
_INTOSCIO // I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN
& _WDT_OFF // pas de Watch Dog
& _PWRTE_ON // on attend un peu au démarrage
& _MCLRE_ON // RE3/MCLR pin function is MCLR
& _CP_OFF // Program memory code protection is disabled
& _CPD_OFF // Data memory code protection is disabled
& _BOR_OFF // BOR Disabled
& _IESO_OFF // Internal/External Switchover mode is disabled
& _FCMEN_OFF // Fail-Safe Clock Monitor is disabled
& _LVP_OFF // RB3 pin is digital I/O, HV on MCLR must be used for programming
& _DEBUG_OFF;// In-Circuit Debugger disabled, RB6/ICSPCLK and RB7/ICSPDAT are general purpose I/O pins
__code __at _CONFIG2 unsigned int Config2 =
_WRT_OFF // No prog memmory write protection
& _BOR21V; // Brown-Out Reset at 2.1V
//-------------------------------------------------------------
// Initialisation
//-------------------------------------------------------------
// on donne des noms significatifs aux PORTs utilisés
#define byte unsigned char
#define PLIGNE PORTB
#define PVERT PORTC
#define PROUGE PORTD
void Setup(void) {
TRISB = 0x00; // PortB est en sortie
TRISC = 0x00; // PortC est en sortie
TRISD = 0x00; // PortD est en sortie
TRISA = 0xFF; // PortA est en entrée
OPTION_REG = 0b11000000; //1 Pas de pull-up pour le portB,
//1 interrupt rising edge of INT
//0 Timer0 utilise l'internal instruction clock
//0 incrément low-to-high de T0CKI (innutile dans ce cas)
//0 Prescaler utilisé pour le timer0
//000 Prescaler divise par 2 (==> 8Mhz / 4 /2 = un incrément toutes les 1us
TMR0 = 0;
T0IF = 0;
}
byte image[16];
__code byte coeur[16] = {
// Vert Rouge PLIGNE
0b11111111,0b00000000, // D0
0b10011001,0b01100110, // D1
0b00000000,0b11111111, // D2
0b00000000,0b11111111, // D3
0b10000001,0b01111110, // D4
0b11000011,0b00111100, // D5
0b11100111,0b00011000, // D6
0b11111111,0b00000000, // D7
};
__code byte pique[16] = {
// Vert Rouge
0b00011000,0b00011000,
0b00111100,0b00111100,
0b01111110,0b01111110,
0b11111111,0b11111111,
0b11111111,0b11111111,
0b01011010,0b01011010,
0b00011000,0b00011000,
0b00111100,0b00111100,
};
__code byte rouge[16] = {
// Vert Rouge
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
0b00000000,0b11111111,
};
__code byte noir[16] = {
// Vert Rouge
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
0b00000000,0b00000000,
};
void CopierImage(byte *newImage){
byte i;
for (i=0;i<16;i++){
image[i] = *newImage;
newImage++;
}
}
void EffacerImage(void) {
byte i;
for (i=0;i<16;i++){
image[i] = 0;
}
}
#define NOIR 0
#define VERT 1
#define ROUGE 2
#define JAUNE 3
void MettrePixel(byte col,byte ligne, byte couleur){
byte BitCol = 0b00000001 << col;
if (couleur & VERT) {
image[ligne*2] = image[ligne*2] | BitCol;
}
else {
image[ligne*2] = image[ligne*2] & ~BitCol;
};
if (couleur & ROUGE) {
image[ligne*2+1] = image[ligne*2+1] | BitCol;
}
else {
image[ligne*2+1] = image[ligne*2+1] & ~BitCol;
}
}
void AfficherImage(int temps) {
//-------------------------------------------------------------
// On affiche l'image "temps" fois si temps vaut 1,
// la procedure AfficherImage dure 1ms
// donc si on écrit AfficherImage(1000) cela prendra 1s
//-------------------------------------------------------------
int n;
byte ligne;
byte *p; //p pointe sur le premier byte du tableau image
for (n=0;n<temps;n+=2){
p = &image[0];
ligne = 0b11111110; // dans Ligne, on aura la ligne active à 0; on décalera le 0 pour chaque ligne
while (ligne != 0b11111111){ // tant qu’il reste un 0, on n'a pas terminé de balayer l'image
while (T0IF==0){
}; // attend que le timer0 soit arrivé au bout
TMR0 = 6; // on remet le timer à 250us : -250 = 6 sur un byte; le compteur comptera de 6 à 256
T0IF = 0;
PLIGNE = 0b11111111; // pour éviter de voir des petits "phantomes" de la ligne précédente
// on ne sélectionne aucune ligne
PVERT = *p++; // on met les bits pour la couleur Rouge
PROUGE = *p++; // on met les bits pour la couleur Verte
PLIGNE = ligne; // on met la ligne (le bon bit à 0)
ligne = (ligne << 1) +1 ; // on décale le bit à 0 de un bit, comme cela met D0 à 0, on
// force D0 à 1 pour n'avoir qu'un bit à 0 (ligne active)
}
}
}
void AfficherSpirale(byte couleur,byte temps){
//-------------------------------------------------------------
// On affiche une spirale qui tourne de manière anti-horaire de
// l'exterieur vers l'intérieur. D'une couleur donnée
// Temps est le nombre de fois 1ms pour afficher un point:
// comme il y a 64 Led, AffichierSpirale(100) met 640ms pour faire la spirale
//-------------------------------------------------------------
short c=0,l=0;
byte rangee;
for (rangee=0;rangee<=3;rangee++) {
for (c=rangee;c<=7-rangee;c++){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
c--;
for (l=rangee+1;l<=7-rangee;l++){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
l--;
for (c=7-1-rangee;c>=rangee;c--){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
c++;
for (l=7-1-rangee;l>=rangee+1;l--){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
l++;
}
}
void AfficherBalayageGauche(byte couleur,byte temps){
//-------------------------------------------------------------
// On balaie de droite à gauche avec une couleur donnée
// Temps est le nombre de fois 1ms pour afficher un point:
// comme il y a 64 Led, AffichierSpirale(100) met 640ms pour faire le balayage
//-------------------------------------------------------------
short c=0,l=0;
for (c=0;c<=7;c++){
for (l=0;l<=7;l++){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
}
}
void AfficherBalayageDroite(byte couleur,byte temps){
//-------------------------------------------------------------
// On balaie de droite à gauche avec une couleur donnée
// Temps est le nombre de fois 1ms pour afficher un point:
// comme il y a 64 Led, AffichierSpirale(100) met 640ms pour faire le balayage
//-------------------------------------------------------------
short c=0,l=0;
for (c=7;c>=0;c--){
for (l=0;l<8;l++){
MettrePixel(c,l,couleur);
AfficherImage(temps);
}
}
}
/*
Pour les débutants: commencez par modifier ce bout de programme
.*/
void Loop(void) {
//-------------------------------------------------------------
// La boucle principale
//-------------------------------------------------------------
int i;
byte l;
EffacerImage();
AfficherSpirale(VERT,1);
AfficherSpirale(JAUNE,2);
AfficherSpirale(ROUGE,3);
for (i=0; i<10; i++){
CopierImage(&noir[0]);
AfficherImage(25);
CopierImage(&rouge[0]);
AfficherImage(25);
}
for (l=2;l<=16;l+=2){
CopierImage(&coeur[l]);
AfficherImage(20);
}
AfficherImage(100);
for (i=0;i<5;i++){
AfficherBalayageGauche(VERT,i);
AfficherBalayageDroite(ROUGE,i);
}
AfficherSpirale(VERT,50);
AfficherSpirale(ROUGE,10);
AfficherSpirale(JAUNE,5);
AfficherSpirale(NOIR,1);
}
//-------------------------------------------------------------
// Programme principal (là où le PIC va démarrer)
//-------------------------------------------------------------
void main(void) {
Setup();
while(1) {
Loop();
}
}