Uživatel:Vlachja5

Z MAM wiki

(Rozdíly mezi verzemi)
Přejít na: navigace, hledání
Řádka 1: Řádka 1:
 +
Céčko ze cvičení / upravené znaky
 +
<pre>
 +
 +
#include <avr/interrupt.h> //definice ISR makra, pokud nedám, tak by neznal přeruščrní
 +
#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, 0x9B, 0x92, 0x93, 0xF8, 0x80, 0x98,
 +
  0x88, 0x80, 0xC6, 0xC0, 0x86, 0x8E };*/
 +
unsigned char code [] = { 0b10000010, 0b10011111, 0b11010000, 0b10010100, 0b10001101, 0b10100100, 0b10100000, 0b10011110, 0b10000000, 0b10001100,
 +
  0b10001000, 0b10100001, 0b11100010, 0b10010001, 0b11100000, 0b11101000 };  //tabulka jaký segmenty mají svítit pro dané číslo (podle pozice v tabulce)
 +
 +
// character to show on display
 +
static volatile unsigned char anumber = 0;  //static - hodnota se nebude menit, volatile: optimalizér ho nebude ignorovat
 +
// Interrupt vector table is created by compiler
 +
// the ISR macro defines interrupt service handlers
 +
 +
// Pin change interrupt 1
 +
// keyboard handler
 +
ISR(PCINT1_vect) //ISR a jako adresu zada symbolické jméno přerušení, za to. Tim enabluju použití makra, to _vect tam je dycky
 +
{
 +
unsigned char keys[10];//pole kam lze ukládat kódy tlačátek,10 bajtů
 +
unsigned char nkeys = 0; //počet stisknutých kláves
 +
register unsigned char column; //register znamená že pokud bude volný registr, nebude proměnnou cpát do zásobníku
 +
 +
//    DDRD &= 0b00000001;//protože mám na D sériovou komunikaci, nesmim se dotýkat ostatních bitů
 +
DDRD &= 0b11110001;//testuju první řádek, ostattní do 3. stavu
 +
PORTD &= 0b11110000; // set keyboard rows at port D to zero, odstranim pull up
 +
if (!(PINC & 4))  //tohle je první sloupeček, odpovídá klávesa 1
 +
keys[nkeys++] = 1;//zapíšu jedničku do keys[0] a pak nkeys inkrementuju, ++ udělá inc, jinak to jde přes ldi...
 +
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;  //vynásobim zpoždění 100 a pošlu do porovnávacího registru
 +
TCNT1 = 0;
 +
}
 +
}
 +
 +
// Timer/Counter1 Compare Match A
 +
// the value shown on the display will be updated here
 +
ISR(TIMER1_COMPA_vect) //časovač 1 - budu porovnávat hodnotu čítače s komparační úrovní v A
 +
{
 +
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); // vlnovka - bitová negace (všechn bity obrátí) 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) // hlavní vstupní bod programu, tam udělám definici
 +
{
 +
// 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); // maskuju jen přerušení PCIE1 (to je název (pořadí) bitu), takže tam d¨ám jedničku rotovanou doleva o to pořadí bitu. Ale je to v podstatě jedno. Pin change interrupt control register, Pin change interrupt enable 1
 +
PCMSK1 = 0b00011100; // allow pin change interrupt on portC bits 2,3,4
 +
 +
// timer configuration - 16 bitů, CTC mód - porovnává hodnoty komp. OCR1A, Když shoda - přerušení a vynulování
 +
TCCR1A = 0; // OC1A/OC1B disconnected, CTC bits WGM11, WGM10
 +
TCCR1B = (1 << CS12) | (1 << CS10) | (1 << WGM12); //| je log součet
 +
// CTC mode, prescaler division factor 1024
 +
OCR1A =  976; // timer compare value, odpovídá zhruba 1 sec; má dvě části OCR1AH, OCR1AL; nejdřív zapsat H a pak L, v C to je jedno
 +
 +
TIMSK1 = (1 << OCIE1A); // enable timer interrupt
 +
 +
set_sleep_mode(SLEEP_MODE_IDLE);
 +
sei(); // set Global Interrupt Enable!!!
 +
 +
while (1) {
 +
sleep_cpu();
 +
}
 +
}
 +
 +
</pre>
 +
 +
 +
Céčko ze cvičení
Céčko ze cvičení
<pre>
<pre>

Verze z 25. 4. 2013, 08:08

Céčko ze cvičení / upravené znaky


#include <avr/interrupt.h>	//definice ISR makra, pokud nedám, tak by neznal přeruščrní
#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, 0x9B, 0x92, 0x93, 0xF8, 0x80, 0x98,
				 		  0x88, 0x80, 0xC6, 0xC0, 0x86, 0x8E };*/
unsigned char code [] = { 0b10000010, 0b10011111, 0b11010000, 0b10010100, 0b10001101, 0b10100100, 0b10100000, 0b10011110, 0b10000000, 0b10001100,
				 		  0b10001000, 0b10100001, 0b11100010, 0b10010001, 0b11100000, 0b11101000 };  //tabulka jaký segmenty mají svítit pro dané číslo (podle pozice v tabulce)

// character to show on display
static volatile unsigned char anumber = 0;  //static - hodnota se nebude menit, volatile: optimalizér ho nebude ignorovat
// Interrupt vector table is created by compiler
// the ISR macro defines interrupt service handlers

// Pin change interrupt 1
// keyboard handler
ISR(PCINT1_vect)		//ISR a jako adresu zada symbolické jméno přerušení, za to. Tim enabluju použití makra, to _vect tam je dycky
{
	unsigned char keys[10];//pole kam lze ukládat kódy tlačátek,10 bajtů
	unsigned char nkeys = 0; //počet stisknutých kláves
	register unsigned char column;	//register znamená že pokud bude volný registr, nebude proměnnou cpát do zásobníku

//    DDRD 	&= 0b00000001;//protože mám na D sériovou komunikaci, nesmim se dotýkat ostatních bitů
	DDRD	&= 0b11110001;//testuju první řádek, ostattní do 3. stavu
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero, odstranim pull up
	if (!(PINC & 4))  //tohle je první sloupeček, odpovídá klávesa 1
		keys[nkeys++] = 1;//zapíšu jedničku do keys[0] a pak nkeys inkrementuju, ++ udělá inc, jinak to jde přes ldi...
	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;  //vynásobim zpoždění 100 a pošlu do porovnávacího registru
		TCNT1 = 0;
	}
}

// Timer/Counter1 Compare Match A
// the value shown on the display will be updated here
ISR(TIMER1_COMPA_vect)		//časovač 1 - budu porovnávat hodnotu čítače s komparační úrovní v A
{
	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);				// vlnovka - bitová negace (všechn bity obrátí) 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)		// hlavní vstupní bod programu, tam udělám definici
{
	// 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);		// maskuju jen přerušení PCIE1 (to je název (pořadí) bitu), takže tam d¨ám jedničku rotovanou doleva o to pořadí bitu. Ale je to v podstatě jedno. Pin change interrupt control register, Pin change interrupt enable 1
	PCMSK1 	= 0b00011100;		// allow pin change interrupt on portC bits 2,3,4

	// timer configuration - 16 bitů, CTC mód - porovnává hodnoty komp. OCR1A, Když shoda - přerušení a vynulování
	TCCR1A	= 0;				// OC1A/OC1B disconnected, CTC bits WGM11, WGM10
	TCCR1B 	= (1 << CS12) | (1 << CS10) | (1 << WGM12); //| je log součet
								// CTC mode, prescaler division factor 1024
	OCR1A 	=  976;				// timer compare value, odpovídá zhruba 1 sec; má dvě části OCR1AH, OCR1AL; nejdřív zapsat H a pak L, v C to je jedno

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

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

	while (1) {
		sleep_cpu();
	}
}


Céčko ze cvičení


#include <avr/interrupt.h>	//definice ISR makra, pokud nedám, tak by neznal přeruščrní
#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, 0x9B, 0x92, 0x93, 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 };  //tabulka jaký segmenty mají svítit pro dané číslo (podle pozice v tabulce)

// character to show on display
static volatile unsigned char anumber = 0;  //static - hodnota se nebude menit, volatile: optimalizér ho nebude ignorovat
// Interrupt vector table is created by compiler
// the ISR macro defines interrupt service handlers

// Pin change interrupt 1
// keyboard handler
ISR(PCINT1_vect)		//ISR a jako adresu zada symbolické jméno přerušení, za to. Tim enabluju použití makra, to _vect tam je dycky
{
	unsigned char keys[10];//pole kam lze ukládat kódy tlačátek,10 bajtů
	unsigned char nkeys = 0; //počet stisknutých kláves
	register unsigned char column;	//register znamená že pokud bude volný registr, nebude proměnnou cpát do zásobníku

//    DDRD 	&= 0b00000001;//protože mám na D sériovou komunikaci, nesmim se dotýkat ostatních bitů
	DDRD	&= 0b11110001;//testuju první řádek, ostattní do 3. stavu
	PORTD	&= 0b11110000;		// set keyboard rows at port D to zero, odstranim pull up
	if (!(PINC & 4))  //tohle je první sloupeček, odpovídá klávesa 1
		keys[nkeys++] = 1;//zapíšu jedničku do keys[0] a pak nkeys inkrementuju, ++ udělá inc, jinak to jde přes ldi...
	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;  //vynásobim zpoždění 100 a pošlu do porovnávacího registru
		TCNT1 = 0;
	}
}

// Timer/Counter1 Compare Match A
// the value shown on the display will be updated here
ISR(TIMER1_COMPA_vect)		//časovač 1 - budu porovnávat hodnotu čítače s komparační úrovní v A
{
	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);				// vlnovka - bitová negace (všechn bity obrátí) 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)		// hlavní vstupní bod programu, tam udělám definici
{
	// 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);		// maskuju jen přerušení PCIE1 (to je název (pořadí) bitu), takže tam d¨ám jedničku rotovanou doleva o to pořadí bitu. Ale je to v podstatě jedno. Pin change interrupt control register, Pin change interrupt enable 1
	PCMSK1 	= 0b00011100;		// allow pin change interrupt on portC bits 2,3,4

	// timer configuration - 16 bitů, CTC mód - porovnává hodnoty komp. OCR1A, Když shoda - přerušení a vynulování
	TCCR1A	= 0;				// OC1A/OC1B disconnected, CTC bits WGM11, WGM10
	TCCR1B 	= (1 << CS12) | (1 << CS10) | (1 << WGM12); //| je log součet
								// CTC mode, prescaler division factor 1024
	OCR1A 	=  976;				// timer compare value, odpovídá zhruba 1 sec; má dvě části OCR1AH, OCR1AL; nejdřív zapsat H a pak L, v C to je jedno

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

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

	while (1) {
		sleep_cpu();
	}
}



Domácí úkol 1:


;--------------------INICIALIZACE--------------------
;----------------------------------------------------

.INCLUDE "m88def.inc"

.ORG 0x000 
	rjmp main ; 

.ORG 0x003 
	rjmp dvere ; přerušení vyvolané otevřením nebo zavřením dveří

.ORG 0x015
	rjmp prevod	;přerušené při hotovém převodu z potenciometru


main: 
	ldi r16,high(RAMEND)  ;nastavení zásobníku
	out SPH,r16
	ldi r16,low(RAMEND)
	out SPL,r16

	ldi r16,0b00000001     ;aktivace sleep modu
	out SMCR,r16


; na pinu B1 čtení, na pinu B0 buzení nulou
	cbi DDRB,1
	sbi PORTB,1
	sbi DDRB,0
	cbi PORTB,0

;nastavim přerušení PCINT0, piny PCINT0-7, vektor 003
	ldi r26, PCICR 		
	clr r27 			
	ldi r16,0b00000001 	
	st 	X, r16 			

;aktivuju pin PB1 jako aktivní pro přerušení klávasnicí
	ldi r26, PCMSK0
	clr r27
	ldi r16,0b00000010  
	st 	X, r16
	sei 


; nastavení dvou nezávislých PWM na čítači 0
	
	ldi r16,0b10100011	; Čítač 2 nezáv. Fast PWM non inverting bez předděličky  
	out	TCCR0A, r16
	
	ldi r16,0b00000001	;čítat bude až nahoru
	out TCCR0B, r16

	ldi r16,0b00000000	;přednastavim si nulové střední hodnoty obou pwm: A řídí světla, B přístrojovku
	out	OCR0A, r16
	
	ldi r16,0b00000000	;přednastavim si nulové střední hodnoty obou pwm: A řídí světla, B přístrojovku
	out	OCR0B, r16	

	sbi DDRD, 6	;	OC0A je na 6. pinu podtu D
	sbi DDRD, 5	;   OC0B na 5. pinu na portu D, musím tedy nastavit jako výstup


;nastavení ADC
	ldi r26, ADMUX
	clr r27
	ldi r16,0b00100000   ;vstup na pinu PC0, referenční hodnota na vstupu AREF; v ADCH 8 nejvyšších bitů
	st 	X, r16

	ldi r26, ADCSRA
	clr r27
	ldi r16,0b10001000	;zapnutí ADC; autotrigger vypnut; povolit přerušení; dělič 32 101 na konci
	st 	X, r16

	ldi r26, DIDR0
	clr r27
	ldi r16,0b00000001	;vypne na PC0 digitální prenosy
	st 	X, r16

	ldi r26, ADCSRA
	clr r27
	ldi r16,0b11001000	;zapnu převod
	st 	X, r16	


;----------- ...TADY JÁ BUDU SKORO FURT... ---------------


spat:
	sleep 
	nop 
	rjmp spat





;----------------OBSLUHA PŘERUŠENÍ-----------

; přerušení při dokončení převodu z potenciometru
prevod:
	lds r20,ADCL	;čtení převedené hodnoty
	lds r21,ADCH

	out OCR0B, R21	;do komparačního registru uložím horních 8 bitů z přenosu 

	ldi r26, ADCSRA
	clr r27
	ldi r16,0b11001000	;zapnu další převod
	st 	X, r16

	reti



; přerušení při změně dvěřního spínače
dvere:
	sbic	PINB,1	; pokud je spínač sepnut (pin B1 stažen do nuly) dvěře se otevřely, tak přeskočim na rozsvitit. Jinak na zhasnout.
	rjmp	zhasnout
	rjmp	rozsvitit
zpet:
	reti

rozsvitit:
	ldi 	R17, 0b10100011	; Zapnu PWM A - byla vypnuta při posledním stmívání
	out 	TCCR0A, R17
	ldi 	R17, 0b11111111	; Hned rozsvítim na plný jas - komparační registru 0xFF
	out 	OCR0A, R17   

	rjmp 	zpet	; skok na zpět: a hned konec přerušení

zhasnout:
	;rcall 	wait5s	; čeká ještě 5 sekund
	ldi 	R17, 0b11111111	  ;budu postupně dekrementovat s plného osvětlení po 12. Když proběhne 20x, z 255 zbyde 15
	ldi		R18, 0b00010100   ;hodnota 20 pro dekrementaci -> bude 20 kroků stmívání (plus jeden poslední)
stmivat:
	subi	R17, 0x0C		;odečtu 12
	out 	OCR0A, R17  	;zapíšu stemělejší hodnotu do komp. registru -> do pwm
	;rcall 	wait100ms		;počkám 100 ms (celé stmívání bude trvat cca  100 ms * 20 = 2 s
	dec 	R18
	brne	stmivat
	
	ldi R17, 0b00000000	;pro jistotu vynuluji pwmku
	out OCR0A, R17

	ldi R17, 0b00100011	; deaktivace PWMky A - neskáčou tam impulsy při startu čítání
	out TCCR0A, R17
	cbi PORTD, 5
	
	rjmp zpet


wait5s:
	LDI		R16, 4			; LDI - Load Immediate
wait5s_1:	
	INC		R1
	BRNE	wait5s_1
	INC		R2
	BRNE	wait5s_1
	DEC		R16
	BRNE	wait5s_1
	RET

wait100ms:
	LDI		R16, 4			; LDI - Load Immediate
wait100ms_1:	
	INC		R1
	BRNE	wait100ms_1
	INC		R2
	BRNE	wait100ms_1
	DEC		R16
	BRNE	wait100ms_1
	RET



;-----------INICIALIZACE----------

.INCLUDE "m88def.inc"

.EQU RES = 0
.EQU OUT_ENABLE = 1
.EQU INPUT = 2
.EQU SHIFT_CLK = 3
.EQU STORE_CLK = 4

.ORG 0x000 
	rjmp main ; 

.ORG 0x003 
	rjmp stisk ; přerušení vyvolané klávesnicí


main: 
	ldi r16,high(RAMEND)  ;nastavení zásobníku??
	out SPH,r16
	ldi r16,low(RAMEND)
	out SPL,r16

;aktivace sleep modu
	ldi r16,0b00000001
	out SMCR,r16
	
	clr r16  ;vynulvání používaných registrů - pro jistotu
	ldi r17,0b00001000 ;osmicka pro dekrementaci při sériovém plnění posuvného reg.
	clr r18  ;pro porovnávání předchozího registru



;---------NASTAVENÍ PŘERUŠENÍ--------------


;nastavim přerušení PCINT0, piny PCINT0-7, vektor 003
	ldi r26, PCICR 		
	clr r27 			
	ldi r16,0b00000001 	
	st X, r16 			

;aktivuju pin PB1 jako aktivní pro přerušení klávasnicí
	ldi r26, PCMSK0
	clr r27
	ldi r16,0b00000010  
	st X, r16
	sei 

; na pinu B1 čtení, na pinu B0 buzení nulou
	cbi DDRB,1
	sbi PORTB,1
	sbi DDRB,0
	cbi PORTB,0



;---------NASTAVENÍ KOMUNIKACE S SHIFT REGISTREM---------------


; nastavení bitů komunikujících s registrem
	sbi DDRC,0
	sbi DDRC,1
	sbi DDRC,2
	sbi DDRC,3
	sbi DDRC,4

	CBI PORTC,RES
	SBI PORTC,RES
	CBI PORTC,OUT_ENABLE
	CBI PORTC,INPUT
	CBI PORTC,SHIFT_CLK
	CBI PORTC,STORE_CLK



;---------STAV DISPLEJE PO RESETU----------------

	ldi r16,0b11000000 ;nula na sedmisegmentovce (spol. anoda = inverzní)
	rcall zapis_znak

;----------- ...TADY JÁ BUDU SKORO FURT... ---------------

spat:
	sleep 
	nop 
	rjmp spat


;-------------PROCEDURY---------------

;prohození nuly a jedničky na 7segmentovce v registru r16
urci_znak:
	ldi r19,0b11000000
	cpse r16,r19
	rjmp zmen_znak1
	rjmp zmen_znak2
zmen_znak2:
	ldi r16,0b11111001
	ret
zmen_znak1:
	ldi r16,0b11000000
	ret

	
; zapsání znaku 7segmentovky do posuvného registru a zobrazení
zapis_znak:
	cbi PORTC,OUT_ENABLE
	ror r16
	brcs jedna ;podprogram pro zápis 1 do shift
	brcc nula  ;podprogram pro zápis 0 do shift
zpet:
	dec r17		;Dekrementuje registr kde je 9
	cpse r17,r18  ;až proběhne 8krát, bude R17 = 0 (=r18) a přestane se opakovat zápis
	rjmp zapis_znak
	sbi PORTC,STORE_CLK
	cbi PORTC,STORE_CLK	
	sbi PORTC,OUT_ENABLE
	ror r16
	ldi r17,0b00001000
	ret
jedna:
	SBI PORTC,INPUT
	SBI PORTC,SHIFT_CLK
	CBI PORTC,SHIFT_CLK
	rjmp zpet
nula:
	CBI PORTC,INPUT
	SBI PORTC,SHIFT_CLK
	CBI PORTC,SHIFT_CLK
	rjmp zpet


;----------------OBSLUHA PŘERUŠENÍ-----------

stisk:
	rcall urci_znak
	rcall zapis_znak
	reti


Příprava na cvičení s 7segmentovkou


;-----------INICIALIZACE----------

.INCLUDE "m88def.inc"

.EQU RES = 0
.EQU OUT_ENABLE = 1
.EQU INPUT = 2
.EQU SHIFT_CLK = 3
.EQU STORE_CLK = 4

.ORG 0x000 
	rjmp main ; 

.ORG 0x003 
	rjmp stisk ; přerušení vyvolané klávesnicí


main: 
	ldi r16,high(RAMEND)  ;nastavení zásobníku??
	out SPH,r16
	ldi r16,low(RAMEND)
	out SPL,r16

;aktivace sleep modu
	ldi r16,0b00000001
	out SMCR,r16
	
	clr r16  ;vynulvání používaných registrů - pro jistotu
	ldi r17,0b00001000 ;osmicka pro dekrementaci při sériovém plnění posuvného reg.
	clr r18  ;pro porovnávání předchozího registru



;---------NASTAVENÍ PŘERUŠENÍ--------------


;nastavim přerušení PCINT0, piny PCINT0-7, vektor 003
	ldi r26, PCICR 		
	clr r27 			
	ldi r16,0b00000001 	
	st X, r16 			

;aktivuju pin PB1 jako aktivní pro přerušení klávasnicí
	ldi r26, PCMSK0
	clr r27
	ldi r16,0b00000010  
	st X, r16
	sei 

; na pinu B1 čtení, na pinu B2 buzení nulou
	cbi DDRB,1
	sbi PORTB,1
	sbi DDRB,2
	cbi PORTB,2



;---------NASTAVENÍ KOMUNIKACE S SHIFT REGISTREM---------------


; nastavení bitů komunikujících s registrem
	sbi DDRC,0
	sbi DDRC,1
	sbi DDRC,2
	sbi DDRC,3
	sbi DDRC,4

	CBI PORTC,RES
	SBI PORTC,RES
	CBI PORTC,OUT_ENABLE
	CBI PORTC,INPUT
	CBI PORTC,SHIFT_CLK
	CBI PORTC,STORE_CLK



;---------STAV DISPLEJE PO RESETU----------------

	ldi r16,0b11000000 ;nula na sedmisegmentovce (spol. anoda = inverzní)
	rcall zapis_znak

;----------- ...TADY JÁ BUDU SKORO FURT... ---------------

spat:
	sleep 
	nop 
	rjmp spat


;-------------PROCEDURY---------------

;prohození nuly a jedničky na 7segmentovce v registru r16
urci_znak:
	ldi r19,0b11000000
	cpse r16,r19
	rjmp zmen_znak1
	rjmp zmen_znak2
zmen_znak2:
	ldi r16,0b11111001
	ret
zmen_znak1:
	ldi r16,0b11000000
	ret

	
; zapsání znaku 7segmentovky do posuvného registru a zobrazení
zapis_znak:
	cbi PORTC,OUT_ENABLE
	ror r16
	brcs jedna ;podprogram pro zápis 1 do shift
	brcc nula  ;podprogram pro zápis 0 do shift
zpet:
	dec r17		;Dekrementuje registr kde je 9
	cpse r17,r18  ;až proběhne 8krát, bude R17 = 0 (=r18) a přestane se opakovat zápis
	rjmp zapis_znak
	sbi PORTC,STORE_CLK
	cbi PORTC,STORE_CLK	
	sbi PORTC,OUT_ENABLE
	ror r16
	ldi r17,0b00001000
	ret
jedna:
	SBI PORTC,INPUT
	SBI PORTC,SHIFT_CLK
	CBI PORTC,SHIFT_CLK
	rjmp zpet
nula:
	CBI PORTC,INPUT
	SBI PORTC,SHIFT_CLK
	CBI PORTC,SHIFT_CLK
	rjmp zpet


;----------------OBSLUHA PŘERUŠENÍ-----------

stisk:
	rcall urci_znak
	rcall zapis_znak
	reti

Finální vezre ovládání ventilátoru

; Soubor ze cvičení k regilaci otáček s detailnějšími komentáři a upraven
; s klávesnicí ve třetím stavu pro eliminaci problému se stisknutím více tlačítek najednou
; odstranění problému s nenulovou střední hodnotou napětí při stisku nuly
; řešení nenulové stř. hod. převzato od kolegy Matyáše Del Campa (delcamat)

.INCLUDE "m88def.inc"

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


.ORG 0x000 
	rjmp Main ; Při resetu (odpovídá vekt. 0000) skoč na Main

.ORG 0x004 
	rjmp isr1 ; Při změně pinu (vektor 0008 - u každého AVR jinak!, definice konkrétního pinu níže) skož na isr1

Main: 

	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 ; Sloupce klávesnice jako vstupy (jen tři - písmena netřeba)
	cbi DDRC, 3
	cbi DDRC, 4

	sbi PORTC, 2 ; nastavení měkkých jedniček na vstupy sloupců klávesnice - pull up odpory
	sbi PORTC, 3
	sbi PORTC, 4

	sbi DDRD, 0 
	sbi DDRD, 1  
	sbi DDRD, 2
	sbi DDRD, 3

	cbi PORTD, 0	
	cbi PORTD, 1
	cbi PORTD, 2
	cbi PORTD, 3


; Timer controlled PWM init:
;
; There are registers TCCR0A and TCCR0B for config, DDRD for output bit
; enabling, OCR0A for counter lenght and OCR0A for pulse "high" lenght.
; Register TIMSK0 controlls interrupts - not used, 0x00 by default 

PWM_INIT:
	ldi R17, 0b00100011	; Nastavení 1. řídicího registru čítače, poslední dva bity nastavují mód čítače (v tomto případě Fast PWM kdy vrchní hodnota čítání bude v registru OCR0A - pozor! O módu rozhoduje také bit 3 v registru TCCR0B!), první čtyři bity nastavují, jak se čítač chová při dosažení porovnávací úrovně (v tomto případě nastaví na pinu OC0B jedničku když má čítač menší hodnotu než OCR0B a naopak)   
	out TCCR0A, R17			; 
	ldi R17, 0b00001001	; nastavení módu viz přechozí komentář, čítání bez předděličky
	out TCCR0B, R17
	ldi R17, PWM_PULSES	; Čítač přeteče při dosažení hodnoty v prom. PWM_PULSES, tzn PWM na frekvenci  frekv. oscil/PWM_PULSES. Změnou OCR0B pak budu měnit střídu PWM
	out OCR0A, R17   		

	sbi DDRD, 5	; Čítač sdílí svůj výstup OC0B s 5. pinem na portu D, musím tedy nastavit jako výstup


; Keyboard interrupt setup
;
; Activation of pin change interrupt - PROBLEM!!! PCICR and PCIMSK are 
; extended I/O registers (0x68 and 0x6C), and must be handled as 
; a memory location


;PCICR je registr nastavující na posledních třech bitech jeden jaký ze tří možných vektorů přerušení pro změnu na pinu budou aktivní
	ldi r26, PCICR ; R26 a 27 tvoří 16bit registr X. Do spodních 8 bitů dám adresu PCICR
	clr r27 ; Hořejšek registru X vymažu
	ldi r16,0b00000010 ; do R 16 si připravim požadované nastavení - v tomto případě PCINT1 - vektor 0008 viz začátek programu
	st X, r16 ; Uložim do X nastavení přerušení - tím nastavim registr PCICR

;PCMSK1 mi určuje piny, které budou způsobovat přerušení PCINT1, stejným způsobem nastavím jako předchozí
	ldi r26, PCMSK1
	clr r27
	ldi r16,0b00011100 ; Přerušení budou způsobovat piny PCINT10, PCINT11 a PCINT12, které mají stejné vývody jako piny 2,3,4 na portu C - to jsou naše slouce klávesnice s pullup odpory
	st X, r16

	sei ; zapnutí přerušení: mělo by být ekvivalentní sbi SREG,7


; Set sleep mode of the CPU
; SMCR: 0,0,0,0,SM2,SM1,SM0,SE   SM2..0: Sleep Mode Select Bits, SE: Sleep enabled)

	ldi r16,0b00000001 ; Aktivace Sleep módu - při provedení instukce sleep skutečně proc usne
	out SMCR,r16 ; Zápis do příslušného registru


; Procesor bude spát dokud nezmáčknu klávesu a nezpůsobim přerušení

loop:
	sleep 
	nop 
	rjmp loop


; PCINT0 Service Routine:
;
; To do: *** rpm reading, regulation, etc.

isr1:
	rcall KEYPRESS
        ldi R17, 0b00100011	;aktivuje nastavení stejného modu čítače jako při inicializaci
	out TCCR0A, R17	
	cpi R16,0	;když je zmáčknuta nula, tak se skočí na off:
	breq off
        mov R17, R16
	lsl R17	; posun vlevo - v bináru násobení dvěmi
	lsl R17	; ještě jednou - takže dohromady 4, maximální hodnota při stisku 9 je tedy 36
	out OCR0B, R17    ; uložim číslo 0 ... 36 v (10 kroků, tlačítek) do porovnávacího registru k nastavení střídy
	reti ; návrat z přerušení na poslední adresu před přerušením +1 (při reti se narozdíl od ret neukládá stavový registr, je nutno to udělat růčo)

off:
	ldi R17, 0b00000011	; deaktivace PWMky - neskáčou tam impulsy při startu čítání
	out TCCR0A, R17
	cbi PORTD, 5
	reti

; Keyboard decoding:

KEYPRESS:
KEY0:		;kontrola stistku nuly - po úpravě 
	cbi		DDRD,0
	cbi 	PORTD, 0
	cbi		DDRD,1
	cbi 	PORTD, 1
	cbi		DDRD,2
	cbi 	PORTD, 2	; řádky které nekontroluji tak nastavím do třetího stavu, tj jako vstupy bez pullup
	
	sbi		DDRD,3		; řádek odpovádající kontrolované klávese jako výstup do nuly
	cbi 	PORTD, 3	
	
	sbic	PINC, 3		; v případě že je kontrolovaná klávesa, a tedy je na PINC sražená měkká 1 na 0, přeskočim následující instrukci
	rjmp	KEY1		; skok na test další klávesy
	ldi		R16, 0		; do uživ. registru šoupnu zmáčknutou hodnotu (v tomto případě nulu) kterou pak vhodně navhájuju, vložim do komparační
	rjmp	KEYRET
KEY1:
	sbi		DDRD,0		; nulu na první řádek, testuju jedničku
	cbi 	PORTD, 0	
	
	cbi		DDRD,1		; třetí stav na ost. řádcích
	cbi 	PORTD, 1
	cbi		DDRD,2	
	cbi 	PORTD, 2
	cbi		DDRD,3
	cbi 	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:
	cbi		DDRD,0		
	cbi 	PORTD, 0
	
	sbi		DDRD,1
	cbi 	PORTD, 1	; log. 0 to the row with 4, 5, 6, B
	
	cbi		DDRD,2
	cbi 	PORTD, 2
	cbi		DDRD,3
	cbi 	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:
	cbi		DDRD,0		
	cbi 	PORTD, 0
	cbi		DDRD,1		
	cbi 	PORTD, 1

	sbi		DDRD,2
	cbi 	PORTD, 2	
	
	cbi		DDRD,3
	cbi 	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:
	sbi DDRD, 0 
	sbi DDRD, 1  
	sbi DDRD, 2
	sbi DDRD, 3

	cbi PORTD, 0	
	cbi PORTD, 1
	cbi PORTD, 2
	cbi PORTD, 3
	ret				; návrat na adresu uloženou na vršku zásobníku - adresa posledního volání podprogramu +1


Cvičení 6, update: větrák s přerušením, časovačem v modu Fast PWM a klávesnicí se třetím stavem.

; Soubor ze cvičení k regilaci otáček s detailnějšími komentáři a upraven
; s klávesnicí ve třetím stavu pro eliminaci problému se stisknutím více tlačítek najednou


.INCLUDE "m88def.inc"

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


.ORG 0x000 
	rjmp Main ; Při resetu (odpovídá vekt. 0000) skoč na Main

.ORG 0x004 
	rjmp isr1 ; Při změně pinu (vektor 0008 - u každého AVR jinak!, definice konkrétního pinu níže) skož na isr1

Main: 

	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 ; Sloupce klávesnice jako vstupy (jen tři - písmena netřeba)
	cbi DDRC, 3
	cbi DDRC, 4

	sbi PORTC, 2 ; nastavení měkkých jedniček na vstupy sloupců klávesnice - pull up odpory
	sbi PORTC, 3
	sbi PORTC, 4

	sbi DDRD, 0 
	sbi DDRD, 1  
	sbi DDRD, 2
	sbi DDRD, 3

	cbi PORTD, 0	
	cbi PORTD, 1
	cbi PORTD, 2
	cbi PORTD, 3


; Timer controlled PWM init:
;
; There are registers TCCR0A and TCCR0B for config, DDRD for output bit
; enabling, OCR0A for counter lenght and OCR0A for pulse "high" lenght.
; Register TIMSK0 controlls interrupts - not used, 0x00 by default 

PWM_INIT:
	ldi R17, 0b00100011	; Nastavení 1. řídicího registru čítače, poslední dva bity nastavují mód čítače (v tomto případě Fast PWM kdy vrchní hodnota čítání bude v registru OCR0A - pozor! O módu rozhoduje také bit 3 v registru TCCR0B!), první čtyři bity nastavují, jak se čítač chová při dosažení porovnávací úrovně (v tomto případě nastaví na pinu OC0B jedničku když má čítač menší hodnotu než OCR0B a naopak)   
	out TCCR0A, R17			; 
	ldi R17, 0b00001001	; nastavení módu viz přechozí komentář, čítání bez předděličky
	out TCCR0B, R17
	ldi R17, PWM_PULSES	; Čítač přeteče při dosažení hodnoty v prom. PWM_PULSES, tzn PWM na frekvenci  frekv. oscil/PWM_PULSES. Změnou OCR0B pak budu měnit střídu PWM
	out OCR0A, R17   		

	sbi DDRD, 5	; Čítač sdílí svůj výstup OC0B s 5. pinem na portu D, musím tedy nastavit jako výstup


; Keyboard interrupt setup
;
; Activation of pin change interrupt - PROBLEM!!! PCICR and PCIMSK are 
; extended I/O registers (0x68 and 0x6C), and must be handled as 
; a memory location


;PCICR je registr nastavující na posledních třech bitech jeden jaký ze tří možných vektorů přerušení pro změnu na pinu budou aktivní
	ldi r26, PCICR ; R26 a 27 tvoří 16bit registr X. Do spodních 8 bitů dám adresu PCICR
	clr r27 ; Hořejšek registru X vymažu
	ldi r16,0b00000010 ; do R 16 si připravim požadované nastavení - v tomto případě PCINT1 - vektor 0008 viz začátek programu
	st X, r16 ; Uložim do X nastavení přerušení - tím nastavim registr PCICR

;PCMSK1 mi určuje piny, které budou způsobovat přerušení PCINT1, stejným způsobem nastavím jako předchozí
	ldi r26, PCMSK1
	clr r27
	ldi r16,0b00011100 ; Přerušení budou způsobovat piny PCINT10, PCINT11 a PCINT12, které mají stejné vývody jako piny 2,3,4 na portu C - to jsou naše slouce klávesnice s pullup odpory
	st X, r16

	sei ; zapnutí přerušení: mělo by být ekvivalentní sbi SREG,7


; Set sleep mode of the CPU
; SMCR: 0,0,0,0,SM2,SM1,SM0,SE   SM2..0: Sleep Mode Select Bits, SE: Sleep enabled)

	ldi r16,0b00000001 ; Aktivace Sleep módu - při provedení instukce sleep skutečně proc usne
	out SMCR,r16 ; Zápis do příslušného registru


; Procesor bude spát dokud nezmáčknu klávesu a nezpůsobim přerušení

loop:
	sleep 
	nop 
	rjmp loop


; PCINT0 Service Routine:
;
; To do: *** rpm reading, regulation, etc.


isr1:	;obsluha přerušení při zmáčknutí klávesy
	rcall KEYPRESS

	mov R17, R16
	lsl R17		; posun vlevo - v bináru násobení dvěmi
	lsl R17		; ještě jednou - takže dohromady 4, maximální hodnota při stisku 9 je tedy 36
	out OCR0B, R17  ; uložim číslo 0 ... 36 v (10 kroků, tlačítek) do porovnávacího registru k nastavení střídy

	reti ; návrat z přerušení na poslední adresu před přerušením +1 (při reti se narozdíl od ret neukládá stavový registr, je nutno to udělat růčo)


; Keyboard decoding:

KEYPRESS:
KEY0:		;kontrola stistku nuly - po úpravě 
	cbi		DDRD,0
	cbi 	PORTD, 0
	cbi		DDRD,1
	cbi 	PORTD, 1
	cbi		DDRD,2
	cbi 	PORTD, 2	; řádky které nekontroluji tak nastavím do třetího stavu, tj jako vstupy bez pullup
	
	sbi		DDRD,3		; řádek odpovádající kontrolované klávese jako výstup do nuly
	cbi 	PORTD, 3	
	
	sbic	PINC, 3		; v případě že je kontrolovaná klávesa, a tedy je na PINC sražená měkká 1 na 0, přeskočim následující instrukci
	rjmp	KEY1		; skok na test další klávesy
	ldi		R16, 0		; do uživ. registru šoupnu zmáčknutou hodnotu (v tomto případě nulu) kterou pak vhodně navhájuju, vložim do komparační
	rjmp	KEYRET
KEY1:
	sbi		DDRD,0		; nulu na první řádek, testuju jedničku
	cbi 	PORTD, 0	
	
	cbi		DDRD,1		; třetí stav na ost. řádcích
	cbi 	PORTD, 1
	cbi		DDRD,2	
	cbi 	PORTD, 2
	cbi		DDRD,3
	cbi 	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:
	cbi		DDRD,0		
	cbi 	PORTD, 0
	
	sbi		DDRD,1
	cbi 	PORTD, 1	; log. 0 to the row with 4, 5, 6, B
	
	cbi		DDRD,2
	cbi 	PORTD, 2
	cbi		DDRD,3
	cbi 	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:
	cbi		DDRD,0		
	cbi 	PORTD, 0
	cbi		DDRD,1		
	cbi 	PORTD, 1

	sbi		DDRD,2
	cbi 	PORTD, 2	
	
	cbi		DDRD,3
	cbi 	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:
	sbi DDRD, 0 
	sbi DDRD, 1  
	sbi DDRD, 2
	sbi DDRD, 3

	cbi PORTD, 0	
	cbi PORTD, 1
	cbi PORTD, 2
	cbi PORTD, 3
	ret				; návrat na adresu uloženou na vršku zásobníku - adresa posledního volání podprogramu +1

Cvičení 6: větrák s přerušením, časovačem v modu Fast PWM a klávesnicí se třetím stavem.


; Soubor ze cvičení k regilaci otáček s detailnějšími komentáři a upraven
; s klávesnicí ve třetím stavu pro eliminaci problému se stisknutím více tlačítek najednou


.INCLUDE "m168def.inc"

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


.ORG 0x0000 
	jmp Main ; Při resetu (odpovídá vekt. 0000) skoč na Main

.ORG 0x0008 
	jmp isr1 ; Při změně pinu (vektor 0008 - u každého AVR jinak!, definice konkrétního pinu níže) skož na isr1

Main: 

	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 ; Sloupce klávesnice jako vstupy (jen tři - písmena netřeba)
	cbi DDRC, 3
	cbi DDRC, 4

	sbi PORTC, 2 ; nastavení měkkých jedniček na vstupy sloupců klávesnice - pull up odpory
	sbi PORTC, 3
	sbi PORTC, 4

	cbi DDRD, 0 ; následujících 8 řádků nastaví řádky klávesnice do třetího stavu
	cbi DDRD, 1 ; 
	cbi DDRD, 2
	cbi DDRD, 3

	cbi PORTD, 0	
	cbi PORTD, 1
	cbi PORTD, 2
	cbi PORTD, 3


; Timer controlled PWM init:
;
; There are registers TCCR0A and TCCR0B for config, DDRD for output bit
; enabling, OCR0A for counter lenght and OCR0A for pulse "high" lenght.
; Register TIMSK0 controlls interrupts - not used, 0x00 by default 

PWM_INIT:
	ldi R17, 0b00100011	; Nastavení 1. řídicího registru čítače, poslední dva bity nastavují mód čítače (v tomto případě Fast PWM kdy vrchní hodnota čítání bude v registru OCR0A - pozor! O módu rozhoduje také bit 3 v registru TCCR0B!), první čtyři bity nastavují, jak se čítač chová při dosažení porovnávací úrovně (v tomto případě nastaví na pinu OC0B jedničku když má čítač menší hodnotu než OCR0B a naopak)   
	out TCCR0A, R17			; 
	ldi R17, 0b00001001	; nastavení módu viz přechozí komentář, čítání bez předděličky
	out TCCR0B, R17
	ldi R17, PWM_PULSES	; Čítač přeteče při dosažení hodnoty v prom. PWM_PULSES, tzn PWM na frekvenci  frekv. oscil/PWM_PULSES. Změnou OCR0B pak budu měnit střídu PWM
	out OCR0A, R17   		

	sbi DDRD, 5	; Čítač sdílí svůj výstup OC0B s 5. pinem na portu D, musím tedy nastavit jako výstup


; Keyboard interrupt setup
;
; Activation of pin change interrupt - PROBLEM!!! PCICR and PCIMSK are 
; extended I/O registers (0x68 and 0x6C), and must be handled as 
; a memory location


;PCICR je registr nastavující na posledních třech bitech jeden jaký ze tří možných vektorů přerušení pro změnu na pinu budou aktivní
	ldi r26, PCICR ; R26 a 27 tvoří 16bit registr X. Do spodních 8 bitů dám adresu PCICR
	clr r27 ; Hořejšek registru X vymažu
	ldi r16,0b00000010 ; do R 16 si připravim požadované nastavení - v tomto případě PCINT1 - vektor 0008 viz začátek programu
	st X, r16 ; Uložim do X nastavení přerušení - tím nastavim registr PCICR

;PCMSK1 mi určuje piny, které budou způsobovat přerušení PCINT1, stejným způsobem nastavím jako předchozí
	ldi r26, PCMSK1
	clr r27
	ldi r16,0b00011100 ; Přerušení budou způsobovat piny PCINT10, PCINT11 a PCINT12, které mají stejné vývody jako piny 2,3,4 na portu C - to jsou naše slouce klávesnice s pullup odpory
	st X, r16

	sei ; zapnutí přerušení: mělo by být ekvivalentní sbi SREG,7


; Set sleep mode of the CPU
; SMCR: 0,0,0,0,SM2,SM1,SM0,SE   SM2..0: Sleep Mode Select Bits, SE: Sleep enabled)

	ldi r16,0b00000001 ; Aktivace Sleep módu - při provedení instukce sleep skutečně proc usne
	out SMCR,r16 ; Zápis do příslušného registru


; Procesor bude spát dokud nezmáčknu klávesu a nezpůsobim přerušení

loop:
	sleep 
	nop 
	rjmp loop


; PCINT0 Service Routine:
;
; To do: *** rpm reading, regulation, etc.


isr1:	;obsluha přerušení při zmáčknutí klávesy
	rcall KEYPRESS

	mov R17, R16
	lsl R17		; posun vlevo - v bináru násobení dvěmi
	lsl R17		; ještě jednou - takže dohromady 4, maximální hodnota při stisku 9 je tedy 36
	out OCR0B, R17  ; uložim číslo 0 ... 36 v (10 kroků, tlačítek) do porovnávacího registru k nastavení střídy

	reti ; návrat z přerušení na poslední adresu před přerušením +1 (při reti se narozdíl od ret neukládá stavový registr, je nutno to udělat růčo)


; Keyboard decoding:

KEYPRESS:
KEY0:		;kontrola stistku nuly - po úpravě 
	cbi		DDRD,0
	cbi 	PORTD, 0
	cbi		DDRD,1
	cbi 	PORTD, 1
	cbi		DDRD,2
	cbi 	PORTD, 2	; řádky které nekontroluji tak nastavím do třetího stavu, tj jako vstupy bez pullup
	
	sbi		DDRD,3		; řádek odpovádající kontrolované klávese jako výstup do nuly
	cbi 	PORTD, 3	
	
	sbic	PINC, 3		; v případě že je kontrolovaná klávesa, a tedy je na PINC sražená měkká 1 na 0, přeskočim následující instrukci
	rjmp	KEY1		; skok na test další klávesy
	ldi		R16, 0		; do uživ. registru šoupnu zmáčknutou hodnotu (v tomto případě nulu) kterou pak vhodně navhájuju, vložim do komparační
	rjmp	KEYRET
KEY1:
	sbi		DDRD,0		; nulu na první řádek, testuju jedničku
	cbi 	PORTD, 0	
	
	cbi		DDRD,1		; třetí stav na ost. řádcích
	cbi 	PORTD, 1
	cbi		DDRD,2	
	cbi 	PORTD, 2
	cbi		DDRD,3
	cbi 	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:
	cbi		DDRD,0		
	cbi 	PORTD, 0
	
	sbi		DDRD,1
	cbi 	PORTD, 1	; log. 0 to the row with 4, 5, 6, B
	
	cbi		DDRD,2
	cbi 	PORTD, 2
	cbi		DDRD,3
	cbi 	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:
	cbi		DDRD,0		
	cbi 	PORTD, 0
	cbi		DDRD,1		
	cbi 	PORTD, 1

	sbi		DDRD,2
	cbi 	PORTD, 2	
	
	cbi		DDRD,3
	cbi 	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 DDRD, 0 ; následujících 8 řádků nastaví řádky klávesnice do třetího stavu
	cbi DDRD, 1 ; 
	cbi DDRD, 2
	cbi DDRD, 3

	cbi PORTD, 0	
	cbi PORTD, 1
	cbi PORTD, 2
	cbi PORTD, 3
	ret				; návrat na adresu uloženou na vršku zásobníku - adresa posledního volání podprogramu +1
Osobní nástroje