 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
1
P
OLITECHNIKA
Ś
LĄSKA
W
YDZIAŁ
A
UTOMATYKI
, E
LEKTRONIKI
I
I
NFORMATYKI
Projekt z Systemów Mikroprocesorowych
Tytuł: Ultradźwiękowy miernik wysokości poziomu cieczy w
zbiorniku
Autorzy: Pawicki Adrian, Serafiniak Robert
AiR, sem. 5, gr. TI 1
Gliwice, styczeń 2013
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
2
Spis treści
1. Wstęp .............................................................................................................................................. 4
2. Cel i zakres projektu........................................................................................................................ 4
3. Harmonogram................................................................................................................................. 4
4. Aplikacja programowa i sprzętowa................................................................................................ 5
4.1.
Część sprzętowa...................................................................................................................... 5
4.1.1.
Schemat połączeniowy ................................................................................................... 5
4.1.2.
Opis elektroniki............................................................................................................... 6
4.2.
Część programistyczna............................................................................................................ 6
4.2.1.
Oprogramowanie mikrokontrolera................................................................................ 6
4.2.1.1. Kod programu ............................................................................................................. 6
4.2.1.2. Schemat blokowy........................................................................................................ 7
4.2.1.3. Opis działania.............................................................................................................. 7
4.2.1.4. Algorytm przeliczania odległości na czas ................................................................... 8
4.2.2.
Terminal (aplikacja w C#) ............................................................................................... 8
4.2.2.1. Kod aplikacji ................................................................................................................ 8
4.2.2.2. Zrzut ekranu ................................................................................................................ 8
4.2.2.3. Opis działania.............................................................................................................. 9
5. Koszt projektu................................................................................................................................. 9
5.1.
Wycena.................................................................................................................................... 9
5.2.
Poświęcony czas.................................................................................................................... 10
6. Główne problemy ......................................................................................................................... 10
6.1.
Komparator analogowy........................................................................................................ 10
6.2.
Taktowanie mikrokontrolera ............................................................................................... 10
6.3.
Wzmocnienie sygnału........................................................................................................... 11
6.4.
Zakłócenia ultradźwięków.................................................................................................... 12
6.5.
Problem przy przenoszeniu układu na płytkę uniwersalną (przy lutowaniu) .................... 12
6.6.
Przenoszalność kodu............................................................................................................. 12
7. Podsumowanie ............................................................................................................................. 13
8. Pomysł na rozwój.......................................................................................................................... 13
9. Literatura....................................................................................................................................... 13
10.
Załączniki................................................................................................................................... 14
10.1.
Załącznik nr 1 (kod oprogramowanie Atmegi16A) .......................................................... 14
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
3
10.2.
Załącznik nr 2 (kod aplikacji) ............................................................................................ 16
10.3.
Załącznik nr 3 – zdjęcie gotowego układu........................................................................ 21
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
4
1. Wstęp
Celem projektu było stworzenie urządzenia monitorującego wysokość poziomu słupa 
cieczy w zaprojektowanym przez nas zbiorniku. Poziom ten miał być monitorowany 
za pomocą ultradźwięków, a następnie otrzymane dane miały zostać wysłane za 
pomocą komunikacji szeregowej do komputera PC, gdzie byłyby w miarę potrzeby na 
bieżąco monitorowane. Za analizę dostarczanych danych (za pomocą portu RS232) 
jest odpowiedzialny stworzony przez nas terminal, napisany w języku C#. Terminal 
dodatkowo posiada opcję graficznego zobrazowania aktualnie wynoszącej wartości 
(w postaci słupa cieczy).
2. Cel i zakres projektu
Naszym celem było stworzenie urządzenia wykorzystywanego do monitorowania 
wysokości poziomu cieczy w zbiorniku. Jego skonstruowanie nie było bez podstawne. 
Został on stworzony w celu monitorowania poziomu wysokości słupa cieczy (zużytego 
oleju silnikowego) w beczkach, jakie są często stosowane m.in. w warsztatach 
samochodowych. Owe urządzenie miało służyć do monitorowanie poziomu 
napełnienia owego zbiornika, aby w odpowiednim momencie zgłosić potrzebę jego 
wymiany na nowy. 
Jednak w ramach rozwoju projektu, został znaleziony szereg innych zastosowań. Po 
drobnych modyfikacjach może ono być stosowane, jako czujnik cofania w 
samochodach lub też alarm domowy, monitorujący czy w danym pomieszczeniu 
porusza się jakaś osoba.
3. Harmonogram
Data
Założenia
19-26.11.2012
Skompletowanie niezbędnego sprzętu do wykonanie projektu.
26.11-3.12.2012
Oprogramowanie nadajnika ultradźwięków.
3-10.12.2012
Oprogramowanie odbiornika ultradźwięków.
10-17.12.2012
Szeregowa transmisja danych.
17-24.12.2012
Stworzenie aplikacji umożliwiającej graficzną reprezentację danych w
postaci wykresu.
31.12-7.01.2013
Przeniesienie projektu z uniwersalnej płytki stykowej na płytkę
drukowaną.
7-14.01.2013
Stworzenie prezentacji multimedialnej.
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
5
Projekt został wykonany zgodnie z harmonogramem. Udało się zrealizować wszystkie 
cele, które zostały wyznaczone przed podjęciem się wykonania projektu.
4. Aplikacja programowa i sprzętowa
Nasze gotowe urządzenie do monitorowania wysokości poziomu cieczy w zbiorniku 
składa się z 2 części – sprzętowej oraz programistycznej.
Część sprzętowa to elektronika, dobór odpowiednich podzespołów (np. rezystorów, 
kondensatorów), żeby układ działał jak najsprawniej, natomiast programistyczna 
składa się również z dwóch części. Pierwszą z nich jest oprogramowanie 
mikrokontrolera (nadawanie/odbieranie ultradźwięków, przesył szeregowy danych), 
druga to natomiast stworzenie terminala w C#.
4.1.
Część sprzętowa
4.1.1. Schemat połączeniowy
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
6
4.1.2. Opis elektroniki
Cały układ mikroprocesorowy zdecydowaliśmy się zbudować w oparciu o 
mikrokontroler z rodziny AVR – Atmega16A. Wybór był uwarunkowany 
tym, że posiadaliśmy już pewną wiedzę dotyczącą programowania AVR.
W celu poprawnego zasilania mikrokontrolera każdy pin zasilający Vcc 
został zaopatrzony w kondensator 100nF podciągnięty do masy, 
umiejscowiony jak najbliżej mikrokontrolera.
Odbiornik ultradźwiękowy został doposażony w rezystor 100k w celu 
eliminacji zakłóceń. Jego wartość została dobrana metodą prób i błędów. 
Jest on potrzebny, ponieważ odbiornik podłączamy do komparatora 
analogowego, który jest bardzo czuły. Działa on na podstawie 
porównywania napięć panujących na nóżkach AIN0 i AIN1. Jeżeli napięcie 
na AIN0 jest wyższe, to wówczas odbiornik otrzymał odbitą falę 
ultradźwiękową (wykrył przeszkodę). 
Nadajnik natomiast generuje nam sygnał prostokątny o częstotliwości 
43kHz (sprawdzone na oscyloskopie). W datasheecie nadajnika widnieje 
wpis, że wysyła on falę o f = 40kHz. Im bliżej, więc tej częstotliwości, tym 
nadajnik generuje lepszy sygnał. Mieścimy się jednak w granicy błędu.
Komunikacja szeregowa została zrealizowana w sposób standardowy, za 
pomocą MAX232. Kondensatory elektrolityczne zostały dobrane z pomocą 
informacji znalezionych w datasheet, czyli 1uF.
W celu pozbycia się tzw. ‘krzaczków’ wysyłanych RS-em do naszego 
terminala zdecydowaliśmy się dołożyć zewnętrzny kwarc 2MHz. W tym 
celu również musieliśmy wykorzystać 2 kondensatory ceramiczne 22pF. 
Tak zmontowany układ zewnętrznego taktowania musimy być wlutowany 
jak najbliżej naszego mikrokontrolera, w celu poprawnego działania.
Dodatkowo układ jest zasilany kablem USB (5V).
Tak zmontowany układ działa poprawnie.
4.2.
Część programistyczna
4.2.1. Oprogramowanie mikrokontrolera
4.2.1.1.
Kod programu
Kod znajduje się w ZAŁĄCZNIKU NR 1
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
7
4.2.1.2.
Schemat blokowy
4.2.1.3.
Opis działania
W celu nadania paczki fal ultradźwiękowych porty PD2 oraz PD3 
ustawione są, jako wyjścia. Następnie z użyciem pętli for() na zmianę 
doprowadzane jest do nóżek nadajnika w przeciwległej fazie napięcie 
wysokie oraz niskie (jeżeli na PD2 jest napięcie wysokie to na PD3 jest 
niskie i odwrotnie). Kolejnym krokiem jest wyłączenie nadajnika oraz 
chwilowe zwarcie do masy odbiornika w celu eliminacji drgań, 
mogących powstać w czasie, gdy nadajnik wysyłał fale. W celu odbioru 
fal odbitych włączamy odbiornik oraz aktywujemy timer zliczający 
czas, po jakim wróciła fala odbita. Odbiór fal dokonywany jest z 
użyciem komparatora analogowego, porównującego napięcia na AIN1 
oraz AIN0. W przypadku odbioru fali odbitej napięcie na AIN0 jest 
wyższe niż na AIN1, w przeciwnym wypadku nic nie zostało wykryte. W 
momencie, gdy AIN0>AIN1(wykryta przeszkoda) timer jest wyłączany, 
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
8
następnie przy użyciu rozdzielczości mikrokontrolera oraz prędkości 
dźwięku dokonywane jest przeliczanie wartości timera na odległość. 
Przeliczona zmienna wysyłana jest poprzez port szeregowy do 
komputera PC.
4.2.1.4.
Algorytm przeliczania odległości na czas
Taktowanie mikroprocesora wynosi 2MHz.
Rozdzielczość:
=0.0000005[s]=0.5 [μs]
Zakres timera 16-bit wynosi: [0 - 65 536]
W celu uzyskania czasu przemnażamy wartość timera przez 0.5.
Prędkość dźwięku:
V=340 m/s, jako iż sygnał przebywa drogę podwójną ( do przeszkody i 
z powrotem), przyjmujemy 170 m/s.
170[m/s]=1/58,7[cm/us]=0.017[cm/us]
Zgodnie ze wzorem na prędkość, obliczamy drogę:
V=s/t => s=t*V;
Odległość = (Wartość_Timera*0.5)/58.7;
4.2.2. Terminal (aplikacja w C#)
4.2.2.1.
Kod aplikacji
Kod aplikacji znajduje się w ZAŁĄCZNIKU NR 2
4.2.2.2.
Zrzut ekranu
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
9
4.2.2.3.
Opis działania
Aplikacja oferuję użytkownikowi podgląd odbieranych danych z 
mikrokontrolera. Ponadto użytkownik ma możliwość podglądu 
odbieranych danych w postaci graficznej(wykres słupkowy).
Użytkownik ma również możliwość doboru parametrów dotyczących 
transferu danych takich jak: prędkości, wybór portu, ilość bitów 
danych, bit stopu oraz bit parzystości. 
W celu połączenia aplikacji z mikrokontrolerem przez port szeregowy 
korzystamy z biblioteki System.IO.Ports. 
Dane są pobierana przy wykorzystaniu metody ReadLine(), która 
pozwala na pobranie ciągu znaków do momentu napotkania znaku 
końca linii („\n”). Następnie dane są wyświetlane w TextBoxie oraz 
konwertowane na format typu Int. 
Przekonwertowana zmienna wysyłana jest do funkcji wyrysowującej 
wykres. W celu rysowania wykresu słupkowego korzystamy z biblioteki 
ZedGraph. Oferuję Ona zestaw gotowych metod do wyrysowywania 
wykresów. Cały proces powtarza się tak długo aż zostanie urwane 
połączenie z mikrokontrolerem.
5. Koszt projektu
5.1.
Wycena
Przedmiot
Cena
Atmega16A
12,29
MAX232
1,90
Nadajnik ultradźwiękowy
6,00
Odbiornik ultradźwiękowy
6,00
Kwarc 2MHz
1,15
2x kondensator ceramiczny 22pF
0,20
Rezystor 100k
0.05
4x kondensator elektrolityczny 1uF
0,40
Gniazdo DB9
0,70
Płytka uniwersalna
10,00
SUMA
38,69
Całkowity koszt zbudowania urządzenia, wraz z płytką uniwersalną, do której 
zostały wlutowane wszystkie elementy wyniósł 38,69zł. 
Jest to stosunkowo niska cena. Została ona osiągnięta dzięki wykorzystaniu 
najtańszych czujników ultradźwiękowych.
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
10
Dodatkowo w celu zmniejszenia kosztów produkcji warto byłoby się zastanowić 
nad wykorzystaniem tańszego mikrokontrolera (np. atmega8) oraz nad 
wytrawianiem własnych płytek. Widzimy, bowiem, że kupno płytki uniwersalnej 
bardzo mocno podnosiło nam koszt wykonania całego projektu.
5.2.
Poświęcony czas
Pomimo pozornej prostoty projektu, czas, który został poświęcony nad jego 
wykonaniem jest naprawdę spory. Jest on rzędu, co najmniej kilkudziesięciu 
godzin ciężkiej pracy. Jest to głównie związane z szeregiem problemów, które 
napotkaliśmy podczas realizacji projektu. Na te temat zostanie poświęcony 
osobny dział.
6. Główne problemy
6.1.
Komparator analogowy
W celu odbioru fal ultradźwiękowych został wykorzystany komparator 
analogowy, porównujące napięcia na AIN1 oraz AIN0. Ze względu na bardzo czułe 
zachowanie się komparatora na jakiegokolwiek rodzaju zakłócenia wystąpił 
problem w rozróżnieniu czy odbiornik odebrał falę odbitą czy też nastąpiło 
zakłócenie. W celu wyeliminowanie problemu pomiędzy nóżki odbiornika został 
wprowadzony rezystor o oporze 100k. Dobór wartości rezystora odbył się na 
zasadzie prób i błędów. Ważne było, aby przy doborze rezystancji, nie dobrać 
rezystora o zbyt dużym oporze mogącym spowodować, iż komparator nie wykryję 
odebranej fali ultradźwiękowej. Wprowadzenie rezystora rozwiązało powyższy 
problem.
6.2.
Taktowanie mikrokontrolera
Przy początkowych testach dotyczących przesyłania informacji portem 
szeregowym z naszego urządzenia na komputer PC okazało się, że czasem w 
terminalu były wyświetlane tzw. ‘krzaczki’ – czyli losowe znaki, nie mające 
większego sensu. Po przewertowaniu forów internetowych w celu znalezienia 
problemu, okazało się, że winą może być taktowanie. Tzn. sposobem rozwiązania 
tego problemu było dołożenie zewnętrznego generatora kwarcowego, który 
generuje stabilniejsze źródło sygnału – w naszym przypadku kwarcu 2MHz.
Po jego dołożeniu do układu problem znikł. 
Należy jednak zaznaczyć, że kwarc musi być zamontowany możliwie blisko 
mikrokontrolera, jest to związane z długością ścieżek, w praktyce odległość ta nie 
powinna być większa niż 3cm.
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
11
6.3.
Wzmocnienie sygnału
W celu zwiększenia zasięgu naszego układu staraliśmy się wzmocnić napięcie 
podawane na nadajnik ultradźwiękowy. Bez wzmacniacza jego zasięg wynosi 
(obecnie) ok. 45 cm. (dokładność +- 1cm.).
W tym celu obraliśmy dwie drogi:
 Wzmocnienie sygnału za pomocą układu MAX232 – 2 krotne wzmocnienie
napięcia
W tak zmontowanym wzmacniaczu, nasz układ zwiększył swój zasięg do 
ok. 80 cm. Jednak wówczas nie radził on sobie z zakresem 0 – 30cm.
 Wzmocnienie z wykorzystaniem wzmacniacza operacyjnego NE5532
W tym przypadku, napięcie wzrosło ok. 2.5 razy. Jednak pomimo tego 
sygnał nie został wzmocniony, tzn. układy wykrywał przeszkody z zakresu 
0 -30cm. Zauważyliśmy natomiast znaczną poprawę stabilności pracy 
naszego urządzenia – brak losowych zakłóceń, zwracających błędne dane.
Problem małego zasięgu przy wykorzystaniu NE5532 nie został 
rozwiązany.
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
12
Na podstawie powyższych doświadczeń zrezygnowaliśmy z dokładania 
wzmacniacza do naszego urządzenia końcowego. Musimy się zadowolić zasięgiem 
ok. 45cm. Nie jesteśmy również w stanie wyjaśnić, dlaczego stosując wzmacniacze 
operacyjne nie otrzymaliśmy oczekiwanych efektów. Więc z braku czasu, 
zrezygnowaliśmy ostatecznie ze wzmocnienia sygnału.
6.4.
Zakłócenia ultradźwięków
Podczas testowania wyżej omówionego układu wystąpił problem związany z 
odbiorem fal ultradźwiękowych. W niektórych pomieszczeniach dochodziło do 
odbioru fal, pomimo iż nie były to fale, które zostały wygenerowane przez nasz 
nadajnik i powróciły w skutek odbicia się od przeszkody. W celu znalezienia źródła 
problemu, obserwowaliśmy zachowanie odbiornika w momencie, kiedy nadajnik 
był odłączony. Wykazało to, iż źródłem problemu nie jest nasz nadajnik. Problem 
nie został rozwiązany po mimo wielu prób. Źródłem takiego zachowania 
odbiornika, może być odbiór fal generowanych przez inne urządzenia znajdujące 
się w pomieszczeniu. Powyższy wniosek nie został udowodniony.
6.5.
Problem przy przenoszeniu układu na płytkę uniwersalną (przy lutowaniu)
Podczas przenoszenia układu z uniwersalnej płytki stykowej na płytkę, 
umożliwiającą zlutowanie ze sobą konkretnego sprzętu elektronicznego pojawił 
się problem z szeregową transmisją danych. Tzn. podczas lutowania 
prawdopodobnie uszkodzeniu uległ MAX232, przez co układ nie działał 
poprawnie. Dodatkowo, gdy do urządzenia zostało doprowadzone napięcie, 
MAX232 przegrzał się do bardzo wysokiej temperatury (wręcz parzył) oraz zaczął 
wydobywać się z niego dym.
Problem został rozwiązany poprzez wprowadzenie nowego Max232, jednak było 
to bardzo problematyczne, gdyż posiadając jedynie lutownicę grotową bardzo 
ciężko było odlutować stary element (łącznie 16 nóżek) oraz wstawić w to miejsce
nowy.
6.6.
Przenoszalność kodu
Nie wiedzieć, dlaczego, nasz kod działa jedynie na jednej atmedze16a. Układ był 
montowany w oparciu o 3 inne atmegi16a oraz 8 i 32. Problem mógł okazać się 
włączony JTAG, natomiast w każdym mikrokontrolerze został on przez nas 
wyłączony.
Powodem może być jakaś zmiana producenta, ponieważ układ obecnie działa w 
oparciu o atmege16a pochodzącą sprzed ok. 2 lat. 
Jednak również (już po skonstruowaniu urządzenia) doszliśmy do wniosku, że 
problemem mógł być po prostu zły dobór rezystora na odbiorniku dla 
pozostałych mikrokontrolerów z rodziny AVR !!!
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
13
7. Podsumowanie
Wszystkie cele postawione podczas rozpoczęcia projektu zostały zrealizowane. Prace 
przebiegały zgodnie z napisanym harmonogramem, który został również w pełni 
wykonany. Nasz miernik wysokości poziomu słupa cieczy został przetestowany w 
zaprojektowanym przez nas zbiorniku 30 litrowym, o wysokości ok. 40cm. Jego 
działanie jest poprawne, zwraca dobre wyniki. 
8. Pomysł na rozwój
Przede wszystkim chcielibyśmy stabilnie wzmocnić działanie naszego układu, żeby 
poprawnie działał dla odległości 0:150cm. Wówczas zakres jego zastosowanie będzie 
znacznie większy i mógłby zostać stosowany z powodzeniem w dużych zbiorniach 
stosowanych jak wcześniej wspominaliśmy przy przechowywaniu m.in. zużytego oleju 
silnikowego. Dodatkowo pragnęlibyśmy udoskonalić nasz terminal oraz z czasem 
udostępniać go darmowo dla osób, które zakupiłyby nasze urządzenie. 
Kolejnym pomysłem jest podmiana czujników na droższe, wodoodporne.
9. Literatura
 M. Kardaś: Mikrokontrolery AVR. Język C. Podstawy programowania.
 Forum internetowe: 
www.elektroda.pl
http://hobby.abxyz.bplaced.net
http://www.forbot.pl/forum/topics20/programowanie-port-szeregowy-i-
interfejs-usart-czyli-komunikacja-mikrokontrolera-z-komputerem-
vt6118.htm
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
14
10. Załączniki
10.1.
Załącznik nr 1 (kod oprogramowanie Atmegi16A)
/*
* Sonar_beta.c
*
* Created: 2012-12-27 11:45:06
*  Author: Pawicki,Serafiniak
*/
//definicja prędkości transferu danych
#define BAUD 2400
//definicja taktowania
#define F_CPU 2000000
//
obliczenie UBRR
#define UBRR F_CPU/BAUD/16-1
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
// Inicjuje port szeregowy AVRa
void USART_init(unsigned int myubrr)
{
// Ustala prędkość transmisji
UBRRH = (unsigned char)(myubrr>>8);
UBRRL = (unsigned char)myubrr;
// Włącza nadajnika
UCSRB = (1<<TXEN);
  
    
// Format ramki: 8 bitów danych, 1 bit stopu, brak bitu parzystości
    UCSRC = (1<<URSEL)|(3<<UCSZ0); 
}
// Wysyła znak do portu szeregowego
static int USART_Transmit(char znak, FILE *stream)
{
    while(!(UCSRA & (1<<UDRE)));
    UDR = znak;
    return 0;
}
//Tworzy strumienia danych o nazwie 'mystdout' połączony z funkcją 'USART_Transmit'
static FILE mystdout = FDEV_SETUP_STREAM(USART_Transmit, NULL, _FDEV_SETUP_WRITE);
int main(void)
{
//zmienna wykorzystywana przy nadawaniu fal
int i=0;
//zmienna, do której przypisujemy wartość timera
int czas=0;
//zmienna przechowująca wartość przeliczonego czasu na odległość
int pomiar=0;
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
15
// Inicjalizuje port szeregowy AVRa
USART_init(UBRR);
// Przekierowuje standardowe wyjście do 'mystdout'
stdout = &mystdout;
//globalne przerwania
sei();
//ODBIORNIK KONFIGURACJA(ustawiamy PD3 jako wyjście, ustawiamy niski stan napięcia)
DDRB |= (1<<PB3);
PORTB &= ~(1 << PB3);
// NADAJNIK KONFIGURACJA(PD2, PD3 jako wyjście, PD2 wysokie napięcie, PD3 niskie napięcie)
DDRD |= (1<<PD2);
PORTD |= (1<<PD2);
DDRD |= (1<<PD3);
PORTD &= ~(1<<PD3);
while(1)
{
//ustawiamy stan wysoki na jednej z nóżcek nadajnika w celu nadawania sygnału
PORTD |= (1<<PD2);
//nadajemy fale
for(i=0;i<10000;i++)
PORTD^=((1<<PD3)|(1<<PD2));
//wyłączenie nadajnika
PORTD &=~((1<<PD2)|(1<<PD3));
_delay_us(5);
//zwarcie do masy odbiornika, w celu zaniku drgań
DDRB |= (1<<PB2);
PORTB &= ~(1<<PB2);
_delay_us(5);
//włączenie odbiornika
DDRB &= ~(1<<PB2);
//włączenie timera 16bitowego
TCCR1B |= (1 << CS10);
//pętla oczekująca na powrót echa, czekamy do momentu aż timer zlicze 65tys (jest to około
0,03sekundy)
while(TCNT1<65000)
{
//jeśli AIN0>AIN1, to odebrano sygnał odbity
if( ACSR & (1<<ACO) )  
{
//przypisanie wartości timera do zmiennej
czas=TCNT1;
//wyłączamy timer
TCCR1B &= ~(1 << CS10);
//przerwanie pętli
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
16
break;
}
}
//jeżeli timer się przepełnił (nic nie zostało wykryte) to wyłączamy timer
if(TCNT1 >= 65000)
{
TCCR1B &= ~(1 << CS10);
czas=0;
}
//przeliczamy uzyskany czas na odległość(algorytm przeliczania został wytłumaczony w
raporcie)
pomiar=(czas/2)/58,7;
//zabezpiczenie przed zakłóceniami ( pomiar nie może przyjąć wartości ujemnej )
if(pomiar > 0){
if(TCNT1 < 65000)
{
//odjęcie uzyskanej wartości od maksymalnej wysokości zbiornika
pomiar=38-pomiar;
//wysyłamy dane poprzez port szeregowy
printf("%d\n",pomiar);
_delay_ms(200);
}
}
//zerujemy czas oraz wartość timera
czas=0;
TCNT1=0;
}
}
10.2. Załącznik nr 2 (kod aplikacji)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports
;
//biblioteka do obsługi RS232
using ZedGraph;
//biblioteka służąca do rysowania wykresów
namespace Terminal
{
public partial class Form1 : Form
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
17
{
//definicja zmiennej port
SerialPort port;
//definicja delegatu
delegate void Delegat1();
//zmienna typu delegat
Delegat1 moj_del1;
//zlicza ilość zmiennych wyświetlonych na ekranie
Int32 licznik;
//zmienna przechowująca zawartość pomiaru
int numVal=-1;
//
zmienna przechowująca odebrany ciąg znaków, używana do konwersji na Inta
string znak;
//potrzebna do wyrysowania wysokości baru
double[] doubleVal= { 0 };
//potrzebne tylko i wyłącznie do ustawienia skalowania wykresu
int licznik2 = 0;
public Form1()
{
InitializeComponent();
//inicjalizacja zmiennej port z domyślnymi wartościami
port = new SerialPort();
//ustawienie timeoutów aby program się nie wieszał
port.ReadTimeout = 500;
port.WriteTimeout = 500;
Opcje.Enter += new EventHandler(Opcje_Enter);
//event od przychodzących danych
port.DataReceived += new SerialDataReceivedEventHandler(DataRecievedHandler);
//inicjalizacja delegatu
moj_del1 = new Delegat1(WpiszOdebrane);
}
//dopisywanie odebranego stringu do textboxa
private void WpiszOdebrane() 
{
Wyswietl(OknoWiadomosci, port.ReadLine(), System.Drawing.Color.Blue);
}
//wywołanie delegata po wykryciu przychodzącej wiadomości
private void DataRecievedHandler(object sender, SerialDataReceivedEventArgs e) 
{
//Invoke pozwala na bezpieczne wywołanie funkcji delegatu, bez zakłócenia pracy innych wątków
OknoWiadomosci.Invoke(moj_del1);
}
void Opcje_Enter(object sender, EventArgs e)
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
18
{
//aktualizacja list
this.ListaPortow.Items.Clear();
this.ListaParzystosci.Items.Clear();
this.ListaStopu.Items.Clear();
foreach (String s in SerialPort.GetPortNames()) this.ListaPortow.Items.Add(s);
foreach (String s in Enum.GetNames(typeof(Parity))) this.ListaParzystosci.Items.Add(s);
foreach (String s in Enum.GetNames(typeof(StopBits))) this.ListaStopu.Items.Add(s);
//aktualizacja nazw
ListaPortow.Text = port.PortName.ToString();
ListaPredkosci.Text = port.BaudRate.ToString();
ListaDanych.Text = port.DataBits.ToString();
ListaParzystosci.Text = port.Parity.ToString();
ListaStopu.Text = port.StopBits.ToString();
}
private void Wyswietl(System.Windows.Forms.RichTextBox RichTextBox, string Text, System.Drawing.Color
Color)
{
try
{
znak = Text;
//konwersja na inta
numVal = Convert.ToInt32(znak);
//w celu wyrysowania wykresu słupkowego należy inta przypisać zmiennej double[] (metoda rysująca
słupek, nie przyjmuje innych wartości)
doubleVal[0] = numVal;
//wyrysowanie wykresu
CreateGraph(zedGraphControl1, doubleVal);
}
catch (FormatException e)
{
Console.WriteLine("Input string is not a sequence of digits.");
}
catch (OverflowException e)
{
Console.WriteLine("The number cannot fit in an Int32.");
}
finally
{
licznik++;
var StartIndex = RichTextBox.TextLength;
RichTextBox.AppendText(Text);
RichTextBox.AppendText("\n");
var EndIndex = RichTextBox.TextLength;
RichTextBox.Select(StartIndex, EndIndex - StartIndex);
RichTextBox.SelectionColor = Color;
//co 10 wyświetlonych informacji, czyścimy TextBoxa
if (licznik > 10)
{
OknoWiadomosci.Clear();
licznik = 0;
}
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
19
}
}
private void Polaczenie_Click(object sender, EventArgs e)
{
//sprawdzamy czy połączenie jest aktywne
if (port.IsOpen) 
{
Polaczenie.BackColor = System.Drawing.Color.Red;
port.Close();
LabelPolaczenie.Text = "Brak połączenia";
Wyswietl(OknoWiadomosci, "\nZakończono połączenie z " + port.PortName + "\n", 
System.Drawing.Color.Orange);
}
else
{
//zabezpieczenie na wypadek błędu
try
{
//przypisanie do portu parametrów z opcji
port.PortName = this.ListaPortow.Text;
port.BaudRate = Int32.Parse(this.ListaPredkosci.Text);
port.DataBits = Int32.Parse(this.ListaDanych.Text);
port.Parity = (Parity)Enum.Parse(typeof(Parity), this.ListaParzystosci.Text);
port.StopBits = (StopBits)Enum.Parse(typeof(StopBits), this.ListaStopu.Text);
//uruchamiamy port
port.Open();
//po uruchomieniu zmieniamy elementy graficzne interfejsu
Polaczenie.BackColor = System.Drawing.Color.Green;
LabelPolaczenie.Text = "Aktywne połączenie (port:" + port.PortName.ToString() + ", prędkość: " + 
port.BaudRate.ToString() + ", bity danych: " +
port.DataBits.ToString() + "\n bity stopu: " + port.StopBits.ToString() + ", parzystość: " +
port.Parity.ToString() + ")";
Wyswietl(OknoWiadomosci, "Rozpoczęto połączenie z " + port.PortName + "\n",
System.Drawing.Color.Orange);
}
//przechwytujemy błąd i wyświetlamy
catch (Exception exc)
{
MessageBox.Show("Błąd połączenia:\n" + exc.Message);
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
CreateGraph(zedGraphControl1, null);
}
//funckcja wyrysowująca wykres słupkowy
private void CreateGraph(ZedGraphControl zg1, double[] y)    
{
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
20
//czyszczenie wykresu, w celu zaznaczenia nowych danych
zg1.GraphPane.CurveList.Clear();
//wysokość zbiornika
double[] z = { 38 };
GraphPane myPane = zg1.GraphPane;
myPane.Title.Text = "Zbiornik";
myPane.XAxis.Title.Text = "";
myPane.YAxis.Title.Text = "Wysokość";
//pozwalamy wyskalować tylko raz wykres, zaraz przy włączeniu programu. Z każdym kolejnym
pomiarem oś ma pozostać niezmieniona
if (licznik2 == 0) 
{
zedGraphControl1.GraphPane.XAxis.Scale.MaxAuto = true;
zedGraphControl1.GraphPane.XAxis.Scale.MinAuto = true;
licznik2 = 1;
}
else
{
zedGraphControl1.GraphPane.XAxis.Scale.MaxAuto = false;
zedGraphControl1.GraphPane.XAxis.Scale.MinAuto = false;
}
//słupek max wysokości zbiornika
BarItem myBar2 = myPane.AddBar("", null, z, Color.Blue);
//słupek wartości obecniej wysokości zbiornika
BarItem myBar = myPane.AddBar("", null, y, Color.Red);
myBar.Bar.Fill = new Fill(Color.Red, Color.White, Color.Red);
//Wypełnienie osi i tła
myPane.Chart.Fill = new Fill(Color.White, Color.FromArgb(255, 255, 166), 90F);
myPane.Fill = new Fill(Color.FromArgb(250, 250, 255));
//dopasowanie osi do wyświetlanych danych
zg1.AxisChange();
zg1.Refresh();
}
}
}
 
Ultradźwiękowy miernik wysokości poziomu cieczy w zbiorniku
21
10.3. Załącznik nr 3 – zdjęcie gotowego układu