Author Topic: Вовед во електроника 9 - микроконтролери  (Read 3348 times)

Offline BorceBT

  • Топ Експерт
  • *****
  • Posts: 1824
  • Gender: Male
    • www.trajkovski.net
Во овој туторијал ќе објаснеме што всушност претставува микроконтролерот и како се употребува.
Во овој туторијал ќе бидат употребени поедноставувања кои на некои експерти во таа област ќе им изгледаат неточно но ќе бидат ставени овде само заради полесно учење на оваа тема.

Микроконтролерите се дигитални или дигитално/аналогни (хибридни) интегрирани кола кои содржат во себе микропроцесор, меморија и некои други периферни влезно/излезни кола како на пример А/Д (аналогно-дигитални) конвертори, компаратори (споредувачи на напон), тајмери, бројачи и друго. Микроконтролерите можат да работат и без додатни електронски компоненти што би значело дека се самостојни (компјутер во чип) и за нив не секогаш е потребна „матична плоча“ за да работат.

Постојат повеќе видови и производители на микроконтролери. Постојат 4 битни, 8 битни, 16 битни и 32 битни микроконтролери во зависност од тоа колку битен микропроцесор содржат во нив и за каква намена е изработен. Бидејќи 4 битните микроконтролери веќе не се користат (беа користени порано во видео-рекордерите) ние во овој туторијал ќе се запознаеме со 8 битен микроконтролер од производителот Microchip со ознака PIC16F628.

Прво нешто што треба да го направите доколку сакате да работите со одреден микроконтролер е да го спуштите неговиот Datasheet (техничкиот документ) за тој микроконтролер. За овој туторијал линкот кон Datasheet-от на PIC16F628 можете да го превземете од овде:

Code: [Select]
http://ww1.microchip.com/downloads/en/DeviceDoc/40300C.pdf
Од овој документ на страна 3 можеме да ги прочитаме карактеристиките за овој микроконтролер кој има:

- од 0 до 20MHz брзина на работа;
- Вграден самостоен осцилатор од 4MHz (не е потебен надворешен кварц кристал);
- простор за 2048 инструкции (наредби) во неговата Flash меморија (3.5KB);
- 224 бајти RAM меморија;
- 18 пинови од кои 16 влезно/излезни пинови и 2 за напојување;
- можност за прекини (interrupts);
- 2 компаратори;
- PWM модул;
- 3 бројачи (тајмери);
- Сериски порт.

Од истиот документ на страна 4 се прикажани сите пинови на овој микроконтролер обележани (со скратеници) сите функции на секој од пиновите:



Во случајов RАх и RВх се влезно/излезни пинови, АNх - аналогни влезови, Тххх - Влезови за тајмерите, Rx и Tx - влез и излез за серискиот порт. Vss е - (минус) на напојувањето а Vdd е + (плус) на напојувањето кое може да изнесува од 2 до 6 волти. Понекогаш повеќе влезно-излезни единици делат ист физички пин и изборот кој од овие единици ќе работи се подесува со помош на регистрите (за ова подоцна).

RAx и RBx се викаат уште и портови и се поделени на групи од 8 (еден бајт). На овој микроконтролер постојат два порта (порт А и порт B) но има микроконтролери кои имаат повеќе пинови и повеќе портови. Влезно-излезните пинови на портовите може максимално да дадат 20mA, имаат заштита од пренапон и поднапон (влез поголем од 5V и помал од -0.7V и преголема струја) но сепак треба да се внимава да не се надмине оваа влезна или излезна струја за да не се уништи пинот. Аналогните влезови се користат за мерење на аналогни величини (на овие пинови има А/D конвертор кој може да биде исчитан како број).

Значи, во глобала главната цел на микроконтролерот е контрола на неговите пинови која се прави со програма. Програмата може да биде напишана во Асемблер или во C програмскиот јазик. Во овој туторијал ќе опишеме програмирање на микроконтролерот во Асемблер за да бидеме поблиску до самиот хардвер и за побрза работа.

Најпроста програма во Асемблер за овој микроконтролер е дадена на следниот листинг:

Code: [Select]
bsf    STATUS,RP0
bcf    TRISA,0
bcf    STATUS,RP0
bsf    PORTA,0

Оваа програма вклучува да свети LED диода поврзана на пинот 17 (RA0).

За да може воопшто да разбереме што значат различните делови од оваа асемблерска програма прво мора да се објасни што е што. Во програмата со мали букви се напишани Асемблерските наредби наречени директиви или мнемоници додека со големи букви се напишани имињата на регистрите и битовите. Регистри се мемориски локации кои постојат во внатрешната меморија на микроконтролерот и со промена на нивната содржина може да се променуваат излезите на микроконтролерот, да се вклучуваат/исклучуваат периферни единици (како компаратори и тајмери) и да се читаат вредности од А/D конверторот. Овој тип на микроконтролери или два типа на регистри - регистер W (кој е еден, фиксен и внатрешен и се употребува како регистер при пресметки и проверки на вредноста на други регистри) и регистри од типот F (регистри за општа намена). За полесна работа регистрите од типот F за овој микроконтролер се дефинирани со имиња наместо со нивната физичка мемориска адреса. Во datasheet-от на микроконтролерот може да се види кој регистер како се вика и на која физичка адреса се наоѓа.

Во нашата програма f регистерот PORTA е всушност регистерот кој ја контролира состојбата на пиновите на портот А. со впишување на вредности (бинарни) нули и единици на секој од осумте битови на овој реситер се сетираат излезите RA0-RA7 на портот А да бидат единици или нули. Наредбата bsf е наредба за сетирање на бит (bsf - bit set f) на даден регистер. Токму ова го прави оваа линија на код во нашата програма за да ја вклучи LED диодата поврзана на пинот 17 (портот А, прв пин - RA0):

Code: [Select]
bsf PORTA,0

Но зошто нашата програма има 4 реда код а не само овој ред? Бидејки имаме проблем, имено, кога се вклучува микроконтролерот тој е само-подесен сите портови да бидат конфигурирани како влезови поради сигурност (на пример за да не тргне машината додека микроконтролерот не е спремен за извршување на програмата). Значи мораме да го подесеме портот А да биде излез а не влез. Тоа се прави преку подесувачки регистер наречен TRISA (за портот А) и TRISB (за портот В). Во datasheet-от пишува дека со впишување на нула на одреден бит на овој регистер одреден пин од портот станува излез, што значи дека единицата која автоматски овој регистер ја добива на старт треба да ја направиме да биде нула. Затоа е наредбата:

Code: [Select]
bcf    TRISA,0

bcf (bit clear f) на првиот бит (бит 0).

Но сепак имаме 4 линии код а не две, што е проблемот? Проблемот е што кај овој микроконтролер сите регистри не се на иста мемориска страна (memory page). Во datsheet-от стои дека одредени регистри се наоѓаат на страна 0, други на страна 1 итн. За несреќа, регистерот за контрола на насоката на пиновите (дали да се влезови или излези) се наоѓа на страната 1 додека регистерот за контрола на портот се наоѓа на страната 0. Па затоа со сетирање на битот RP0 (името на битот е предефиниран и е наречен RP0) во регистерот STATUS (регистер за контрола и проверка на работата на микроконтролерот) ја вклучуваме мемориската страница 1. со негово нулирање ја враќаме мемориската страница 0. Па сега, веројатно е сосема јасна нашата кратка програма и сите нејзини редови:

Code: [Select]
bsf    STATUS,RP0
bcf    TRISA,0
bcf    STATUS,RP0
bsf    PORTA,0
« Last Edit: 24.01.2015, Saturday, 19:47:39 by BorceBT »
Никогаш неможеш да знаеш се, но секогаш можеш да знаеш повеќе.

Offline BorceBT

  • Топ Експерт
  • *****
  • Posts: 1824
  • Gender: Male
    • www.trajkovski.net
Вовед во електроника 9 - микроконтролери
« Reply #1 on: 23.01.2015, Friday, 21:56:19 »
За преведување на нашата асемблерска програма во машински (HEX) код ни треба програмот МPASM кој може бесплатно да се симне од страната на производителот (Microchip). Меѓутоа ако пробате програмата директно да ја преведете, MPASM јавува грешка. Проблемот е што во самата асемблерска програма мора да пишува точно и за кој микроконтролер се работи за да знае MPASM при преведувањето. Ова се прави со две линии код на самиот почеток:

Code: [Select]
LIST p=16F628
include "P16F628.inc"

Исто така MPASM мора да знае каде всушност нашата програма почнува а каде завршува со тоа нашата програма за пример наречена "LED.ASM" ја добива оваа форма:

Code: [Select]
LIST p=16F628
include "P16F628.inc"

START
   bsf    STATUS,RP0
   bcf    TRISA,0
   bcf    STATUS,RP0
   bsf    PORTA,0
END

Наредно би сакале на пример нашата LED диода да трепка. За тоа да го направиме треба да напишеме програма "BLINK.ASM" која ќе ја вклучи LED диодата, ќе почека некое време, ќе ја исклучи, пак ќе почека и потоа ќе го прави истото од почеток во loop. Програмaтa е следнa:

Code: [Select]
LIST p=16F628
include "P16F628.inc"

START
   bsf    STATUS,RP0
   bcf    TRISA,0
   bcf    STATUS,RP0

loop
   bsf    PORTA,0
   call    delay
   bcf    PORTA,0
   call    delay
   goto  loop

delay
   movlw   255
   movwf   0x0C
   movwf   0x0D

L1
    decfsz   0x0C,f
    goto L1
    movlw   255
    movwf   0x0C
    decfsz   0x0D,f
    goto L1
    return
END

Од програмата може да се забележат некои работи, имено директивата (наредбата) goto се пишува кога сакаме извршувањето на програмата да продолжи на друго место определено со име наречено лабела (label), a во случајот лабели ни се: START, loop, L1, END и delay. Меѓутоа, гледаме и една друга наредба наречена call. Oва е посебна наредба која е слична со goto меѓутоа откако програмата ќе почне да работи од лабелата дадена во наредбата call потоа со наредбата return му кажуваме на микроконтролерот програмата да продолжи од истото место од каде што програмата прескокнала со наредбата call. Оваа метода се вика повикување на подпрограма или процедура. Ова значи дека делот од програмата кој се наоѓа помеѓу лабелата delay и наредбата return ни претставува подпрограма (процедура) која ја повикуваме повеќе пати, во случајот ја повикуваме кога сакаме микроконтролерот да почека додека LED диодата свети или е исклучена.

Без процедурата delay микроконртолерот толку брзо ќе ја трепка LED диодата да таа ќе ни се чини дека свети со половина сјај (ќе се вклучува и исклучува милион пати во секунда).

Самата процедура delay во себе содржи нови работи кои ќе бидат дополнително објаснети:

Code: [Select]
delay
   movlw   255
   movwf   0x0C
   movwf   0x0D

L1
    decfsz   0x0C,f
    goto L1
    movlw   255
    movwf   0x0C
    decfsz   0x0D,f
    goto L1
    return

Во оваа процедура едноставно "губиме време" што значи микроконтролерот брои внатре во меморијата одредено време. При броењето го користиме регистерот W и слободните мемориски локации 0C и 0D кои ги користиме како наши регистри или променливи (тие се 8 битни бидејќи PIC16F628 e 8 битен микроконтролер). Бидејќи во мемориските локации неможе диретно да се задаваат вредности го користиме регистерот W како посредник. Затоа се наредбите:

Code: [Select]
  movlw   255
   movwf   0x0C

Наредбите треба да ги паметиме како кратенки, имено movlw значи: move literal to w, во превод "додели константа во регистерот W". Исто така movwf значи: move W to register f, или "додели го W во регистерот f на адреса 0x0C" (0x0C е хексадецимална репрезентација на бројот 12 а го користеме во овој формат затоа што адресите во datasheet-от се дадени во овој формат).

Во нашата процедура значи ги полниме нашите променливи што се наоѓаат на адресите 0C и 0D со максимална вредност од 255. Потоа следува броењето. Имено, после лабелата L1 имаме наредба:

Code: [Select]
   decfsz   0x0C,f

Оваа наредба значи: decrease f, skip if zero или во превод "намалувај го регистерот f, доколку е нула скокни инструкција". Како се користи: регистерот 0C ни беше полн со број 255. Наредбава го намалува регистерот за еден и продолжува на наредната иструкција која во случајов ни е:

Code: [Select]
   goto    L1

Ова значи дека програмот ќе продолжи да ја намалува вредноста на нашиот регистер се додека не стане нула. Кога ќе стане нула оваа наредба ќе ја прескокне наредната инструкција, што значи дека ќе го прескокне goto L1 и ќе продолжи подолу. Со ова парче код изгубивме околу 769 микросекунди. Како ова го пресметуваме, имено во datasheet-от стои дека за извршување на наредбата decfsz на микроконтролерот му е потребен еден циклус што е 1 микросекунда доколку микроконтролерот работи на 4MHz. На наредбата goto му се потребни два циклуци (2 микросекунди) а исто така и на наредбата decfsz му се потребни 2 циклуси наместо еден доколку условот f=0 е исполнет. Бидејќи нашата променлива 0C беше 255 наредбите decfsz и goto се извршуваат 256 пати * 3 микросекунди = 768+1 микросекунда кога прескокнува = 769.

Бидејќи 769 микросекунди е прекратко време за трепкач ние овој дел од процедурата го повторуваме 256 пати користејќи ја истата метода со нашата друга променлива на локацијата (регистарот) 0D. Со ова добиваме вкупно време на каснење (delay) од 256 * 769 = 196864 микросекунди, плус уште некоја микросекунда за почетните наредби и за наредбата return и добиваме околу 200.000 микросекунди што е 0.2 секунди, а бидејќи процедурата ја повикуваме двапати во еден циклус на трепкање нашата LED диода ќе трепка со циклус од околу 0.4 секунди со што сега дефинитивно ќе биде видлива.
« Last Edit: 24.01.2015, Saturday, 20:03:13 by BorceBT »
Никогаш неможеш да знаеш се, но секогаш можеш да знаеш повеќе.

Offline BorceBT

  • Топ Експерт
  • *****
  • Posts: 1824
  • Gender: Male
    • www.trajkovski.net
Се разбира дека оваа тематика е екстремно сложена и бара многу информации, читање и експериментирање за да работи се како што е замислено, меѓутоа со доволно труд и заинтересираност се може да се направи.

За програмирање на самите микроконтролери (програмирање на HEX фајлот) мора да се користи програматор, а освен фабрички програматори на овој форум се опишани повеќе направени програматори и софтвери за програмирање на микроконтролери.

Некои дополнителни информации на кои треба да се внимава кога се работи со микроконтролери се:

1. Контролните битови наречени fuses треба да се правилно подесени пред да се програмира микроконтролерот, а особено типот на осцилатор и WDT (Watchdog Timer-от) кој ќе ви го ресетира микроконтролерот доколку не е исклучен и не го ресетирате во програмата.

2. Со користење на контролните регистри на микроконтролерот на почетокот да ги исклучите работите кои не ви требаат, како на пример интераптите (interrupts), тајмерите, компараторите и A/D конверторите бидејќи често се случува некоја од овие периферни уреди да ви го "земат" пинот и да неможете да го контролирате.

3. Внимавајте на која мемориска страна се наоѓаат одредени регистри и сменете страна преку регистерот STATUS доколку е потребно.

Се разбира дека освен Assembler, за програмирање на микроконтролерите може да се користи програмскиот јазик C, па дури и Basic, но најдобро се учи доколку се почне со учење од самите основи.
Исто така и постојат комплетни развојни околини (како на пример Arduino) за кои постојат голем број на библиотеки со готови процедури кои многу ја олеснуваат работата и создавањето на уреди со микроконтролер но тие развојни околини овде нема да се разгледуваат бидејќи тие во суштина се веќе поблиски до информатиката отколку до електрониката.
« Last Edit: 23.01.2015, Friday, 22:51:07 by BorceBT »
Никогаш неможеш да знаеш се, но секогаш можеш да знаеш повеќе.