środa, 10 sierpnia 2016

Hello world AVR! - część 2 kursu języka C dla AVR

Zestaw testowy ATB v1.05 (Atnel)
W dniu dzisiejszym zabierzemy się za programowanie. Zaświecimy diodami, zabrzęczymy brzęczykiem (buzzerem) i poklikamy w przyciski (microswitche).

Mam nadzieję, że forma "lekcji" jaką dla was przygotowałem spodoba się, a przede wszystkim każdy z was wyciągnie z niej coś dla siebie. Nie ma na co czekać, przygotujcie kawę czy herbatę, odpalajcie Eclipse, mkAVRCalculatora, przygotujcie zestawy / stykówki i bierzemy się za naukę ;)



Na sam początek troszkę teorii...
W kursie nie będę pisać książki, ani prowadzić żadnych wykładów, a jak to większość początkujących mówi (chociażby w szkołach technicznych) "oo tylko teoria i teoria, ja to bym wolał praktycznie coś spróbować, a nie tylko te książki...". Dlatego też postaram się wam pokazać programowanie od strony praktycznej. Zobaczymy jak "myśli" mikroprocesor i wykonamy od razu ćwiczenia praktyczne, tak żeby coś się świeciło i coś brzęczało.

...
... ale zanim zaczniemy ...
...
...
... wybierz odpowiednią pigułkę ...
... jak raz wejdziesz do świata elektroniki ...
... to zostaniesz tu na dobre ... ;)

Na materiale wideo będę tłumaczył poszczególne kroki pisania programu oraz wyjaśniał pojęcia jakie będą się pojawiać min. kierunki portów i pinów, rodzaje zmiennych, pętle itd... W tym momencie, chciałbym zwrócić uwagę na to, że nie jestem żadnym renomowanym dydaktykiem i podczas prowadzenia tego kursu będę się wspierał o książkę Mikrokontrolery AVR Język C - podstawy programowania.
Bluebook
Wszystkim naprawdę zainteresowanym polecam również zacząć lekturę książek traktujących o języku C. 

Dodatkowo przed podejściem do ćwiczenia polecam przeczytać ten artykuł:


Schemat i określenie celu.
Zanim przygotujemy schemat do ćwiczenia, wypadało by się zastanowić jakie zadanie będzie miało spełniać nasze "urządzenie". Możemy sobie w tym momencie obrać za cel miganie diodą. Jednak czy samo zamiganie diodę będzie takie satysfakcjonujące (w szczególności kiedy zobaczysz jakie to proste)? Postawmy sobie poprzeczkę nieco wyżej i zróbmy program, który będzie nam migał diodami od lewej do prawej i na odwrót, a za pomocą przycisku będziemy mogli regulować prędkość z jaką diody będą się "przemieszczać", dodatkowo za każdym razem kiedy diody "przejadą" z jednej na drugą stronę to zapiszczy buzzer. Uważam, że na sam początek to dobry cel, oczywiście po drodze przejdziemy przez samo zamiganie diodą, obsługę microswitcha, dowiemy się co nie co o pętlach, zmiennych, bibliotekach... co się będę rozpisywał, na następnym etapie (programowania) sami zobaczycie ;)

Do zrobienia takiego "urządzenia" będziemy potrzebowali:
  • Diod LED (8 szt.)
  • Rezystor do diod (8 szt.)
  • Buzzer (1 szt.) + tranzytor NPN (1 szt.) + rezystor 2,2K (1 szt.)
  • ATmega32 (może być dowolny inny procek z rodziny AVR, ja będę pokazywał na tym przykładzie)
  • Rezystor 10K (1 szt.)
  • Microswitch (2 szt.)
  • (Opcjonalnie) Kondensator bipolarny 22uF (1 szt.)
  • (Opcjonalnie) Kondensator ceramiczny 100nF (1 szt.)
  • (Opcjonalnie) Kwarc 110592 MHz (1 szt.) + kondensator ceramiczny 22pF (2 szt.)
  • (Opcjonalnie) Złącze KANDA (1 szt.)

Ja korzystam z zestawu testowego ATB v1.05, gdzie wszystkie te elementy mam już zamontowane, jeżeli nie macie dostępu do takiej płytki przygotuję dla was schemat do podłączenia tych elementów na np. płytce stykowej.
Schemat do ćwiczenia 1

Czas na parę wyjaśnień:
  • Części opcjonalnych nie musicie używać (bez kwarcu z kondensatorami 22pF będzie trzeba ustawić wewnętrzne taktowanie w procesorze, ale to można zrobić dosłownie kilkoma kliknięciami myszką przy pomocy programu mkAVRCalculator, a kondensatory 100nF i 22uF służą do filtrowania zasilania, zagadnienie to jest bardzo ważne dla elektroników i każdy powinien wiedzieć jak prawidłowo filtrować zasilanie do swojego uC. Przeczytajcie koniecznie ten artykuł - filtrowanie zasilania).
  • O co chodzi ze złączem KANDA? Do wyjść MOSI, MISO, SCK i RESET trzeba podłączyć się przez programator, a do tego właśnie celu zostało stworzone to gniazdo, przeczytaj ten artykuł, żeby wiedzieć o co chodzi - ISP - KANDA - koniec problemów !.
  • Dlaczego nie napisałem wartości rezystorów dla diod LED? Ponieważ w zależności jakie diody sobie wybierzecie, to od tego zależy jakie rezystory będzie trzeba dobrać. Pamiętajcie, że diodę LED zawsze podłączamy przez rezystor! (z doświadczenia praktycznego powiem wam, że do testów z diodami nie trzeba się bawić w nie wiadomo jakie dobieranie i obliczanie rezystorów wystarczy dorzucić jakiś o wartości w przedziale od 180Ohm - 1k) Jak właściwie dobrać ten rezystor? Żeby nie tracić czasu wykorzystajcie do tego celu kalkulator rezystorów dla diod - kalkulator majsterkowicza, a w niedalekiej przyszłości przygotuję artykuł dotyczący właśnie takich przeliczeń. W moim przypadku korzystam z zielonych diod i przy napięciu zasilania ok. 5V wykorzystuję rezystory o wartości 180 Ohm.
  • Jeżeli nie posiadacie zestawu ATB 1.05 z wbudowanym programatorem USBASP i zastanawiacie się jaki wybrać dla siebie, przeczytajcie koniecznie ten artykuł - Jaki wybrać programator sprzętowy ?

Piszemy program.
Przed rozpoczęciem pisania kodu do większych projektów zawsze powinniśmy wyznaczyć sobie punktowo założenia jakie będzie spełniać nasze urządzenie. Następnie zabrać się za pisanie algorytmu, żeby podczas pisania programu dokładnie wiedzieć co się robi. Uwierzcie mi, że z algorytmem się nie zgubicie ;)

Jednak do tak prostego projektu, gdzie naszym zadaniem jest zaświecenie diodami, obsłużenie dwóch przycisków i brzęczyka, postawienie celu w postaci ogólnikowej (tak jak to zrobiłem w punkcie "Schemat i określenie celu") jest w zupełności wystarczające. 

Zaczynajmy więc! 
Zapraszam do oglądania drugiej części kursu języka C na moim kanale youtube ;)


Challenge 4 you!



Napisz program w języku C na dowolnym AVR, który będzie realizował funkcję zegarka binarnego. Wykorzystując do tego celu 8 diod led ułożonych w jednym rzędzie, nie więcej niż 5 przycisków i brzęczyk.

Przyjmujesz wyzwanie?
Zachęcam do podzielenia się efektami swojej pracy, chociażby poprzez wysłanie mi na maila: pawel@mikropasja.pl. Jeżeli macie jakieś pytania, bądź uwagi zapraszam do dyskusji w komentarzach poniżej.

P.S. Nie zapomnijcie ocenić filmiku na youtubie i subskrybować kanału ;)

Kod napisany podczas kursu:
/*
 * main.c
 *
 *  Created on: 8 sie 2016
 *      Author: Paweł
 */

/* Podciąganie bibliotek */
#include <avr/io.h>   // podstawowa
#include <util/delay.h>  // obsługa opóźnień _delay_()

/* Makro definicje preprocesora */
#define LED1 (1<<PC0)
#define LED1_ON PORTC &= ~LED1 // podanie stanu niskiego na PC0
#define LED1_OFF PORTC |= LED1 // podanie stanu wysokiego na PC0
#define LED1_TOG PORTC ^= LED1 // zmiana stanu na PC0

#define BUZZ (1<<PA0)
#define BUZZ_ON PORTA |= BUZZ // podanie stanu wysokiego na PA0
#define BUZZ_OFF PORTA &= ~BUZZ // podanie stanu niskiego na PA0
#define BUZZ_TOG PORTA ^= BUZZ // zmiana stanu na PA0

#define KEY1 (1<<PA1)
#define KEY2 (1<<PA2)

/* Deklaracje zmiennych */
uint16_t key_lock1=0, key_lock2=0;  // zmienne potrzebne do obsługi przycisków
uint16_t zmiana_czasu = 500;

/* Deklaracje funkcji */
void moja_zmiana_czasu( uint16_t ms );

/* Funkcja główna programu */
int main( void ) {

 DDRC |= 0xff; // ustawienie całego portu C na wyjście
 DDRA |= BUZZ; // ustawienie pinu PA0 na wejście
// DDRA &= ~KEY1 | ~KEY2; // ustawienie pinów PA1 i PA2 na wejścia (nie potrzebne bo domyślnie, rejestr DDRX jest ustawiony jako wejście

 PORTA |= KEY1 | KEY2; // podciągnięcie przycisków do VCC

 /* Inicjalizacja */
 LED1_ON;
 BUZZ_ON;
 _delay_ms(200);
 LED1_OFF;
 BUZZ_OFF;
 PORTC |= 0xff; // podanie stanu wysokiego na caly port C - wygaszenie wszystkich diod

 /* Pętla główna programu */
 while(1) {
  /* Miganie diod od prawej do lewej */
  for( uint8_t i=0; i<8; i++ ) {
   PORTC &= ~(1<<i);     // PC0 = 0; PC = 1; PC2 = 2...
   if( i>0 ) PORTC |= (1<<(i-1));  // wygaszanie diody na pozycji i-1
//   _delay_ms(200);
   moja_zmiana_czasu( zmiana_czasu ); // opóźnienie
  }
  BUZZ_ON;
  _delay_ms(50);
  BUZZ_OFF;

  /* Miganie diod od lewej do prawej */
  for( int8_t i=8; i>-1; i-- ) {
   PORTC &= ~(1<<i);
   PORTC |= (1<<(i+1));  // wygaszanie diody na pozycji i+1
   //_delay_ms(200);
   moja_zmiana_czasu( zmiana_czasu );
  }
  BUZZ_ON;
  _delay_ms(50);
  BUZZ_OFF;
 } //koniec pętli głównej

} //koniec funkcji głównej

/* Definicje własnych funkcji */
void moja_zmiana_czasu( uint16_t ms ) {

 /* Zmniejszaj wartośc argumentu do 0 */
 while( ms-- ) {
  /* Obsługa klawisza - 1 */
  if( !key_lock1 && !(PINA & KEY1) ) {
   key_lock1 = 500;
   zmiana_czasu += 100; // zapist ten jest równoważny z zapisem: zmiana_czasu = zmiana_Czasu + 100;
   if( zmiana_czasu > 800 ) zmiana_czasu = 800;
  } else if( key_lock1 && (PINA & KEY1) ) key_lock1--;

  /* Obsługa klawisza - 2 */
  if( !key_lock2 && !(PINA & KEY2) ) {
   key_lock2 = 500;
   zmiana_czasu -= 50; // zapist ten jest równoważny z zapisem: zmiana_czasu = zmiana_Czasu - 50;
   if( zmiana_czasu < 50 ) zmiana_czasu = 50;
  } else if( key_lock2 && (PINA & KEY2) ) key_lock2--;

  _delay_ms(0.95);
 }
}

9 komentarzy:

  1. Witam, poradniki spoko:)
    Ale czy to nie jest błąd
    zmiana_czasu += 100; // zmiana_czasu == zmiana_czasu + 100??
    np.
    zmiana_czasu=200;
    zmiana_czasu == zmiana_czasu + 100 // wyrażenie to zwraca false

    Zapis zmiana_czasu += 100; jest równoważny zmiana_czasu = zmiana_czasu + 100

    == operator logiczny
    = operator przypisania

    OdpowiedzUsuń
    Odpowiedzi
    1. Zgadza się. Jeżeli było by to zapisane jako część kodu, nie otrzymalibyśmy zamierzonego efektu. Jednak jest to komentarz.

      Czujny kolega Raf na warcie ;)
      Taki zapis w komentarzu może wywołać zamęt w głowie, dlatego też co prędzej podmienię go na fragment, który napisałeś :)

      Stawiam, że czytałeś jakąś książkę o programowaniu ;) ?

      Usuń
    2. Dokładnie tylko komentarz.. ale początkującym, takim jak ja, może zawrócić w głowie.
      Tak czytałem książki, czytam nadal BB, GB czeka na YB:) do tego forum, bloga, poradniki...
      Pozdrwiam

      Usuń
    3. I dlatego ważne jest kolorowanie składni :) +100 do czytelności.

      Usuń
  2. Cześć. W jakim programie jest zrobiony schemat? Pozdrawiam, Piotr.
    Ps.Fajny poradnik .

    OdpowiedzUsuń
    Odpowiedzi
    1. Schemat przygotowałem w programie Altium Designer.

      Usuń
  3. poradnik fajny, tylko jeśli ma być dla początkujących, to za dużo informacji na jeden raz i wydaje mi się,że jeśli coś tłumaczysz , a później się okazuje,że to poprawnie nie działa i znów poprawiasz , to można się w tym pogubić. Ja jestem początkującym i dla mnie jest to właśnie zbyt zagmatwane. Jeśli chcesz, aby ludzie uczyli się z Twoich poradników , tak jak z poradników Twojego ojca, to znacznie zwolnij z informacjami w jednym poradniku. No chyba,że nie jest to poradnik dla początkujących ;) Pozdrawiam

    OdpowiedzUsuń
    Odpowiedzi
    1. Dzięki za opinię, w przyszłych częściach na pewno stonuję z ilością przekazywanych informacji.

      Usuń
  4. SUPER PORADNIK.PROSZĘ WIĘCEJ TAKICH.
    TAKICH PORADNIKÓW POTRZEBUJĄ POCZĄTKUJĄCY.
    GRATULUJĘ.
    ADAM

    OdpowiedzUsuń