Jelenlét-érzékelés infravörös fény segítségével

Végre hosszú idő után előkerült a PICkit a fiókból. Az [intlink id=”559″ type=”post”]el%u0151z%u0151 PIC[/intlink]-es próbálkozásom után most egy kicsit bonyolultabb probléma megoldására vállalkoztam. Konkrétan arra, hogy a kütyü képes legyen érzékelni valakinek a jelenlétét. Erre a leggyakrabban alkalmazott módszer infravörös fényt vetít a vizsgált térrész felé, és méri a visszaverődött fény mennyiségét. Minél több fény verődik vissza, annál közelebb van a tárgy, amiről visszaverődött. Az elmélet egyszerű, és mint azt a továbbiakban olvashatjátok, a gyakorlat se sokkal bonyolultabb.

Az első probléma ami felmerült, az a jelentős háttérzaj kérdése. Az infravörös tartományban a nap és a legtöbb mesterséges fényforrás is sugároz, ráadásul sokkal erősebben, mint egy ilyen alkalmazásban szóba jöhető infra-led. A háttérzaj és az infra-led jelét szétválasztani csak úgy lehet, ha modulált jelet sugározunk a térbe, és ezt a modulált jelet keressük a mért értékekben is. Léteznek olyan infra-vevők, melyek hardveresen támogatják a modulált jel érzékelését (pl. TSOP), de hasonló alkatrészt tucatnyi boltot körbejárva sem találtam (ha tud valaki olyan boltot, ahol vásárolható ilyen, kérem írjon). Ilyen célezköz hiányában a modulációt szoftveresen oldottam meg.

A szoftveres moduláció miatt a hardver rendkívül egyszerű lett, a következő alkatrészekre volt szükségem:

  • Pic16F690
  • 1db infra led
  • 1db fotodióda
  • 1db npn tranzisztor
  • 4db 1kOhm ellenállás
  • 2db vörös led (egy a bekapcsolt állapotot jelzi – folyton világít, egy pedig a végeredményt adja meg, hogy érzékel-e jelenlétet az eszköz)

A munkát minimalizálandó felhasználtam a programozóhoz adott próbapanelt, amin beépített ledek állnak rendelkezésre, ezeket felhasználtam az állapotjelzések számára, így csak a fotódiódát és az infraledet kell hozzákötni, ami egy breadboard segítségével könnyedén kivitelezhető. Az infra-ledet a PIC rc0 kimenete fogja meghajtani, egy ellenállással bekötve ez a rész készen van. A kimenetet jelző led az rc1, a power-led az rc2-re van kötve hasonló módon. A fotódiódát a tranzisztorral erősítve kötjük a beépített A/D konverter bemenetére, hogy erősebb jelet kapjunk, ezzel megnövelve az érzékelés felbontását. A további félreértések rövidre zárásához felraktam egy kapcsolási rajzot:

pdetector.png

A szoftver ezzel a következő módon tud együttműködni: az alapötlet az, hogy kikapcsolt infra-leddel lemérjük a bejövő fény mennyiségét, majd bekapcsoljuk az infrát, és újra mérünk. A bekapcsolt illetve kikapcsolt infra-led melletti mérések különbsége adja meg az infra-led által leadott és visszavert fény mennyiségét. Ha ez a különbség több iteráció után is meghaladja a küszöbértéket, akkor a kimeneten jelezzük az érzékelt jelenlétet. Azaz két paraméter a küszöbérték (mekkora különbséget várunk el kikapcsolt és bekapcsolt infra-led melletti mérések között), és a kitartás (hány iteráción át kell tartani ezt a különbséget).

És íme, a kód. A dolog nehézségét jelzi, hogy a legtöbb időt két érték összehasonlítása vette el. A kódban szereplő makrót a Microchip MPasm leírásából vettem, én egy kétszer olyan hosszú megoldást csináltam elötte.


#include __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF &
_IESO_OFF & _FCMEN_OFF)

;presence detector code.
;assumed peripheres:
; infra-led on RC0
; photo-diode connected to AN0
; detected proximity output on RC1
; power led on RC2
;
;we measure input on photo diode, while infra-led is turned off.
;then we measure again with turned on infra-led.
;if the infra-ray is reflected from anything, the second measurement
;should return a higher value

;=================================================
;========VARIABLES================================
;=================================================

cblock 0x20
offmeasure ;stores measurement without infra led
onmeasure ;stores measurement with infra led
output ;output bits
waitcount ;wait count
surecount ;make sure that something is there and not moves
endc

OUT_ILED EQU H’0000′ ;bit for infra led
OUT_RES EQU H’0001′ ;bit for output
OUT_POWER EQU H’0002′ ;power led

THRESHOLD EQU H’0002′ ;threshold for measurment gain

SURENESS EQU H’000C’ ;number of measurements before we’re sure in the result

;===================================================
;==============macros for selecting banks
;====================================================
SELECT_BANK0 macro
bcf STATUS,RP0
bcf STATUS,RP1
endm

SELECT_BANK1 macro
bsf STATUS,RP0
bcf STATUS,RP1
endm

SELECT_BANK2 macro
bcf STATUS,RP0
bsf STATUS,RP1
endm

SELECT_BANK3 macro
bsf STATUS,RP0
bsf STATUS,RP1
endm

;==============================================
;=====MACRO TO WAIT=============================
;==============================================

WAIT macro us
local a = 0
while a < us
nop
a += 1
endw
endm

;============================================
;========EXECUTE A MEASUREMENT===============
;============================================

MEASURE macro
WAIT 5
bsf ADCON0,GO ; start conversion
btfsc ADCON0,GO ; this bit will change to zero when the conversion is complete
goto $-1

movf ADRESH,w

btfsc output,OUT_ILED
goto $+3
movwf onmeasure
goto $+2
movwf offmeasure
nop
endm

;========================================
;=======SWITCH output led================
;========================================

SWITCH_ILED macro
movlw 0x01
xorwf output,F
endm

;========================================
;========REFRESH OUTPUT==================
;========================================

REFRESH_OUTPUT macro
movfw output
movwf PORTC
endm

;======================================================
; compare file to constant and jump if file
; >= constant.
;======================================================
cfl_jge macro file, con, jump_to
movlw con & 0xff
subwf file, w
btfsc STATUS, C
goto jump_to
endm

;===============================================
;==============MAIN PROGRAM=====================
;===============================================
org 0
Init:
;set variables to zero
movlw 0x00
movwf output
movwf onmeasure
movwf offmeasure

;set powerled on
bsf output,OUT_POWER

;initialize devices
SELECT_BANK1
movlw 0xFF
movwf TRISA ; Make PortA all input
clrf TRISC ; Make PortC all output
movlw 0x10 ; A2D Clock Fosc/8
movwf ADCON1
SELECT_BANK2
movlw 0xFF ; we want all Port A pins Analoge
movwf ANSEL
SELECT_BANK0
movlw 0x01
movwf ADCON0 ; configure A2D for Channel 0 (RA0), Left justified, and turn on the A2D module

Loop:
MEASURE ;measure with light off
SWITCH_ILED ;turn light on
REFRESH_OUTPUT
call SubWait ;wait a bit

MEASURE ;measure with light on
SWITCH_ILED ;turn light off
call DecideOutput ;decide output
REFRESH_OUTPUT
call SubWait ;wait a bit
goto Loop

;==============================================
;=====Decide output============================
;==============================================
DecideOutput:
;onmeasure-offmeasure >= threshold
movfw offmeasure
subwf onmeasure,F
cfl_jge onmeasure,THRESHOLD,DecideYes
goto DecideNo
DecideYes:
;bsf output,OUT_RES
incf surecount,F
goto DecideOutputReturn
DecideNo:
clrf surecount
bcf output,OUT_RES
DecideOutputReturn:
cfl_jge surecount,SURENESS, SwitchOn
goto SwitchOff
SwitchOn:
bsf output, OUT_RES
return
SwitchOff:
bcf output, OUT_RES
return

;===========================================
;===========Subroutine for long wait========
;===========================================
SubWait:
movlw 0xFF
movwf waitcount
StartWait:
WAIT 100
decfsz waitcount,F
goto StartWait
return

;===============================================
;=====PROGRAM END===============================
;===============================================
end

A kütyüt felprogramoztam, a perifériákat megépítettem, és pár iteratív hibajavítás/paraméterfinomítás után eljutottam arra az állapotra, amit elégségesnek neveztem a koncepció működésének a bizonyítására.

dscf1957_small.jpeg

A fenti köntörfalas megfogalmazás nem költői önkifejezés, és nem is véletlen. Az eszköz működik, de épp hogy. A környezet által kifejtett fényerő fehérzajként adódik a rendszerhez, és csak magas “kitartás” és “küszöbérték” paraméter mellett lehet kiszűrni a téves jelzéseket. Ennek az az eredménye, hogy kb. két másodperc után jelzi ha 5cm-nél közelebb teszem a kezemet az infra-led+fotódióda pároshoz. 10cm-nél már bizonytalan a mérés, és akkor is előfordul egy-egy téves jelzés, ha nincs semmi a közelben.

Ezen problémák orvoslására több ötletem is van, egy részük azonnal megoldódna, ha találnék egy rendes infra adó-vevőt. Persze ötleteket, javaslatokat, hasonló problémákban szerzett tapasztalatokat szívesen fogadok.

PICkit 2 + PIC16F690, avagy új játék nagy gyereknek

Talán ez lesz az első eset, hogy olyan dologgal kezdtem el foglalkozni, ahol minden első kattintásra úgy működött, ahogy az meg van írva. Pedig néhány lépésnél határozottan kételkedtem az azonnali sikerben. Hozzávetőleg fél éve elmélkedek egy hardveres probléma megoldásán, amihez kézenfekvő és egyszerű lehetőségként merült fel PIC alapú megoldás. A döntést felgyorsította egy akció, amivel vizsonylag olcsón juthattam egy PICkit 2 programozóhoz, és egy pic16F690-es processzorhoz.

Talán ez lesz az első eset, hogy olyan dologgal kezdtem el foglalkozni, ahol minden első kattintásra úgy működött, ahogy az meg van írva. Pedig néhány lépésnél határozottan kételkedtem az azonnali sikerben. Hozzávetőleg fél éve elmélkedek egy hardveres probléma megoldásán, amihez kézenfekvő és egyszerű lehetőségként merült fel PIC alapú megoldás. A döntést felgyorsította egy akció, amivel vizsonylag olcsón juthattam egy PICkit 2 programozóhoz, és egy pic16F690-es processzorhoz. A csomag ráadásul tartalmaz egy egyszerű próbapanelt, néhány leddel, egy kapcsolóval és egy potméterrel továbbá természetesen kivezetésekkel más kapcsolásokhoz. Az említett processzor nagy előnye a beépített A/D konverter, amire nagy szükségem lesz a tervezett munkában (erről egy másik bejegyzés fog szólni, várhatóan néhány hónappal később).

Az első ismerkedésem az új játékszerrel arra fókuszálódott, hogy megoldást keressek a programozó linux alatti használatára, mivel természetesen a csomaghoz adott lemezeken csak windows-kompatibilis szoftverek találhatóak. Nem estem kétségbe, ugyanis vásárlás elött tájékozódtam a rendelkezésre álló eszközökről, így volt kiindulási alapom. Szerencsére a [[http://www.microchip.com|Microchip]] kiadta a programozóját parancssorból vezérlő, pk2cmd program forráskódját, így egy lelkes fejlesztő munkája nyomán ez a program megjelent linuxra is, immár [[http://home.pacbell.net/theposts/picmicro/|pk2cmdlinux]] névre keresztelve. A Microchip által fejlesztett MPLab IDE fejlesztői környezettel már egészen más a helyzet, bár a [[http://piklab.sourceforge.net/|Piklab]] értelmesnek látszó alternatíva, az általam használt eszközt egyelőre nem támogatja. Mindenesetre érdemes követni a fejlődését.

A csomagban kapott lemezen találtam pár példaprogramot előrefordított programfájlokkal, amikkel sikeresen felprogramozva a kütyüt néhány látványos LED-villogtatást sikerült kicsikarnom. A példaprogramok között számomra a leghasznosabbnak az A/D konverter működéséét bemutató alkalmazás tünt, ami a próbapanelen található potméterrel beállított feszültséget 4 bitre skálázva jeleníti meg a rendelkezésre álló 4 leden.

A következő megoldandó feladat az volt, hogy az előrefordított program felhasználása helyett a forráskódot magam fordítsam le, így kipróbálva a teljes fejlesztési folyamatot. Fordítónak a [[http://gputils.sourceforge.net/|GNU Pic utils]] csomagot választottam. Valójában nem vártam, hogy módosítás nélkül lefordul a kód, azonban kellemes meglepetésként a fordító csupán néhány “message” szintű megjegyzést adott. A lefordított kóddal se volt semmilyen probléma, bár néhány részletében különbözött az előrefordítotthoz képest.

Az első bátortalan lépéseim a PIC világában biztatóak, az egyszerű használat, a rengeteg integrált periféria, és az alacsony ára remekül használható eszközzé teszik a kütyüt.

Az általam kipróbált példaprogram:

#include __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF &
_IESO_OFF & _FCMEN_OFF)

cblock 0x20
Delay1 ; Assign an address to label Delay1
Delay2
Display ; define a variable to hold the diplay
endc

org 0
Start:
bsf STATUS,RP0 ; select Register Page 1
movlw 0xFF
movwf TRISA ; Make PortA all input
clrf TRISC ; Make PortC all output
movlw 0x10 ; A2D Clock Fosc/8
movwf ADCON1
bcf STATUS,RP0 ; back to Register Page 0

bcf STATUS,RP0 ; address Register Page 2
bsf STATUS,RP1
movlw 0xFF ; we want all Port A pins Analoga
movwf ANSEL
bcf STATUS,RP0 ; address Register Page 0
bcf STATUS,RP1

movlw 0x01
movwf ADCON0 ; configure A2D for Channel 0 (RA0), Left justified, and turn on the A2D module
MainLoop:
nop ; wait 5uS for A2D amp to settle and capacitor to charge.
nop ; wait 1uS
nop ; wait 1uS
nop ; wait 1uS
nop ; wait 1uS
bsf ADCON0,GO ; start conversion
btfss ADCON0,GO ; this bit will change to zero when the conversion is complete
goto $-1

swapf ADRESH,w ; Copy the display to the LEDs
movwf PORTC
goto MainLoop
end

A kód lefordítása:

gpasm -p pic16F690 A2D.asm

A kütyü felprogramozása a lefordított programmal:

pk2cmd -Ppic16f690 -Fad_proba/A2D.hex -M

A felprogramozott kütyü bekapcsolása:

pk2cmd -Ppic16f690 -t

Ha kijátszottuk magunkat, ki is kapcsolhatjuk:

pk2cmd -Ppic16f690

  • A gyártó: [[http://www.microchip.com|Microchip]]
  • A csomag oldala: [[http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en023805|PICkit 2]]
  • A processzor adatlapja elérhető itt: [[http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1335&dDocName=en023112|PIC16F690]]
  • GNU assembler PIC készülékekhez: [[http://gputils.sourceforge.net/|GNU Pic utils]]
  • A pk2cmd linux portolása: [[http://home.pacbell.net/theposts/picmicro/|pk2cmdlinux]]
  • QT alapú GUI a pk2cmdlinux programhoz: [[http://www.cannasoftware.com/component/option,com_jdownloads/Itemid,33/task,viewcategory/catid,1/|KPK2cmd]]

A próbapanel kapcsolási rajza:
Próbapanel

A programozó, és a próbapanel:
PICkit 2

A lényeg, egy PIC16F690:
pic16f690