Створення вимірювального апаратно-програмного комплексу термометра на основі мікроконтролерів

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

МІНІСТЕРСТВО ОСВІТИ І науки України

Черкаський Національній університет імені Богдана Хмельницького

Кафедра програмного забезпечення автоматизованих систем

Курсова робота на тему:

"Створення вімірювального апаратно - програмного комплексу термометра на основі мікро контролерів сім'ї ATMEGA"

Виконала: Перевірів:

Студент групи КС-061 Доцент к. н. т.

Голубченко Юрій Сергійович Хамід

Черкаси 2008р.

Завдання:

Створити вимірювальний апаратно - програмний комплекс термометра на основі мікроконтролерів сімейства ATMEGA.

1) схемотехнічне рішення поставленої задачі:

Схема включає в себе:

1) Мікроконтролер ATTINY 2313;

2) 2 датчика температури DS 18 S 20;

3) Індикатором служить 3-хзначний, загальний анод, динамічна індикація, зелений;

4) Два дискретних виведення переведені на вхід для кнопок для керування індикацією;

5) Визначення до двох датчиків на одній шині 1-Wire;

6) Висновок значення першого, другого, різниці першого з другим, різниці другого з першого на дисплей за допомогою двох кнопок. Так само можливе підключення одного датчика;

Застосування термометра для регулювання температури усередині корпусу комп'ютера:

У корпусі сучасного комп'ютера сконцентрована велика кількість елементів, що виділяють тепло. За великим рахунком, тепло виділяє практично всі, так як будь-яка працююча електронна схема розсіює деяку потужність. Однак є елементи, які є досить інтенсивними джерелами тепла. Це процесор, чіпи на материнській платі і на відеокарті, елементи на платі жорсткого диска, елементи блоку харчування і т.д. Давно минули ті часи, коли процесор міг працювати без примусового охолодження. Вже став звичним кулер на відеокарті, іноді він встановлюється також на північний міст чіпсета і на жорсткий диск. Сучасний корпус зазвичай має місця для встановлення додаткових вентиляторів, які покликані продувати весь внутрішній об'єм корпусу комп'ютера. Особливо гостро проблема охолодження коштує для комп'ютерів, насичених платами розширення, а також для комп'ютерів з «розігнаними» процесорами.

Надійність напівпровідникових приладів при підвищенні робочої температури падає, не кажучи вже про надійність та довговічність жорсткого диска. Проте підвищена температура всередині корпусу комп'ютера веде не тільки до скорочення терміну служби компонентів, але і до нестійкої роботи, якщо якийсь компонент перегрівається.

У світлі сказаного дуже важливо забезпечити належне охолодження компонентів і правильну вентиляцію корпусу. Правильно вибрати кількість і тип вентиляторів, а також правильно організувати повітряні потоки є досить складною справою, тому що вільний об'єм всередині корпусу має складну конфігурацію, і потокам повітря заважають різні предмети, у тому числі дроти. Іноді застосування більш потужного вентилятора дає гірший ефект, ніж правильний розподіл повітряних потоків від малопотужного вентилятора. До того ж потужний вентилятор зазвичай має високий рівень шуму. Теоретично розрахувати потоки не представляється можливим, тому діяти доводиться інтуїтивно, методом проб і помилок. Основна складність полягає в тому, що дуже важко оцінити ефективність тієї чи іншої прийнятої заходи через відсутність засобів контролю температури. Наявні на деяких материнських платах і жорстких дисках термодатчики дозволяють судити лише про температуру в декількох точках. Тому доводиться заміряти температуру компонентів «на дотик», що не можна назвати точним і повторюваним методом.

При експериментах з охолодженням компонентів комп'ютера неоціненну допомогу може надати незалежний термометр. Такий термометр повинен мати невеликий за розмірами датчик для його легкого розміщення на різних компонентах, датчик повинен мати маленьку інерційність для можливості швидкого проведення вимірювань, ну і, звичайно, досить високу точність вимірювань. До того ж, термометр повинен бути не дорогим. Усім цим вимогам задовольняють цифрові датчики температури, що випускаються фірмою DALLAS Semiconductor (тепер це вже MAXIM), які можуть бути підключені до послідовного порту комп'ютера.

За допомогою додаткових обчислень дискретність представлення температури можна зменшити, в нашому випадку вона дорівнює 0.1 ° C. Найпривабливішим є те, що такий термометр вже відкалібрований на заводі, гарантована точність становить ± 0.5 ° C у діапазоні -10 .. +85 ° C і ± 2 ° C у всьому діапазоні робочих температур. Типова крива помилки вимірювання температури наведена на рис

Незважаючи на обмежену абсолютну точність, мала дискретність представлення температури є дуже бажаною, тому що дуже часто на практиці потрібні відносні вимірювання.

DS 18 S 20 допускає напруга живлення від +3 до +5.5 В. У режимі очікування споживаний струм близький до нуля (менше 1мкА), а під час перетворення температури він дорівнює приблизно 1мА. Процес перетворення триває максимум 750мс.

Принцип дії цифрових датчиків температури фірми DALLAS заснований на підрахунку кількості імпульсів, вироблюваних генератором з низьким температурним коефіцієнтом у тимчасовому інтервалі, який формується генератором з великим температурним коефіцієнтом. Лічильник ініціалізується значенням, відповідним -55 ° C (мінімальної вимірюваної температурі). Якщо лічильник досягає нуля перед тим, як закінчується часовий інтервал (це означає, що температура більше -55 ° C), то регістр температури, який також инициализирован значенням -55 ° C, инкрементируется. Одночасно лічильник передвстановлюють новим значенням, що задається схемою формування нахилу характеристики. Ця схема потрібна для компенсації параболічної залежності частот генераторів від температури. Лічильник знову починає працювати, і якщо він знову досягає нуля, коли інтервал ще не закінчений, процес повторюється знову. Схема формування нахилу завантажує лічильник значеннями, які відповідають кількості імпульсів генератора на один градус Цельсія для кожного конкретного значення температури. По закінченню процесу перетворення регістр температури буде містити значення температури.

Для DS 18 S 20 температура представляється у вигляді 9-бітного значення в додатковому коді. Оскільки це значення займає 2 байти, усі розряди старшого байта дорівнюють знакової розряду. Дискретність представлення температури складає 0.5 ° C. Залежність вихідного коду від температури приведена в таблиці:

Температура

Вихідний код (Binary)

Вихідний код (Hex)


Ст. байт

Мол. байт


+125 ° C

0000 0000

1111 1010

00 FAh

+25 ° C

0000 0000

0011 0010

0032h

+0.5 ° C

0000 0000

0000 0001

0001h

0 ° C

0000 0000

0000 0000

0000h

-0.5 ° C

1111 1111

1111 1111

FFFFh

-25 ° C

1111 1111

1100 1110

FFCEh

-55 ° C

1111 1111

1001 0010

FF92h

Більш висока роздільна здатність може бути отримана, якщо провести додаткові обчислення на основі значень COUNT _ REMAIN (значення, що залишився в лічильнику наприкінці вимірювання) і COUNT _ PER _ C (кількість імпульсів на один градус для даної температури), які доступні. Для обчислень потрібно взяти лічене значення температури і відкинути молодший біт. Отримане значення назвемо TEMP _ READ. Тепер дійсне значення температури може бути обчислене за формулою:

TEMPERATURE = TEMP_READ-0.25 + (COUNT_PER_C - COUNT_REMAIN) / COUNT_PER_C

У нашому випадку такий розрахунок дозволяє отримати дискретність представлення температури 0.1 ° C.

Кожен екземпляр DS 18 S 20 має унікальний 48-бітний номер, записаний за допомогою лазера в ПЗП в процесі виробництва. Цей номер використовується для адресації пристроїв. Крім серійного номера в ПЗП міститься код сімейства (для DS 18 S 20 це 10 h) і контрольна сума.

Крім ПЗУ DS 18 S 20 має проміжне ОЗП обсягом 8 байт, плюс два байти енергонезалежної пам'яті. Карта пам'яті DS 18 S 20 показана на малюнку:

Байти TH і TL являють собою температурні пороги, з якими порівнюються 8 біт кожного виміряного значення температури (молодший біт відкидається). За допомогою спеціальної команди можна організувати сигналізацію виходу температури за межі цих порогів. Якщо така функція не потрібна, байти TH і TL можна використовувати для зберігання будь-яких даних користувача.

Зчитування значення виміряної температури, а також передача команди почала перетворення та інших команд здійснюється за допомогою 1-провідного інтерфейсу (1 - WireTM) фірми DALLAS. На основі цього інтерфейсу фірма DALLAS навіть створила мережу, звану microLAN (або μ LAN). Для роботи в цій мережі випускається цілий ряд пристроїв, таких як адресовані ключі, АЦП, термометри, годинник реального часу, цифрові потенціометри. До речі, такий же протокол обміну мають і цифрові ключі IButton (або Touch Memory), які зараз широко використовуються в системах обмеження доступу.

Протокол, який використовується 1-провідним інтерфейсом, досить простий. У будь-який момент часу на 1-провідний шині можна виділити пристрій-майстер, яким може бути мікропроцесор або комп'ютер, і підлеглий пристрій, в нашому випадку це мікросхема термометра. Так як у нас на шині присутні тільки майстер і всього одне підлеглий пристрій, можна опустити все те, що пов'язано з адресацією пристроїв. У результаті потрібно знати лише протокол передачі байтів, які можуть бути командами або даними.

Спочатку розглянемо апаратну конфігурацію. 1-провідна шина є у двох напрямках. На рис. 4 показана апаратна конфігурація інтерфейсної частини DS 18 S 20 і майстри шини. У кожного 1-провідного пристрою до шини підключений вхід приймача і вихід передавача з відкритим стоком. Відкритий сток дозволяє підключати до шини безліч пристроїв, забезпечуючи логіку «монтажне або». Генератор струму 5мкА забезпечує на вході 1-провідного пристрою низький логічний рівень, коли шина не підключена. Так як лінія тактового сигналу відсутня, обмін є синхронним. Це означає, що в процесі обміну потрібно досить точно витримувати необхідні тимчасові співвідношення.

1-провідна шина оперує з TTL-рівнями, тобто логічна одиниця представлена ​​рівнем напруги близько 5В, а логічний нуль - напругою поблизу 0В. У вихідному стані на лінії присутній рівень логічної одиниці, який забезпечується підтягуючим резистором номіналом близько 5Ком.

Ініціатором обміну по 1-провідний шині завжди виступає майстер. Всі пересилання починаються з процесу ініціалізації. Ініціалізація проводиться в такій послідовності

Майстер посилає імпульс скидання (reset pulse) - сигнал низького рівня тривалістю не менш 480 мкс.

За імпульсом скидання слід відповідь підлеглого пристрою (presence pulse) - сигнал низького рівня тривалістю 60 - 240 мкс, що генерується через 15 - 60 мкс після завершення імпульсу скидання.

Відповідь підлеглого пристрою дає майстру зрозуміти, що на шині присутній термометр і він готовий до обміну. Після того, як майстер виявив відповідь, він може передати термометру одну з команд. Передача ведеться шляхом формування майстром спеціальних тимчасових інтервалів (time slots). Кожен часовий інтервал служить для передачі одного біта. Першим передається молодший біт. Інтервал починається імпульсом низького рівня, тривалість якого лежить в межах 1 - 15 мкс. Оскільки перехід з одиниці в нуль менш чутливий до ємності шини (він формується відкритим транзистором, в той час як перехід з нуля в одиницю формується підтягуючим резистором), саме цей перехід використовують 1-провідні пристрої для синхронізації з майстром. У підпорядкованому пристрої запускається схема тимчасової затримки, яка визначає момент зчитування даних. Номінальне значення затримки дорівнює 30 мкс, однак, воно може коливатися в межах 15 - 60 мкс. За імпульсом низького рівня слід передається біт. Він повинен утримуватися майстром на шині протягом 60 - 120 мкс від початку інтервалу. Часовий інтервал завершується переведенням шини в стан високого рівня на час не менше 1 мкс. Потрібно відзначити, що обмеження на цей час зверху не накладається. Аналогічним чином формуються тимчасові інтервали для всіх переданих бітів

Першою командою, яку повинен передати майстер для DS 18 S 20 після ініціалізації, є одна з команд функцій ПЗУ. Всього DS 18 S 20 має 5 команд функцій ПЗУ:

Read ROM [33 h]. Ця команда дозволяє прочитати вміст ПЗУ. У відповідь на цю команду DS 18 S 20 передає 8-бітний код сімейства (10 h), потім 48-бітний серійний номер, а потім 8-бітну CRC для перевірки правильності прийнятої інформації.

Match ROM [55 h]. Ця команда дозволяє адресувати на шині конкретний термометр. Після цієї команди майстер повинен передати потрібний 64-бітний код, і тільки той термометр, який має такий код, буде «відгукуватися» до наступного імпульсу скидання.

Skip ROM [CCh]. Ця команда дозволяє пропустити процедуру порівняння серійного номера і тим самим заощадити час у системах, де на шині є всього один пристрій.

Search ROM [F 0 h]. Ця досить складна у використанні команда дозволяє визначити серійні номери всіх термометрів, присутніх на шині.

Alarm Search [ECh]. Ця команда аналогічна попередньої, але «відгукуватися» будуть тільки ті термометри, у яких результат останнього виміру температури виходить за встановлені межі TH і TL.

Оскільки у нас всього один пристрій, найбільш відповідною для нас функцією є функція Skip ROM. Крім неї ще може бути корисною функція Read ROM, яка дозволяє ідентифікувати підключене на шину пристрій за його кодом сімейства і серійним номером.

Прийнявши команду Read ROM, DS 18 S 20 буде готовий передати 64-бітний код, який майстер повинен прийняти.

При прийомі даних від підлеглого пристрою тимчасові інтервали для прийнятих бітів теж формує майстер. Інтервал починається імпульсом низького рівня тривалістю 1 - 15 мкс. Потім майстер повинен звільнити шину, щоб дати можливість термометру вивести біт даних. По переходу з одиниці в нуль DS 18 S 20 виводить на шину біт даних і запускає схему тимчасової затримки, яка визначає, як довго біт даних буде присутній на шині. Це час лежить в межах 15 - 60 мкс. Для того щоб дані на шині, яка завжди має деякою ємністю, гарантовано встановилися, потрібен якийсь час. Тому момент зчитування даних майстром повинен відстояти якомога далі, але не більше ніж на 15 мкс від початку тимчасового інтервалу

Прийом байта починається з молодшого біта. Спочатку йде байт коду сімейства. За кодом сімейства йде 6 байт серійного номера, починаючи з молодшого. Потім йде байт контрольної суми (CRC). У обчисленні байта контрольної суми беруть участь перші 7 байт, або 56 переданих біт. Для обчислення використовується наступний поліном:

CRC = X 8 + X 5 + X 4 +1

Після прийому даних майстер повинен обчислити контрольну суму і порівняти вийшло значення з переданої CRC. Якщо ці значення збігаються, значить, прийом даних пройшов без помилок. Можна також обчислити контрольну суму для всіх 64 прийнятих біт, яка в цьому випадку повинна бути дорівнює нулю. Блок-схема алгоритму обчислення контрольної суми показана на рис. 8. Алгоритм використовує операції зсуву та «виключає або». Квадратиками показані біти змінної, яка використовується для обчислення CRC. Перед обчисленням її необхідно обнулити, а потім на вхід алгоритму потрібно послідовно подати 56 прийнятих біт в тому порядку, в якому вони були прийняті. В результаті змінна буде містити значення CRC.

Такий же алгоритм обчислення контрольної суми використовується і у випадку читання проміжного ОЗУ, тільки там лічена з термометра CRC (9-й байт) розрахована для 8-ми байтів даних.

Після обробки однієї з команд функцій ПЗУ, DS 18 S 20 здатний сприймати ще кілька команд:

Write Scratchpad [4 Eh]. Ця команда дозволяє записати дані в проміжне ОЗУ DS 18 S 20.

Read Scratchpad [BEh]. Ця команда дозволяє вважати дані з проміжного ОЗУ.

Copy Scratchpad [48 h]. Ця команда копіює байти TH і TL з проміжного ОЗУ в енергонезалежну пам'ять. Ця операція вимагає близько 10мс.

Convert T [44 h]. Ця команда запускає процес перетворення температури.

Recall E 2 [B 8 h]. Ця команда діє зворотним чином по відношенню до команди Copy Scratchpad, тобто вона дозволяє вважати байти TH і TL з енергонезалежної пам'яті в проміжне ОЗУ. При включенні харчування ця команда виконується автоматично.

Read Power Supply [B 4 h]. Ця команда дозволяє перевірити, чи використовує DS 18 S 20 паразитне харчування. Справа в тому, що DS 18 S 20 можна підключати все з допомогою двох проводів, в цьому випадку для живлення використовується лінія даних. Особливості цього режиму ми тут розглядати не будемо.

При використанні DS 18 S 20 тільки для вимірювання температури потрібні всього дві з цих команд: Convert T і Read Scratchpad.

Послідовність дій при вимірюванні температури повинна бути такою:

Надсилаємо імпульс скидання і приймаємо відповідь термометра.

Надсилаємо команду Skip ROM [CCh].

Надсилаємо команду Convert T [44 h].

Формуємо затримку мінімум 750мс.

Надсилаємо імпульс скидання і приймаємо відповідь термометра.

Надсилаємо команду Skip ROM [CCh].

Надсилаємо команду Read Scratchpad [BEh].

Читаємо дані з проміжного ОЗУ (8 байт) і CRC.

Перевіряємо CRC, і якщо дані лічені вірно, обчислюємо температуру.

Для підключення DS 18 S 20 до COM-порту комп'ютера використовується адаптер, схема якого наведена на малюнку, де показано вікно допомоги програми.

Схема цього адаптера не так проста, як, наприклад, схема адаптера DS9097 фірми Dallas. Це пов'язано в першу чергу з тим, що хотілося мати загальну «землю» комп'ютера і 1-провідний шини. Для живлення DS18S20 використовується лінія DTR послідовного порту. Адаптер забезпечує на вході RXD порту комп'ютера лише однополярні рівні, що, строго кажучи, не відповідає специфікації RS-232C. Однак більшість портів з такими рівнями працюють нормально. Замість зазначених на схемі n-канальних МОН-транзисторів можна застосувати близькі за параметрами транзистори інших типів, наприклад, 2N7000. Підійдуть також вітчизняні транзистори КП501 або КП505. У принципі, можна застосувати і біполярні транзистори, додавши в бази обмежувальні резистори. Конструктивно адаптер виконаний в корпусі роз'єму D-SUB-25:

Роз'єм паяется прямо на плату, яка входить між рядами контактів. Інша сторона плати виконана подовженою і виходить за межі корпусу роз'єму. У цю частину плати впаяний 3-х контактний гвинтовий термінал

Можна взагалі обійтися без друкованої плати, а виконати монтаж адаптера навісним способом на контактах роз'єму.

До гвинтовому терміналу підключається мікросхема термометра за допомогою проводів, довжина яких може становити до декількох метрів. Якщо датчик термометра використовується в кімнатних умовах, то жодних заходів щодо його захисту застосовувати не потрібно, необхідно тільки заізолювати висновки. Якщо ж передбачається вимірювати температуру зовнішнього повітря або якихось агресивних середовищ, датчик термометра необхідно упакувати. Наприклад, можна взяти алюмінієвий корпус електролітичного конденсатора відповідного діаметру і помістити туди датчик, заповнивши весь вільний обсяг теплопроводящей пастою. Зверху такий стакан необхідно загерметизувати.

Описаний адаптер також підходить для зчитування електронних ключів IButton і для підключення інших однопровідні пристроїв.

Програма ds1820.exe, що працює під Win95/98/ME/NT, дозволяє зчитувати і відображати показання термометра, а також зчитувати серійний номер і програмувати два користувальницьких байта. Ця програма крім термометра DS18S20 підтримує і його попередника DS1820.

Вид головного вікна програми показано на малюнку

Вікно має такі елементи управління:

Поле Device ID, куди виводиться код сімейства 1-провідного пристрою. Для DS1820 і DS18S20 він дорівнює 10h.

Поле Device Name, де наводиться розшифровка типу пристрою.

Поле Serial number, куди виводиться серійний номер, записаний в ПЗП.

Поле CRC, де відображається результат перевірки контрольної суми (OK або FAIL).

Поле TH / User byte 1, куди можна ввести значення в шістнадцятковій формі, яке буде записано в регістр TH.

Поле TL / User byte 2, куди можна ввести значення в шістнадцятковій формі, яке буде записано в регістр TL.

Кнопка Start запускає процес вимірювання температури. Перетворення виконуються періодично, а виміряна величина виводиться в полі температури. Дискретність представлення складає 0.1 ° C, що досягається додатковими обчисленнями.

Кнопка Exit дозволяє вийти з програми.

Крім того, вгорі вікна є меню, яке складається з трьох пунктів: Port, Utilites і Help.

Меню Port в розгорнутому вигляді показано на рис. 13. Це меню дозволяє відкрити один з чотирьох портів COM1 - COM4. Крім того, меню дозволяє закрити порт і вийти з програми. У списку активні тільки доступні порти (тобто ті, які є фізично присутніми і не зайняті в даний момент іншими додатками). Коли порт відкривається, перевіряється наявність на цьому порту адаптера (досить з'єднання TXD - RXD). Якщо адаптер не виявлений, виводиться відповідне повідомлення

Меню Help містить малюнок принципової схеми адаптера і відомості про розробника програми.

Для зберігання установок програма використовує ini-файл, який створюється автоматично в тому ж директорії, де розташований exe-файл. У ini-файлі міститься інформація про стан вікна програми і номер використовуваного COM-порта:

[General]

Left = 427

Top = 295

COM port = 2

Якщо в існуючому ini-файлі вказано номер COM-порту, який на момент запуску програми зайнятий або відсутній, виводиться спеціальне повідомлення

Меню Utilites містить три пункти:

Read ROM - зчитування вмісту ПЗУ (код сімейства, серійний номер), а також зчитування TH і TL.

Start Conv. - Дублює кнопку Start основного вікна.

Write User Bytes - записує значення TH і TL, які введені у відповідних полях.

Обмін, який проводиться у 1-провідний шині, вимагає досить точного дотримання часових співвідношень мікросекундного діапазону. Працюючи під Windows, точно сформувати такі інтервали програмним способом неможливо. Тому необхідні тимчасові інтервали формуються апаратно мікросхемою прийомопередавача послідовного порту, який використовується не зовсім звичайно.

Для генерації імпульсу скидання і прослухати відповідь порт налаштовується на швидкість 9600 бод, довжина символів 8 біт, і передається число F0h. Це призводить до формування імпульсу скидання низького рівня (з урахуванням інверсії адаптера) тривалістю приблизно 520 мкс (стартовий біт + 4 переданих біта). За ним слідує імпульс високого рівня такої ж тривалості (4 переданих біта + стоповий біт), протягом якого очікується відповідь термометра. Якщо термометр не підключений, то порт прийме число F0h не спотвореним. Але якщо термометр сформував імпульс відповіді, то прийняте число буде містити більшу кількість одиниць, ніж чотири. Таким чином визначається наявність відповіді.

Для генерації інтервалів прийому і передачі бітів, порт налаштовується на швидкість 115200 бод. Стартовий біт починає часовий інтервал, потім йдуть 8 поодиноких або нульових біт, у залежності від значення біта, який потрібно передати. Закінчується послідовність стоповим бітом, який на деякий час встановлює на 1-провідний шині високий рівень. Вид цієї послідовності повністю відповідає необхідного вигляду тимчасового інтервалу передачі біта, за винятком того, що обмін є більш повільним, ніж спроможна забезпечити 1-провідна шина: на один біт витрачається приблизно 87 мкс.

Прийом з боку передавача послідовного порту нічим не відрізняється від передачі одиничного біта. Проаналізувавши прийнятий послідовним портом символ можна встановити, який біт передав термометр. У випадку нульового біта один або кілька бітів прийнятого портом байта будуть одиничними (з урахуванням інверсії адаптера).

Для роботи з COM-портом програма користується функціями API через спеціальну «обгортковий» динамічну бібліотеку comapi32.dll. Однак швидкість обміну виходить набагато нижче розрахункової через те, що перемикання швидкості COM-порту (виклик функції SetCommState зі зміненим значенням поля BaudRate структури DCB) йде дивно довго (близько 200 мілісекунд!). Це дуже неприємну властивість API.

Програма DS1820.zip разом з вихідним текстом на Delphi 5 source20.zip поширюється безкоштовно.

При використанні термометра необхідно враховувати, що корпус DS18S20 зроблений з матеріалу з відносно поганою теплопровідністю. Тому витік тепла через висновки і підключені до них дроти може бути вельми відчутною. Для зменшення помилки вимірювання слід використовувати проводи малого перетину.

Окрім вимірювання температури компонентів всередині корпусу комп'ютера, цей термометр можна використовувати і для інших цілей, наприклад, як кімнатний або як зовнішній термометр.

3) Робота з COM-портом в середовищі ОС Windows:

Питання «як працювати з COM-портами?» Став класичним на багатьох конференціях з мов програмування. Рано чи пізно мало не кожному програмісту доводиться працювати з портами введення / виводу. Сьогодні я хочу розповісти про роботу з послідовним портом з-під найпоширенішою на сьогоднішній день 32-розрядної операційної системи - Windows. До статті додається приклад програми, що працює з COM-портом, написаної на Borland Delphi 7.

Стаття побудована за принципом «від простого до складного». Спочатку будуть викладені основи роботи з портами з-під Win32 з описом необхідних функцій. Потім розглянемо застосування цих функцій на прикладі Delphi-програми. Кінцевим результатом буде клас, призначений для роботи з COM-портом, і приклад використовує його програми.

Дуже часто програмісту доводиться управляти за допомогою комп'ютера будь-яким зовнішнім пристроєм, або просто аналізувати стан цього пристрою. Порти введення / виводу - найпоширеніший спосіб сполучення комп'ютера і зовнішнього пристрою. Давним-давно вже написано безліч класів, бібліотек та компонент для роботи з портами, тому можна, звичайно, скористатися вже готовим і до того ж безкоштовним рішенням. Саме так я і поступив років сім тому, при цьому втративши найголовніше - своєчасне розуміння того, як все-таки працювати з портами з-під Win32. Незнання внутрішніх механізмів - це, по-перше, прогалину в стрункому ряду знань, а по-друге, актуальна можливість помилок у роботі програми.

З портами з-під Win32 працюють так само, як і зі звичайними файлами, використовуючи при цьому всього декілька специфічних функцій WinAPI. Проте комунікаційний порт - це не зовсім звичайний файл. Для нього, наприклад, не можна виконати позиціонування файлового покажчика, або ж створити порт, якщо такий відсутній. Будь-яка робота з портом починається з його відкриття. Для цього використовується файлова функція WinAPI (описи WinAPI-функцій взяті з MSDN (Microsoft Developer Network), отже, наводяться в синтаксисі C):

HANDLE CreateFile (

LPCTSTR lpFileName,

DWORD dwDesiredAccess,

DWORD dwShareMode,

LPSECURITY_ATTRIBUTES lpSecurityAttributes,

DWORD dwCreationDistribution,

DWORD dwFlagsAndAttributes,

HANDLE hTemplateFile

);

lpFileName - покажчик на рядок з нульовим завершальним символом. Звичайно це ім'я файлу, що відкривається, але в нашому випадку це має бути назва порту (COM1, COM2, ...).

dwDesiredAccess - тип доступу. У нашому випадку повинен бути рівний GENERIC_READ | GENERIC_WRITE.

dwShareMode - параметр спільного доступу. Для комунікаційних портів завжди дорівнює 0.

lpSecurityAttributes - атрибут захисту. Для комунікаційних портів завжди дорівнює NULL.

dwCreationDistribution - режим автосозданія. Для комунікаційних портів завжди дорівнює OPEN_EXESTING.

dwFlagsAndAttributes - атрибут режиму обробки. Для комунікаційних портів повинен бути дорівнює 0 або FILE_FLAG_OVERLAPPED.

hTemplateFile - описувач файлу-шаблона. Для комунікаційних портів повинен бути дорівнює NULL.

При успішному відкритті порту функція повертає його описувач, а в разі помилки повертає INVALID_HANDLE_VALUE.

Відразу обмовлюся: всі відсутні описи можна знайти на http://msdn.microsoft.comі ще по ряду адрес, які вам підкаже пошуковий сервер.

З усіх параметрів функції CreateFile () особливого пояснення вимагає dwFlagsAndAttributes. Робота з портом може бути організована в синхронному (nonoverlapped) або асинхронному (overlapped) режимах обробки, що і задається цим прапором. При синхронному режимі (коли параметр dwFlagsAndAttributes = 0) тільки один потік програми може або читати, або писати в порт. Пам'ятайте переговорний пристрій у ліфті? Натиснули кнопку - можемо тільки говорити, відпустили кнопку - можемо тільки слухати.

Синхронний режим обробки простий в реалізації. Якщо треба записати дані в порт, то викликаємо функцію запису і чекаємо, поки вона не завершиться. Якщо ж треба читати дані, то викликаємо функцію читання і чекаємо, поки вона не відпрацює. Для простих завдань синхронний режим обробки цілком підходить, проте у світі Windows він майже завжди приречений на невдачу. Очікування операції читання або запису сприймається користувачем програми як «зависання».

Асинхронний режим (коли параметр dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED) дозволяє проводити операції читання і запису в порт паралельно з різних потоків. У той час, поки один потік додатку приймає дані, інший потік може паралельно з першим передавати дані - як при розмові по телефону, коли ви можете слухати і говорити одночасно. Даний режим обробки більше імпонує ідеї багатозадачності Windows. Але за все треба платити: для реалізації цього режиму обробки потрібно у два рази більше написаного коду, до того ж, вміння писати багатопотокові програми. Який режим вибрати - вирішуйте самі. Але якщо вже розбиратися у роботі порту, то розбиратися «по-дорослому», до кінця, а тому і розглянемо більш складний варіант - асинхронну обробку.

На практиці відкриття порту для асинхронного режиму обробки з програми на Delphi виглядає приблизно так:

OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

if hPort = INVALID_HANDLE_VALUE then

raise Exception.Create ('Error opening port');

Функція повертає дескриптор порту (hPort), який нам потім знадобиться для виклику інших функцій роботи з портом. Якщо в результаті відкриття порту описувач не отриманий, то порушується виключення з відповідним текстом помилки. Відкривши порт, ми отримуємо його у своє розпорядження. Тепер із цим портом може працювати тільки наша програма (точніше, тільки наш процес). Після закінчення роботи з портом його слід закрити, викликавши функцію:

BOOL CloseHandle (

HANDLE hObject

);

В якості єдиного параметра треба передати отриманий раніше описувач порту (hPort).

Хоч система при завершенні виконання програми та звільняє всі виділені їй ресурси (в тому числі і порти), хорошим тоном програмування вважається власноручне закриття портів. Відкривати / закривати порт начебто нескладно. Крім того, нам буде потрібно програмна настройка порту. Думаю, всі бачили діалог налаштування послідовного порту в диспетчері пристроїв системи. Всі ці налаштування ми можемо зробити програмно. Для цих цілей використовується функція WinAPI:

BOOL SetCommState (

HANDLE hFile,

LPDCB lpDCB

);

hFile - описувач відкритого порту.

lpDCB - покажчик на структуру DCB.

Основні параметри послідовного порту описуються структурою DCB. Вона містить масу полів, кожне з яких відповідає певному параметру настройки порту. Ми розглянемо декілька полів, які нам потрібні:

BaudRate - швидкість передачі даних. Можливо вказівку констант-CBR_100, CBR_300, CBR_600, CBR_1200, ..., CBR_256000.

Parity - схема контролю парності. Може містити одне з наступних значень: EVENPARITY, MARKPARITY, NOPARITY, ODDPARITY, SPACEPARITY.

ByteSize - число інформаційних біт в переданих і прийнятих байтах.

StopBits - кількість степових біт. Може бути ONESTOPBIT, ONE5STOPBIT, TWOSTOPBIT.

Щоб не заповнювати структуру DCB вручну, її можна заповнити інформацією про поточний стан порту викликом функції GetCommState (), потім змінити поля та встановити налаштування викликом функції SetCommState (). Налаштування порту бажано робити відразу після його відкриття. На Delphi це виглядає так:

var

Dcb: TDcb;

...

if not GetCommState (hPort, Dcb) then

raise Exception.Create ('Error setting port state');

Dcb.BaudRate: = CBR_9600;

Dcb.Parity: = NOPARITY;

Dcb.ByteSize: = 8;

Dcb.StopBits: = ONESTOPBIT;

if not SetCommState (hPort, Dcb) then

raise Exception.Create ('Error setting port state');

Ще одна операція, яка нам знадобиться відразу після відкриття порту - його скидання.

BOOL PurgeComm (

HANDLE hFile,

DWORD dwFlags

);

Виклик цієї функції очищає чергу прийому / передачі і завершує все знаходяться в очікуванні запити вводу / виводу.

hFile - описувач відкритого порту.

dwFlags - вироблені дії у вигляді набору прапорів PURGE_TXABORT, PURGE_RXABORT, PURGE_TXCLEAR, PURGE_RXCLEAR.

Приклад на Delphi:

if not PurgeComm (hPort, PURGE_TXCLEAR or PURGE_RXCLEAR) then

raise Exception.Create ('Error purging port');

На цьому підготовча фаза закінчується, і можна приступати безпосередньо до прийому / передачі даних. Прийом даних у нас буде відбуватися за подієвої схемі; програма буде очікувати прийом одного або декількох символів (байт). Для переведення порту в цей режим необхідно викликати функцію SetCommMask () з прапором EV_RXCHAR:

if not SetCommMask (hPort, EV_RXCHAR) then

raise Exception.Create ('Error setting port mask');

Прийом і передача даних виконується функціями ReadFile () і WriteFile (), тобто тими ж самими функціями, які використовуються для роботи з дисковими файлами. Ось їх опис:

BOOL ReadFile (

HANDLE hFile,

LPVOID lpBuffer,

DWORD nNumberOfBytesToRead,

LPDWORD lpNumberOfBytesRead,

LPOVERLAPPED lpOverlapped

);

BOOL WriteFile (

HANDLE hFile,

LPCVOID lpBuffer,

DWORD nNumberOfBytesToWrite,

LPDWORD lpNumberOfBytesWritten,

LPOVERLAPPED lpOverlapped

);

hFile - описувач відкритого порту.

lpBuffer - адреса буфера.

nNumberOfBytesToRead / nNumberOfBytesToWrite - число очікуваних до прийому або призначених для передачі байт.

lpNumberOfBytesRead / lpNumberOfBytesWritten - число фактично прийнятих або переданих байт.

lpOverlapped - адреса структури OVERLAPPED, використовуваної для асинхронних операцій.

Передача даних є досить швидкої операцією, тому як правило її виконують з головного потоку додатки. На Delphi це виглядає так:

var

dwWrite: DWORD;

OverWrite: TOverlapped;

WriteBytes: array of Byte;

...

begin

OverWrite.hEvent: = CreateEvent (nil, True, False, nil);

if OverWrite.hEvent = Null then

raise Exception.Create ('Error creating write event');

...

if (not WriteFile (hPort, WriteBytes, SizeOf (WriteBytes),

dwWrite, @ OverWrite))

and (GetLastError <> ERROR_IO_PENDING) then

raise Exception.Create ('Error writing port');

end;

У даному прикладі функція WriteFile () виконує асинхронну запис масиву байтів WriteBytes в порт. Вона відразу повертає управління, і запис в порт відбувається паралельно з виконанням основного коду потоку. Якщо результат WriteFile () дорівнює False, то це означає, що на момент повернення управління передача масиву байтів ще не закінчилася. Тому код помилки виконання WriteFile () в даному випадку повинен бути рівний ERROR_IO_PENDING. Змінна OverWrite - overlapped-структура, необхідна для асинхронних операцій.

У принципі, вас не повинно хвилювати, коли закінчиться передача масиву байтів. Зате момент прийому одного або декількох символів дійсно важливий. Тому його можна розбити на дві частини: ініціювання прийому й визначення моменту прийому з подальшим читанням символів. Оскільки при цьому доводиться рахуватися з фактором очікування прийому символу, рекомендується функції прийому даних винести в окремий потік. Передавати дані можна і з основного потоку програми, оскільки це відбувається досить швидко. А ось подія прийому символу будемо чекати в окремому потоці.

Розгляд роботи з потоками в Windows, зокрема того, як це реалізовано в Delphi, виходить за рамки цієї статті. Припускаю, що читач зустрічався або принаймні знайомий з цим. Скажу лише, що у будь-якого потоку є головна функція, яка починає виконуватися після його створення. У Delphi для потоків існує клас TThread, а його головна процедура називається TThread.Execute ().

Ось так виглядає головна процедура окремого потоку, яка очікує поява одного або декількох символів і зчитує їх:

procedure TReadThread.Execute;

var

ComStat: TComStat;

dwMask, dwError: DWORD;

OverRead: TOverlapped;

Buf: array [0 .. $ FF] of Byte;

dwRead: DWORD;

begin

OverRead.hEvent: = CreateEvent (nil, True, False, nil);

if OverRead.hEvent = Null then

raise Exception.Create ('Error creating read event');

FreeOnTerminate: = True;

while not Terminated do

begin

if not WaitCommEvent (hPort, dwMask, @ OverRead) then

begin

if GetLastError = ERROR_IO_PENDING then

WaitForSingleObject (OverRead.hEvent, INFINITE)

else

raise Exception.Create ('Error waiting port event');

end;

if not ClearCommError (hPort, dwError, @ ComStat) then

raise Exception.Create ('Error clearing port');

dwRead: = ComStat.cbInQue;

if dwRead> 0 then

begin

if not ReadFile (hPort, Buf, dwRead, dwRead, @ OverRead) then

raise Exception.Create ('Error reading port');

/ / У Buf знаходяться прочитані байти

/ / Далі йде обробка прийнятих байтів

end;

end; {while}

end;

У наведеному прикладі в потоці крутиться цикл, тим самим ініціюється очікування події порту викликом функції WaitCommEvent (), очікування ж самого цієї події задається функцією WaitForSingleObject (). Для визначення кількості прийнятих символів використовується функція ClearCommError (). Коли кількість прийнятих символів (dwRead) відомо, безпосереднє читання символів виконується функцією ReadFile ().

Використовуючи вищеописані викладки, я написав на Borland Delphi 7 клас TComPort для роботи з COM-портами. До класу додається приклад програми, що використовує його. Для перевірки працездатності програми я просто з'єднав нуль-модемним кабелем два COM-порту на своєму комп'ютері і запустив два примірники програми для кожного порту. Дані передаються через один порт і одночасно приймаються через інший.

Для передачі та прийому даних передбачені окремі вікна. Формат переданих даних - рядок. Прийняті дані представляються у вигляді масиву байт.

Додати в блог або на сайт

Цей текст може містити помилки.

Комунікації, зв'язок, цифрові прилади і радіоелектроніка | Курсова
110.7кб. | скачати


Схожі роботи:
Створення вимірювального апаратно програмного комплексу термометра на основі мікроконтролерів сім`ї
Електронні вироби на основі програмованих мікроконтролерів
Реалізація цифрового термометра на основі мікроконтролера ATmega 128 з іспользовніє термодатчика
Принцип роботи електричних термометрів і створення вимірювального
Принцип роботи електричних термометрів і створення вимірювального перетворювача для датчика
АІС управління серверним програмним забезпеченням на базі програмного комплексу WebminAlterator
Особливості побудови і функціонування програмного комплексу розрахунку тарифів на теплову енергію
Практичні аспекти створення програмного забезпечення
Створення програми з використанням програмного продукту Turbo Assembler
© Усі права захищені
написати до нас