En aquest cas van considerar que la bàscula tenia un límit màxim de 8 kg. L'usuari pot indicar el número de persones i la bàscula li indicarà el pes mesurat i també el pes per persona.
El polsador BTN0 serveix per activar i desactivar la bàscula. El polsador BTN1 guarda el pes actual com a tara. El polsador BTN2 serveix per canviar d'unitats entre g, kg, lb (lliura avoirdupois) i N. El polsador BTN3 permet emmagatzemar un valor de pes per a futura consulta i el BTN4 recupera el valor guardat. Finalment, el polsador BTN5 canvia el signe decimal entre punt i coma.
El programa és el següent:
/* * File: Balança.c * Author: Iñaki * * Created on 16 de octubre de 2017, 22:26 */ #pragma config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF #pragma config CPD = OFF, BOREN = OFF, IESO = OFF, FCMEN = OFF #include "pic16f690.h" // Carrega el fitxer d'adreces i paràmetres del PIC 16F690 #include <xc.h> // Carrega el fitxer de funcions necessari per al compilador XC8 #include <string.h> #define Polsador RA3 // Li assigna un nom a l'adreça del polsador #define _XTAL_FREQ 4000000 // La freqüència del rellotge és 4 MHz
// Declarem variables que utilitzarem char Polsad; // Polsador que s'ha premut bit ON; // Balança encesa char uni=0; // Unitats en que es mesura (0=kg;1=g;2=lb;3=N) unsigned short long pes=0; // Massa en g unsigned short long Lectura; // Valor llegit del sensor unsigned short long L0; // Valor de pes 0 char Port; // Bits del port C // RC0 a RC3 són els LED // RC4 és DAT (DOUT del sensor) // RC6 és CLK (PD_SCK del sensor) // RC5 és on hi ha el brunzidor unsigned short long marge=200000; // Marge prou grans per evitar números // negatius en la lectura de pes bit test=0; // Variable per determinar si es troba en un cas // excepcional (0=normal;1=excepció) int error=0; // Tipus d'error (0=cap error; 1=sobrepes; // 2=cal realitzar una tara) bit borra=0; // Variable que indica si s'ha d'esborrar la // pantalla (0=False;1=True) unsigned short long memoria=0; // Variable que emmagatzema el valor a mostrar en // cas de premer el botó corresponent bit coma=0; // Quin tipus de signe de spearacó // decimal utilitzar (0='.'; 1=',') unsigned short long pesm=0; // Variable que emmagatzema la massa minima detectada // per tal de fer comparació per sobrepes
// Declarem les funcions que utilitzarem unsigned short long LlegirHX(void); // Lectura del sensor unsigned short long conver(unsigned short long Lectura); // Converteix el valor obtingut pel sensor a grams // i defineix els límits char Premut(void); // Funció de lectura dels polsadors char decimal(void); // Insereix '.' o ',' void encesa(void); // Funció amb missatge a la pantalla al encendre void apaga(void); // Funció amb missatge a la pantalla al apagar void E00(void); // Funcióqueposa a 0 la pantalla void Escriu(unsigned short long Valor); // Escriu un valor de 24 bits a la pantalla void EnviaL(char Caracter); // Envia un caràcter ASCII void Esborra(void); // Esborra la pantalla i posa el cursor a l'inici void Cursor(char Filera, char Columna); // Posiciona el cursor (filera 1 a 2 // i columna 1 a 32, segons pantalla) void unis(void); // Afegeix darrere del valor pesat les unitats // en que està mesurat void Tara(unsigned short long Lectura); // Actualitza el valor a partir el qual es mesura // la diferència de pes void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B); // Fa sonar a una certa tonalitat depenent // dels valors proporcionats void TN(char nota[]); // Fa sonar tonalitats properes a les notes especificades
void main(void) {
ON=1; // La balança començarà apagada
ANSEL = 0b00000101; // Configura AN0 i AN2 com entrada analògica
ANSELH = 0; // Desactiva les altres entrades analògiques
TRISC = 0b00110000; // Definim com volem les E/S del port C
TRISB = 0b00000000; // Tot el port B és de sortida
TRISA = 0xFF; // Posa RA3 com a entrada
TXSTAbits.BRGH = 1; // Configuració de velocitat
BAUDCTLbits.BRG16 = 0; // Paràmetre de velocitat de 8 bits
SPBRG = 25; // Velocitat de 9600 baud
TXSTAbits.SYNC = 0; // Comunicació asíncrona
TXSTAbits.TX9 = 0; // Comunicació de 8 bits
RCSTAbits.SPEN = 1; // Activa comunicació sèrie
TXSTAbits.TXEN = 1; // Activa comunicació
ADCON1 = 0b00010000; // Posa el conversor a 1/8 de la freqüència
ADCON0 = 0b00001001; // Activa el conversor A/D connectat a AN2
PORTB = 0; // Desactiva tots els bits del port B
Port = 0; // Desactiva tots els bits de Port
// RC5 (sortida del PWM), de moment, com a entrada
PORTC = 0; // Desactiva les sortides del port C
CCP1CON = 0b00001100; // Configura el PWM, bits P1M (bits 7-6) a 00 mode senzill
// DC1B = 11 (bits 5-4) els dos bits de menys pes són 0
// CCP1M = 11xx en mode senzill els bit 0 i 1 no afecten
// Ho posa com a configuració del PWM
CCPR1L = 49; // Valor que correspon a un cicle del 35 % a 440 Hz
// Registre que ens dona l'amplada de tON
PIR1bits.TMR2IF = 0; // Desactiva el bit d'interrupció del Timer 2
T2CON = 0b00000011; // Configura el Timer 2
// bits T2KCPS (bits 1-0) a 11 prescalat de 16
// bit 2 (TMR2ON) a 0, Timer aturat
// Postscaler TOUTPS (bits 6-3) no afecten al PWM
while (1){
unsigned char Compta = 0; // Variable local per comptar
if (Polsador==0){ // Si el polsador s'activa
int mante=1; // Fins que no canvii,
while (mante){ // es mantindra dins del bucle
if (Polsador){ // Si es deixa anar abans de temps
mante=0; // surt del bucle
} else{
Compta++; // Si no contunua comptant
_delay(1000); // Espera 1000 cicles
}
if (Compta>4){ // Si el comptador arriba a 5
if (ON){ // Si està encès,
ON=0; // apaga
apaga();
} else{ // Si està apagat,
ON=1; // encen
encesa(); // executa la funcio
Lectura = LlegirHX();
// Emmagatzema el valor actual en Lectura
Tara(Lectura); // actualitza
pesm=L0; // Fixa la massa minima amb el pes actual
}
while(Polsador==0){
; // Espaera fins que es deixi anar el posador
}
mante=0; // Després d'haver acabat surt del bucle
}
}
}
if (ON){ // Si està encès
RC0=1; // Encen el LED 1
Polsad=Premut(); // Actualitza quin polsador està premut
Lectura = LlegirHX(); // Llegeix el valor del sensor HX711
if (Lectura<pesm){ // Si la lectura actual és menor
// que el pes minim detectat fins ara,
pesm=Lectura; // actualitza
}
pes=conver(Lectura); // Converteix la lectura feta a grams
if (Polsad==2){ // Si el polsador 2 està activat,
uni++; // passsa a la seguent unitat.
if (uni==4){ // Si ja no hi ha mes,
uni=0; // torna a la primera
}
} else{
if (Polsad==1){ // Si el polsador 1 està activat,
Tara(Lectura); // actualitza la tara
} else{
if(Polsad==3){ // Si el polsador 3 està activat,
memoria=pes; // actualitza la memoria
Cursor(2,1); // Ubica el cursor al començament
// de la segona linia
EnviaL('S'); // Escriu
EnviaL('a'); // Escriu
EnviaL('v'); // Escriu
EnviaL('i'); // Escriu
EnviaL('n'); // Escriu
EnviaL('g'); // Escriu
EnviaL('.'); // Escriu
EnviaL('.'); // Escriu
EnviaL('.'); // Escriu
RC2=1; // encen el LED 3
__delay_ms(500); // epsera 0,5s
Esborra(); // deixa la pantalla en blanc
RC2=0; // apaga el LED 3
} else{
if (Polsad==4){ // Si el polsador 4 està activat,
Escriu(memoria); // mostra en pantalla el
// valor emmagatzemat
unis(); // escriu les unitats
// corresponents
RC1=1; // encen el LED 2
__delay_ms(2000); // espera 2s
RC1=0; // apaga el LED 2
Esborra(); // deixa la pantalla en blanc
} else{
if (Polsad==5){ // Si el polsador 2
// està activat,
coma=!coma; // canvia tipus
}
}
}
}
}
RC0=1; // torna a encendre el LED 1
Escriu(pes); // escriu el pes o l'error
if (!(test)){ // si no hi ha hagut error,
unis(); // afegeix les unitats
}
if (borra){ // si s'ha d'esborrar:
Esborra(); // esborra
borra=0; // i descativa l'ordre d'esborrar
}
Cursor(1,1); // ubica el cursor al començament de la pantalla
RC0=1; // torna a encendre el LED 1
__delay_ms(100); // Retard de 0,1 s
RC0=1; // torna a encendre el LED 1
} else{ // Si està apagat
RC0=0; // apaga el LED 1
}
}
}
char Premut(void) {
char Pols = 0;
ADCON0bits.GO = 1; // Posa en marxa el conversor
while (ADCON0bits.GO == 1) // Mentre no acabi
; // ens esperem
if (ADRESH < 220 && ADRESH > 200) {
Pols = 1; // Comprova polsador 1
}
if (ADRESH < 194 && ADRESH > 174) {
Pols = 2; // Comprova polsador 2
}
if (ADRESH < 163 && ADRESH > 143) {
Pols = 3; // Comprova polsador 3
}
if (ADRESH < 90 && ADRESH > 70) {
Pols = 4; // Comprova polsador 4
}
if (ADRESH < 55 && ADRESH > 35) {
Pols = 5; // Comprova polsador 5
}
return Pols;
}
void encesa(void){
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
EnviaL('O'); // Escriu
EnviaL('N'); // Escriu
TN("do"); // Toca do
TN("re#"); // Toca re#
TN("fa"); // Toca fa
__delay_ms(300); // Espera 0,3s
TN("do"); // Toca do
TN("re#"); // Toca re#
TN("fa#"); // Toca fa#
TN("fa"); // Toca fa
__delay_ms(200); // Espera 0,2s
TN("do"); // Toca do
TN("re#"); // Toca re#
TN("fa"); // Toca fa
__delay_ms(200); // Espera 0,2s
TN("re#"); // Toca re#
__delay_ms(20); // Espera 0,02s
TN("do"); // Toca do
//_delay(1000000); // Espera
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
}
void apaga(void){
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
EnviaL('O'); // Escriu
EnviaL('F'); // Escriu
EnviaL('F'); // Escriu
TN("do#"); // Toca do
_delay(1000000); // Espera
Esborra(); // Esborra la pantalla i posa el cursor a l'inici
}
unsigned short long LlegirHX(void) {
unsigned short long Buffer; // Valor rebut
Port = Port & 0b10111111; // Desactiva PD_SCK
PORTC = Port;
for (int j = 1; j <= 24; j++){ // 24 bits
Port = Port | 0b01000000; // Activa PD_SCK
PORTC = Port;
Buffer = Buffer << 1; // Rodem els bits per situar el següent
// a la dreta hi quedarà un zero
if (RC4 == 1) { // Si DOUT està activat, posem un 1
Buffer = Buffer | 0b00000001;
}
Port = Port & 0b10111111; // Desactiva PD_SCK
PORTC = Port;
__delay_us(3); // Espera 3 us per fer els polsos de la mateixa amplada
}
Port = Port | 0b01000000; // Activa PD_SCK per dir-li el guany
PORTC = Port;
__delay_us(6); // Espera 6 us per fer els polsos de la mateixa amplada
Port = Port & 0b10111111; // Desactiva PD_SCK
PORTC = Port;
return Buffer; // Retorna el valor
}
void EnviaL(char Caracter) {
TXREG = Caracter; // Agafa el caràcter i l'envia
_delay(5); // Donem temps
while (PIR1bits.TXIF == 0) // Esperem que s'acabi d'enviar
; // No fem res
}
void Esborra(void) {
EnviaL(254); // Caràcter de control
EnviaL(1); // Esborra la pantalla i posa el cursor a l'inici
}
void Cursor(char Filera, char Columna) {
char Posicio = 0; // Variable per a calcular la posició
if (Filera == 2) {
Posicio = 64; // La primera columna de la segona fila és 64;
}
if (Columna > 0 && Columna < 33) { // Comprovem que sigui un valor raonable
Posicio = Posicio + Columna; // Sumem les adreces
Posicio = Posicio - 1; // Restem 1 perquè numera des de 0
}
Posicio = Posicio + 128; // Posa el bit de posicionat a 1
EnviaL(254); // Control de la posició del cursor
EnviaL(Posicio); // Canvia el cursor de lloc
}
void unis(void){
if (uni==0){ // Si són kg
Cursor(1,15); // ubica el cursor al començament
EnviaL('k'); // Escriu
EnviaL('g'); // Escriu
} else{
if (uni==1){ // Si son g
Cursor(1,15); // ubica el cursor al començament
EnviaL(' '); // Escriu
EnviaL('g'); // Escriu
} else{
if (uni==2){ // Si son lb
Cursor(1,15); // ubica el cursor al començament
EnviaL('l'); // Escriu
EnviaL('b'); // Escriu
} else{
if (uni==3){ // Si son N
Cursor(1,15); // ubica el cursor al començament
EnviaL(' '); // Escriu
EnviaL('N'); // Escriu
}
}
}
}
}
unsigned short long conver(unsigned short long Lectura){
unsigned short long a=Lectura+marge; // Assegurar que sigui un numero positiu
unsigned short long r; // Lectura en g
unsigned short long h; // auxiliar
if (a>L0){ // Si la lectura està per sobre de 0
r=(a-L0)/214; // massa
h=(a-pesm)/214; // massa sense Tara
if (h>8000){ // si h passa dels 8 kg
test=1; // error
error=1; // sobrepes
RC0=1; // Encen el LED 1
RC1=1; // Encen el LED 2
RC2=1; // Encen el LED 3
RC3=1; // Encen el LED 4
TN("sol"); // Toca do
return 9000;
} else{ // si h es menor de 8 kg
if (test){ // Si hi havia error
test=0; // desactiva error
borra=1; // i esborra el missatge
if (error){ // Si hi havia sobrepes
RC1=0; // Apaga el LED 2
RC2=0; // Apaga el LED 3
RC3=0; // Apaga el LED 4
}
}
return r; // envia massa
}
} else{ // Si la lectura està per sota de 0
r=(L0-a)/214; // calcula la massa "negativa"
if (r<1){ // si es menor d'1 g
if (test){ // (i hi havia error
test=0; // desactiva error
borra=1; // i esborra el missatge)
if (error){ // Si hi havia sobrepes
RC1=0; // Apaga el LED 2
RC2=0; // Apaga el LED 3
RC3=0; // Apaga el LED 4
}
}
return 0; // envia 0
} else{ // si es "molt negativa"
error=2; // massa insuficient
test=1; // error
TN("do"); // Toca sol3
return 9000;
}
}
}
void Tara(unsigned short long Lectura){
L0=Lectura+marge; // Assegurar que sigui un numero positiu
}
void Escriu(unsigned short long Valor){
char Digits[5]; // Aquí guardarem els 5 dígits
unsigned short long Result; // Variable de treball
if (uni==2 && !(test)){ // Si està en lb i no hi ha algun error
Valor=Valor*1000/453.59; // converteix a lb
} else{
if (uni==3 && !(test)){ // Si esta en N i no hi ha algun error
Valor=Valor*9.81; // converteix a N
}
}
Result = Valor % 10;
Digits[0] = (char) Result; // Unitats
Valor = Valor / 10;
Result = Valor % 10;
Digits[1] = (char) Result; // Desenes
Valor = Valor / 10;
Result = Valor % 10;
Digits[2] = (char) Result; // Centenes
Valor = Valor / 10;
Result = Valor % 10;
Digits[3] = (char) Result; // Milers
Valor = Valor / 10;
Result = Valor % 10;
Digits[4] = (char) Result; // Desenes de miler
if (test){ // Si hi ha algun error
Esborra(); // Esborra
EnviaL('E'); // Escriu
EnviaL('r'); // Escriu
EnviaL('r'); // Escriu
EnviaL('o'); // Escriu
EnviaL('r'); // Escriu
EnviaL(','); // Escriu
Cursor(2,1); // Ubica el cursor al començament de la segona linia
if (error==1){ // Si hi ha sobrepes
EnviaL('E'); // Escriu
EnviaL('n'); // Escriu
EnviaL('o'); // Escriu
EnviaL('u'); // Escriu
EnviaL('g'); // Escriu
EnviaL('h'); // Escriu
EnviaL(' '); // Escriu
EnviaL('m'); // Escriu
EnviaL('a'); // Escriu
EnviaL('s'); // Escriu
EnviaL('s'); // Escriu
EnviaL('.'); // Escriu
} else{ // Si no hi ha prou pes
EnviaL('N'); // Escriu
EnviaL('e'); // Escriu
EnviaL('e'); // Escriu
EnviaL('d'); // Escriu
EnviaL(' '); // Escriu
EnviaL('m'); // Escriu
EnviaL('o'); // Escriu
EnviaL('r'); // Escriu
EnviaL('e'); // Escriu
EnviaL(' '); // Escriu
EnviaL('m'); // Escriu
EnviaL('a'); // Escriu
EnviaL('s'); // Escriu
EnviaL('s'); // Escriu
EnviaL('.'); // Escriu
}
} else{ // Si no hi ha error
if (uni==0){ // Si esta en kg
for (int j = 4; j >= 0; j--){ // 8 dígits
Digits[j] = Digits[j] + '0'; // Li sumem el codi ASCII de 0
if (j==2) { // Posem espais per separar
EnviaL(decimal()); // Espai
}
EnviaL(Digits[j]); // Número
}
} else{
if (uni==1){ // Si esta en g
for (int j = 4; j >= 0; j--){ // 8 dígits
Digits[j] = Digits[j] + '0'; // Li sumem el codi ASCII de 0
if (j==2) { // Posem espais per separar
EnviaL(' '); // Espai
}
EnviaL(Digits[j]); // Número
}
} else{
if (uni==2){ // Si esta en lb
for (int j = 4; j >= 0; j--){ // 5 dígits
Digits[j] = Digits[j] + '0';
// Li sumem el codi ASCII de 0
if (j==2) { // Posem espais per separar
EnviaL(decimal()); // Espai
}
EnviaL(Digits[j]); // Número
}
} else{
if (uni==3){ // Si esta en N
for (int j = 4; j >= 0; j--){ // 5 dígits
Digits[j] = Digits[j] + '0';
// Li sumem el codi ASCII de 0
if (j==2) { // Posem espais per separar
EnviaL(decimal()); // Espai
}
EnviaL(Digits[j]); // Número
}
}
}
}
}
}
}
char decimal(void){
if (coma){ // Si es ','
return ','; // Escriu ','
}
else{ // Si es '.'
return '.'; // Escriu '.'
}
}
void TocaNota(char ValPR2, char ValCCPR1L, char ValDC1B) {
TRISC = 0b00100000; // Definim com volem les E/S del port C
// RC5 (sortida del PWM), de moment, com a entrada
PR2 = ValPR2; // Carrega PR2
CCP1CON = CCP1CON & 0b11001111; // Posa a zero els bits que corresponen a DC1B
ValDC1B = ValDC1B % 4; // DC1B va de 0 a 3
ValDC1B = ValDC1B * 16; // Desplaça els bits a la posició que els correspon a CCP1CON
CCP1CON = CCP1CON + ValDC1B; // Coloca DC1B al seu lloc
CCPR1L = ValCCPR1L; // Carrega CCPR1L, registre que ens dona l'amplada de tON
PIR1bits.TMR2IF = 0; // Desactiva el bit d'interrupció del Timer 2
T2CON = 0b00000111; // Configura el Timer 2
// bits T2KCPS (bits 1-0) a 11 prescalat de 16
// bit 2 (TMR2ON) a 1, Timer activat
// Postscaler TOUTPS (bits 6-3) no afecten al PWM
while (PIR1bits.TMR2IF == 0) // Espera l'activació del bit d'interrupció del Timer 2
; // Esperem
TRISC = 0b00000000; // Posem RC5 (sortida del PWM) com a sortida
__delay_ms(200); // Retard de 0,2 s
TRISC = 0b00110000; // Posem RC5 (sortida del PWM) com a entrada
// O sigui, silenci
__delay_ms(100); // Retard de 0,2 s
}
void TN(char nota[]){
if (nota=="do"){
TocaNota(238,119,2); // Valor que correspon aproximadament a do3
}
if (nota=="re#"){
TocaNota(200,100,2); // Valor que correspon aproximadament a re#3
}
if (nota=="fa"){
TocaNota(178,89,2); // Valor que correspon aproximadament a fa3
}
if (nota=="fa#"){
TocaNota(168,84,2); // Valor que correspon aproximadament a fa#3
}
if (nota=="sol"){
TocaNota(158,79,2); // Valor que correspon aproximadament a sol3
}
if (nota=="do#"){
TocaNota(224,112,2); // Valor que correspon aproximadament a do#3
}
if(nota=="re"){
TocaNota(212,106,2); // Valor que correspon aproximadament a re3
}
if(nota=="mi"){
TocaNota(189,95,0); // Valor que correspon aproximadament a mi3
}
if(nota=="sol#"){
TocaNota(149,75,0); // Valor que correspon aproximadament a sol#3
}
if(nota=="la"){
TocaNota(141,71,0); // Valor que correspon aproximadament a la3
}
if (nota=="la#"){
TocaNota(133,67,0); // Valor que correspon aproximadament a la#3
}
if(nota=="si"){
TocaNota(126,63,2); // Valor que correspon aproximadament a si3
}
if(nota=="do4"){
TocaNota(118,59,2); // Valor que correspon aproximadament a do4
}
}

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