En aquest cas el marcador anava destinat a l'handbol. La funció dels LED és indicar els modes:
| LED | Significat |
| 1 | Funcionament normal del marcador |
| 2 | Canvi de part |
| 3 | Bloqueig del marcador |
| 4 | So que imita el xiulet de l'àrbitre |
El potenciòmetre permet passar d'un mode a l'altre. La funció dels polsadors és la següent:
| Polsador | Funció |
| 0 | Accepta el que s'ha seleccionat amb el potenciòmetre |
| 1 | Inicia o atura el temps |
| 2 | Afegeix un gol a l'equip local |
| 3 | Anul·la un gol a l'equip local |
| 4 | Afegeix un gol a l'equip visitant |
| 5 | Anul·la un gol a l'equip visitant |
El programa d'aquest grup està dividit en nombrosos fitxers, tal com es mostra a continuació.
AD.h
#ifndef __AD_H #define __AD_H #include <xc.h>
/* CONFIGURA AD */ void AD_glob_config(); /* ACTIVA AD */ void AD_on(); /* DESACTIVA AD */ void AD_off(); /* INICIA AD */ void AD_go(); /* SELECCIONAR CANAL AD */ void AD_channel(char ch);
#endif
AD.c
#include "AD.h"
void AD_glob_config(){
ADCON0bits.ADON = 0;
ADCON0bits.GO = 0;
ADCON0bits.VCFG = 0;
ADCON0bits.ADFM = 0;
ADCON1bits.ADCS = 0b101;
ADIF = 0;
}
void AD_on(){
ADCON0bits.ADON = 1;
}
void AD_off(){
ADCON0bits.ADON = 0;
ADCON0bits.GO = 0;
}
void AD_go(){
ADCON0bits.GO = 1;
}
void AD_channel(char ch){
ADCON0bits.CHS = ch;
}
Buttons.h
#ifndef __BUTTONS_H #define __BUTTONS_H #include <xc.h> #include "AD.h" #define _XTAL_FREQ 4e6
/* INICIALITZA ELS BOTONS */ void config_lectura_buttons(); /* ACTIVA AD AL CANAL 2 PER LLEGIR BOTONS */ void start_lectura_buttons(); /* DESACTIVA LECTURA DELS BOTONS */ void stop_lectura_buttons();
#endif
Buttons.c
#include "Buttons.h"
void config_lectura_buttons(){
TRISAbits.TRISA3 = 1;
ANSELbits.ANS2 = 1;
TRISAbits.TRISA2 = 1;
AD_glob_config();
}
void start_lectura_buttons(){
AD_channel(2);
AD_on();
__delay_ms(5);
AD_go();
}
void stop_lectura_buttons(){
AD_off();
}
Buzzer.h
#ifndef __BUZZER_H #define __BUZZER_H #include <xc.h> #define _XTAL_FREQ 4e6
/* INICIALITZA EL PWM */ void BUZZ_configure(); /* FREQ CALCULADA PEL PR2 I PRE CALCULADA PEL PRESCALER DEL TMR2*/ void BUZZ_set_freq(char freq, char pre); /* INICIA EL PWM */ void BUZZ_play(); /* PARA EL PWM */ void BUZZ_stop();
#endif
Buzzer.c
#include "Buzzer.h"
void BUZZ_configure(){
/* Configurar el mòdul CCP1 al CCP1CON */
TRISCbits.TRISC5 = 1; // Disable
CCP1CONbits.P1M = 00; // Only activate P1A
CCP1CONbits.CCP1M = 0b1100;
TMR2IF = 0;
}
void BUZZ_set_freq(char freq, char pre){
TMR2IF = 0;
T2CONbits.T2CKPS = pre; // PRE 1 4 16
TMR2ON = 1;
PR2 = freq; // Period
// Duty cycle
CCP1CONbits.DC1B = ((PR2+1)*2)%4;
CCPR1L = (PR2+1)/2;
while(!TMR2IF);
}
void BUZZ_play(){
TRISCbits.TRISC5 = 0;
}
void BUZZ_stop(){
TRISCbits.TRISC5 = 1; // Disable
}
LCD.h
#ifndef __LCD_H
#define __LCD_H
#ifdef __cplusplus
extern "C" {
#endif
#include <string.h>
#include <xc.h>
/* INICIA UART PER LCD */ void LCD_enable(); /* ENVIAR UN STRING AL LCD */ void LCD_send(char s[]); /* ENVIA UN CARÀCTER AL LCD */ void LCD_sendChar(char a); /* ENVIA UN NÚMERO DE 2 XIFRES AL LCD */ void LCD_sendNum(unsigned char n); /* ENVIA UN DÍGIT AL LCD */ void LCD_sendDigit(unsigned char n); /* AJUSTA EL BRILLANTOR DEL LCD */ void LCD_brightness(int value); /* BORRA EL CONTINGUT DEL LCD */ void LCD_clear(); /* MOU EL CURSOR A LA DRETA */ void LCD_move_cursor_right(); /* MOU EL CURSOR A L'ESQUERRA*/ void LCD_move_cursor_left(); /* MOU CURSOR SUMANT OFFSET*/ void LCD_set_cursor_position(int offset); /* DESACTIVA LA LCD */ void LCD_disable(); /* ENVIA COMANDA VAL A LA LCD*/ void LCD_sendCommand(char val);
#ifdef __cplusplus } #endif #endif
LCD.c
#include "LCD.h" #define _XTAL_FREQ 4e6 #pragma config WDTE=OFF // Disable FRIGGIN WATCHDOG
void LCD_enable(){
SYNC = 0;
BRGH = 0;
BRG16 = 1;
SPBRG = 25;
SPEN = 1;
TXEN = 1;
TXREG = 0xFE;
__delay_ms(1);
while(!TXIF)
;
// __delay_ms(10);
TXREG = 0x01;
__delay_ms(1);
while(!TXIF)
;
}
void LCD_brightness(int value){
if(128 <= value && value <= 157){
TXREG = 0x7C;
__delay_ms(1);
while(!TXIF)
;
TXREG = value;
__delay_ms(1);
while(!TXIF)
;
}
}
void LCD_clear(){
TXREG = 0xFE;
__delay_ms(1);
while(!TXIF)
;
TXREG = 0x01;
__delay_ms(1);
while(!TXIF)
;
}
void LCD_move_cursor_right(){
TXREG = 0xFE;
__delay_ms(1);
while(!TXIF)
;
TXREG = 0x14;
__delay_ms(1);
while(!TXIF)
;
}
void LCD_move_cursor_left(){
TXREG = 0xFE;
__delay_ms(1);
while(!TXIF)
;
TXREG = 0x10;
__delay_ms(1);
while(!TXIF)
;
}
void LCD_sendCommand(char val){
TXREG = 0xFE;
__delay_ms(1);
while(!TXIF)
;
TXREG = val;
__delay_ms(1);
while(!TXIF)
;
}
void LCD_set_cursor_position(int offset){
TXREG = 0xFE;
__delay_ms(1);
while(!TXIF)
;
TXREG = 0x80 + offset;
__delay_ms(1);
while(!TXIF)
;
}
void LCD_send(char str[]){
for(char i = 0; i < strlen(str); ++i){
TXREG = str[i];
__delay_ms(1);
while(!TXIF)
;
}
}
void LCD_sendChar(char a){
TXREG = a;
__delay_ms(1);
while(!TXIF)
;
}
void LCD_disable(){
TXEN = 0;
}
void LCD_sendDigit(unsigned char n){
LCD_sendChar('0' + n);
}
void LCD_sendNum(unsigned char n){
// LCD_sendDigit((n/1000)%10);
// LCD_sendDigit((n/100)%10);
LCD_sendDigit((n/10)%10);
LCD_sendDigit(n%10);
}
LED.h
#ifndef __LED_H #define __LED_H #include <xc.h>
/* INICIALITZA ELS LCD */ void LED_enable(); /* S'ACTIVA EL LED N SI N NO ÉS 0 1 2 O 3 S'ACTIVEN TOTS*/ void LED_light(unsigned char n); /* ES DESACTIVA ELS LEDS*/ void LED_off();
#endif
LED.c
#include "LED.h"
void LED_enable(){
TRISC = 0;
}
/* ELS PORTS S'ESCRIUEN TOT DE COP PERÒ AIXÒ ENS FUNCIONA */
void LED_light(unsigned char n){
switch(n){
case 0:
RC0 = 1;
break;
case 1:
RC1 = 1;
break;
case 2:
RC2 = 1;
break;
case 3:
RC3 = 1;
break;
default:
PORTC = -1;
}
}
void LED_off(){
RC0 = 0;
RC1 = 0;
RC2 = 0;
RC3 = 0;
}
TMR1.h
#ifndef __TMR1_H #define __TMR1_H #include <xc.h>
/* INICIALITZA EL TMR1 */ void TMR1_config(int TMR1_DEF); /* ACTIVA EL TMR1 */ void TMR1_start(char IE); /* PARA EL TMR1 */ void TMR1_stop(); /* VALOR PER DEFECTE DEL TMR1 */ void TMR1_set(int val);
#endif
TMR1.c
#include "TMR1.h"
void TMR1_config(int TMR1_DEF){
TMR1CS = 0;
TMR1 = TMR1_DEF;
T1CONbits.T1CKPS = 0b11;
TMR1IF = 0;
}
void TMR1_start(char IE){
TMR1IE = IE;
TMR1ON = 1;
}
void TMR1_stop(){
TMR1ON = 0;
TMR1IE = 0;
TMR1IF = 0;
}
void TMR1_set(int val){
TMR1 = val;
}
#include <stdio.h> #include <stdlib.h> #include "LCD.h" #include "TMR1.h" #include "LED.h" #include "Buttons.h" #include "AD.h" #include "Buzzer.h" #define _XTAL_FREQ 4e6 #pragma config MCLRE = OFF #pragma config WDTE=OFF #define TMR1_DEF 3036 /* Valors placa #define BTN1 0xD1 #define BTN2 0xB8 #define BTN3 0x98 #define BTN4 0x50 #define BTN5 0x2C */ /* Valors simulador */ #define BTN1 0xD1 #define BTN2 0xB7 #define BTN3 0x98 #define BTN4 0x4F #define BTN5 0x2C /* Posició cursor */ #define PART 7 #define VISITOR 14 #define LOCAL 5
/* Variables globals | Atributs del marcador */
struct Time{
unsigned char min;
unsigned char sec;
};
struct Time time;
unsigned char local;
unsigned char visitor;
char part;
int loc;
char TMR1_control ;
char mode;
/* WRAPPERS D'ALGUNES FUNCIONS DEL TMR1 */
void configure_TMR1(){
TMR1_config(TMR1_DEF);
TMR1_control = 1;
}
void start_TMR1(){
TMR1_control = 1;
TMR1_start(1);
}
void stop_TMR1(){
TMR1_stop();
TMR1_set(TMR1_DEF);
}
/* INICIALITZA LCD */
void init_LCD(){
LCD_enable();
LCD_sendNum(time.min);
LCD_sendChar(':');
LCD_sendNum(time.sec);
LCD_set_cursor_position(PART);
LCD_send("STOP");
LCD_set_cursor_position(64); // Line 2 position 0
LCD_send("Loc: 00 ");
LCD_send("Vis: 00");
LCD_set_cursor_position(0);
}
/* INICILITZA ELS ATRIBUTS DEL MARCADOR */
void init_GAME(){
time.min = 30;
time.sec = 0;
local = 0;
visitor = 0;
part = 0;
}
/* CONTROL DELS CANVIS DE PART */
void switchPart(){
part = part%4;
switch(part){
case 1:
LCD_set_cursor_position(0 + PART);
LCD_send("PART: 1");
break;
case 2:
LCD_set_cursor_position(0);
time.min = 30;
time.sec = 0;
LCD_sendNum(30);
LCD_sendChar(':');
LCD_sendNum(00);
LCD_set_cursor_position(0 + PART);
LCD_send("DESCANS");
break;
case 3:
LCD_set_cursor_position(0+PART);
LCD_send("PART: 2");
break;
default:
local = 0;
LCD_set_cursor_position(64 + LOCAL);
LCD_sendNum(local);
visitor = 0;
LCD_set_cursor_position(64 + VISITOR);
LCD_sendNum(visitor);
LCD_set_cursor_position(0);
time.min = 30;
time.sec = 0;
LCD_sendNum(30);
LCD_sendChar(':');
LCD_sendNum(00);
LCD_set_cursor_position(0 + PART);
LCD_send("STOP ");
}
}
/* CONTROLAR ELS GOLS */
void addLOCAL(){
if(local < 99)
++local;
else
local = 0;
LCD_set_cursor_position(64 + LOCAL);
LCD_sendNum(local);
}
void subsLOCAL(){
if(local > 0)
--local;
else
local = 99;
LCD_set_cursor_position(64 + LOCAL);
LCD_sendNum(local);
}
void addVISITOR(){
if(visitor < 99)
++visitor;
else
visitor = 0;
LCD_set_cursor_position(64 + VISITOR);
LCD_sendNum(visitor);
}
void subsVISITOR(){
if(visitor > 0)
--visitor;
else
visitor = 99;
LCD_set_cursor_position(64 + VISITOR);
LCD_sendNum(visitor);
}
/* MODE MARCADOR */
void menu_ctrl(){
if(part == 0 || part == 2)
++part;
start_lectura_buttons();
LED_off();
while(1){
int RA3 = RA3;
while(!ADIF)
;
ADIF = 0;
int aux = ADRESH;
if(aux <0x20 && loc == BTN1){
if(TMR1ON == 1){
stop_TMR1();
LCD_set_cursor_position(0 + PART);
LCD_send("STOP");
} else {
start_TMR1();
switchPart(part);
}
}
if(aux<0x20 && loc == BTN2){
addLOCAL();
}
if(aux <0x20 && loc == BTN3){
subsLOCAL();
}
if(aux <0x20 && loc == BTN4){
addVISITOR();
}
if(aux <0x20 && loc == BTN5){
subsVISITOR();
}
loc = aux;
__delay_ms(5);
if(RA3 == 1 && RA3 == 0){
LED_light(mode>>6);
AD_channel(0);
return;
}
ADCON0bits.GO = 1;
}
}
/* MODE BLOQUEJAT, ESPERAR FINS QUE S'APRETA BTN0 */
void block_mode(){
LED_off();
while(1){
int RA3 = RA3;
__delay_ms(5);
if(RA3 == 1 && RA3 == 0){
LED_light(mode>>6);
AD_channel(0);
return;
}
}
}
void __interrupt() temporit(void){
GIE = 0;
if (TMR1IF){
if(TMR1_control != 0){
TMR1_control = 0;
TMR1 = TMR1_DEF;
TMR1IF = 0;
if(time.sec == 0){
time.sec = 59;
if(time.min == 0){
stop_TMR1();
switchPart(++part);
} else
--time.min;
} else
--time.sec;
/* NO S'ATURA AI EL TMR1, AQUESTES OPERACION SÓN MENORS A 500ms */
LCD_set_cursor_position(0);
LCD_sendNum(time.min);
LCD_sendChar(':');
LCD_sendNum(time.sec);
LCD_set_cursor_position(0);
} else {
TMR1IF = 0;
TMR1 = TMR1_DEF;
TMR1_control = 1;
}
}
GIE = 1;
}
int main(int argc, char** argv) {
__delay_ms(1000); // Boot LCD
/* INIT ATRIBUTS DEL MARCADOR */
init_GAME();
init_LCD();
LED_enable();
configure_TMR1();
BUZZ_configure();
BUZZ_set_freq(249, 1);
config_lectura_buttons();
/* INIT INTERRUPTS */
GIE = 1;
PEIE = 1;
/* INIT AD I BTN0 */
ANSELbits.ANS0 = 1;
TRISAbits.TRISA0 = 1;
ADCON0bits.CHS = 0b0000;
ADIF = 0;
ADCON0bits.ADON = 1;
__delay_ms(5); // ESPERAR INICI DE L'AD
while(1){
/* VALOR DEL POTENCIÒMETRE*/
ADCON0bits.GO = 1;
while(!ADIF)
;
mode = ADRESH; // AD DE 8 BITS MÉS SIGNIFICATIUS
LED_light(mode>>6); // MARCAR EL MODE ALS LED
int RA3 = RA3;
__delay_ms(5); // CONTROLAR REBOTS
if(RA3 == 1 && RA3 == 0){
if(mode>>6 == 0) menu_ctrl(); // MODE MARCADOR
if(mode>>6 == 1){
if(TMR1ON == 0 && (part == 1 || part == 3)){
switchPart(++part); // NOMÉS SI NO CORRE EL TEMPS I ESTEM PART 1 O 2
} else {
LED_light(255);
__delay_ms(200); // AVÍS VISIBLE
}
}
if(mode>>6 == 2){
block_mode(); // MODE BLOQUEJAT
}
__delay_ms(5);
}
/* SONA EL BRUNZIDOR MENTRE ESTIGUI APRETAT BTN0 AL MODE CORRESPONENT */
if(RA3==0 && mode>>6 == 3){
BUZZ_play();
} else {
BUZZ_stop();
}
}
return (EXIT_SUCCESS);
}

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.