Programació en mpasm del PIC 16F690

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 dona 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:3 de manera que Lectura+2 tindrà el byte més significatiu i Lectura el byte meys significatiu.

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:3 i mostra a la pantalla els tres bytes.

#include <p16F690.inc>
	__config (_INTRC_OSC_NOCLKOUT&_WDT_OFF&_PWRTE_OFF&_MCLRE_OFF&_CP_OFF&_BOR_OFF&_IESO_OFF&_FCMEN_OFF)
	cblock 0x20
Lectura:3		; Lectura del sensor
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
Caracter		; Caràcter o codi a enviar a la pantalla
Compta			; Comptador d'iteracions
D1			; Variable unitats	
D2			; Variable desenes	
D3			; Variable centenes	
Retard1			; Variables per als cicles de retard
Retard2
Retard3
	endc
	org 0
Inici
	bsf		STATUS,RP1	; Tria el banc 2
	movlw		b'00000101'
	movwf		ANSEL		; Configura AN0 i AN2 com entrada analògica
	clrf		ANSELH		; Desactiva les altres entrades analògiques
	bcf		STATUS,RP1
	bsf		STATUS,RP0	; Tria el banc 1
	movlw		0xFF		; Posa l'acumulador a FFh (tot uns)
	movwf		TRISA		; Posa tots els bits del port A com a entrada
	movlw		b'00010000'	; Posa RC4 com a entrada
	movwf		TRISC		; La resta del port C és de sortida
	clrf		TRISB		; Tot el port B és de sortida
	bsf		TXSTA,BRGH	; Configuració de velocitat
	bcf		BAUDCTL,BRG16	; Paràmetre de velocitat de 8 bits
	movlw		.25		; Velocitat de 9600 baud
	movwf		SPBRG		; Paràmetre de velocitat
	bcf		TXSTA,SYNC 	; Comunicació asíncrona
	bcf		TXSTA,TX9 	; Comunicació de 8 bits
	bcf		STATUS,RP0	; Tria el banc 0
	bsf		RCSTA,SPEN	; Activa comunicació sèrie
	bsf		STATUS,RP0	; Tria el banc 1
	bsf		TXSTA,TXEN 	; Activa comunicació
	bcf		STATUS,RP0	; Tria el banc 0
	clrf		Port		; Desactiva tots els bits de Port
	clrf		PORTB		; Desactiva tots els bits del port B
	clrf		PORTC		; Desactiva tots els bits del port C
Bucle
	call		LlegirHX	; Llegeix el valor del sensor HX711
					; Enviem l'adreça i els valors
	movlw		.254		; Caràcter de control
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		.1		; Esborra la pantalla i posa el cursor a l'inici
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf		Lectura+2,w	; Agafem el byte més significatiu
	call		EnviaValor	; Ho envia a la pantalla
	movlw		' '		; Espai
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf		Lectura+1,w	; Agafem el byte intermedi
	call		EnviaValor	; Ho envia a la pantalla
	movlw		' '		; Espai
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movf		Lectura,w	; Agafem el byte menys significatiu
	call		EnviaValor	; Ho envia a la pantalla
	movlw		.4
	call		Rets
	goto		Bucle
					;
					; Llegeix el valor del sensor HX711
					;
					; Lectura+2 té el byte més significatiu
LlegirHX
	movlw		.24		; Llegim 24 bits
	movwf		Compta		; Ho guarda a Compta
	bcf		Port,6		; Desactiva PD_SCK
	movf		Port,w		; Copia Port a l'acumulador
	movwf		PORTC		; I ho posa al PORTC
BucleLec
	bsf		Port,6		; Activa PD_SCK
	movf		Port,w		; Copia port a l'acumulador
	movwf		PORTC		; I ho posa al PORTC
	bcf		STATUS,C	; Preventivament posa C a zero
	btfsc		PORTC,4		; Llegeix DOUT
	bsf		STATUS,C	; Si l'entrada està activada activem C
	rlf		Lectura,f	; Entrem el bit a Lectura
	rlf		Lectura+1,f	; I fem rodar els altres bits
	rlf		Lectura+2,f
	bcf		Port,6		; Desactiva PD_SCK
	movf		Port,w		; Copia Port a l'acumulador
	movwf		PORTC		; I ho posa al PORTC
	nop				; Espera 3 us per fer els polsos de la mateixa amplada
	nop
	nop
	decfsz		Compta,f	; Ja hem llegit un bit
	goto		BucleLec	; Repetim fins tenir els 24
	bsf		Port,6		; Activa PD_SCK per dir-li el guany
	movf		Port,w		; Copia Port a l'acumulador
	movwf		PORTC		; I ho posa al PORTC
	nop				; Espera 6 us per fer els polsos de la mateixa amplada
	nop
	nop
	nop
	nop
	nop
	bcf		Port,6		; Desactiva PD_SCK
	movf		Port,w		; Copia Port a l'acumulador
	movwf		PORTC		; I ho posa al PORTC
	return
					;
					; Envia un valor a la pantalla
					;
					; El valor està a W
EnviaValor
	call		BCD		; Ho converteix en BCD
	movlw		'0'		; Per passar a ASCII, sumarem el codi de 0
	addwf		D3,w		; Agafa les centenes
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		'0'		; Per passar a ASCII, sumarem el codi de 0
	addwf		D2,w		; Agafa les desenes
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	movlw		'0'		; Per passar a ASCII, sumarem el codi de 0
	addwf		D1,w		; Agafa les unitats
	movwf		Caracter	; Ho guarda a la variable
	call		EnviaL		; Ho envia
	return
					;
					; Enviem caràcters a visualitzar
					;
EnviaL					
	movf		Caracter,w	; Agafa el caràcter
	movwf		TXREG		; L'envia
	nop			
	nop				; Espera 2 us
	btfss		PIR1,TXIF	; El registre TXREG ha quedat lliure?
	goto		$-1		; No, doncs esperem
	return				; Tornem al lloc des d'on hem vingut
					;
					; Funció de retard de 0,2 W s
					;
Rets					
	movwf		Retard3
Bucles
	decfsz		Retard1,f		
	goto		Bucles		
	decfsz		Retard2,f		
	goto		Bucles		
	decfsz		Retard3,f	
	goto		Bucles
	return
					;
					; Funció que converteix un número de 8 bits a BCD (3 dígits)
					;
					; El valor a convertir està a W
BCD	
	clrf		D3		; Posa D3 (centenes) a zero
	clrf		D2		; Posa D2 (desenes) a zero
	movwf		D1		; Guarda W (valor a convertir) a D1 
					; D1 són les unitats
Cent					; Anem a trobar les centenes (D3)
	movlw		.100		; Carrega 100 decimal a W
	subwf		D1,w		; Li resta W a D1
	btfss		STATUS,C	; Mira C i si és 1 no fa la següent
					; Si és 1 vol dir resultat positiu
	goto		Desen		; Si el resultat és negatiu les centenes ja estan
					; el valor de W es perd i anem a les desenes
	movwf		D1		; Guarda el resultat (W) a D1
	incf		D3,f		; La centena restada a D1 l'afegeix a D3
	goto		Cent		; Tornem-ho a fer
Desen					; Anem a trobar les desenes
	movlw		.10		; Carrega 10 decimal a W
	subwf		D1,w		; Li resta W a D1
	btfss		STATUS,C	; Mira C i si és 1 no fa la següent
					; Si és 1 vol dir resultat positiu
	goto		Final		; Si el resultat és negatiu les desenes ja estan
					; el valor de W es perd i anem a ASCII
	movwf		D1		; Guarda el resultat (W) a D1
	incf		D2,f		; La desena restada a D1 l'afegeix a D2
	goto		Desen		; Tornem-ho a fer
Final
	retlw		0		; Retorn amb un 0 a W
	end

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ó. A títol d'exemple, anem a veure com podríem fer una aplicació.

En aquest exemple, hem suposat que el rang de mesura va de 0 a 8 kg i que volem una resolució de 5 g. 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 Byte més significatiu
(Lectura+2)
Byte intermedi
(Lectura+1)
Byte menys significatiu
(Lectura)
Valor numèric
0 g 2
0000 0010
116
0111 0100
142
1000 1110
160 910
8025 g 28
0001 1100
95
0101 1111
129
1000 0001
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 5 mg que és un valor massa sensible si no volem que la lectura ens estigui fluctuant constantment.

D'altra banda, si observem els bits del byte més significatiu observem que els tres primers sempre són zero. Treballar amb valors de 24 bits sembla poc raonable i, a més, ja hem vist que els bits menys significatius tenen una sensibilitat excessiva. Una possible proposta seria dividir el valor llegit per 64 i tindríem uns valors de 16 bits suficientment bons. Repetim la taula amb aquesta divisió.

Pes aplicat Byte més significatiu
(Valor+1)
Byte menys significatiu
(Valor)
Valor numèric
0 g 9
0000 1001
210
1101 0010
2 514
8025 g 113
0111 0001
126
0111 1110
29 054

Si restem els valors de la darrera columna, trobem que per passar de 0 a 8025 g el valor ha augmentat 26540 unitats. Si ho dividim pels 8025 g obtenim que cada gram ens fa augmentar el valor en unes tres unitats. Per tant, cada unitat són 0,3 g que és un valor prou adequat.

La divisió per 64 la podríem aconseguir fent rodar sis vegades els bits cap a la dreta però és més ràpid i senzill fer-los rodar dos cops cap a l'esquerra i descartar el byte menys significatiu.

Si el que volem és obtenir el pes en grams, podríem dividir el valor per 26540 i multiplicar el resultat per 8025. Això és equivalent a multiplicar el valor per

			                    8025
			Pes [g] = Valor · ------- = Valor · 0,30237377
			                   26540

S'ha de tenir present que el valor a utilitzar s'ha d'obtenir després d'haver restat el corresponent a l'absència de pes.

Treballant en assemblador no és fàcil dividir ni tampoc operar amb nombres reals. En canvi, sí que és fàcil dividir per valors que siguin potència de dos ja que només cal fer rodar els bits cap a la dreta. Anem a veure com quedaria aquest factor si el multipliquéssim per diferents potències de dos.

Rotacions 0 1 2 3 4 5 6 7
Multiplicador 1 2 4 8 16 32 64 128
Fracció 0,30237377 0,60474755 1,20949510 2,41899020 4,83798040 9,67596081 19,3519216 38,7038432
Rotacions 8 9 10 11 12 13 14 15
Multiplicador 256 512 1024 2048 4096 8192 16384 32768
Fracció 77,4076865 154,815373 309,630746 619,261492 1238,52298 2477,04596 4954,09193 9908,18387

Ara cal triar una de les opcions. Ens interessa una opció que no estigui molt a l'esquerra (perquè la precisió no seria molt bona) i que tingui un nombre petit després de la coma. Ja és veu que l'ideal seria agafar el cas de 13 rotacions ja és el que té un valor més petit després de la coma. Amb els casos de 14 o 15 rotacions no hi guanyem.

			                    8025             2477
			Pes [g] = Valor · ------- = Valor · ------
			                   26540             8192

En aquest cas, hem tingut una mica de mala sort. En altres casos, podem obtenir bons resultats amb nombres menors de rotacions.

Així doncs, podem agafar el Valor, multiplicar-lo per 2477 i dividir-lo per 8192. Per multiplicar per 2477 podríem sumar el valor amb ell mateix 2477 vegades i per dividir per 8192 caldria fer rodar els bits cap a la dreta 13 vegades (entrant zeros per l'esquerra). Ara veurem que hi ha opcions més pràctiques.

En lloc de sumar 2477 cops, podem jugar amb les potències de dos, com mostra la taula següent. Recordem que Valor l'havíem obtingut dividint Lectura per 64, per tant podem agafar aquesta variable com a base per guanyar precisió.

Factor Rotació teòrica
a l'esquerra
(sobre Valor)
Rotació real (sobre Lectura)
Número Sentit
2048 11 5 esquerra
256 8 2 esquerra
128 7 1 esquerra
32 5 1 dreta
8 3 3 dreta
4 2 4 dreta
1 0 6 dreta
2477  

En aquest cas tampoc hem tingut gaire sort. Altres vegades es poden fer moltes menys operacions.

Si no ens cal la variable Valor, podem prescindir d'ella. Per fer les operacions ens caldrà una variable X de 32 bits (quatre bytes) i una variable Resultat de 32 bits també.

La seqüència completa de passos seria:

Un cop fet això, ja tenim a Resultat el contingut de Valor multiplicat per 2477.

Ara hauríem de dividir per 8192, és a dir fer rodar els bits de Resultat 13 cops cap a la dreta per obtenir el Pes que serà una variable de 16 bits. El que podem fer és rodar Resultat cinc cops cap a la dreta i quedar-nos amb els dos bytes del mig. Finalment, caldria ajustar el valor de Resultat per a la resolució requerida (en el nostre exemple, 5 g).

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 (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). En el cas de tenir lectures negatives, els valors ens apareixeran codificats en complement a dos. Per tant, sabrem que el valor és negatiu si el bit 7 de Lectura+2 està activat. Amb el programa que hem presentat no ens sortirà un valor negatiu a la pantalla sinó un valor extraordinàriament gros. La taula següent mostra un exemple.

Pes aplicat Byte més significatiu
(Lectura+2)
Byte intermedi
(Lectura+1)
Byte menys significatiu
(Lectura)
Valor numèric Valor pantalla
0 g 254
1111 1110
59
0011 1011
106
0110 1010
-115 862 16 661 354
574 g 0
0000 0000
32
0010 0000
104
0110 1000
8 296 8 296
8025 g 24
0001 1000
176
1011 0000
219
1101 1011
1 618 139 1 618 139

Atès que per a pesos petits tindrem lectures negatives, hem de trobar una solució que ens permeti fer els càlculs de manera senzilla. Una possible solució és sumar un valor (significativament superior a 115 862) a totes les lectures, per exemple 250 000 o, millor, 262 144 que és un valor que és potència de 2 i, per tant, facilita la feina.

 

 

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