Uživatel:Rakosma2

Z MAM wiki

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


Obsah

Semestrální práce Pomůcka pro třídění odporů

Spolupráce s Jakub Macháček

Zadání

Pomůcka na třídění odporů se kterou lze rychle roztřídit odpory použité během cvičení v kontaktních polích. Odpor se připojí k zařízení a rozsvítí se jedna z 10 LED, která určí, do které krabičky odpor patří.

Postup řešení

Využijeme funkci AD převodníku implementovanou v našem procesoru. Zadaný odpor budeme měřit pomocí metody odporového děliče, kdy pomocí referenčního odporu budeme zjišťovat velikost napětí na daném rezistoru, a dle toho budeme schopni posoudit velikost odporu.

Velikost odporů

Posuzované rezistoy rozdělíme do deseti kategorií, dle předem daných vypočtených hodnot, které dosáhneme po konverzi převodníku. Tyto bitové hodnoty pak následně posuzujeme, a dle velikosti uloženého čísla budeme rozsvěcet patřičnou diodu.

Velikost odporu [Ω] Binární hodnota
< 80 < 2
80 - 500 2 - 12
500 - 900 12 - 21
900 - 5k 21 - 85
5k - 9k5 85 - 124
9k5 - 50k 124 - 213
50k - 95k 213 - 231
95k - 500k 231 - 250
500k - 1M 250 - 253
> 1M > 253

Schéma zapojení

Soubor:Schema odpory.jpg

Zapojení registrů přerušení a AD převodníku

Soubor:preruseni.png

v registru SMCR je nutné nastavit jaký druh režimu spánku je povolen, a povolit režim spánku jako takový. V registru PCICR se nastavují možnosti přerušení od jednotlivých bran, zatímco v PCMSK jednotlivé bity na nichž přerušení budeme hlídat.

Soubor:admux.png v registru admux nastavíme více věcí, konkrétně referenční napětí pomocí REFS0 a REFS1. V části ADLAR zvolíme zarovnání výsledků konverze, jsou zde dva druhy, tak je nutné vědět který požíváme, abychom data správně zpracovali. Nakonec v části MUX zvolíme, na kterém pinu bude připojen náš dělič napětí.

Soubor:adcsra.png

V registru ADCSRA provedeme poslední nutná nastavení. ADEN slouží k zapínání a vypínání převodu, to je možné i během konverze. ADSC startuje konverzi jako takovou. ADIF značí přerušení, ADIE povolení k přerušení od dokončení konverze. ADPS je pak dělička kmitočtu vůči systémovému.

Program

.INCLUDE "m88def.inc"
.org 0x0000 ;hlavni program/preruseni RESET
	rjmp main
.org 0x0004	; preruseni od stisknuteho tlacitka
	rjmp tlacitko
.org 0x0015 ;preruseni ADC conversion complete
	rjmp vyhodnoceni
main:
; Stack pointer init: 
	ldi r16,high(RAMEND); Main program start
	out SPH,r16 ; Set Stack Pointer to top of RAM
	ldi r16,low(RAMEND)
	out SPL,r16
; povoleni vystupu vsech diod
	Ldi R16, 0xFF
	OUT DDRB, R16
	sbi DDRD, 6
	sbi DDRD, 7
	Ldi R16, 0
	OUT PortB, R16
	cbi PortD, 6
	cbi PortD, 7

; nastaveni ADC
; viz. datasheet str.254,...
; aktivni ADC bude ADC5,  na pinu PORTC5 [napajeni Vcc + je potreba pripojit kapacitor na pin AVCC (pin 20)]
	clr R27				; vrchnich 8 bitu 16bit adresy(RAM)
	LDI R26, ADMUX		; spodnich 8 bitu 16bit adresy(RAM) [primo cast pameti pro ADMUX]
	ldi R17, 0b01100101 ; nasteveni bitu, ktere budou nastaveny na vyse definovanou adresu
	ST X, R17			; zapis hodnoty na danou adresu
	

	clr R27	
	ldi R26, ADCSRA		; 
	ldi R16, 0b00001000	; vypnuty ADC, ale zapnuta moznost preruseni
	ST X,R16
	
; nastaveni sleep modu
  	ldi r16,0b00000011 ; Povolení sleep modu, a konkretni sleep mode
	out SMCR,r16 	   ; Nahrání do SMCR

; povoleni preruseni od portu C
	ldi r26, PCICR
	clr r27
	ldi r16,0b00000010 ; Povolení přerušení c int 7-14
	st X, r16
; preruseni povoleno od bitu 1, portu C
	ldi r26, PCMSK1
	clr r27
	ldi r16,0b00000010;povoleni preruseni od pinu 1 portu C
	st X, r16
	cbi DDRC, 1 	;pin C.1 nastaven jako vstupni s urovni "1"
	sbi PortC, 1

	sei; interrupt enable
	rjmp spanek

V nastavení výše vidíme práci s PCICR a PCMSK, nastavení jednotlivých bitů. Využití st X

spanek: 
	sleep		; prikaz na uspani
	nop			; vykona cykl, ale nic neudela(aby se hybal cas)
	rjmp spanek

;////OBSLUHY PRERUSENI////;
tlacitko:
	rcall wait
;zapnuti konverze ADC
	ldi R26, ADCSRA
	ldi R27, 0
	LD R16, X
	ldi R17, 0b11000000
	OR R16, R17	; R16b00001000 ; R17b11000000
	ST X, R16
	reti		;navrat s povolenim preruseni

vyhodnoceni:
	ldi R26, ADCH	;pokud vysledek 8 bit a min, cist jen ADCH[jinak nejprve cist ADCL a pak ADCH]
	ldi R27, 0
	LD R20, X ;hodnota konverze je uložena do registru R20
;vypnuti ADC
	ldi R26, ADCSRA
	ldi R27, 0
	LD R16, X
	ldi R17, 0b01111111
	AND R16, R17
	ST X, R16

Nastavení analogově digitálního převodníku, způsobu zpracování dat

ldi R21, 0
	ldi R22, 0

	 cpi R20, 2		;compare R20mensi c=0, R20vetsi c=1 (c...carry flag)
	 brcc dd1		;kdyz je c=0 tak neskoci (kdyz c=1 skoci na dd1)
	 ;LOW stav(R<80)
	 LDI R22, 0b01000000
	 rjmp ddend
dd1: CPI R20, 12
	 brcc dd2
	 ;(80ohm - 500ohm)
	 LDI R21, 0b00000001 
	 rjmp ddend
dd2: CPI R20, 21
	 brcc dd3
	 ;(500ohm - 900ohm)
	 LDI R21, 0b00000010 
	 rjmp ddend
dd3: CPI R20, 85
	 brcc dd4
	 ;(900ohm - 5kohm)
	 LDI R21, 0b00000100
	 rjmp ddend
dd4: CPI R20, 124
	 brcc dd5
	 ;(5kohm - 9,5kohm)
	 LDI R21, 0b00001000
	 rjmp ddend
dd5: CPI R20, 213
	 brcc dd6
	 ;(9,5kohm - 50kohm)
	 LDI R21, 0b00010000
	 rjmp ddend
dd6: CPI R20, 231
	 brcc dd7
	 ;(50kohm - 95kohm)
	 LDI R21, 0b00100000
	 rjmp ddend
dd7: CPI R20, 250
	 brcc dd8
	 ;(95kohm - 500kohm)
	 LDI R21, 0b01000000
	 rjmp ddend
dd8: CPI R20, 253
	 brcc dd9
	 ;(500kohm - 1Mohm)
	 LDI R21, 0b10000000
	 rjmp ddend
dd9: ;HIGH stav (>1Mohm)
	LDI R22, 0b10000000
ddend: 
OUT PORTB, R21	;
	OUT PORTD, R22	; zobrazeni malych/velkych nemeritelnych odporu
	reti

Vzdy zkontrolujeme, jaka hodnota je ulozena, primo porovname a nasledne rozhodneme, ejstli posleme signal na diodu, nebo budeme testovat dale

WAIT:
	LDI	R16, 4
WAIT1:	INC	R1
	BRNE	WAIT1
	INC	R2
	BRNE	WAIT1
	DEC	R16
	BRNE	WAIT1
	RET

obsluha preruseni stejna jako v zakladnich ulohach MAM


Domácí úkol č.2

Zadání

Navrhněte zapojení potřebných propojení a dekodérů (přednostně na základě připravených 74HCT138 a příp. dodatečné logiky) pro rozšíření procesoru ATmega64 o paměť a vstupní a výstupní porty podle schémat a podle požadovaných rozsahů adres. Soubor:ATmega64-1ext.png

Řešení

Úkol byl odevzdáván papírově.

Zapojení LED displeje a naprogramování pomocí C

Spolupráce s Jakub Macháček a Jan Kolomazník

Ukázka programu

#include <avr/interrupt.h>
#include <avr/sleep.h>

#define SER		PD5
#define SRCLK	PD6
#define RCLK	PD7
#define SRCLR	PB0

// global constants and variables
// static code table used for 7-segment led display decoding (common anode)
unsigned char code [] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x98,
				 		  0x88, 0x80, 0xC6, 0xC0, 0x86, 0x8E };
/*unsigned char code [] = { 0x3F, 0x06, 0x5B, 0x4F, 0x64, 0x6D, 0xFC, 0x07, 0x7F, 0x67,
				 		  0xF7, 0x7F, 0x39, 0x3F, 0x79, 0x71 };*/

// character to show on display
static volatile unsigned char anumber = 0;
// Interrupt vector table is created by compiler
// the ISR macro defines interrupt service handlers

// Pin change interrupt 1
// keyboard handler
ISR(PCINT1_vect)
{
	unsigned char keys[10];
	unsigned char nkeys = 0;
	register unsigned char column;

//    DDRD 	&= 0b00000001;
	DDRD	&= 0b11110001;
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 4))
		keys[nkeys++] = 1;
	if (!(PINC & 8))
		keys[nkeys++] = 2;
	if (!(PINC & 16))
		keys[nkeys++] = 3;

	DDRD	&= 0b11110000;
	DDRD	|= (1 << PD1);
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 4))
		keys[nkeys++] = 4;
	if (!(PINC & 8))
		keys[nkeys++] = 5;
	if (!(PINC & 16))
		keys[nkeys++] = 6;

	DDRD	&= 0b11110000;
	DDRD	|= (1 << PD2);
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 4))
		keys[nkeys++] = 7;
	if (!(PINC & 8))
		keys[nkeys++] = 8;
	if (!(PINC & 16))
		keys[nkeys++] = 9;

	DDRD	&= 0b11110000;
	DDRD	|= (1 << PD3);
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero
	if (!(PINC & 8))
		keys[nkeys++] = 0;

	DDRD 	|= 0b00001111;		// configure rows as outputs
	PORTD 	&= 0b11110000;		// set keyboard rows at port D to zero

	if (nkeys > 0) {
		OCR1A = keys[0] * 100;
		TCNT1 = 0;
	}
}

// Timer/Counter1 Compare Match A
// the value shown on the display will be updated here
ISR(TIMER1_COMPA_vect)
{
	unsigned char tmp = code[anumber];
	volatile char loopcounter = 8;

	do {
		PORTD &= ~(1 << SRCLK);			// assert 0 on serial clock line
		if (tmp & 0x80)					// test LSB
			PORTD |= (1 << SER);		// if 1, assert 1 on serial data line
		else
			PORTD &= ~(1 << SER);		// assert 0 otherwise
		PORTD |= (1 << SRCLK);			// assert 1 on serial clock line - rising edge writes bit into the serial shift register
		tmp <<=  1;					// shift right to proceed next bit
		loopcounter--;
	} while (loopcounter > 0); 
	PORTD &= ~(1 << RCLK);				// toggle parallel register clock 0-1 to make a rising edge
	PORTD |= (1 << RCLK);
	
	// update value to display for next time
	if (anumber < 15)
	    anumber++;
	else
		anumber = 0;
}

void main(void)
{
	// keyboard (and serial shift register connection) ports init
	DDRD 	|= 0b11101111;		// configure rows as outputs (PD0 ... PD3), serial shift register pins PD5 .. PD7
	PORTD 	= 0;				// set port D to zero
	DDRC	= 0;				// configure port C as input port
	PORTC	|= 0b00011100;		// activate pul-up resistors on three columns

	DDRB	|= (1 << SRCLR);	// configure PB0 as output - serial shoft register clear
	PORTB	|= (1 << SRCLR);	// toggle PB0 1-0-1 to clear the serial shift register
	PORTB	&= ~(1 << SRCLR);
	PORTB	|= (1 << SRCLR);

	// an interrupt masking must be here
	// keyboard interrupt
	PCICR 	= (1 << PCIE1);		// Pin change interrupt control register, Pin change interrupt enable 1
	PCMSK1 	= 0b00011100;		// allow pin change interrupt on portC bits 2,3,4

	// timer configuration
	TCCR1A	= 0;				// OC1A/OC1B disconnected, CTC bits WGM11, WGM10
	TCCR1B 	= (1 << CS12) | (1 << CS10) | (1 << WGM12);
								// CTC mode, prescaler division factor 1024
	OCR1A 	=  976;				// timer compare value

	TIMSK1 = (1 << OCIE1A);		// enable timer interrupt

	set_sleep_mode(SLEEP_MODE_IDLE);
	sei();						// set Global Interrupt Enable!!!

	while (1) {
		sleep_cpu();
	}
}

Ukázka funkčního zapojení:

Sedmisegmentovka


Domácí úkol č. 1

Spolupráce s Jakub Macháček

Zadání

Zvolte vhodné zapojení a procesor a v assembleru naprogramujte 2 na sobě nezávislé PWM regulace osvětlení do auta. Jedna je pro vnitřní osvětlení, po sepnutí dveřního kontaktu nastaví okamžitě plný svit, po rozpojení ještě asi 5 s plný svit a následuje asi 2 sekundy dosvit s poklesem od maxima do nuly, druhá PWM je pro regulované osvětlení palubní desky, vstup potenciometr, výstup výkonová PWM regulace asi 10 % až 100 %. Napájecí napětí auta je 12 V, špičky rušení mohou dosáhnout až 20 V.


Inicializace

.nolist
.include "m88def.inc"
.list

;*********************************************************************
;************************ 1.Domaci Ukol ******************************
;*********************************************************************

.equ PWM_door = 40	; PWMfreq 25  kHz pro osvetleni interieru
.equ PWM_ADC = 70	; PWMfreq 14.3kHz pro osvetleni palubi desky


;****************** reset a interruption vektory *********************
.org 0x000 
	rjmp Start 				; reset vektor
.org 0x00D
	rjmp Tim1_Ovf			; preruseni pri preteceni TMR1

;*********************************************************************


Start:

;********************** inicializace portu ***************************

	ldi	r16, 0b011110		; PC0 je vstup ADC a PC5 je vstup pro tlacitko
	out	DDRC, r16			;
	ldi	r16, 0b000101		; vystupy do 0 a interni pull-up pro PC5
	out	PORTC, r16			; ok
	ser	r16				    ; PORTD a PORTB jako vystupy (implicitne v 0)
	out	DDRD, r16			; ok
	out	DDRB, r16			; ok
	clr	r16			    	; PORTD a PORTB jsou vsechny v 0
	out	PORTB, r16			; ok
	out	PORTD, r16			; ok



;********************* inicializace PWM ******************************
;----- TMR0 
	ldi r16, 0b00100011	; Fast PWM Mode, out on OC0B, non Inverting
	out TCCR0A, r16		; 
	ldi r16, 0b00001001	; WGM2:1 (Fast PWM), CS2..0:001 (internal clock, prescale=1)
	out TCCR0B, r16
	ldi r16, PWM_door; load number of clock pulses for 1 PWM period
	out OCR0A, r16
;----- TMR2 
; jako TMR0, jen jiny zpusob, protoze registry nejsou dostupne pomoci "out" nepouzivam TIMER1 - je 16ti bitovej.
; timer 0 a 2 sou stejny 8bitovy
	ldi	r16, 0b00100011	; Fast PWM Mode, out on OC0B, non Inverting
	sts	TCCR2A	, r16		; ok
	ldi	r16, 0b00001001	; WGM2:1 (Fast PWM), CS2..0:001 (internal clock, prescale=1)
	sts	TCCR2B, r16		; ok
	ldi	r16, PWM_ADC; load number of clock pulses for 1 PWM period
	sts	OCR2A, r16

;******************* inicializace preruseni *************************

 ldi r26, PCICR ; dam adresu do R26 PCICR in Y low
 clr r27 ; load high byte with 0
 ldi r16,0b00000010 ; aktivace preruseni na pinech PCINT 14-8
 st X, r16 ; store new PCINT1
 ldi r26, PCMSK1 ; ulozim adresu PCMSK1
 clr r27 ; load high byte with 0
 ldi r16,0b00011100 ; Vyberu na kterych pinech PCINT 14-8 reaguju na preruseni 2,3,4
 st X, r16 ; store new PCMSK1
 sei ; Enable interrupts	
 
 			

;********************** inicializace ADC (datasheet) *****************

	ldi	r16, 0b11100000 	; Zleva 1-vlastni 1,1V reference;1 s externim Cap na pinu AREF ; 1 zaokrouhleni doleva- asi fuk
							;  bit 4-nedefinovan; 3-0  nastaveni ADC u nas ADC0
	sts	ADMUX, r16			; ok
	ldi	r16, 0b10000110 	; ADC enabled, 3bit rozhoduje jestli to bude reagovat na preruseni 1 ano 0 ne,autotriger off,
							; prvni 3 bity 0-2 urcuje prescaler 2-128 My 64
	sts	ADCSRA, r16	    	; ok  ADC control and status register A
	clr	r16			    	; autotriger source -> autotriger je off, takze jen pro poradek

	sts	ADCSRB, r16	    	; ok

Hlavní část

;************************* main *****************************************************
Main:
rjmp Main     ; nekonecna smycka, cekame na interupt


Tim1_Ovf:

; testovani tlacitka
    sbis PINC,2  ; preskoc ak je spinac vypli
	rjmp Tim1_Ovf
	rcall Zap
    sbic PINC,2  ; preskoc jestli je spinac zapli
	rjmp Tim1_Ovf
	rcall Vyp
	reti

;*********************** Tlacitko ******************************************

Zap:
ldi r16,0b00101000
out OCR0A, r16   ; zapnuti spinace
sbi PORTB,0   ; nastaveni minulyho stavu jako 1
ret

Vyp: ; vypnuty spinac
sbic PINB,0  ; preskoc jestli i v minulem kroku byl vypli
rcall Dim    ; 5s cekani + 2s zatemnovani
sbic PINB,0  
ldi r16,0b00000000
out OCR0A, r16   ; vypnuti spinace
cbi PORTB,0

ret


Dim:
ldi r16,0b00101000
out OCR0A, r16  ; nastaveni vystupu na zapli
rcall wait5sec
ldi r16,0b00100111
ldi r17,0b00000000
out OCR0A, r16


  	loop:   ; zatemnovaci smycka
   	 	rcall wait50ms    ;(2s/40 kroku v PWMku = 50ms)
		dec r16
		out OCR0A, r16
		cpse r16,r17 
	rjmp loop
  
cbi PORTB,0
ret

Čekací smyčky

wait50ms:

ldi r18, 0b00000000    ; horni bit
ldi r19, 0b00000000    ; spodni bit
ldi r20, 0b11000011    ; pro porovnani horniho bitu, 50000 cyklu = 50ms
ldi r21, 0b00000000    ; pro porovnani preteceni spodniho bitu
loop1:
inc r19;
cpse r19,r21
inc r18
cpse r18,r20
rjmp loop1


ret

wait5sec:

ldi r21, 0b00000000  
ldi r22, 0b01100100  
loop3:
rcall wait50ms
inc r21;
cpse r21,r22
rjmp loop1

ret

Regulace větráčku, maticová klávesnice:

Spolupráce s Jakub Macháček

.INCLUDE "m88def.inc"

.EQU PWM_PULSES = 36 ; value for 27.8 kHz PWM
;


.INCLUDE "m88def.inc"

.ORG 0x0000
rjmp Main ; Reset Handler

.ORG 0x0008
rjmp isr1 ; PCINT1 Handler


Main:

; Stack pointer init:
ldi r16,high(RAMEND); Main program start
out SPH,r16 ; Set Stack Pointer to top of RAM
ldi r16,low(RAMEND)
out SPL,r16


; Hardware initialization

; Keyboard init:
cbi DDRC, 2 ; set inputs for keyboard (COL1-3)
cbi DDRC, 3
cbi DDRC, 4

sbi PORTC, 2 ; set internal Pull-Ups for keyboard
sbi PORTC, 3
sbi PORTC, 4

sbi DDRD, 0 ; set driving outputs for keyboard
sbi DDRD, 1 ; (ROW1-ROW4)
sbi DDRD, 2
sbi DDRD, 3

cbi PORTD, 0 ; log. 0 on all rows
cbi PORTD, 1
cbi PORTD, 2
cbi PORTD, 3




PWM_INIT:
ldi R17, 0b00100011 ; Fast PWM Mode, out on OC0B, non Inverting
out TCCR0A, R17 ;
ldi R17, 0b00001001 ; WGM2:1 (Fast PWM), CS2..0:001 (internal clock, prescale=1)
out TCCR0B, R17
ldi R17, PWM_PULSES ; load number of clock pulses for 1 PWM period
out OCR0A, R17  

sbi DDRD, 5 ; set pin 11 as PWM output OC0B (PD5 pin)




ldi r26, PCICR ; load address of PCICR in Y low
clr r27 ; load high byte with 0
ldi r16,0b00000010 ; activate PCINT1
st X, r16 ; store new PCINT1

ldi r26, PCMSK1 ; load address of PCMSK1 in Y low
clr r27 ; load high byte with 0
ldi r16,0b00011100 ; allow pin change interrupt on portC bits 2,3,4
st X, r16 ; store new PCMSK1

sei ; Enable interrupts




ldi r16,0b00000001 ; Idle mode
out SMCR,r16 ; Sleep mode set




loop:
sleep ; now AVR sleeps
nop ; return from Interrupt to this instruction
rjmp loop ; and sleep again





isr1:
rcall KEYPRESS

mov R17, R16
lsl R17
lsl R17 ; multiply key number by 4 for 10 steps in 40 clock pulses of PWM
out OCR0B, R17  ; output pulse "high" lenght to PWM compare unit

reti ; return from Interrupt


; Keyboard decoding:

KEYPRESS:
KEY0:
sbi PORTD, 0
sbi PORTD, 1
sbi PORTD, 2
cbi PORTD, 3 ;log. 0 to the row with *, 0, #, D
sbic PINC, 3
rjmp KEY1
ldi R16, 0 ;pressed key 0
rjmp KEYRET
KEY1:
cbi PORTD, 0 ;log. 0 to the row with 1, 2, 3, A
sbi PORTD, 1 ;log. 1 on another three
sbi PORTD, 2
sbi PORTD, 3
sbic PINC, 2
rjmp KEY2
ldi R16, 1 ;pressed key 1
rjmp KEYRET
KEY2:
sbic PINC, 3
rjmp KEY3
ldi R16, 2
rjmp KEYRET
KEY3:
sbic PINC, 4
rjmp KEY4
ldi R16, 3
rjmp KEYRET

KEY4:
sbi PORTD, 0
cbi PORTD, 1 ;log. 0 to the row with 4, 5, 6, B
sbi PORTD, 2
sbi PORTD, 3
sbic PINC, 2
rjmp KEY5
ldi R16, 4 ;pressed key 4
rjmp KEYRET
KEY5:
sbic PINC, 3
rjmp KEY6
ldi R16, 5
rjmp KEYRET
KEY6:
sbic PINC, 4
rjmp KEY7
ldi R16, 6
rjmp KEYRET

KEY7:
sbi PORTD, 0
sbi PORTD, 1
cbi PORTD, 2 ;log. 0 to the row with 7, 8, 9, C
sbi PORTD, 3
sbic PINC, 2
rjmp KEY8
ldi R16, 7 ;pressed key 7
rjmp KEYRET
KEY8:
sbic PINC, 3
rjmp KEY9
ldi R16, 8
rjmp KEYRET
KEY9:
sbic PINC, 4
rjmp KEYRET
ldi R16, 9

KEYRET:
cbi PORTD, 0 ; log. 0 on all rows for next key press catch
cbi PORTD, 1
cbi PORTD, 2
cbi PORTD, 3
ret


Osobní nástroje