Mikrokontrolery - Jak zacząć?

... czyli zbiór praktycznej wiedzy dot. mikrokontrolerów.

poniedziałek, 4 kwietnia 2011

SmartPIP: Czujnik światła - testowanie


Autor: Dondu


Artykuł jest częścią cyklu: SmartPIP - Elektroniczny dręczyciel

Nadszedł czas na przetestowanie opracowanego czujnika światła. Schemat układu testowego ograniczymy do niezbędnego minimum:

SmartPIP: Układ testowy czujnika światła.


Do powyższego schematu należy dodać jedną z wersji interfejsu RS-232, które znajdziesz tutaj: RS-232: Komunikacja ATmega8 z komputerem. Na schemacie zaznaczyłem etykietami MIKR-RXD oraz MIKR-TXD piny, które należy połączyć z pinami interfejsu RS-232 oznaczonych tymi samymi etykietami.

Zamiast RS-232 możesz wykorzystać wyświetlacz LCD, ale to już opracuj we własnym zakresie.

Dioda LED dodana jest wyłącznie w celach  testowych (np. gdyby terminal nie wyświetlał danych), więc nie musi być zamontowana. Jeżeli ją zamontujesz, to w kierunku zgodnym z powyższym schematem, by nie pobierała prądu z pinu mikrokontrolera. Rezystor diody LED oznaczony jako R2 jest nieco większy niż standardowy, ponieważ chcemy ograniczyć skoki prądu w czasie testów. Najlepszym rozwiązaniem będzie usunięcie diody w czasie, gdy terminal będzie prawidłowo odbierał dane.

Schemat naszego układu testowego w zakresie minimalnych podłączeń odpowiada wersji totalne minimum. Dlaczego stosujemy wersję "totalne minimum"? Ponieważ spokojnie wystarczy nam rozdzielczość pomiarowa 8-bitów, a dodatkowy kondensator na pinie AREF, to dodatkowa upływność, której nie chcemy w naszym SmartPIP'ie.




Opis algorytmu


Program przygotowany jest (jak w każdej części cyklu o SmartPIP'ie) w wersji wieloplikowej z podziałem na funkcjonalności:
  • pomiar światła,
  • komunikacja RS-232,
  • program główny.

W programie na razie nie wykorzystujemy jeszcze licznika czasu, a opóźnienie między pomiarami wykonujemy za pomocą funkcji _delay_ms(x). Jest to celowy zabieg uproszczenia programu testowego, który w wersji wieloplikowej jest i tak (na pierwszy rzut oka) wystarczająco skomplikowany :-). Licznik czasu będziemy używać już w następnym artykule, gdzie dokonywać będziemy pierwszych pomiarów dobowych.

Do testowania czujnika będziemy dokonywać pomiarów światła z uwzględnieniem wykorzystania usypiania mikrokontrolera do trybu ADC Noise reduction, który jak już ustaliliśmy będziemy wykorzystywać w celu zwiększenia dokładności pomiaru i redukowania pobieranego prądu z baterii.

Dla potrzeb tego testu na stałe włączymy elementy czujnika światła (zasilanie czujnika i masę rezystora).

Wyniki pomiarów będziemy obserwować za pośrednictwem komputera podłączonego do mikrokontrolera za pomocą prostego interfejsu RS-232. Algorytm wysyłania opracowany jest dla wersji opartej o przerwania i tablicę bufora tekstu w pamięci SRAM mikrokontrolera.






dd_swiatlo.c
dd_swiatlo.h


Pliki te zawierają funkcjonalności dot. pomiaru światła za pomocą naszego czujnika z wykorzystaniem przetwornika ADC.


dd_swiatlo_adc_ini()

Funkcja odpowiedzialna za przygotowanie do pomiarów, czyli:

Włączenie czujnika - ustawienie odpowiednich stanów na pinach zasilania fototranzystora oraz masy rezystora, według ustalonych wcześniej zasad.

Inicjalizacja przetwornika ADC - ustawienie parametrów przetwornika ADC realizowane jest przez funkcję:
  • ustawiamy kanał wejściowy ADC1 (PC1) zgodnie ze schematem,
  • włączamy zasilanie czujnika światła oraz masę jego rezystora,
  • ponieważ używamy tylko ośmiu najbardziej znaczących bitów, stąd wykorzystujemy dostępne w tym przypadku wyrównanie wyniku do lewej (ADLAR). 
  • preskaler ADC ustawiamy go na 8, co daje nam częstotliwość taktowania przetwornika ADC równą 125kHz (przy taktowaniu mikrokontrolera wewnętrznym generatorem RC o częstotliwości 1MHz).
  • włączamy przerwania zakończenia pomiaru ADC, by móc wykorzystać tryb ADC Noise reduction oraz przygotowujemy odpowiedni tryb snu.

dd_swiatlo_adc_pomiar_start()

Funkcja ta zawiera jedynie rozkaz uśpienia mikrokontrolera dlatego, że tę funkcję będziemy rozbudowywać w dalszych artykułach o SmartPIP'ie.

ISR(ADC_vect)

Funkcja przerwania wywoływana po zakończeniu pomiaru przez przetwornik ADC jest pusta, a przyczyna wyjaśniona w komentarzu w kodzie. Podobnie jak funkcja powyżej, także i ta będzie rozbudowywana w dalszych artykułach.


Plik dd_swiatlo.c:
/*************************************************************************
* SmartPIP - Elektroniczny dręczyciel
* 
* Data:  kwiecień 2013
* Autor: Dondu
* www:   http://mikrokontrolery.blogspot.com/2011/04/SmartPIP-elektroniczny-dreczyciel-spis-tresci.html
* 
* Plik:  dd_swiatlo.c
* Opis:  Funkcjonalności dot. pomiaru światła
**************************************************************************/


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

#include "dd_main.h"
#include "dd_swiatlo.h"


//-------------------------------------------------------------------------

void dd_swiatlo_adc_ini(void){

 //Funkcja włącza czujnik światła oraz inicjuje przetwornik ADC

 //KROK 1 - włącz czujnik światła
 //włącz zasilanie fototranzystora
 ADC_PIN_ZAS_DDR  |= (1<<ADC_PIN_ZAS_NAZWA); //wyjście
 ADC_PIN_ZAS_PORT |= (1<<ADC_PIN_ZAS_NAZWA); //załącz napięcie
 //włącz masę rezystora pomiarowego
 ADC_PIN_REZ_DDR  |=  (1<<ADC_PIN_REZ_NAZWA);//wyjście
 ADC_PIN_REZ_PORT &= ~(1<<ADC_PIN_REZ_NAZWA);//załącz masę (zero)


 //KROK 2 - przygotuj przetwornik ADC
 //korzystamy tylko z 8 najbardziejznaczących bitów (wyrównanie do lewej)
 //częstotliwość ADC = 1MHz + preskaler 8 = 125kHz
 //ustaw pin pomiarowy ADC
 ADC_PIN_POM_DDR   &=   ~(1<<ADC_PIN_POM_NAZWA); //wejście
 ADC_PIN_POM_PORT  &=   ~(1<<ADC_PIN_POM_NAZWA); //wyłącz pull-up
 //inicjuj przetwornik ADC
 ADMUX  =      (1<<REFS0)        //VCC jako napięcie referencyjne
             | (1<<ADLAR)        //wyrównaj pomiar do lewej
             | ADC_PIN_POM_MUX;  //przełącz na kanał wybranego pinu ADC
 ADCSRA =      (1<<ADEN)         //włącz ADC
             | (1<<ADIE)         //włącz przerwania 
             | (1<<ADPS0)        //preskaler 8
             | (1<<ADPS1);

 //ustaw tryb snu ADC Noise Reduction
 set_sleep_mode(SLEEP_MODE_ADC); 
 sleep_enable();
}


//-------------------------------------------------------------------------

void dd_swiatlo_adc_pomiar_start(void){

 //Funkcja odpowiedzialna za rozpoczęcie pomiaru światła
 //rozpocznij pomiar światła poprzez uśpienie mikrokontrolera
 sleep_cpu();  
}


//-------------------------------------------------------------------------

ISR(ADC_vect){

 //Przerwanie ADC - pomiar zakończony
 //Funkcja pusta ponieważ odczyt ADC dokonujemy w main()
 //tej funkcji nie można usunąć po nieważ pomiar światła
 //dokonywany jest w trakcie snu mikrokontrolera
 //a pomiar kończy się przerwaniem
}


Plik dd_swiatlo.h:
/*************************************************************************
* SmartPIP - Elektroniczny dręczyciel
* 
* Data:  kwiecień 2013
* Autor: Dondu
* www:   http://mikrokontrolery.blogspot.com/2011/04/SmartPIP-elektroniczny-dreczyciel-spis-tresci.html
* 
* Plik:  dd_swiatlo.h
* Opis:  Plik nagłówkowy pliku dd_swiatlo.c
*************************************************************************/


//Definicje pinów czujnika światła oraz ustawienia kanału multipleksera ADC
//pin pomiarowy
#define ADC_PIN_POM_DDR   DDRC
#define ADC_PIN_POM_PORT  PORTC
#define ADC_PIN_POM_NAZWA PC1
#define ADC_PIN_POM_MUX   (1<<MUX0) //kanał multipleksera
//pin zasilania czujnika
#define ADC_PIN_ZAS_DDR   DDRC
#define ADC_PIN_ZAS_PORT  PORTC
#define ADC_PIN_ZAS_NAZWA PC0
//pin masy rezystora
#define ADC_PIN_REZ_DDR   DDRC
#define ADC_PIN_REZ_PORT  PORTC
#define ADC_PIN_REZ_NAZWA PC2


//--- Funkcje -------------------------------
extern void dd_swiatlo_adc_ini(void);
extern void dd_swiatlo_adc_pomiar_start(void);




dd_usart.c
dd_usart.h

Obserwacja wyników za pomocą RS-232 i terminal zrealizujemy, wykorzystują opisane wcześniej rozwiązanie wraz z omówieniem obsługi programu terminala Realterm. W związku z tym, nie będę tutaj opisywał dokładnie jak działa transmisja RS-232. Dodam jedynie tę część programu by można było ją przeanalizować.


Plik dd_usart.c:
/*************************************************************************
* SmartPIP - Elektroniczny dręczyciel
* 
* Data:  kwiecień 2013
* Autor: Dondu
* www:   http://mikrokontrolery.blogspot.com/2011/04/SmartPIP-elektroniczny-dreczyciel-spis-tresci.html
* 
* Plik:  dd_usart.c
* Opis:  Funkcje komunikacji RS-232
*************************************************************************/


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

#include "dd_usart.h"

//USART - tablica bufora wysyłki oraz zmienna indeksu tablicy
char usart_bufor[USART_BUFOR_DLUGOSC] = "Testowanie czujnika swiatla:"; 
volatile unsigned int usart_bufor_ind;


//--------------------------------------------------------------

void usart_inicjuj(void)
{
 //definiowanie parametrów transmisji za pomocą makr zawartych w pliku
 //nagłówkowym setbaud.h. Jeżeli wybierzesz prędkość, która nie będzie 
 //możliwa do realizacji otrzymasz ostrzeżenie: 
 //#warning "Baud rate achieved is higher than allowed"

 #define BAUD 9600         //tutaj podaj żądaną prędkość transmisji
 #include <util/setbaud.h>  //linkowanie tego pliku musi być 
                            //po zdefiniowaniu BAUD
 
 //ustaw obliczone przez makro wartości
 UBRRH = UBRRH_VALUE;  
 UBRRL = UBRRL_VALUE;
 #if USE_2X
    UCSRA |= (1 << U2X);
 #else
    UCSRA &= ~(1 << U2X);
 #endif

 //Ustawiamy pozostałe parametry moduł USART
 //zobacz: http://mikrokontrolery.blogspot.com/2011/04/Pulapki-AVR-Rejestry-pod-tym-samym-adresem.html 
 UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);   //bitów danych: 8
                                                 //bity stopu:   1
                                                 //parzystość:   brak
 //włącz nadajnik
 UCSRB |= (1<<TXEN);
}


//--------------------------------------------------------------

void usart_wyslij_bufor(void){

 //funkcja rozpoczyna wysyłanie, wysyłając pierwszy znak znajdujący się
 //w tablicy wynik[]. Pozostałe wyśle funkcja przerwania, 
 //która zostanie wywołana automatycznie po wysłaniu każdego znaku.

 //Dodaj do tekstu wyniku znaki końca linii (CR+LF), by na 
 //ekranie terminala wyniki pojawiały się w nowych liniach
 unsigned int z;
 for(z=0; z<USART_BUFOR_DLUGOSC; z++){
  if(usart_bufor[z]==0){   //czy to koniec tekstu w tablicy
   //tak znaleziono koniec tekstu, dodajemy znaki CR i LF
   usart_bufor[z]    = 13; //znak powrotu karetki CR (Carrige Return)
   usart_bufor[z+1]  = 10; //znak nowej linii LF (Line Feed)
   usart_bufor[z+2]  = 0;  //znak końca ciągu tekstu w tablicy
   break;                  //przerwij pętlę for()
  }
 }

 //Zaczekaj, aż bufor nadawania będzie pusty
 while (!(UCSRA & (1<<UDRE))); 

 //następny znak do wysyłki to znak nr 1
 usart_bufor_ind = 0;

 //włącz przerwania pustego bufora UDR, co rozpocznie transmisję
 //aktualnej zawartości bufora 
 UCSRB |= (1<<UDRIE);

}


//--------------------------------------------------------------

ISR(USART_UDRE_vect){

 //przerwanie generowane, gdy bufor nadawania jest już pusty, 
 //odpowiedzialne za wysłanie wszystkich znaków z tablicy usart_bufor[]
 //z wyjątkiem pierwszego

 //static unsigned char znak = 1;

 //sprawdzamy, czy bajt do wysłania jest znakiem końca tekstu, czyli zerem
 if(usart_bufor[usart_bufor_ind]!= 0){
  //załaduj znak do rejestru wysyłki i ustaw indeks na następny znak
  UDR = usart_bufor[usart_bufor_ind++]; 
 }else{
  //osiągnięto koniec napisu w tablicy usart_bufor[]
  UCSRB &= ~(1<<UDRIE); //wyłącz przerwania pustego bufora nadawania
 }
}


Plik dd_usart.h:
/*************************************************************************
* SmartPIP - Elektroniczny dręczyciel
* 
* Data:  kwiecień 2013
* Autor: Dondu
* www:   http://mikrokontrolery.blogspot.com/2011/04/SmartPIP-elektroniczny-dreczyciel-spis-tresci.html
* 
* Plik:  dd_usart.h
* Opis:  Plik nagłówkowy pliku dd_usart.c
*************************************************************************/

//USART - tablica bufora wysyłki oraz zmienna indeksu tablicy
#define USART_BUFOR_DLUGOSC  30    //rozmiar bufora
extern char usart_bufor[USART_BUFOR_DLUGOSC]; //bufor
extern volatile unsigned int usart_bufor_ind; //indeks bufora

//Funkcje
extern void usart_inicjuj(void);
extern void usart_wyslij_bufor(void);





dd_main.c
dd_main.h

Program główny zawiera jedynie funkcję main() wraz z niezbędnymi definicjami w pliku nagłówkowym.

Zadania:

  • dobre praktyki w zakresie dbania o to, by każdy pin miał wymuszony poziom napięcia,
  • wywołanie funkcji przygotowujących mikrokontroler do pracy,
  • wysłanie początkowego napisu do terminala,
  • inicjowanie pomiarów,
  • przetwarzanie wyniku,
  • inicjowanie wysłania wyniku do terminala.

Sądzę, że nie trzeba tutaj omawiać dokładnie każdego z powyższych punktów, bo są opisane w kodzie programu.

Fusebity

Należy wspomnieć, że poniższy program pracuje poprawnie z domyślnymi ustawieniami fusebitów (fabrycznymi), czyli:
  • low: 0xE1
  • high: 0xC9
W celu przyspieszenia wybudzenia mikrokontrolera można ustawić fusebity także tak:
  • low: 0xC1
  • high: 0xC9
O docelowym ustawieniu fusebitów zadecydujemy w następnym artykule.

Plik dd_main.c:
/*************************************************************************
* SmartPIP - Elektroniczny dręczyciel
* 
* Data:  kwiecień 2013
* Autor: Dondu
* www:   http://mikrokontrolery.blogspot.com/2011/04/SmartPIP-elektroniczny-dreczyciel-spis-tresci.html
* 
* Plik:  dd_main.c
* Opis:  Testowanie czujnika światła
*
* Mikrokontroler:  ATmega8A
* Fusebity:        low:  0xC1
*                  high: 0xC9
* Kompilator:    GCC
* 
* W opcjach projektu należy ustawić:  zegar:         1000000Hz
*                                     optymalizację: -Os
*************************************************************************/


#include <avr/io.h> 
#include <stdio.h>  
#include <util/delay.h> 
#include <avr/interrupt.h> 
#include <avr/sleep.h>

#include "dd_main.h"
#include "dd_usart.h"
#include "dd_swiatlo.h"


//-------------------------------------------------------------------------

int main(void) 
{ 

 //--- Dobre praktyki ---
 //Po resecie (włączeniu zasilania) piny ustawione są domyślnie jako 
 //wejścia. Włączamy rezystory pull-up. To bardzo istotne w projektach
 //zasilanych z baterii! Dla ATmega8A włączamy wszystkie z wyjątkiem
 //pinu RESET ponieważ mamy tam podłączony zewnętrzny rezystor pull-up
 //szczegóły: http://mikrokontrolery.blogspot.com/2011/04/zakocenia-w-pracy-mikrokontrolerow.html
 PORTB  = 0xff; 
 PORTC  = 0xff;
 PORTD  = 0x3f;

 //jeżeli włączony tryb testowy (szczegóły w pliku dd_main.h)
 #ifdef  TRYB_TEST
  //Ustaw pin LED jako wyjście
  LED_TEST_DDR |= (1<<LED_TEST_PIN_NAZWA);
  LED_TEST_ON;
 #endif

 //przygotuj moduł USART do transmisji danych do komputera
 usart_inicjuj();

 //włącz przerwania globalne
 sei(); 

 //wysyłamy napis początkowy domyślnie umieszczony w tablicy usart_bufor[]
 //patrz plik: dd_usart.c
 usart_wyslij_bufor();
 //opóźnienie na poprawne wysłanie napisu startowego
 _delay_ms(1000); 

 //przygotuj czujnik światła oraz przetwornik ADC
 dd_swiatlo_adc_ini();


 //pętla główna
 while(1){ 

  //wykonaj pomiar
  dd_swiatlo_adc_pomiar_start();

  //konwertuj wynik na ciąg znaków i umieść w tablicy usart_bufor[]
  sprintf(usart_bufor, "%u", ADCH);

  //wyślij dane do komputera
  usart_wyslij_bufor();
  
  #ifdef  TRYB_TEST
   //zmień stan LED na przeciwny
   LED_TEST_TOGGLE;
  #endif

  //opóźnienie między kolejnymi pomiarami
  _delay_ms(2000);
 } 
}



Plik dd_main.h:
/*************************************************************************
* SmartPIP - Elektroniczny dręczyciel
* 
* Data:  kwiecień 2013
* Autor: Dondu
* www:   http://mikrokontrolery.blogspot.com/2011/04/SmartPIP-elektroniczny-dreczyciel-spis-tresci.html
* 
* Plik:  dd_main.h
* Opis:  Plik nagłówkowy pliku dd_main.c
*
*************************************************************************/


//======= TESTOWE =====================
//Definicje do fragmentów programu wykorzystywanych do testów
#define TRYB_TEST 1 //zakomentowanie tej linijki wyłącza tryb testowy
#ifdef  TRYB_TEST
 //definicje dot. testowej diody LED
 #define LED_TEST_DDR        DDRB
 #define LED_TEST_PORT       PORTB
 #define LED_TEST_PIN_NAZWA  PB0
 #define LED_TEST_ON         LED_TEST_PORT &= ~(1<<LED_TEST_PIN_NAZWA)
 #define LED_TEST_OFF        LED_TEST_PORT |=  (1<<LED_TEST_PIN_NAZWA)
 #define LED_TEST_TOGGLE     LED_TEST_PORT ^=  (1<<LED_TEST_PIN_NAZWA)
#endif






Do pobrania

Poniżej link do spakowanego:
  • projektu AVR Studio 4,
  • plików .c oraz .h
  • pliku .hex skompilowanego dla 1MHz i fusebitów określonych powyżej.

Plik: SmartPIP_Czujnik_testowanie.zip





Wyniki pomiarów

W przypadku mojej wersji czujnika światła i powyższego programu zgodnie z założeniami, czujnik na oświetlenie reaguje w sposób bardzo "agresywny",  co przejawiać się będzie stromymi zboczami na wykresie pomiarów, gdyż już przy niewielkim oświetleniu wartości pomiarów szybko rosną.

Taka charakterystyka czujnika jest podyktowana wymogiem oszczędzania baterii i w niczym nam nie będzie przeszkadzać, a wręcz pomagać podczas analizy wyników przez program.

Efekt jaki powinieneś zobaczyć na terminalu Realterm, jest następujący:

SmartPIP: Terminal Realterm (RS-232) - parametry transmisji oraz pierwsze dane.


Specjalnie pokazuję zakładkę Port, abyś wiedział jak ustawić parametry odbioru. Po ich ustawieniu kliknij przycisk Change. W prawym dolnym rogu są (w skrócie) pokazane aktualne ustawienia terminala - muszą być identyczne, by program działał poprawnie.

Pierwszy pomiar

Na powyższym ekranie możesz zauważyć, że pierwszy pomiar znacząco odbiega od pozostałych. Jest to związane z faktem, że po zmianie ustawień ADC (wybór napięcia odniesienia) pierwszy pomiar może być nieprawidłowy.

Informację w tej sprawie znajdziesz w dalszej części tego cyklu.

W zakładce Display, możesz włączyć opcję Ansi, co wyłączy pokazywanie znaków specjalnych:


Terminal Realterm (RS-232): Zakładka Display - usunięcie znaków specjalnych (ansi).


Więcej o ustawieniach terminala Realterm pisałem tutaj.





Podsumowanie

Mamy już przetestowany i działający czujnik światła, o dość agresywnej charakterystyce. Jest on prosty i zużywa bardzo mało energii z baterii. Powinniśmy teraz przetestować jakie straty poniesiemy, na kondensatorze pomiarowym i o tym będzie kolejny artykuł.


Artykuł jest częścią cyklu: SmartPIP - Elektroniczny dręczyciel
Oceń artykuł.
Wasze opinie są dla nas ważne, gdyż pozwalają dopracować poszczególne artykuły.
Pozdrawiamy, Autorzy
Ten artykuł oceniam na:

5 komentarzy:

  1. Terminal Realterm a nie realtime ;)

    OdpowiedzUsuń
  2. Mam pytanie czy pojawią się kolejne części cyklu?

    OdpowiedzUsuń
    Odpowiedzi
    1. Niestety dopiero jesienią. Teraz muszę rozpocząć obiecany temat dot. robotów.

      Usuń
    2. Którego roku?

      Usuń

Działy
Działy dodatkowe
Inne
O blogu




Dzisiaj
--> za darmo!!! <--
1. USBasp
2. microBOARD M8


Napisz artykuł
--> i wygraj nagrodę. <--


Co nowego na blogu?
Śledź naszego Facebook-a



Co nowego na blogu?
Śledź nas na Google+

/* 20140911 Wyłączona prawa kolumna */
  • 00

    dni

  • 00

    godzin

  • :
  • 00

    minut

  • :
  • 00

    sekund

Nie czekaj do ostatniego dnia!
Jakość opisu projektu także jest istotna (pkt 9.2 regulaminu).

Sponsorzy:

Zapamiętaj ten artykuł w moim prywatnym spisie treści.