Uživatel:Krivdvla

Z MAM wiki

Přejít na: navigace, hledání

Obsah

[editovat] Samostatná práce - Zámek ovládaný animovaným obrázkem na mobilu

[editovat] Zadání

Mobil se přiloží displejem ke čtveřici LED, možná trojbarevných, použitých jako senzor. Animovaný gif v mobilu bliká různobarevnými čtverci na čtvrtinách displeje. Při správné kombinaci po sobě následujících různobarevných obrazců dojde k odemknuti nějakého obvodu.

[editovat] Popis

Nejprve jsme chtěli využít pro detekci fotovoltaicky jev LED diody. Vzhledem k tomu však, že obyčejná LEDka nevybudí při silném osvětlení ani proud 1 uA, tak jsme od tohoto nápadu hodně rychle upustili. Podrobněji o fotovoltajickém jevu LED se lze dočíst třeba zde: Fotovoltaický jev u diod LED


K detekci jednotlivých barev jsme tedy využili závěrné kapacity barevných LED diod. Nejprve se dioda nabije v závěrném směru výstupním pinem PB0 - PB3 na 3V (log 1). Pak se tento pin nastaví jako vstupní a odečítá se stav napětí (log 0,log 1) na diodě po vypršení předem určeného časového úseku. Vzhledem k poznatku z práce zabývající se detekci osvětlení: ZDE, jsme zvolili tento časový úsek na 10 ms. Pokud je dioda málo osvětlená, tak její vybíjení trvá dlouho a za 10 ms je na jejích svorkách stále napětí větší než 1,5V - tedy log 1. Pokud je dioda hodně osvětlená, vybíjí se rychle a za 10 ms napětí na ní poklesne pod 1,5V a MCU zaznamená log0. Zajímavý článek s LED senzorem osvětlení pracujícím na tomto principu je ještě tu: LED sensor


Rozlišení jednotlivých barev jsme dosáhli použitím čirých diod s různými brvami. Na čipu těchto diod je již nanesen barevný filtr, který propouští nejvíce právě tu vlnovou délku světla, kterou příslušná dioda svítí. Tyto diody se nikdy nepoužívají k indikací a tedy výhodou je, že nepovolaná osoba neví jaké jsou barvy. Vzhledem k největší citlivostí na svou barvu a povahou LCD displejů mobilů byly zvoleny LED tří základních barev spektra: červená, zelená a modrá - RGB (Red, Green, Blue).


Celé zařízení je poháněno nízkonapěťovým mikrokontrolérem Atmel ATiny 2313A, který má dostatek portu pro naše využití a nemá žádné zbytečností navíc. O napájení se stará knoflíková 3V baterie CR2032. Aby baterie vydržela co nejvíce je obvod během nečinností uspán do SLEEP režimu a sleduje přerušení pouze na jednom svém portu PD2.

[editovat] Popis činností zámku

Mobil s připraveným GIF obrázkem se přiloží na spínací krýt, přitlačením krytu sepneme spínač J1 a na port PD2 připojíme napětí 3V, tímto dojde k přerušení, MCU probudíme z režimu spánku a rozsvítí se červena LED na portu PD0. Spuštění GIFu ze zajistí zmačknutím dotykového resistivního displeje mobilního telefonu o spínací krýt zařízení (popř. senzorem přiblížení u telefonu s kapacitním displejem). GIF obrázek bliká dvěma snímky za sekundu.

MCU nastaví svoje porty PB0 - PB3 na výstupní a pošle na ně log 1, kterou tam ponechá 300 ms. Po uplynutí této doby přepne výstupy na vstupy a po uplynutí 10 ms odečte logické stavy na těchto vstupech a zaznamená si je do paměti.

Po vypršení 500 ms opět přepne vstupy na výstupy, nastaví je do log 1 a situace se opakuje. Toto provede celkem 6 krát. Do pamětí tedy uloží celkem 6 po sobě následujících kombinací logických stavů na detekčních LED diodách.

Následně získanou posloupnost kombinací porovnáme s uloženým vzorem v ROM pamětí. My jsme si jako vzor zvolili posloupnost kombinací GRBR: 1111 0111 0001 1100 1000 1001 BIN (= 15 07 01 12 08 09 DEK), kde každý bit přestavuje logický stav na LEDce umístěné v příslušném kvadrantu (1., 2., 3., 4.).

Pokud jsou obě posloupnosti identické, MCU zhasne červenou LED na portu PD0 a uvede výstup PD1 do log 1 - rozsvítí se zelená LEDka.

Jsou-li obě posloupností odlišné, 3 krát zabliká červenou LED na portu PD0, zhasne ji a přejde opět do režimu spánku SLEEP.

Celá doba detekce trvá přibližně 3 sekundy.

[editovat] GIF obrázek v mobilu

Na následujících obrázcích je zobrazená již zmíněná kombinace barev, které se budou zobrazovat na displeji mobilního telefonu. Logická "1" znamená, že se v daném kvadrantu objeví správná barva (tzn. pro stav "1111" budou barvy ve všech kvadrantech odpovídat vzoru a pro stav "0001" bude správná barva pouze ve čtvrtém kvadrantu a v ostatních kvadrantech bude barva jakákoli, ale jiná než ve vzoru). První obrázek zobrazuje animaci kódu ve stejném tvaru, jako je rozložení led diod ve spínacím krytu na který se telefon přikládá (zmíněn pouze ilustračně, aby v něm byla lépe vidět kombinace posloupnosti), pro reálné použití je zapotřebí obrázek zrcadlit (obrázek 2).

Jedná se o 6 obrázků složených do jedné animace ve formátu gif, kde je každý obrázek zobrazen po dobu 500ms. Celková perioda animace je tedy 3s.


ilustrační animace kódu pro odemknutí


animace kódu pro odemknutí


[editovat] Detail spínacího krytu s rozmístěním jednotlivých LED diod

Spínací krýt

[editovat] Schéma zapojení periferií

Schéma zapojení periferií

[editovat] Připojení periferií k portům mikrokontroléru

Připojení periferií k portům mikrokontroléru


[editovat] Zdrojový kód programu v mikrokontroléru

#define F_CPU 8000000UL

#include <avr/io.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include <avr/interrupt.h>


//timers: 300ms, 310ms, 500ms -> 300 (discharge), 10 (measure, check_state), 190 (charge)

unsigned char combination[] = {15, 7, 1, 12, 8, 9}; //TODO: right combination
int ok = 0;

unsigned char t_ovf_cnt = 0;
unsigned char t_ten_ms = 0;
unsigned char state = 0;

void charge(){
	DDRB = 0b00001111;
	PORTB = 0b00001111;
}

void discharge(){
	DDRB = 0x00;	
	PORTB = 0x00;
}

unsigned char measure(){
	return 0x0F &!PINB;
}

void unlocked(){
	// spravny kod
	PORTD |= 0x00000010;
	DDRD = 1<<DDD0;
	_delay_ms(5000);
}

void locked(){
	// nespravny kod
	int i;
	for(i=0; i<4; i++) {
		PORTD = PORTD & 0xFE;
		_delay_ms(20);
		PORTD = 1<<PD0;;
		_delay_ms(20);
	}
	PORTD = PORTD & 0xFE;
}


void check_state(unsigned char input){
	if (combination[state] != input) {
		ok = 1;
	}
}

// using delay
void check_code() {

	for(state=0; state<6;state++) {
		charge();
		_delay_ms(300);
		discharge();
		_delay_ms(10);
		unsigned char input = measure();
		if (combination[state] != input) {
			ok = 1;
		}
		_delay_ms(190);
	}

	if(ok == 0) {
		unlocked();
	} else {
		locked();
	}
}


// using timer0
void timer0_init()
{
    //1024 prescaler
    TCCR0B |= (1 << CS02)|(1 << CS00);
    // initialize counter
    TCNT0 = 0;
	// enable counter overflow
	TIMSK |= (1 << TOIE0);
}

void timer0_stop() {	
	TIMSK = TIMSK & 0b11111101;
	t_ten_ms = 0;
	t_ovf_cnt = 0;

	if(ok == 0) {
		unlocked();
	} else {
		locked();
	}
}

// timer0 overflow interrupt
ISR(TIMER1_OVF_vect) {

    t_ovf_cnt++;

	if (t_ovf_cnt = 77){
		t_ten_ms++;
		t_ovf_cnt = 0;
	}
	// 300 ms
	if (t_ten_ms = 30){
		discharge();
		return;
	}
	// 310 ms
	if (t_ten_ms = 31){
		check_state(measure());
		state++;
		return;
	}
	// 500 ms
	if (t_ten_ms = 50){
		charge();
		t_ten_ms = 0;
		if (state>5) {
			timer0_stop();
		}
		return;
	}
}


// external interrupt
ISR(INT0_vect) {
	DDRD = 1<<PD0;
	PORTD = 1<<DDD0;

	// USING TIMER
	timer0_init();

	// USING DELAY INSTEAD OF TIMER
	// check_code();
}


int  main(void){
	DDRD = 1<<PD2; // PD2 (INT0) as button input
	MCUCR = 1<<ISC01 | 1<<ISC00; // rising edge
	GIMSK = 1<<INT0;	 // enable external interrupt 0
	sei(); // global interrupt enable


	while(1){
		sleep_mode();
	}
}

[editovat] Předchozí příspěvky

[editovat] Cvičení č. 2

	.EQU DDRB = $17		; DDRB address
	.EQU PORTB = $18	; PORTB address

	.EQU LED_X = 0		; LED_X is on PB0, pin 12 of ATtiny2313
	.EQU LED_Y = 1		; LED_Y is on PB1, pin 13 of ATtiny2313



	SBI	DDRB, LED_X	; SBI - Set Bit in I/O Register ; nastavuje vystup
;	HOP:
	SBI	PORTB, LED_X ; nastavuje ze tam bude jednicka
;	CBI POTRB, LED_X ;
;	RJMP HOP


[editovat] 1. Domácí úkol (od jiného autora) - program odzkoušen v simulátoru AVR Studio 4

.NOLIST
.INCLUDE "m88def.INC"
.LIST

;PORTC
.EQU Button = 0				; na PC0 tlacitko, spina pull-up rezistor na zem.
.EQU Trimmer = 1 			; vstup z trimru, komparator ADC1

;PORTD
.EQU Light = 0				; port PD0 ovlada osvetleni interieru
.EQU Board = 1				; port PD1 ovlada osvetleni palubovky

;NADEFINOVANI REGISTRU
.DEF Temp = r16				; docasny registr pro prenos hodnot		
.DEF PWM_In = r17			; hodnota PWM pro osvetleni interieru
.DEF PWM_Board = r18		; hodnota PWM pro palubni desku
.DEF Symptoms = r19			; registr priznaku
.DEF T5 = r20				; citac pro 5s osvetleni interieru
.DEF T2 = r21				; citac pro postupne zhasinani behem 2s

;SYMPTOMS
.EQU S_Timer1 = 0			; bit0 registru Symptoms rika, zda doslo k preruseni od Timer1
.EQU S_In_ON = 1			; bit1, zda sviti svetlo interieru
.EQU S_Second = 2			; bit2, zda probiha druhy cyklus citani registru T5 
.EQU S_Twilight = 3			; bit3, zda probiha 2s proces stmivani

;KONSTANTY PRO PWM
.EQU PWM_In_Pulse = 40		; PWMfreq 25 kHz pro osvetleni interieru
.EQU PWM_Board_Pulse = 36	; PWMfreq 27,8kHz pro osvetleni palubi desky
	
;RESET A INTERUPTION VEKTORY
.ORG 0x000 
	RJMP START 				; reset vektor
.ORG 0x00D
	RJMP Timer1_Over		; preruseni pri preteceni Timer1

;PORTY
	LDI Temp, 0b11111100	; PC0 je vstup ADC a PC0 je vstup pro Button
	OUT DDRC, Temp			; 
	LDI Temp, 0b00000001	; vystupy do 0 a interni pull-up pro PC0
	OUT PORTC, Temp			; 
	SER Temp				; PORTD a PORTB jako vystupy 
	OUT DDRD, Temp			; 
	OUT DDRB, Temp			; 
	CLR Temp				; PORTD a PORTB nastavit do 0
	OUT PORTD, Temp			; 
	OUT PORTB, Temp			


;----------------------------------------------------------------------------------------------------

START:

;inicializace zasobniku 
	LDI Temp,high(RAMEND)		 
	OUT SPH, Temp			
	LDI Temp,low(RAMEND)		
	OUT SPL, Temp	
			 

;----PWM----PWM----PWM----PWM----PWM----PWM----PWM----PWM----PWM----PWM----

;INTERIER

	LDI Temp, 0b00100011		; Fast PWM Mode, OUT on OC0B, non Inverting
	OUT TCCR0A, Temp		 
	LDI Temp, 0b00001001		; WGM2:1 (Fast PWM), CS2..0:001 (internal clock, prescale=1)
	OUT TCCR0B, Temp
	LDI Temp, PWM_In_Pulse		; load number of clock pulses for 1 PWM period
	OUT OCR0A, Temp

	IN  Temp, TCCR0A			; odpojeni vystupu od PWM generatoru (standartni vystup v 0) 
	CBR Temp, 0x10		
	OUT TCCR0A, Temp			; 

;BOARD

	LDI Temp, 0b00100011		; Fast PWM Mode, OUT on OC0B, non Inverting
	STS TCCR2A, Temp			; 
	LDI Temp, 0b00001001		; WGM2:1 (Fast PWM), CS2..0:001 (internal clock, prescale=1)
	STS TCCR2B, Temp			; 
	LDI Temp, PWM_Board_Pulse	; load number of clock pulses for 1 PWM period
	STS OCR2A, Temp				; 

;ADC			
	LDI Temp, 0b11100000		; Vniřtní reference 1,1V, kapacitor na AREF,zarovnání Left, ADC0
	STS ADMUX, Temp				; 
	LDI Temp, 0b10000100		; ADC enabled, int. off, autotriger off, prescaler 16 (62,5kHz)
	STS ADCSRA, Temp			; 
	CLR Temp					; deaktivace autotrigeru
	STS ADCSRB, Temp			; 
	LDI Temp, 0x02				; disable digital input buffer for pin ADC1 (snizeni spotreby)
	STS DIDR0, Temp				; 

;PRERUSENI OD Timer1
	LDI Temp, 0xD8				; nastavi Timer1 na 10000 (10E+4 * 1us = 10ms)
	STS TCNT1H, Temp		
	LDI Temp, 0xF0		
	STS TCNT1L, Temp			; 	
	CLR Temp					; CLR TCCR1A
	STS TCCR1A, Temp			; 
	LDI Temp, 0b00000001		; Clock Select -> CLKio/1 (no prescaler)
	STS TCCR1B, Temp			; 
	STS TIMSK1, Temp			; povoleni preruseni pri preteceni Timer1
	SEI							; povoleni preruseni	
	CLR Temp					; vynulovani hodnoty T2
	MOV T2, Temp				; 

;-----MAIN PROGRAM------------------------------------------------------------------------------

Main:
	SBRS  Symptoms, S_Timer1	; bylo preruseni od Timer1?
	RJMP  Main					; NE preskoc testovani tlacitka a ADC, hodnoty PWM se nemeni
	CLT							; ANO, zrus priznak preruseni od Timer1 
	BLD   Symptoms, S_Timer1	; 
	RCALL Butt					; otestuj, zda je stisknute tlacitko
	SBRC  Symptoms, S_In_ON		; sviti interier?
	RCALL Watcher				; ANO, dekrementuj hodnotu T5 nebo T2
	OUT   OCR0B, PWM_In			; nastav PWM interieroveho svetla podle aktualni hodnoty
	RCALL AD_Convert			; zjisti hodnotu napeti z potenciometru
	STS   OCR2B, PWM_Board		; nastav PWM svetla palubni desky podle aktualni hodnoty
	RJMP  Main


;-----SECONDARY FUNCTIONS---------------------------------------------------------------------------------------------

Timer1_Over:					; ulozeni Status registru do zasobniku
	PUSH Temp					;
	IN   Temp, SREG				;
	PUSH Temp					; reinicializace Timer1
	LDI  Temp, 0xD8				; nastav Timer1 na hodnotu 10000 (10E+4 * 1us = 10ms)	
	STS  TCNT1H, Temp		
	LDI  Temp, 0xF0			
	STS  TCNT1L, Temp			; 
	SET							; nastav priznak, ze doslo k preruseni od Timer1 
	BLD  Symptoms, S_Timer1		; 								
	POP  Temp					; obnoveni Status registru ze zasobniku pro navrat z preruseni
	OUT  SREG, Temp		
	POP  Temp		 			; 
	RETI

Butt:							; testovani tlacitka
	SBIC PINC, Button			; je tlacitko stisknute?
	RET							; NE, ukonci testovani tlacitka
	SET				  			; ANO, nastav priznak, ze interier sviti
	BLD Symptoms, S_In_ON	;
	LDI PWM_In, PWM_In_Pulse 	; PWM na nejvetsi stridu	
	IN  Temp, TCCR0A		  	; pripojeni PWM generatoru na vystup
	SET				
	BLD Temp, 5			
	OUT TCCR0A, Temp		  	; 
	LDI Temp, 0xFF			  	; ulozi do T5 hodnotu 255
	MOV T5, Temp		  		; 
	CLT				 			; 
	BLD Symptoms, S_Second 		; vynuluj priznak Second - nedoslo k druhemu pricitani T2
	BLD Symptoms, S_Twilight	; neprobiha proces stmivani
	RET

Watcher:
	SBRC Symptoms, S_Twilight	; bezi proces Twilight?
	RJMP Twilight				; ANO, prejdi na Twilight
	DEC  T5						; NE, bezi 5s plneho svitu, dekrementuj T5
	BRNE Return 				; kdyz neni nula, konec
	SBRC Symptoms, S_Second		; kdyz je nula, bezel uz druhy cyklus?
	RJMP Twilight				; ANO, skoncilo 5s plneho svitu, zacni stmivat
	SET							; NE, nastav priznak, ze T5 jde znovu
	BLD  Symptoms, S_Second		; 
	RJMP Return					; 

Twilight: 	
	SET							; nastaveni priznaku, ze odted dochazi ke stmivani
	BLD Symptoms, S_Twilight	; 		
	INC  T2						; zvys hodnotu T2, hodnota 10 -> 100ms
	MOV  Temp, T2				; T2 nejde porovnat primo instrukci CPI (r1)
	CPI  Temp, 0x0A				; testuj na 10
	BRNE Return					; kdyz neni 10, nic se nedeje
	CLR  Temp					; kdyz je 10, zacni znova
	MOV  T2, Temp				; 
	SUBI PWM_In, 0x02			; odecti hodnotu 2 od aktualniho svitu (20 kru)
	TST  PWM_In					; otestuj, zda doslo k nule?
	BRNE Return					; NE, vrat se zpet
	CLT							; ANO, stmivani dokonceno (interier je zhasnuty)
	BLD  Symptoms, S_In_ON		; zrus priznak stmivani 

	IN  Temp, TCCR0A			; odpojeni vystupu od PWM generatoru (standartni vystup v 0)
	CLT				
	BLD Temp, 5 				; CLR 5.bit
	OUT TCCR0A, Temp			; 

AD_Convert:
	CLR Temp					; odstran vysledek posledniho prevodu
	STS ADCH, Temp				; 
	LDS Temp, ADCSRA			; prekopiruj ADCSRA do Temp
	SET							; nastav 6.bit, tj. zacatek AD prevodu
	BLD Temp, 6					; 
	STS ADCSRA, Temp			; spusteni AD prevodu

AD_Run:
	LDS  Temp, ADCSRA			; prekopiruj ADCSRA do Temp
	SBRC Temp, 6				; je ADSC nastaven?
	RJMP AD_Run					; ANO, testuj znovu
								; NE, prevod skoncil, vysledek ulozen do ADCH

; uprava vysledku pro pouziti v PWM
	LDS Temp, ADCH				; hodnotu H bytu z AD prevodu do Temp
	LSR Temp					; /2
	LSR Temp					; /2
	LSR Temp					; /2
	MOV PWM_Board, Temp			; hodnota ADCH/8 do PWM_Board
	LDI Temp, 0x04				;
	ADD PWM_Board, Temp			; pricte k PWM_Board 4
	RET

Return:
	RET
Osobní nástroje