Programació en C del PIC 16F690

Referència Trucs Perifèrics   Recursos CITCEA
Tutorial Exemples Projectes   Inici

Marcador esportiu

Programa del grup 3

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);
}

 

 

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