Table of Contents

L1 Digital

Comment: Partial translation is needed!

Digital input/output

Warm-Up

Lights up:

//
// HomeLab User interface module
// Warm-up exercise
//
 
#include <homelab/pin.h>
#include <homelab/delay.h>
 
pin led_red    = PIN(C, 5);
pin led_yellow = PIN(C, 4);
pin led_green  = PIN(C, 3);
 
pin button1 = PIN(C, 0);
pin button2 = PIN(C, 1);
pin button3 = PIN(C, 2);
 
 
int main(void)
{
	// LED setup
	pin_setup_output(led_red);
	pin_setup_output(led_yellow);
	pin_setup_output(led_green);
 
	// Button setup
	pin_setup_input_with_pullup(button1);
	pin_setup_input_with_pullup(button2);
	pin_setup_input_with_pullup(button3);
 
	// Switches LEDs off
	pin_set(led_green);
	pin_set(led_yellow);
	pin_set(led_red);
 
	while(true)
	{
		// Pressing S1 lights up LED1 (green)
		if(!pin_get_debounced_value(button1))
		{
			pin_clear(led_green);
			pin_set(led_yellow);
			pin_set(led_red);
		}
		// Pressing S2 lights up LED2 and LED3 (green and yellow)
		if(!pin_get_debounced_value(button2))
		{
			pin_clear(led_green);
			pin_clear(led_yellow);
			pin_set(led_red);
		}
		// Pressing S3 lights up all LEDs
		if(!pin_get_debounced_value(button3))
		{
			pin_clear(led_green);
			pin_clear(led_yellow);
			pin_clear(led_red);
		}
	}
 
}

Beginners exercise 1

Imiteerib ülekäiguraja autode valgusfoori tööd. Kuni pole vajutatud ühelegi nupule, põleb autodele roheline LED. Pärast suvalisele nupule vajutamist hakkab roheline kolmeks sekundiks vilkuma, seejärel süttib kolmeks sekundiks kollane ning kümneks sekundiks punane ja lõpuks jääb uuesti pidevalt põlema roheline LED.

//
// Traffic light
//
 
#include <homelab/pin.h>
#include <homelab/delay.h>
 
pin led_red    = PIN(C, 5);
pin led_yellow = PIN(C, 4);
pin led_green  = PIN(C, 3);
 
pin button1 = PIN(C, 0);
pin button2 = PIN(C, 1);
pin button3 = PIN(C, 2);
 
 
int main(void)
{
	unsigned char new_value, old_value = 0;
	unsigned short i;
 
	// Seab LEDid töökorda
	pin_setup_output(led_red);
	pin_setup_output(led_yellow);
	pin_setup_output(led_green);
 
	// Seab nupud töökorda
	pin_setup_input_with_pullup(button1);
	pin_setup_input_with_pullup(button2);
	pin_setup_input_with_pullup(button3);
 
	// Lülitab rohelise LED sisse ja teised LEDid välja
	pin_clear(led_green);
	pin_set(led_yellow);
	pin_set(led_red);
 
	while(true)
	{
		// Eelmise ja uue nupuväärtuse lugemine
		new_value = pin_get_debounced_value(button1) & pin_get_debounced_value(button2) & pin_get_debounced_value(button3);
 
		// Kui nuppu on vajutatud ja seejärel vabastatud
		if((!new_value) && (old_value))
		{
			// Vilgutab rohelist LED'i 3 sekundit
			for(i = 0; i < 6; i++)
			{
				pin_toggle(led_green);
				sw_delay_ms(500);
			}
			// Kustutab rohelise ja lülitab 3 sekundiks sisse kollase LEDi
			pin_set(led_green);
			pin_clear(led_yellow);
			sw_delay_ms(3000);
			// Kustutab kollase ja lülitab 10 sekundiks sisse punase LEDi
			pin_set(led_yellow);
			pin_clear(led_red);
			sw_delay_ms(10000);
			// Kustutab punase ja lülitab uuesti sisse rohelise LEDi
			pin_set(led_red);
			pin_clear(led_green);
		}
 
		old_value = new_value;
	}
 
}

Beginners exercise 2

Loendab nupuvajutusi. Vajutus loetakse lõppenuks alles siis, kui nupp vabastatakse. Tulemus kuvatakse kahendkoodis LED-idel. Maksimaalne tulemus kolmel LED-il on 23-1. Roheline LED tähistab 1. bitti, kollane 2. bitti, punane 3. bitti.

//
// Nupuvajutusi loendav programm
// Väljund binaarkoodis, maksimaalselt 7
//
 
#include <homelab/pin.h>
#include <homelab/delay.h>
 
pin led_red    = PIN(C, 5);
pin led_yellow = PIN(C, 4);
pin led_green  = PIN(C, 3);
 
pin button1 = PIN(C, 0);
pin button2 = PIN(C, 1);
pin button3 = PIN(C, 2);
 
 
int main(void)
{
	unsigned char new_value, old_value = 0;
	unsigned short count = 0;
 
	// Seab LEDid töökorda
	pin_setup_output(led_red);
	pin_setup_output(led_yellow);
	pin_setup_output(led_green);
 
	// Seab nupud töökorda
	pin_setup_input_with_pullup(button1);
	pin_setup_input_with_pullup(button2);
	pin_setup_input_with_pullup(button3);
 
	// Lülitab LEDid välja
	pin_set(led_green);
	pin_set(led_yellow);
	pin_set(led_red);
 
	while(true)
	{
		// Eelmise ja uue nupuväärtuse lugemine
		new_value = pin_get_debounced_value(button1) & pin_get_debounced_value(button2) & pin_get_debounced_value(button3);
 
		// Kui nuppu on vajutatud ja seejärel vabastatud
		if((!new_value) && (old_value))
		{
			// Liidab loendurile ühe juurde
			count++;
 
			// Kõrgeim bitt (4)
			// Aktiveeritakse kui loendurit neljaga jagades on tulemus >= 1
			if(((count % 8) / 4) > 0)
				pin_clear(led_red);
			else
				pin_set(led_red);
 
			// Keskmine bitt (2)
			// Aktiveeritakse kui eelmise tehte jääki kahega jagades on tulemus >= 1
			if(((count % 4) / 2) > 0)
				pin_clear(led_yellow);
			else
				pin_set(led_yellow);
 
			// Madalaim bitt (1)
			// Aktiveeritakse kui eelmise tehte jääk on >= 1
			if((count % 2) > 0)
				pin_clear(led_green);
			else
				pin_set(led_green);
		}
 
		old_value = new_value;
	}
 
}

Beginners exercise 3

Vajutades nupule S1, süttib korraga LED1 ja LED3, vajutades nupule S2, süttib LED2, vajutades nupule S3, kustuvad kõik LED-id. Operatsioonid teostatakse otse vastavate registrite väärtusi muutes (ilma Kodulabori teegita).

//
// Digitaalsete sisendite-väljundite ilma kodulabori teegita kasutamise näide
//
 
#include <avr/io.h>
#include <util/delay.h>
 
#define LED1	PC5
#define LED2	PC4
#define LED3	PC3
 
#define S1		0
#define S2		1
#define S3		2
 
int checkButton(int pin);
 
int main(void)
{
	DDRC = (1<<LED1) | (1<<LED2) | (1<<LED3);	// LED viigud väljunditena, ülejäänud sisenditena
	PORTC = (1<<LED1) | (1<<LED2) | (1<<LED3);	// Lülitab LEDid välja
 
	while(1)
	{
		// Nupu S1 vajutamisel lülitatakse sisse LED1 ja LED3
		if(checkButton(S1))
		{
			PORTC &= ~(1<<LED1) & ~(1<<LED3);
		}
		// Nupu S2 vajutamisel lülitatakse sisse LED2
		if(checkButton(S2))
		{
			PORTC &= ~(1<<LED2);
		}
		// Nupu S3 vajutamisel lülitatakse kõik LEDid välja
		if(checkButton(S3))
		{
			PORTC |= (1<<LED1) | (1<<LED2) | (1<<LED3);
		}
	}
 
}
 
//
// Kontrollib antud nupu väärtust
//
int checkButton(int pin)
{
	int i;	
	// Nupp on sees kui bitt on madal (0)
	if ((PINC & (1<<pin)) == 0)
	{
		// Põrkamise silumine
		for(i=0;i<25;i++)
		{
			if ((PINC & (1<<pin)) != 0)
				return 0;
			_delay_ms(1);
		}
	}
	else
		return 0;
 
	return 1;
}

Beginners exercise 4

Loendab nupuvajutusi. Tulemus kuvatakse LED-i vilkumistega. Pärast igat nupule vajutamist suureneb vilgutamiste arv ühe võrra. Valida võib suvalise nupu. LED-i vilgutamiseks kasutada alamfunktsiooni, mille parameetriks on vilkumiste arv.

//
// Nupuvajutusi loendav programm
// Väljund LEDi vilkumisega
//
 
#include <homelab/pin.h>
#include <homelab/delay.h>
 
void blink(int c); // Deklareerib alamfunktsiooni LEDi vilgutamiseks
 
pin led_yellow = PIN(C, 4);
 
pin button1 = PIN(C, 0);
pin button2 = PIN(C, 1);
pin button3 = PIN(C, 2);
 
 
int main(void)
{
	unsigned char new_value, old_value = 0;
	unsigned short count = 0;
 
	// Seab LEDi töökorda
	pin_setup_output(led_yellow);
 
	// Seab nupud töökorda
	pin_setup_input_with_pullup(button1);
	pin_setup_input_with_pullup(button2);
	pin_setup_input_with_pullup(button3);
 
	// Lülitab LEDi välja
	pin_set(led_yellow);
 
	while(true)
	{
		// Eelmise ja uue nupuväärtuse lugemine
		new_value = pin_get_debounced_value(button1) & pin_get_debounced_value(button2) & pin_get_debounced_value(button3);
 
		// Kui nuppu on vajutatud ja seejärel vabastatud
		if((!new_value) && (old_value))
		{
			// Liidab loendurile ühe juurde
			count++;
 
			// Vilgutab õige arv kordi LEDi
			blink(count);
		}
 
		old_value = new_value;
	}
 
}
 
//
// Alamfunktsioon LEDi vilgutamiseks
//
void blink(int c)
{
	int i = 0;
 
	// Muudab LEDi olekut iga 500ms tagant
	// Üheks vilgutuseks on tarvis LEDi olekut 2x muuta
	// Üks vilgutus võtab seega 1s
	for(i = 0; i < (c * 2); i++)
	{
		pin_toggle(led_yellow);
		sw_delay_ms(500);
	}
}

Beginners exercise 5

Vajutades nupule S1, vilgutab punane LED morsekoodis „SOS“, vajutades nupule S2, vilgutab kollane LED „CQD“ ja, vajutades nupule S3, vilgutab roheline LED „OK“.

//
// Morsekoodis teateid edastav programm
// Nupp 1 : punane SOS
// Nupp 2 : kollane CQD
// Nupp 3 : roheline OK
//
 
#include <homelab/pin.h>
#include <homelab/delay.h>
 
// Defineeri vajaminevad morsetähed
#define C	1
#define D	2
#define K	3
#define O	4
#define Q	5
#define S	6
 
// Deklareeri alamfunktsioonid
void blinkSos(void);
void blinkCqd(void);
void blinkOk(void);
void blinkChar(int c, pin led);
void blinkDot(pin led);
void blinkDash(pin led);
 
pin led_red    = PIN(C, 5);
pin led_yellow = PIN(C, 4);
pin led_green  = PIN(C, 3);
 
pin button1 = PIN(C, 0);
pin button2 = PIN(C, 1);
pin button3 = PIN(C, 2);
 
 
int main(void)
{
	// Seab LEDid töökorda
	pin_setup_output(led_red);
	pin_setup_output(led_yellow);
	pin_setup_output(led_green);
 
	// Seab nupud töökorda
	pin_setup_input_with_pullup(button1);
	pin_setup_input_with_pullup(button2);
	pin_setup_input_with_pullup(button3);
 
	// Lülitab LEDid välja
	pin_set(led_green);
	pin_set(led_yellow);
	pin_set(led_red);
 
	while(true)
	{
		// Nupu 1 vajutamisel vilgutatakse SOS
		if(!pin_get_value(button1))
			blinkSos();
		// Nupu 2 vajutamisel vilgutatakse CQD
		if(!pin_get_value(button2))
			blinkCqd();
		// Nupu 3 vajutamisel vilgutatakse OK
		if(!pin_get_value(button3))
			blinkOk();
	}
 
}
 
// Vilgutab SOS punase LEDiga
void blinkSos(void)
{
	blinkChar(S, led_red);
	blinkChar(O, led_red);
	blinkChar(S, led_red);
}
 
// Vilgutab CQD kollase LEDiga
void blinkCqd(void)
{
	blinkChar(C, led_yellow);
	blinkChar(Q, led_yellow);
	blinkChar(D, led_yellow);
}
 
// Vilgutab OK rohelise LEDiga
void blinkOk(void)
{
	blinkChar(O, led_green);
	blinkChar(K, led_green);
}
 
// Vilgutab parameetris määratud LEDiga punkti
void blinkDot(pin led)
{
	pin_clear(led);
	sw_delay_ms(100); // Standardse pikkusega punkt
	pin_set(led);
	sw_delay_ms(100); // Märgile järgnev paus
}
 
// Vilgutab parameetris määratud LEDiga kriipsu
void blinkDash(pin led)
{
	pin_clear(led);
	sw_delay_ms(300); // Standardse pikkusega kriips
	pin_set(led);
	sw_delay_ms(100); // Märgile järgnev paus
}
 
// Vilgutab eeldefineeritud mustri järgi
// parameetris 'c' olevat tähte parameetris 'led' oleval LEDil
void blinkChar(int c, pin led)
{
	switch(c)
	{
		// -.-.
		case C:
			blinkDash(led);
			blinkDot(led);
			blinkDash(led);
			blinkDot(led);
			break;
		// -..
		case D:
			blinkDash(led);
			blinkDot(led);
			blinkDot(led);
			break;
		// -.-
		case K:
			blinkDash(led);
			blinkDot(led);
			blinkDash(led);
			break;
		// ---
		case O:
			blinkDash(led);
			blinkDash(led);
			blinkDash(led);
			break;
		// --.-
		case Q:
			blinkDash(led);
			blinkDash(led);
			blinkDot(led);
			blinkDash(led);
			break;
		// ...
		case S:
			blinkDot(led);
			blinkDot(led);
			blinkDot(led);
			break;
	}
	sw_delay_ms(200); // Lisapaus peale tähte
}

Alternative solutions without library

For all exercises: Project→Configuration Options

Exercise 1

Pressing S1 lights up 1 LED, pressing S2 lights up 2 LEDs and pressing S3 lights up 3 LEDs.

/*
Title: Lab 1.1 LEDs
Platform: Atmega128 & Digital i/o board v3
Author: Raivo Sell 
Date: 2008
Comment:
LED = 0 (turned on)  		LED = 1 (turned off)
S = 0 (switch is on) 	S = 1 (switch is off)
PORT direction settings: 1-out	0-in
*/
 
#include <avr/io.h>
 
int main(void) {
 
    DDRC  = 0x38;  // DDRC  0b00111000
    PORTC = 0x3F;  // PORTC 0b00111111
 
	//Infinite loop
	while(1) {
		// If a button is pressed
		if (bit_is_clear(PINC, 0))	//Button S1
			PORTC=0x30; //LED 1 on - 0b00110000
		else if (bit_is_clear(PINC, 1))//Button S2
			PORTC=0x20; //LED 1&2 on - 0b00100000
		else if (bit_is_clear(PINC, 2))//Button S3
			PORTC&=0x00; //LED 1-3 on - 0b00000000
		else //Nothing pressed
			PORTC=0x3F; // All LEDs off
	}
}

Exercise 2

Imitates a traffic light on key press (blinking of the yellow and green lights etc.)

NB! Optimization must be turned off and the frequency defined.

/*
Title: Lab 1.2 Traffic lights
Platform: Atmega128 & Digital i/o board v3
Author: Raivo Sell 
Date: 2006-2008
Comment: Optimization -O0
*/
 
#include <avr/io.h>
 
#define SET(x) |= (1<<x)  //define the high bit in port x
#define CLR(x) &=~(1<<x)  //define the low bit in port x
#define INV(x) ^=(1<<x)	//define the bit inverting in port x
 
// Empty cycle just to waste time
void aeg(int t) {
	int i,j;
	for (i=0;i<t;i++){
		for (j=0;j<32000;j++){;}
	}
}
 
// LED = 0 (on)  LED = 1 (off)
// Switch on = 0
 
int main(void) {
 
    int z;
 
    DDRC   = 0x38;  // PORTC three first bits are inputs, three next ports are outputs
    PORTC |= 0x3F;  // All LEDs off and button pull-ups on
 
	//loops until S1 is pressed
	while (bit_is_set(PINC, 0)){
		PORTC INV(4); // Blink yellow
		aeg(10);	
	}
	PORTC SET(4); // Yellow off
 
	//Infinite loop	
	while(1) {
 
 
			PORTC CLR(3); // Green on	
			aeg(100);
			for (z=0;z<5;z++){
				PORTC INV(3); // Blink green
				aeg(10);
			}	
			PORTC CLR(4); // Yellow on
			aeg(50);
			PORTC SET(4); // Yellow off
			PORTC CLR(5); // Red on
			aeg(100);
			PORTC CLR(4); // Add yellow
			aeg(50);
			PORTC SET(4); // Yellow off
			PORTC SET(5); // Red off
	}
}

Exercise 3

Counts the key presses (key press ends when the button is released) in binary - max 7

/*
Title: Lab 1.3 Binary counter
Platform: Atmega128 & Digital i/o board v3
Author: Raivo Sell, Rain Ellermaa 
Date: 2006-2008
Comment: 
*/
 
#define TRUE    1
#define FALSE   0
#define SET(x) |= (1<<x)  //define the high bit in port x
#define CLR(x) &=~(1<<x)  //define the low bit in port x
 
#define bit_get(p,m) ((p) & (m))
 
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>
 
uint8_t button_debounce();
uint8_t button_read();
int i= 0;
 
uint8_t button_debounce(){
   static uint16_t button_state = 0;   
 
   button_state = ( (button_state << 1) | !button_read() | 0xE000 );
   if ( button_state == 0xF000 ) return TRUE;
   return FALSE;
   }
 
uint8_t button_read(){
      return bit_get( PINC , 1 );
   } 
 
int main(void) {
 
    DDRC   = 0x38;  // DDRC  0b00111000 // PORTC three first bits are inputs, three next ports are outputs
    PORTC |= 0x3F;  // PORTC 0b00111000 // All LEDs off and button pull-ups on
    unsigned char led;
 
    while(1) {
	if ( button_debounce() == TRUE ) i++;
	_delay_ms( 1 );
	if (i>7) i=0;		
	led=~i;
	led <<=3;
	PORTC &= (0xC7 | led);
	PORTC |= (0x38 & led);
     }
}

Exercise 4

Simulates door code lock. When pressing switches in this order S3 – S2 - S1 green LED goes on. All other combination will end up red LED. Every button pressing is indicated with yellow LED.

NOT COMPLETED !!!

/*
Title: Lab 1.4 Code lock
Platform: Atmega128 & Digital i/o board v3
Author: Rain Ellermaa 
Date: 2009
Comment: 
*/
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
 
#define LOCKED 		1
#define UNLOCKED 	2
 
uint8_t code[3];
static uint8_t password[3] = {3,2,1};
 
//Blink LED on "pin"
static inline void Blink(uint8_t pin)
{
	PORTC &= ~(1<<pin);
	_delay_ms(100);
	PORTC |= (1<<pin);
	_delay_ms(100);
}
 
int Button(uint8_t pin)
{
	/* button is on when BIT is low (0) */
    if ((PINC & (1<<pin)) == 0) 
    {
    	for(uint8_t i=0;i<25;i++)
		{
        	if ((PINC & (1<<pin))!=0)
				return 0;
			_delay_ms(1);
		}
    }
	else
		return 0;
    return 1;
}
 
int CheckPress()
{
	if(Button(0)) 				//SW1 pressed
	{
		Blink(PC4);
		_delay_ms(100);
		return 1;
	}
	else if (Button(1)) 		//SW2 pressed
	{
		Blink(PC4);
		_delay_ms(100);
		return 2;
	}
	else if (Button(2)) 		//SW3 pressed
	{
		Blink(PC4);
		_delay_ms(100);
		return 3;
	}
	else
		return 4;
}
 
//get the user input 3 digit code.
void GetCode()
{
	for(uint8_t i=0;i<3;i++)
	{
		while(1)
		{
			uint8_t temp = CheckPress();
			if(temp != 4)
			{	
				code[i] = temp;
				break;
			}
		}
	}
	Blink(PC4);
}
 
//code to compare user inputted "code" buffer to the hardcoded "password" buffer
int CheckCode()
{
	for(uint8_t i=0;i<3;i++)
	{
		if(code[i] != password[i])
			return 0;
	}
	return 1;
}
 
 
int main(void)
{
	DDRC = (1<<PC3)|(1<<PC4)|(1<<PC5);	//LED pins as outputs, other inputs
	PORTC = (1<<PC3)|(1<<PC4)|(1<<PC5);	//LEDs off
 
	uint8_t status = UNLOCKED;
 
	while(1)
	{
		if((status == UNLOCKED) && (CheckPress() == 2))
		{
			status = LOCKED;
 
		}
		else if(status == LOCKED)
		{
			PORTC &= ~(1<<PC5);
			PORTC |= (1<<PC3);
			GetCode();
			if(!CheckCode())
			{
				PORTC &= ~(1<<PC5);
				PORTC |= (1<<PC3);
				status = LOCKED;
			}
			else if (CheckCode())
			{
				PORTC &= ~(1<<PC3);
				PORTC |= (1<<PC5);
				status = UNLOCKED;
			}
		}
	}
}

Exercise 5

Simulates memory game. Every LED corresponds a button (LED1⇒S1, etc.) Controller flashed LEDs in random order and user have to repeat this order. Every next step in the sequence goes longer. After every insertion controller test the result. If wrong insertion is detected the game is over.

/*
Title: Lab 1.5 Memory game
Platform: Atmega128 & Digital i/o board v3
Author: Rain Ellermaa 
Date: 2009
Comment: 
=====================================================
                  ++ INSTRUCTIONS: ++
 
   When the MCU powers up, all four lights will be active.
   Press any of the four corresponding buttons to start
   the game. Once the button is released, a single LED
   will flash briefly - press the corresponding button.
 
   All four LEDs will flash three times to indicate a
   correct entry. The same LED will again light, followed
   by another random LED. Repeat the sequence, the LEDs
   will all flash again and the sequence will begin again,
   getting longer by one LED after each correct entry. If
   at any point you make an error in repeating the sequence,
   all four LEDs will turn on and you will need to reset
   the MCU to begin another game.
   =====================================================
*/
 
// INCLUDES
#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"
#include "lcd.c"
 
// STATE DEFINES
#define STATE_Setup          0
#define STATE_PlayNextSeq    1
#define STATE_WaitForPlayer  2
#define STATE_CorrectSeq     3
#define STATE_LoseGame       4
#define STATE_WinGame        5
 
// MACROS
#define GetButton() (uint8_t)(~PINC & 7)
#define Timer0On()  TCCR0  |= (1<<CS00);
 
 
// PROTOTYPES
uint8_t CreateTimerRand(void);
 
 
// PROGRAM ROUTINES
int main(void)
{
	uint8_t CurrentState            = STATE_Setup;
	uint8_t SequenceBuffer[20]		= {};
	uint8_t CurrSeqPosC             = 0;
	uint8_t CurrentLevel            = 0;
	unsigned char echo[10];
 
	DDRC = (1<<PC3)|(1<<PC4)|(1<<PC5);       // LED port set as outputs
	PORTC = (1<<PC3)|(1<<PC4)|(1<<PC5);       // All LEDs off initially
 	lcd_init(LCD_DISP_ON);
	lcd_clrscr(); // Clear display and home cursor
 
	Timer0On();                   // Turn on the timer 0, to run at 1MHz (clock). This is used to determine the
	                              // Random sequence bytes; it's value is read after the last sequence byte is
	                              // entered by the user.
 
	while (1)                     // Infinite Loop
	{
		switch (CurrentState)
		{
			case STATE_Setup:
				CurrentLevel = 1;          	// Reset current level variable
				CurrSeqPosC  = 0;          	// Reset current sequence position variable
 
				PORTC &= ~(7<<PC3);       	// All LEDs on
 
				while (!(GetButton()))		// Wait until a button is pressed, store pressed button
					;  						
 
				PORTC |= (7<<PC3);        	// All LEDs off
 
				SequenceBuffer[0] = CreateTimerRand(); // Create a random sequence byte from the timer value for the first sequence
 
				_delay_ms(400);           	// Wait a 400ms before continuing
 
				CurrentState = STATE_PlayNextSeq;
				break;
 
			case STATE_PlayNextSeq:
				PORTC &= (~SequenceBuffer[CurrSeqPosC]<<PC3);    	// Turn on sequence LED
				_delay_ms(200);                                    	// Wait 200ms
				PORTC |= (SequenceBuffer[CurrSeqPosC]<<PC3);   		// Turn off sequence LED
				_delay_ms(200);                                     // Wait 200ms
 
				if (++CurrSeqPosC == CurrentLevel)                  // Sequence playing complete, wait for player input
				{
					CurrSeqPosC  = 0;                               // Reset sequence position counter to 0
					CurrentState = STATE_WaitForPlayer;
				}
				else                                                // Sequence still playing
				{
					CurrentState = STATE_PlayNextSeq;
				}
				break;
 
			case STATE_WaitForPlayer:
				while (GetButton()) {};                             // Wait until all buttons released before accepting key
 
    			uint8_t PressedButton = 0;
 
				while (!(PressedButton))                            // Wait until a button is pressed, store pressed button
					PressedButton = GetButton();
 
				PORTC &= (~PressedButton<<PC3);                  	// Light up the pressed button's LED
				_delay_ms(200);                                     // Wait 200ms
				PORTC |= (PressedButton<<PC3);                  	// Turn off the pressed button's LED
				_delay_ms(200);                                     // Wait 200ms
 
				if (PressedButton == SequenceBuffer[CurrSeqPosC])   // Correct button pressed
				{
					if (++CurrSeqPosC == CurrentLevel)              // Sequence finished by player
					{
						CurrentLevel++;                             // Increase the level by one
						CurrSeqPosC = 0;                            // Reset sequence position counter to 0
 
						if (CurrentLevel > 20)                    	// A genious has completed the entire sequence
						{
							CurrentState = STATE_WinGame;
						}
						else                                        // Still more room in the buffer, create a new random byte and set the state accordingly
						{
							SequenceBuffer[CurrentLevel - 1] = CreateTimerRand(); // Create the next sequence byte from the timer
 
							CurrentState = STATE_CorrectSeq;
						}
					}
					else
					{
						CurrentState = STATE_WaitForPlayer;
					}
				}
				else
				{
					CurrentState = STATE_LoseGame;
				}
				break;
 
			case STATE_CorrectSeq:
				for (uint8_t FlashCount=0; FlashCount<3; FlashCount++) // Flash the LEDs three times
				{
					PORTC &= ~(7<<PC3);                            	// Turn on all the LEDs
					_delay_ms(100);                                 // Wait 100ms
					PORTC |= (7<<PC3);                             	// Turn off all the LEDs
					_delay_ms(100);                                 // Wait 100ms
				}
 
				CurrentState = STATE_PlayNextSeq;
				break;
 
			case STATE_LoseGame:
				PORTC &= ~(7<<PC3);            	// Turn on all LEDs
				// Put string to display (line 1) with linefeed
				itoa(CurrentLevel-1,echo);
				lcd_gotoxy(0,0);
				lcd_puts("Vastasid:");
				lcd_gotoxy(0,1);
				lcd_puts(echo);
 
				CurrentState = STATE_LoseGame;
				break;
 
			case STATE_WinGame:
				PORTC ^= (7<<PC3);  			// Invert LEDs status
				_delay_ms(200);                 // Wait 200ms before continuing
 
				CurrentState = STATE_WinGame;
				break;
		}
	}
}
 
uint8_t CreateTimerRand(void)
{
	uint8_t RVal = TCNT0;   // Get the timer0 value into a variable
 
	// Priority encoder: Uses ordered tests to save code so that only
	// the first matching test code is executed.
	if      (RVal <= 85)  RVal = (1<<0);
	else if (RVal <= 170) RVal = (1<<1);
	else                  RVal = (1<<2);
 
	return RVal;            // Shift 1 by the new random number between 0 and 2, return the new sequence byte
}

Exercise 6

Measures reaction time. Program start when one button is pressed, then a LED goes on and user have to press a button under the LED. Sequence and time when LED goes on is random. Best result in milliseconds is presented to the user (on the 7-seg display or LCD). (lcd.c lcd.h)

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include "lcd.h"
 
 
volatile uint8_t ovf = 0;
 
//Timer 1 Overflow interrupt to indicate too slow input
ISR(TIMER1_OVF_vect)
{
	ovf =1;
}
 
//Starts the Timer Counter unit
static inline void TimerStart()
{
	TCNT1 = 0;
	TCCR1B = (4<<CS10); //57600 Hz clock (256 prescale)
}
 
//Stops the Timer
static inline void TimerStop()
{
	TCCR1B = 0;
}
 
//Blink all LEDs
static inline void Blink()
{
	PORTC &= ~((1<<PC3)|(1<<PC4)|(1<<PC5));
	_delay_ms(100);
	PORTC |= (1<<PC3)|(1<<PC4)|(1<<PC5);
	_delay_ms(100);
}
 
static inline int Button(uint8_t pin)
{
	/* button is on when BIT is low (0) */
    if ((PINC & (1<<pin)) == 0)
    {
    	for(uint8_t i=0;i<25;i++)
		{
        	if ((PINC & (1<<pin))!=0)
				return 0;
			_delay_ms(1);
		}
    }
	else
		return 0;
    return 1;
}
 
int CheckPress()
{
	if(Button(0)) 				//SW1 pressed
	{
		Blink();
		_delay_ms(500);
		return 1;
	}
	else if (Button(1)) 		//SW2 pressed
	{
		Blink();
		_delay_ms(500);
		return 2;
	}
	else if (Button(2)) 		//SW3 pressed
	{
		Blink();
		_delay_ms(500);
		return 3;
	}
	else
		return 4;
}
 
int main(void)
{
	DDRC = (1<<PC3)|(1<<PC4)|(1<<PC5);	//LED pins outputs, other inputs
	PORTC = (1<<PC3)|(1<<PC4)|(1<<PC5);	//LEDs off
 
	TIMSK = (1<<TOIE1);					//Enable overflow interrupt for Timer1
	sei();								//Global interrupts enable
 
	//initialize LCD, clear screen and display welcome text
	lcd_init(LCD_DISP_ON);
	lcd_clrscr();
	lcd_puts("Reaction timer\n");
	_delay_ms(1000);
	lcd_puts("press any key");
 
	uint16_t rng = 500;
	uint16_t temp = 0;
 
	while(1)
	{
		if(CheckPress()!=4)				//Wait for "any key"
		{
			char buffer[6];
			rng = rng * 10;
			lcd_clrscr();
 
			_delay_ms(rng);				//Wait for random amount of time calculated from
										//the time it took to press "any key"			
 
			if(rng < 2000)				//select which random LED to turn on and wait for
			{
				PORTC &= ~(1<<PC3);
				TimerStart();
				while((PINC & (1<<PC0))&&(!ovf)) 	//wait for user input or timer overflow
					;
				TimerStop();
			}
			else if((rng >= 2000)&&(rng < 3500))
			{
				PORTC &= ~(1<<PC4);
				TimerStart();
				while((PINC & (1<<PC1))&&(!ovf))	//wait for user input or timer overflow
					;
				TimerStop();
			}
			else if(rng >= 3500)
			{
				PORTC &= ~(1<<PC5);
				TimerStart();
				while((PINC & (1<<PC2))&&(!ovf))	//wait for user input or timer overflow
					;
				TimerStop();
			}
 
			lcd_clrscr();
			lcd_puts("Time: ");
 
			if(ovf == 1)					//if it took too long to input say so
			{
				lcd_puts(" Too slow");
				ovf = 0;
			}
			else							//else calculate time in ms
			{
				temp = TCNT1 / 576 * 10 ;
				itoa(temp,buffer,10);
				lcd_puts(buffer);
			}
			lcd_puts("ms\nPress any key");	//displat information on screen
			PORTC = (1<<PC3)|(1<<PC4)|(1<<PC5);
			_delay_ms(500);
		}
		rng++;
 
		if(rng > 500)
			rng = 50;
	}
}

Exercise 7

Flashes LEDs with different frequency using timer. Frequency can be changed by the buttons. (S1 – 1 Hz, S2 – 0,5 Hz, S3 – 0,1 Hz).

#include <avr/io.h>
#include <avr/interrupt.h>
 
ISR(TIMER1_COMPA_vect)
{
	PORTC ^= (1<<PC3);		//Toggle LED1
}
 
int main(void)
{
	DDRC = (1<<PC3)|(1<<PC4)|(1<<PC5);		//LED's as outputs all other inputs
	PORTC = (1<<PC3)|(1<<PC4)|(1<<PC5);		//LED pins high - LED's off
 
	//Initialize Timer1, CTC mode, TOP OCR1A
	TCCR1A = 0;
	TCCR1B = (1<<WGM12);
 
	TIMSK = (1<<OCIE1A);			//Enable Timer 1 OCR1A Compare match Interrupt
	sei();
 
	while(1)
	{
		if((PINC & 7) == 6) 		//SW1 pressed
		{
			OCR1A = 14400;			//1Hz
			TCNT1 = 0;		
			TCCR1B |= (5<<CS10);	//Timer Start
		}
		else if ((PINC & 7) == 5) 	//SW2 pressed
		{
			OCR1A = 7200;			//0.5Hz
			TCNT1 = 0;
			TCCR1B |= (5<<CS10);	//Timer Start
		}
		else if ((PINC & 7) == 3) 	//SW3 pressed
		{
			OCR1A = 1440;			//0.1Hz
			TCNT1 = 0;
			TCCR1B |= (5<<CS10);	//Timer Start
		}
	}
}

Exercise 8

Flashes LEDs with different frequency using timer. S1 increases flashing frequency and S3 decreases.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
 
 
ISR(TIMER1_COMPA_vect)
{
	PORTC ^= (1<<PC3)|(1<<PC4)|(1<<PC5); //toggle all LEDs
}
 
int main(void)
{
	uint16_t freq;
 
	DDRC = (1<<PC3)|(1<<PC4)|(1<<PC5);	//LED pins outputs, other inputs
	PORTC = (1<<PC3)|(1<<PC4)|(1<<PC5);	//LED's off
 
	//Initialize Timer1, CTC mode, F_CPU/1024 Hz,  
	TCCR1A = 0;
	TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);
	OCR1A = 1000;
	freq = 1000;
 
	TIMSK = (1<<OCIE1A); 				//enable  COMPA interrupt
 
	sei();								//enable global interrupts
 
	while(1)
	{
		if((PINC & 7) == 6) 			//SW1 pressed
		{
			if (freq > 100)
				freq = OCR1A - 100;
			else
				freq = 100;
			OCR1A = freq;				//increase frequency
			TCNT1 = 0;	
		}
		else if ((PINC & 7) == 3) 		//SW3 pressed
		{
			if (freq < 20000)
				freq = OCR1A + 100;
			else
				freq = 20000;	
 
			OCR1A = freq;				//decrease frequency
			TCNT1 = 0;
		}
		_delay_ms(100);
	}
}

Exercise 9

Counts numbers on 7-seg display from 1 to 9. If button S1 is pressed the counting starts to go backward. If S3 is pressed the counting resumes to go forward. Digit change frequency is 1 second.

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
 
#define FORWARDS	0
#define BACKWARDS	1
 
//global variables
volatile uint8_t direction = FORWARDS;
volatile uint8_t num = 0;
 
//function declarations
void WriteDisplay(uint8_t);
int main();
 
 
//Timer 1 interrupt (every 1 second)
ISR(TIMER1_COMPA_vect)
{
	if((direction == FORWARDS) && (num < 9)) 		//count up until 9
		num++;
	else if ((direction == BACKWARDS) && (num > 0))	//count down until 0
		num--;
	WriteDisplay(num);
}
 
void WriteDisplay (uint8_t digit) 
{
	 volatile uint8_t nr;
	 switch (digit) //table read to get segment map representation of the digit
	 {
		 case 0 : {nr = 0b00111111;break;} //every bit corresponds to one segment
		 case 1 : {nr = 0b00000110;break;} //"1"
		 case 2 : {nr = 0b01011011;break;} //"2" and so on
		 case 3 : {nr = 0b01001111;break;} 
		 case 4 : {nr = 0b01100110;break;} 
		 case 5 : {nr = 0b01101101;break;} 
		 case 6 : {nr = 0b01111100;break;} 
		 case 7 : {nr = 0b00000111;break;}
		 case 8 : {nr = 0b01111111;break;} 
		 case 9 : {nr = 0b01100111;break;}  
		 default: {nr = 0b01111001;}//E
	 }
 
	 PORTG &= ~(1<<PG2); 				//latch low
	 for(uint8_t i=8; i>0; i--) 		//for every bit in the byte
	 {
	 	//if bit is set, sets the data out pin
		if (nr & (1<<(i-1))) 
			PORTC |= (1<<PC6); 			//serial out
		else 
			PORTC &= ~(1<<PC6); 		//serial out
 
		PORTC |= (1<<PC7); 				//clock high
		_delay_us(10);					//series of one cycle delays to ensure required timing (according to datasheet)
 
		PORTC &= ~(1<<PC7); 			//clock low
		_delay_us(10);
	 }
	 PORTG |= (1<<PG2); 				//latch high
}
 
int main(void)
{
	DDRC = (1<<PC3)|(1<<PC4)|(1<<PC5)|(1<<PC6)|(1<<PC7);	//declare input-outputs
	DDRG = (1<<PG2);
 
	PORTC = (1<<PC3)|(1<<PC4)|(1<<PC5); //all LED's off
 
	//Initialize Timer1, CTC mode, OCRA interrupt 1s 
	TCCR1A = 0;
	TCCR1B = (1<<WGM12)|(5<<CS10);
 
	TIMSK = (1<<OCIE1A);
	OCR1A = 14400;
 
	sei();
 
	while(1)
	{
		if((PINC & 7) == 6) 			//SW1 pressed
		{
			direction = BACKWARDS;
		}
		else if ((PINC & 7) == 3) 		//SW3 pressed
		{
			direction = FORWARDS;
		}
	}
}

~~DISCUSSION~~