Това е нашият 9-и урок за обучение на PIC микроконтролери, използващи MPLAB и XC8. Досега разгледахме много основни уроци, като начало с MPLABX, мигане на LED с PIC, таймери в PIC, свързване на LCD, свързване на 7-сегмент и т.н. Ако сте абсолютно начинаещ, моля, посетете пълния списък с PIC уроци тук и започнете да учите.
В този урок ще научим как да използваме ADC с нашия PIC микроконтролер PICF877A. Повечето проекти за микроконтролер ще включват ADC (аналогово-цифров преобразувател) в него, тъй като това е един от най-използваните начини за четене на данни от реалния свят. Почти всички сензори като сензор за температура, сензор за поток, сензор за налягане, токови сензори, сензори за напрежение, жироскопи, акселерометри, сензор за разстояние и почти всеки известен сензор или преобразувател произвеждат аналогово напрежение от 0V до 5V въз основа на показанията на сензорите. Например датчик за температура може да издава 2.1V, когато температурата е 25C и да достигне до 4.7, когато температурата е 60C. За да знае температурата в реалния свят, MCU трябва просто да прочете изходното напрежение на този температурен сензор и да го свърже с реалната температура. Следователно ADC е важен работен инструмент за проекти на MCU и позволява да научим как можем да го използваме на нашия PIC16F877A.
Проверете и предишните ни статии за използването на ADC в други микроконтролери:
- Как да използвам ADC в Arduino Uno?
- Raspberry Pi ADC Урок
- Връзка ADC0808 с 8051 микроконтролер
ADC в PIC микроконтролер PIC16F877A:
Налични са много видове ADC и всеки има своя собствена скорост и резолюция. Най-често срещаните типове ADC са флаш, последователно сближаване и сигма-делта. В вида на ADC, използвани в PIC16F877A, както се нарича на последователното приближение ADC или СИП в кратък. Така че нека научим малко за SAR ADC, преди да започнем да го използваме.
Последователно приближаване ADC: SAR ADC работи с помощта на компаратор и някои логически разговори. Този тип ADC използва референтно напрежение (което е променливо) и сравнява входното напрежение с референтното напрежение с помощта на компаратор и разликата, която ще бъде цифров изход, се запазва от най-значимия бит (MSB). Скоростта на сравнението зависи от тактовата честота (Fosc), на която PIC работи.
Сега, след като познаваме някои основи на ADC, нека отворим листа с данни и да научим как да използваме ADC на нашия PIC16F877A MCU. PIC, който използваме, има 10-битов 8-канален ADC. Това означава, че изходната стойност на нашия ADC ще бъде 0-1024 (2 ^ 10) и има 8 пина (канала) на нашия MCU, които могат да четат аналогово напрежение. Стойността 1024 се получава от 2 ^ 10, тъй като нашият ADC е 10 бита. Осемте щифта, които могат да четат аналоговото напрежение, са споменати в листа с данни. Нека разгледаме снимката по-долу.
Аналоговите канали AN0 до AN7 са подчертани за вас. Само тези щифтове ще могат да четат аналогово напрежение. Така че, преди да прочетем входно напрежение, трябва да посочим в нашия код кой канал трябва да се използва за отчитане на входното напрежение. В този урок ще използваме канал 4 с потенциометър за отчитане на аналоговото напрежение в този канал.
A / D модулът има четири регистри, които трябва да бъдат конфигурирани за четене на данни от входните щифтове. Тези регистри са:
• A / D резултат висок регистър (ADRESH)
• A / D резултат с нисък регистър (ADRESL)
• A / D контролен регистър 0 (ADCON0)
• A / D контролен регистър 1 (ADCON1)
Програмиране за ADC:
В програмата за използване на ADC с PIC микроконтролер е много проста, ние просто трябва да разберем тези четири регистри и след това четене всяко аналогово напрежение ще бъде просто. Както обикновено инициализираме конфигурационните битове и нека започнем с void main ().
Вътре във void main () трябва да инициализираме ADC, като използваме регистрите ADCON1 и ADCON0. Регистърът ADCON0 има следните битове:
В този регистър трябва да включим ADC модула, като направим ADON = 1 и да включим A / D преобразуващия часовник, като използваме битовете ADCS1 и ADCS0 бита, останалите засега няма да бъдат зададени. В нашата програма часовникът за A / D преобразуване е избран като Fosc / 16, можете да опитате собствените си честоти и да видите как се променя резултатът. Пълни подробности можете да намерите на страница 127. Информационен лист за данни, следователно ADCON0 ще бъде инициализиран, както следва.
ADCON0 = 0b01000001;
Сега регистърът ADCON1 има следните битове:
В този регистър трябва да направим A / D Result Format Select bit high by ADFM = 1 и да направим ADCS2 = 1, за да изберем Fosc / 16 отново. Останалите битове остават нула, тъй като сме планирали да използваме вътрешното референтно напрежение. Пълни подробности са налични на лист с данни на страница 128. Следователно ADCON1 ще зададем, както следва.
ADCON1 = 0x11000000;
След като инициализираме модула ADC вътре в нашата основна функция, нека влезем в цикъла while и да започнем да четем стойностите на ADC. За да прочетете ADC стойност, трябва да се изпълнят следните стъпки.
- Инициализирайте модула ADC
- Изберете аналоговия канал
- Стартирайте ADC, като направите Go / Done малко високо
- Изчакайте битът Go / DONE да намалее
- Вземете резултата от ADC от ADRESH и ADRESL регистър
1. Инициализиране на модула ADC: Вече научихме как да инициализираме ADC, така че просто извикваме тази функция по-долу, за да инициализираме ADC
Функцията void ADC_Initialize () е както следва.
невалиден ADC_Initialize () {ADCON0 = 0b01000001; // ADC ON и е избран Fosc / 16 ADCON1 = 0b11000000; // Вътрешно референтно напрежение е избрано}
2. Изберете аналоговия канал: Сега трябва да изберем кой канал ще използваме, за да прочетем стойността на ADC. Нека направим функция за това, така че да ни е лесно да превключваме между всеки канал вътре в цикъла while .
unsigned int ADC_Read (неподписан char char) {// **** Избиране на канала ** /// ADCON0 & = 0x11000101; // Изчистване на битове за избор на канал ADCON0 - = канал << 3; // Задаване на необходимите битове // ** Изборът на канал завършен *** ///}
След това канал, който трябва да бъде избран, се получава вътре в променливия канал. В линията
ADCON0 & = 0x1100101;
Предишният избор на канал (ако има такъв) се изчиства. Това се прави с помощта на битовия и оператора “&”. Битовете 3, 4 и 5 са принудени да бъдат 0, докато останалите са оставени да бъдат в предишните си стойности.
След това желаният канал се избира чрез трикратно преместване на номера на канала и задаване на битовете с помощта на битовия или оператор “-”.
ADCON0 - = канал << 3; // Задаване на необходимите битове
3. Стартирайте ADC, като направите Go / Done bit high: След като каналът бъде избран, ние трябва да стартираме ADC преобразуването, просто като направим GO_nDONE bit high:
GO_nDONE = 1; // Инициализира A / D преобразуване
4. Изчакайте бита Go / DONE да се понижи: Битът GO / DONE ще остане висок, докато преобразуването на ADC не приключи, следователно трябва да изчакаме, докато този бит отново стане нисък. Това може да се направи с помощта на цикъл while .
докато (GO_nDONE); // Изчакайте A / D преобразуването да завърши
5. Вземете ADC резултата от ADRESH и ADRESL регистъра: Когато битът Go / DONE отново стане нисък, това означава, че ADC преобразуването е завършено. Резултатът от ADC ще бъде 10-битова стойност. Тъй като нашият MCU е 8-битов MCU, резултатът е разделен на горните 8-битови и долните 2-битови. Горният 8-битов резултат се съхранява в регистъра ADRESH, а долният 2-бит се съхранява в регистъра ADRESL. Следователно трябва да ги добавим към регистрите, за да получим нашата 10-битова ADC стойност. Този резултат се връща от функцията, както е показано по-долу:
връщане ((ADRESH << 8) + ADRESL); // Връща резултат
Цялата функция, която се използва за избор на ADC канал, задействане на ADC и връщане на резултата, е показана тук.
unsigned int ADC_Read (неподписан char канал) {ADCON0 & = 0x11000101; // Изчистване на битове за избор на канал ADCON0 - = канал << 3; // Задаване на необходимите битове __delay_ms (2); // Време за придобиване за зареждане на кондензатор за задържане GO_nDONE = 1; // Инициализира A / D преобразуване докато (GO_nDONE); // Изчакайте A / D преобразуването да завърши връщането ((ADRESH << 8) + ADRESL); // Връща резултат}
Сега имаме функция, която приема избора на канал като вход и ни връща стойността ADC. Следователно можем директно да извикаме тази функция в нашия цикъл while , тъй като четем аналоговото напрежение от канал 4 в този урок, извикването на функцията ще бъде както следва.
i = (ADC_Read (4)); // съхраняваме резултата от adc в “i”.
За да визуализираме изхода на нашия ADC, ще ни трябва някакъв вид дисплейни модули като LCD или 7-сегментен. В този урок използваме 7-сегментен дисплей, за да проверим резултата. Ако искате да знаете как да използвате 7-сегментен с pic, следвайте урока тук.
В пълния код е даден по-долу и на процеса също е обяснено в Видео в края.
Настройка и тестване на хардуер:
Както обикновено симулираме кода с помощта на Proteus, преди действително да отидем с нашия хардуер, схемите на проекта са показани по-долу:
Връзките на 4-цифрения седемсегментен дисплеен модул с PIC микроконтролер са същите като при предишния проект, току-що добавихме потенциометър към щифт 7, който е аналоговият канал 4. Чрез промяна на пота, променливо напрежение ще бъде изпратено към MCU които ще бъдат прочетени от модула ADC и изведени на 7-сегментния дисплеен модул. Проверете предишния урок, за да научите повече за 4-цифрения 7-сегментен дисплей и неговото взаимодействие с PIC MCU.
Тук използвахме същата платка за микроконтролер PIC, която сме създали в урок за мигащи LED. След като осигурите връзка, качете програмата в PIC и трябва да видите изход като този
Тук прочетохме стойността на ADC от пота и я преобразувахме в действителното напрежение чрез картографиране на изхода 0-1024 като 0-5 волта (както е показано в програмата). След това стойността се показва на 7-сегмента и се проверява с помощта на мултицет.
Това е, сега сме готови да използваме всички налични на пазара аналогови сензори, опитайте това и ако имате някакви проблеми, както обикновено, използвайте раздела за коментари, ще се радваме да ви помогнем.