Table of Contents

0x02 Migająca dioda

Migająca dioda to typowa aplikacja “Hello world” w świecie MCU. Pozwala ona przetestować toolchain czyli zestaw narzędzi za pomocą których wygenerujemy i wgramy kod. Pozwala ona również sprawdzić czy układ działa.

Wymagania

  1. Działający programator, połączenie z układem
  2. Skonfigurowane środowisko
  3. Diody LED, odpowiednie rezystory
  4. Dobra znajomość języka C
  5. Znajomość praw logiki Boolea, podstawowych operacji NOT, AND, OR, XOR

Pierwszy program

Do pinu PB0 należy podpiąć przez odpowiedni rezystor diodę LED (w dowolnym kierunku). Stwórz nowy projekt i w pliku main.c wklej poniższy kod:

/*
 * main.c
 *
 *  Created on: 26-02-2011
 *      Author: Maciek
 *      Najprostszy program
 */
 
//io.h zawiera informacje o portach w układzie (np DDRB, PORTB)
#include <avr/io.h>
//delay.h zawiera podprogram _delay_ms
#include <util/delay.h>
 
int main()
{
   DDRB = 0xFF;
   PORTB = 0x00;
 
   //Nieskończona pętla
   //W C 0 oznacza fałsz a każda inna liczba to prawda
   while(1)    
   {
      PORTB ^= 1;      //przełącz pin 0 portu B (0->1 lub 1->0)
      _delay_ms(1000); //Czekaj 1 sekundę
   }
}

Porty wejścia wyjścia

Najbardziej podstawowym elementem mikroprocesora są porty wejścia/wyjścia, umożliwiają one podstawową komunikację programu z peryferiami układu. Pozwalają na proste operacje (zapalenie diody, włączenie brzęczyka, załączenie tranzystora, przekaźnika itd.) jak również na bardziej skomplikowane operacje (przetwarzanie C/A1), realizację interfejsów). Większość pinów (wyprowadzeń, nóżek układu) jest kontrolowana przez porty I/O2) (oczywiście piny posiadają różne funkcje, wiele z nich może pracować jako I/O lub pełnić inną funkcję. Patrz nota katalogowa układu rozdział 12.3 Alternate Port Functions), są niezwykle uniwersalnym narzędziem.

Praktycznie porty układu mogą znajdować się w 3 stanach (Są trójstanowe):

Co więcej za pomocą portu możemy:

Sterowaniem zachowania portów zajmują się 3 rejestry:

Każdy z powyższych rejestrów jest 8 bitowy. W przypadku układu ATmega8 zamiast x możemy wpisać B, C lub D (takie porty posiada układ - patrz nota). Pinowi numer 0 odpowiadają zerowe bity rejestrów DDRx,PORTx,PINx (analogicznie dla wszystkich 8 [0→7] pinów). Port składa się z 8 przerzutników czyli bitów informacji i można go interpretować jako 8 bitową liczbę. Porty są dostępne przez szynę adresową a ich modyfikacja w C jest bardzo prosta, wystarczy użyć ich nazwy jak zmiennej (Patrz przykłady poniżej).

Możliwe stany portów I/O przedstawia poniższa tabela:

DDR PORT I/O Komentarz
0 0 Input Floating
0 1 Input Hi!3))
1 0 Output Lo
1 1 Output Hi

Układ ATmega8 posiada:

To co tutaj napisałem to minimum wiedzy. Portom I/O poświęcony jest cały 12 rozdział noty katalogowej, warto go całego przeczytać i spróbować zrozumieć.

Programowanie w C

Na początku w ramach przypomnienia trochę podstawowych informacji dotyczących zapisu w C oraz trochę informacji specyficznych dla C AVR.

Typy danych

uint8_t  # 8 bitowa liczba bez znaku 0->255 (unsigned char)
int8_t   # 7 bitowa liczba ze znakiem -128->127 (signed char)
 
uint16_t # 16 bitowa liczba bez znaku (unsigned int)
int16_t  # 15 bitowa liczba ze znakiem (signed int)
uint32_t # 32 bitowa liczba bez znaku (unsigned long int)
int32_t  # 31 bitowa liczba ze znakiem (signed long int)
 
char*    # Standardowy string w C

Zapis liczb

Poniższe przypadki są jednoznaczne:

uint8_t liczba = 0xCD        #Zapis hexadecymalny
uint8_t liczba = 0b11001101  #Zapis binarny
uint8_t liczba = 205         #Zapis dziesiętny

Warto umieć płynnie zamieniać liczby pomiędzy tymi 3 systemami liczbowymi.

Podstawowe operacje na bitach

Przykłady

W poniższych przykładach diody zapalane są stanem logicznym 1 czyli łączymy anodę przez rezystor do układu a katodę do masy. Połączenie odwrotne spowoduje że diody będą zapalane stanem logicznym niskim (anoda do VCC, katoda do uC).

/*
 * main.c
 *
 *  Created on: 2-03-2011
 *      Author: Maciek
 *      Najprostszy zegar binarny
 */
 
#include <avr/io.h>
#include <util/delay.h>
 
//Knfiguracja sprzętowa: do portu B podpięte są 4 diody do pinów 0-3
 
int main()
{
   DDRB = 0x0F;  //Modyfikacja rejestru DDRB:  Ustaw piny 0-3 portu B jako wyjście
   PORTB = 0x00; //Modyfikacja rejestru PORTB: Ustaw początkowo wszystkie piny portu B na stan niski
 
   //Nieskończona pętla
   while(1)
   {
      PORTB++;         //Inkrementacja wartości rejestru
      _delay_ms(1000); //Czekaj 1 sekundę
   }
 
   // Lepiej nie dopuszczać programu żeby wychodził z main (stosować nieskończoną pętle)
   // Dopoki nasz program nie korzysta z przerwań w wypadku braku pętli kompilator sam ją doda, ale z instrukcją
   // blokującą przerwania! (Stan na 2011, wcześniej mogło być inaczej)
}
/*
 * main.c
 *
 *  Created on: 2-03-2011
 *      Author: Maciek
 *      Kolejny przykład
 */
 
#include <avr/io.h>
#include <util/delay.h>
 
//Knfiguracja sprzętowa: do portu B podpięte są 4 diody do pinów 0-3
 
//Dobrze jest na początku okrelić połączenia w poniższy sposób, w razie zmiany
//konfiguracji sprzętowej łatwiej jest zaminić dane w jednym miejscu niż w 50 :)
#define LED_DIR DDRB
#define LED_P   PORTB
 
int main()
{
	//Inicjalizacja portów
	LED_DIR = 0x0F;
	LED_P = 0x00;
 
	//Zapal pierwszą diodę
	LED_P |= (1<<0);
	_delay_ms(1000);
 
	//Zapal 3 diodę
	LED_P |= (1<<2);
	_delay_ms(1000);
 
	//Przełącz (zgaś) pierwszą diodę
	LED_P ^= (1<<0);
	_delay_ms(1000);
 
	// Zgaś 3 diodę
	LED_P &=~(1<<2);
 
	//Nieskończona pętla
	for(;;);
}

Zadania

Uwagi

1)
cyfrowo-analogowe
2)
Input/Output - wejścia/wyjścia
3)
Pomimo że wejście, będzie pracował również jak wyjście w stanie Hi (podciągnięcie pod Vcc
4)
Można skonfigurować pin reset jako port PC6 wtedy mamy do dyspozycji 7 pinów portu C ale na razie warto zapomnieć o takiej możliwości.
5)
Nota katalogowa 25.1 Absolute Maximum Ratings