Programació en C del PIC 16F690 amb PICkit 2

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

Cèl·lula de càrrega

Una cèl·lula de càrrega és un sensor que permet mesurar forces i, per tant, saber el pes dels objectes. Una cèl·lula de càrrega típica consisteix en una peça que es subjecta per un costat i se li aplica una força al costat contrari. Aquesta força provoca una flexió a la peça que depèn de la força aplicada.

Cèl·lula de càrrega

Per mesurar la flexió de la peça, fem servir galques extensiomètriques. Una galga extensiomètrica té una resistència elèctrica que varia en ser estirada o comprimida. Les galgues que posem a la part superior de la barra s'estiraran i les de la part inferior es comprimiran. Si connectem quatre galgues formant un pont i alimentem a tensió constant per dos extrems oposats obtindrem una tensió de sortida als altres dos extrems que dependrà de la força aplicada. La tensió de sortida és molt petita i, per tant, caldrà algun sistema amplificador per poder-la llegir amb el microcontrolador.

Nosaltres farem servir una cèl·lula de càrrega de 10 kg que connectarem a un amplificador que es basa en el circuit integrat HX711. Aquest amplificador no dóna un senyal analògic sinó que proporciona la lectura a partir d'una comunicació sèrie. El circuit serà el següent.

Cèl·lula de càrrega

El circuit integrat HX711 ens donarà un valor de 24 bits que correspondrà a la lectura del sensor. El nostre programa guardarà el valor llegit a la variable Lectura.

Per llegir el valor, farem un bucle de 24 iteracions. A cada iteració activarem RC6 per demanar un nou bit i llegirem el valor a RC4. Tot seguit desactivarem RC6. El circuit integrat HX711 té tres modes de treball diferents que se seleccionen en funció del nombre de polsos que es fan en el procés de lectura. En el nostre cas ens interessa llegir el port A amb guany elevat, que correspon a 25 polsos. Per això, un cop llegits els 24 valors farem un pols més a RC6.

El següent programa de prova llegeix el valor del sensor (amb la funció LlegirHX), el guarda a la variable Lectura i mostra a la pantalla els tres bytes.

#pragma config FOSC = INTRCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF, 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
#define _XTAL_FREQ  4000000			// La freqüència del rellotge és 4 MHz
unsigned short long Lectura;			// Valor llegit del sensor
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
						// Definició de les funcions que farem servir 
unsigned short long LlegirHX(void);		// Lectura del sensor
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 main (void) {
	ANSEL = 0b00000101;			// Configura AN0 i AN2 com entrada analògica
	ANSELH = 0;				// Desactiva les altres entrades analògiques
	TRISC = 0b00010000;			// Posa RC4 com a entrada, la resta és de sortida
	TRISB = 0;				// Tot el port B és de sortida
	TRISA = 0b11111111;			// Tot el port A és d'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ó
	PORTB = 0;				// Desactiva tots els bits del port B
	PORTC = 0;				// Desactiva tots els bits del port C
	Port = 0;				// Desactiva tots els bits de Port
	while (1) {				// Inici del bucle de programa
		Lectura = LlegirHX();		// Llegeix el valor del sensor HX711
		Esborra();			// Esborra la pantalla
		Escriu(Lectura);		// Escriu la lectura a la pantalla
		__delay_ms(1000);		// Retard d'1 s
	}
}
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 (PORTCbits.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 Escriu(unsigned short long Valor) {
	char Digits[8];				// Aquí guardarem els 8 dígits
	unsigned short long Result;		// Variable de treball
	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
	Valor = Valor / 10;
	Result = Valor % 10;
	Digits[5] = (char) Result;		// Centenes de miler
	Valor = Valor / 10;
	Result = Valor % 10;
	Digits[6] = (char) Result;		// Unitats de milió
	Result = Valor / 10;
	Digits[7] = (char) Result;		// Centenes de milió
	for (int j = 7; j >= 0; j--){		// 8 dígits
		Digits[j] = Digits[j] + '0';	// Li sumem el codi ASCII de 0
		if (j == 5 || j == 2) {		// Posem espais per separar
			EnviaL(' ');		// Espai
		}
		EnviaL(Digits[j]);		// Número
	}
}
void EnviaL(char Caracter) {
	TXREG = Caracter;			//  Agafa el caràcter i l'envia
	_delay(5);				// Donem temps
	while (PIR1bits.TXIF == 0);		// Esperem a 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
}

Cada cèl·lula de càrrega i cada amplificador poden ser una mica diferents. També cada usuari pot triar en quin rang de pesos vol treballar (sempre amb un màxim absolut de 10 kg) i amb quina resolució. Anem a veure un cas com a exemple. Hem suposat que el rang de mesura va de 0 a 8 kg. Hem fet una mesura sense pes (0 kg) i una altra amb un pes proper al límit del rang i hem obtingut els següents resultats:

Pes aplicat Lectura
0 g 160 910
8025 g 1 859 457

Si restem els valors de la darrera columna, trobem que per passar de 0 a 8025 g el valor ha augmentat 1 698 547 unitats. Si ho dividim pels 8025 g obtenim que cada gram ens fa augmentar el valor en 212. Per tant, cada unitat són, aproximadament, 5 mg que és un valor massa sensible si no volem que la lectura ens estigui fluctuant constantment. Cada usuari haurà de triar quina resolució vol donar, tenint present que si tenim més resolució les lectures fluctuaran més.

El nostre programa haurà de llegir el sensor sense pes i guardar-ho com a tara. Després haurà de llegir el sensor amb el pès que volem mesurar i guardar-ho com a lectura. Si restem la tara de la lectura obtindrem el valor que correspon al pes. Si fem això amb un objecte de pes conegut podrem determinar el factor que ens permetrà obtenir el valor del pes en cada mesura.

Important: Ha de quedar clar que aquesta explicació correspon a una cèl·lula de càrrega concreta amb un amplificador determinat i, per tant, les dades llegides poden variar d'un cas a un altre. D'altra banda, cada usuari pot triar el rang de pes amb el que vol treballar (sense passar de 10 kg) i la resolució. En cada cas, doncs, els càlculs poden ser diferents.

En l'exemple explicat s'ha fet servir un pes d'aproximadament 8 kg per a les proves. Sempre és bo fer l'ajust amb el valor límit de l'escala desitjada per aconseguir la màxima precisió però no és imprescindible. Podíem haver fet l'ajust, per exemple, amb un pes al voltant de 3 kg i després haver treballat amb un rang més gran.

Observació: Existeix la possibilitat que les lectures corresponents a pesos petits siguin números negatius i que a l'arribar a un determinat pes es canviï el signe. A la pantalla, però, no veuríem números negatius (ja que el programa no ho contempla) sinó valors extraordinàriament grans. Per exemple, imaginem que a la pantalla llegim 16 661 354, que correspon a -115 862. Una possible solució és sumar un valor (significativament superior a 115 862) a totes les lectures, per exemple 250 000.

Si la cèl·lula estigués muntada amb els cables permutats també pot ser que els valors siguin majoritàriament negatius però aquest altre cas no el contemplarem perquè el raonable és muntar el circuit correctament.

 

 

Licencia de Creative Commons
This obra by Oriol Boix is licensed under a Creative Commons Reconocimiento-NoComercial-SinObraDerivada 3.0 Unported License.