Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

В биринчи бөлүгү Мен Arduino шымынан чоңойгон хобби электроника инженерлерине маалымат баракчаларын жана микроконтроллерлердин башка документтерин кантип жана эмне үчүн окуу керектигин айтууга аракет кылдым. Текст чоң болуп чыкты, ошондуктан мен өзүнчө макалада практикалык мисалдарды көрсөтүүгө убада бердим. Ооба, ал өзүн сүт козу карын деп атады...

Бүгүн мен сизге абдан жөнөкөй, бирок көптөгөн долбоорлорго, STM32 (Blue Pill) жана STM8 контроллерлорундагы тапшырмаларды чечүү үчүн маалымат баракчаларын кантип колдонууну көрсөтөм. Бардык демо-долбоорлор менин сүйүктүү диоддорго арналган, биз аларды көп санда күйгүзөбүз, ал үчүн ар кандай кызыктуу перифериялык түзүлүштөрдү колдонушубуз керек.

Текст кайрадан чоң болуп чыкты, ошондуктан мен ыңгайлуулук үчүн мазмунду жасап жатам:

STM32 Blue Pill: DM16 айдоочусу менен 634 LED
STM8: Алты PWM пиндерин орнотуу
STM8: Үч төөнөгүчтөгү 8 RGB LED, үзгүлтүккө учурайт

Жоопкерчиликтен баш тартуу: Мен инженер эмесмин, электроника боюнча терең билимим бар деп ойлобойм, макала мага окшогон ышкыбоздорго арналган. Чынында, мен өзүмдү эки жыл мурун максаттуу аудитория катары эсептечүмүн. Эгер кимдир бирөө мага бейтааныш чиптеги маалымат баракчаларын окуу коркунучтуу эмес деп айтса, мен Интернеттен коддун бир бөлүгүн издеп, кайчы жана скотч менен балдактарды ойлоп табууга көп убакыт коротмок эмесмин.

Бул макаланын максаты долбоорлорго эмес, маалымат баракчаларына багытталган, андыктан код өтө тыкан жана көп учурда тар болбошу мүмкүн. Жаңы чип менен биринчи таанышууга ылайыктуу болсо да, долбоорлордун өзү абдан жөнөкөй.

Менин макалам хоббиге чөмүлүүнүн ушундай баскычында кимдир бирөөнө жардам берет деп үмүттөнөм.

STM32

DM16 жана SPI менен 634 LED

Blue Pill (STM32F103C8T6) жана DM634 LED драйверин колдонгон чакан долбоор. Маалымат баракчаларын колдонуу менен биз драйверди, STM IO портторун аныктайбыз жана SPI конфигурациялайбыз.

DM634

16 16-бит PWM чыгышы бар Тайвандык чипти чынжыр менен туташтырууга болот. Төмөнкү 12-бит модели ата мекендик долбоордон белгилүү Lightpack. Бир убакта, DM63x жана белгилүү TLC5940 ортосунда тандоо, мен бир нече себептерден улам DM тандап: 1) Aliexpress боюнча TLC, албетте, жасалма, бирок бул эмес; 2) DM өзүнүн жыштык генератору бар автономдуу PWMге ээ; 3) Алиден посылканы күтпөй, Москвадан арзан сатып алса болот. Анан, албетте, даяр китепкананы колдонбой, чипти өз алдынча башкарууну үйрөнүү кызыктуу болду. Чиптер азыр негизинен SSOP24 пакетинде берилген; аларды адаптерге ширетүү оңой.

Өндүрүүчүсү Тайвандык болгондуктан, маалымат жадыбалы чип кытай англис тилинде жазылган, бул кызыктуу болот дегенди билдирет. Алгач биз пинутту карайбыз (Pin Connection) кайсы бутту эмнеге туташтырууну түшүнүү жана төөнөгүчтөрдүн сүрөттөлүшү (Пин сүрөттөлүшү). 16 пин:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
DC раковина булактары (ачык дренаж)

жууна турган жер / Ачык дренаждык чыгаруу - дренаж; агып жаткан токтун булагы; чыгаруу активдүү абалда жерге туташтырылган - LEDs катоддор менен айдоочуга туташтырылган. Электрдик жактан алганда, бул, албетте, "ачык дренаж" эмес (ачык дренаж), бирок маалымат жадыбалдарында бул дренаж режиминдеги төөнөгүчтөр үчүн белги көп кездешет.

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Чыгуу учурдагы маанисин коюу үчүн REXT жана GND ортосундагы тышкы резисторлор

REXT пин менен жердин ортосуна шилтеме резистор орнотулган, ал чыгуулардын ички каршылыгын көзөмөлдөйт, маалымат баракчасынын 9-бетиндеги графикти караңыз. DM634те бул каршылык жалпы жарыктыкты (глобалдык жарыктык); Мен бул макалада майда-чүйдөсүнө чейин кирбейм, мен бул жерге 2.2 - 3 кОм резисторду коём.

Чипти кантип башкарууну түшүнүү үчүн, аппараттын интерфейсинин сыпаттамасын карап көрөлү:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

Ооба, мына, кытай англисчеси бардык даңкы менен. Муну которуу көйгөйлүү, эгер кааласаңыз, аны түшүнө аласыз, бирок дагы бир жолу бар - функционалдык жактан окшош TLC5940 менен байланыш маалымат жадыбалында кантип сүрөттөлгөндүгүн карап көрүңүз:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
... Аппаратка маалыматтарды киргизүү үчүн үч гана пин талап кылынат. SCLK сигналынын көтөрүлгөн чети маалыматтарды SIN пининен ички регистрге жылдырат. Бардык маалыматтар жүктөлгөндөн кийин, кыска жогорку XLAT сигналы ырааттуу түрдө берилген маалыматтарды ички регистрлерге бекитет. Ички регистрлер XLAT сигнал деңгээли тарабынан ишке киргизилген дарбазалар. Бардык маалыматтар эң маанилүү бит биринчи өткөрүлөт.

эшиктин тээги – кулпу/кулпу.
Өсүп жаткан кыр – импульстун алдыңкы чети
Биринчи MSB – эң маанилүү (сол жактагы) бир аз алдыга.
саат маалыматтарына – маалыматтарды ырааттуу (бит-бит) берүү.

сөз эшиктин тээги көбүнчө чиптердин документтеринде кездешет жана ар кандай жолдор менен которулат, ошондуктан түшүнүү үчүн мен өзүмө уруксат берем

кичинекей билим берүү программасыLED айдоочусу негизинен бир нөөмөт реестри болуп саналат. "Swift" (өзгөрүү) аталышында - аппараттын ичиндеги маалыматтардын бит боюнча кыймылы: ичине түртүлгөн ар бир жаңы бит бүт чынжырды алдыга түртөт. Нөөмөттө светодиоддордун башаламан күйүп-жанышын эч ким байкагысы келбегендиктен, процесс жумушчу регистрлерден демпер менен бөлүнгөн буфердик регистрлерде жүрөт (эшиктин тээги) биттер каалаган ырааттуулукта жайгаштырылган күтүү залынын бир түрү. Баары даяр болгондо, жапкыч ачылат жана биттер мурунку партияны алмаштырып, ишке киришет. Сөз эшиктин тээги микросхемалардын документтеринде дээрлик ар дайым ушундай демпферди билдирет, ал кандай комбинацияларда колдонулбасын.

Ошентип, DM634ге маалыматтарды берүү төмөнкүдөй ишке ашырылат: DAI киргизүүнү алыскы LEDдин эң маанилүү битинин маанисине коюп, DCKди өйдө жана ылдый тартыңыз; DAI киргизүүнү кийинки биттин маанисине коюңуз, DCK тартыңыз; жана башка бардык биттер өткөрүлмөйүнчө (саат кирди), андан кийин биз LAT тартабыз. Бул кол менен жасалышы мүмкүн (bit-bang), бирок бул үчүн атайын ылайыкташтырылган SPI интерфейсин колдонгон жакшы, анткени ал биздин STM32де эки нускада берилген.

Blue Pill STM32F103

Киришүү: STM32 контроллерлору Atmega328ге караганда бир топ татаалыраак, алар коркунучтуу сезилиши мүмкүн. Мындан тышкары, энергияны үнөмдөө максатында, дээрлик бардык перифериялык жабдуулар башталгычта өчүрүлөт, ал эми саат жыштыгы ички булактан 8 МГц. Бактыга жараша, STM программисттери чипти "эсептелген" 72 МГцге жеткирүүчү кодду жазышты жана мен билген бардык IDEлердин авторлору аны инициализациялоо процедурасына киргизишти, ошондуктан бизге сааттын кереги жок (бирок чындап кааласаң болот). Бирок сиз перифериялык түзүлүштөрдү күйгүзүшүңүз керек болот.

Documentation: Blue Pill популярдуу STM32F103C8T6 чип менен жабдылган, ал үчүн эки пайдалуу документ бар:

Маалымат баракчасында бизди кызыктырышы мүмкүн:

  • Pinouts – чип pinouts – эгерде биз такталарды өзүбүз жасоону чечсек;
  • Memory Map - белгилүү бир чип үчүн эстутум картасы. Маалыматтык колдонмодо бүт линиянын картасы бар жана анда биздикинде жок регистрлер айтылат.
  • Pin аныктамалары таблицасы – пиндердин негизги жана альтернативалуу функцияларынын тизмеси; "көк таблетка" үчүн сиз Интернетте төөнөгүчтөрдүн жана алардын функцияларынын тизмеси менен ыңгайлуураак сүрөттөрдү таба аласыз. Ошондуктан, биз дароо Google Blue Pill pinout жана бул сүрөттү колубузда сактайбыз:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Эскертүү: Интернеттен алынган сүрөттө ката кетти, аны комментарийлерде белгилешти, бул үчүн рахмат. Сүрөт алмаштырылды, бирок бул сабак - маалымат баракчаларынан эмес, маалыматты текшерүү жакшы.

Биз маалымат баракчасын алып салабыз, маалымдама колдонмосун ачабыз жана мындан ары аны гана колдонобуз.
Процедура: биз стандарттык киргизүү/чыгарма менен алектенебиз, SPI конфигурациялайбыз, керектүү перифериялык түзүлүштөрдү күйгүзөбүз.

Input Output

Atmega328де I/O өтө жөнөкөй ишке ашырылган, ошондуктан STM32 варианттарынын көптүгү баш аламан болушу мүмкүн. Эми бизге корутунду гана керек, бирок булардын да төрт варианты бар:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
ачык дренаж, түртүү, альтернативдик түртүү, альтернативалуу ачык дренаж

"Тартуу-түртүү" (түртүү тартуу) Arduino'нун кадимки чыгарылышы, пин ЖОГОРКУ же ТӨМҮГҮН маанини ала алат. Бирок "ачык дренаждар" бар кыйынчылыктар, бул жерде баары жөнөкөй болсо да:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Чыгуу конфигурациясы / порт чыгарууга дайындалганда: / чыгаруу буфери иштетилген: / – ачык дренаж режими: чыгаруу регистриндеги “0” N-MOSти иштетет, чыгаруу регистриндеги “1” порттон Hi-Z режиминде ( P-MOS иштетилген эмес ) / – түртүү режими: чыгаруу регистриндеги “0” N-MOSти активдештирет, чыгуу регистриндеги “1” P-MOSти активдештирет.

Ачык дренаждын ортосундагы бардык айырмачылыктар (ачык дренаж) "түртүү-тартуудан" (түртүү тартуу) биринчи пинде ЖОГОРКУ абалды кабыл ала албайт: чыгуу регистрине жазып жатканда, ал жогорку каршылык режимине өтөт (жогорку импеданс, Hi-Z). Нөлдү жазууда пин эки режимде тең логикалык жактан да, электрдик жактан да бирдей аракеттенет.

Кадимки чыгаруу режиминде пин жөн гана чыгуу регистринин мазмунун таркатат. "Альтернативада" ал тиешелүү перифериялык түзүлүштөр тарабынан башкарылат (9.1.4-пунктту караңыз):

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Эгерде порт бит кошумча функция пин катары конфигурацияланса, пин регистр өчүрүлөт жана пин перифериялык пинге туташтырылган.

Ар бир пиндин альтернативалуу функциялары сүрөттөлгөн Пин аныктамалары Маалымат баракчасы жүктөлүп алынган сүрөттө. Эгерде төөнөгүчтүн бир нече альтернативалуу функциялары бар болсо, эмне кылуу керек деген суроого маалымат баракчасындагы шилтеме менен жооп берилет:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Эгерде бир нече перифериялык түзүлүштөр бир эле пинди колдонсо, альтернативдик функциялардын ортосундагы карама-каршылыктарды болтурбоо үчүн, перифериялык саатты иштетүү битинин (тиешелүү RCC реестринде) жардамы менен которулган бир убакта бир гана перифериялык түзүлүш колдонулушу керек.

Акыр-аягы, чыгаруу режиминдеги төөнөгүчтөр да саат ылдамдыгына ээ. Бул дагы бир энергияны үнөмдөөчү өзгөчөлүк; биздин учурда, биз аны максимумга коюп, аны унутуп калабыз.

Ошентип: биз SPI колдонуп жатабыз, бул эки пин (маалымат жана саат сигналы менен) "альтернативдик түртүү функциясы" болушу керек, ал эми дагы бири (LAT) "кадимки түртүү" болушу керек. Бирок аларды дайындоодон мурун, келгиле, SPI менен иштешели.

Элиза

Дагы бир чакан билим берүү программасы

SPI же Serial Peripheral Interface (сериялык перифериялык интерфейс) МКны башка МКлар жана жалпысынан тышкы дүйнө менен туташтыруу үчүн жөнөкөй жана абдан эффективдүү интерфейс. Анын иштөө принциби жогоруда сүрөттөлгөн, мында кытайлык LED айдоочусу жөнүндө (маалыматтык колдонмодо 25-бөлүмдү караңыз). SPI кожоюн ("мастер") жана кул ("кул") режиминде иштей алат. SPI төрт негизги каналга ээ, алардын бардыгын колдонууга болбойт:

  • MOSI, Master Output / Slave Input: бул пин кожоюн режимде маалыматтарды өткөрөт жана кул режиминде маалыматтарды кабыл алат;
  • MISO, Master Input / Slave Output: тескерисинче, кожоюнда кабыл алат, ал эми кулда өткөрөт;
  • SCK, Сериялык саат: кожоюнда маалыматтарды берүүнүн жыштыгын орнотот же кулда саат сигналын кабыл алат. Негизинен уруп-сабоо;
  • SS, Slave Select: бул каналдын жардамы менен кул андан бир нерсе талап кылынганын билет. STM32де ал NSS деп аталат, мында N = терс, б.а. башкаруучу бул каналда жер болсо, кул болуп калат. Бул Open Drain Output режими менен жакшы айкалышат, бирок бул башка окуя.

Бардык башка нерселер сыяктуу эле, STM32деги SPI функционалдуулукка бай, бул аны түшүнүүнү бир аз кыйындатат. Мисалы, ал SPI менен гана эмес, I2S интерфейси менен да иштей алат жана документацияда алардын сыпаттамалары аралаш, керексизди өз убагында кесип салуу керек. Биздин милдет өтө жөнөкөй: биз жөн гана MOSI жана SCK аркылуу маалыматтарды жөнөтүү керек. Биз 25.3.4 (жарым дуплекстүү байланыш, жарым дуплекстүү байланыш) бөлүмүнө барабыз, ал жерден табабыз 1 саат жана 1 бир багыттуу маалымат зымы (1 саат сигналы жана 1 бир багыттуу маалымат агымы):

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Бул режимде, тиркеме SPIди бир гана жөнөтүү же кабыл алуу режиминде колдонот. / Өткөрүүчү гана режим дуплекстүү режимге окшош: маалымат берүү пининде өткөрүлөт (мастер режимде MOSI же кул режиминде MISO), ал эми кабыл алуу пинди (MISO же MOSI тиешелүүлүгүнө жараша) кадимки I/O пин катары колдонсо болот. . Бул учурда, тиркеме Rx буферине көңүл бурбай коюусу керек (эгерде ал окулса, анда эч кандай берилиштер болбойт).

Жакшы, MISO пини бекер, ага LAT сигналын туташтыралы. Slave Select программасын карап көрөлү, аны STM32де программалык түрдө башкарууга болот, бул абдан ыңгайлуу. Ушул эле аталыштагы абзацты 25.3.1 SPI бөлүмүндө окуйбуз.

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Программаны башкаруу NSS (SSM = 1) / Кул тандоо маалыматы SPI_CR1 реестринин SSI битинде камтылган. Тышкы NSS пин башка колдонмо муктаждыктары үчүн бекер бойдон калууда.

Реестрге жазууга убакыт келди. Мен SPI2ди колдонууну чечтим, анын базалык дарегин маалымат баракчасынан издеңиз - 3.3 Memory Map бөлүмүндө:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

Мейли, баштайлы:

#define _SPI2_(mem_offset) (*(volatile uint32_t *)(0x40003800 + (mem_offset)))

25.3.3 бөлүмүн "Мастер режимде SPI конфигурациялоо" өзүн-өзү түшүндүрүүчү аталышы менен ачыңыз:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

1. SPI_CR2 регистринде BR[0:1] биттери менен сериялык тактык жыштыгын коюңуз.

Реестрлер ошол эле аталыштагы маалымдама колдонмо бөлүмүндө чогултулган. Даректи жылдыруу (Дарек алмаштыруу) CR1 – 0x00 үчүн, демейки боюнча бардык биттер тазаланат (Маани кайра коюу 0x0000):

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

BR биттери контроллердин саат бөлгүчүн орнотуп, SPI иштей турган жыштыгын аныктайт. Биздин STM32 жыштыгы 72 МГц болот, LED драйвери, анын маалымат баракчасына ылайык, 25 МГц жыштык менен иштейт, ошондуктан биз төрткө бөлүшүбүз керек (BR[2:0] = 001).

#define _SPI_CR1 0x00

#define BR_0        0x0008
#define BR_1        0x0010
#define BR_2        0x0020

_SPI2_ (_SPI_CR1) |= BR_0;// pclk/4

2. CPOL жана CPHA биттерин дайындарды өткөрүү менен сериялык сааттын убактысынын ортосундагы байланышты аныктоо үчүн коюңуз (240-беттеги диаграмманы караңыз)

Биз бул жерде маалымат жадыбалын окуп, схемаларды карап жаткан жокпуз, келгиле, 704-беттеги CPOL жана CPHA биттеринин тексттик сүрөттөмөсүн жакшылап карап көрөлү (SPI General Description):

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Сааттын фазасы жана полярдуулугу
SPI_CR1 реестринин CPOL жана CPHA биттерин колдонуу менен сиз төрт убакыт мамилелерин программалык түрдө тандай аласыз. CPOL (саат полярдуулугу) бит эч кандай маалымат берилбей турганда саат сигналынын абалын көзөмөлдөйт. Бул бит мастер жана кул режимдерин башкарат. Эгерде CPOL баштапкы абалга келтирилсе, эс алуу режиминде SCK пин аз болот. Эгерде CPOL бит коюлса, эс алуу режиминде SCK пин бийик болот.
CPHA (саат фазасы) бит орнотулганда, жогорку бит тузак строб SCK сигналынын экинчи чети болуп саналат (CPOL ачык болсо төмөндөйт, CPOL коюлган болсо көтөрүлөт). Маалыматтар саат сигналынын экинчи өзгөрүүсү менен кармалат. Эгерде CPHA бит ачык болсо, жогорку бит тузак строб SCK сигналынын көтөрүлүп жаткан чети болуп саналат (CPOL орнотулган болсо, түшөт, CPOL тазаланган болсо, көтөрүлүүчү чети). Маалымат сааттын сигналынын биринчи өзгөрүшүнө кабыл алынат.

Бул билимди өзүнө сиңирип, биз эки бит тең нөл бойдон калышы керек деген жыйынтыкка келебиз, анткени Биз SCK сигналы колдонулбаган учурда төмөн бойдон калышын жана маалымат импульстун көтөрүлгөн четинде берилишин каалайбыз (сүрөттү караңыз). Rising Edge DM634 маалымат жадыбалында).

Айтмакчы, бул жерде биз алгач ST маалымат баракчаларында лексиканын өзгөчөлүгүнө туш болдук: аларда “битти нөлгө кайтаруу” деген сөз айкашы жазылган. бир аз калыбына келтирүү үчүнАл эмес, бир аз тазалоо үчүн, мисалы, Atmega сыяктуу.

3. Маалымат блогу 8-бит же 16-бит форматта экенин аныктоо үчүн DFF битти коюңуз

DM16 сыяктуу 634 биттик PWM берилиштерин өткөрүү менен убара болбоо үчүн мен атайын 12 бит DM633 алдым. DFFти бирине коюу мааниси бар:

#define DFF         0x0800

_SPI2_ (_SPI_CR1) |= DFF; // 16-bit mode

4. Блок форматын аныктоо үчүн SPI_CR1 регистриндеги LSBFIRST битин конфигурациялаңыз

LSBFIRST, анын аты айтып тургандай, биринчи эң аз маанилүү бит менен өткөрүүнү конфигурациялайт. Бирок DM634 эң маанилүү биттен баштап маалыматтарды алууну каалайт. Ошондуктан, биз аны баштапкы абалга калтырабыз.

5. Аппараттык режимде, эгерде NSS пининен киргизүү талап кылынса, бүтүндөй байт өткөрүү ырааттуулугу учурунда NSS пинине жогорку сигналды колдонуңуз. NSS программалык режиминде SPI_CR1 регистринде SSM жана SSI биттерин орнотуңуз. Эгерде NSS пинди чыгаруу катары колдонула турган болсо, SSOE битин гана коюу керек.

NSS аппараттык режимин унутуу үчүн SSM жана SSI орнотуңуз:

#define SSI         0x0100
#define SSM         0x0200

_SPI2_ (_SPI_CR1) |= SSM | SSI; //enable software control of SS, SS high

6. MSTR жана SPE биттери коюлушу керек (алар NSS сигналы жогору болгондо гана коюлган бойдон кала берет)

Чынында, бул биттер менен биз SPIди мастер катары белгилеп, аны күйгүзөбүз:

#define MSTR        0x0004
#define SPE         0x0040

_SPI2_ (_SPI_CR1) |= MSTR; //SPI master
//когда все готово, включаем SPI
_SPI2_ (_SPI_CR1) |= SPE;

SPI конфигурацияланган, келгиле дароо драйверге байттарды жөнөтүүчү функцияларды жазалы. Окууну улантыңыз 25.3.3 "SPI мастер режиминде конфигурациялоо":

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Маалыматтарды өткөрүү тартиби
Берүү Tx буферине байт жазылганда башталат.
Маалымат байты нөөмөт регистрине жүктөлөт параллелдүү режими (ички автобустан) биринчи бит берүү учурунда, андан кийин ал берилет ырааттуу MOSI пин режими, CPI_CR1 регистриндеги LSBFIRST биттин жөндөөсүнө жараша алдыга биринчи же акыркы бит. TXE желеги маалыматтарды берүүдөн кийин коюлат Tx буферинен сменалык регистрге, ошондой эле CPI_CR1 регистриндеги TXEIE бити коюлган болсо үзгүлтүккө учуратууну жаратат.

STM контроллерлорунда SPI ишке ашыруунун бир өзгөчөлүгүнө көңүл буруу үчүн котормодо бир нече сөздөрдү баса белгиледим. Atmega боюнча TXE желеги (Tx Empty, Tx бош жана маалыматтарды алууга даяр) бүт байт жөнөтүлгөндөн кийин гана коюлат чыккан. Жана бул жерде бул желек ички нөөмөт регистрине байт киргизилгенден кийин коюлат. Ал жерде бардык биттер менен бир убакта түртүлгөндүктөн (параллельде), андан кийин маалыматтар ырааттуу түрдө өткөрүлүп берилгендиктен, TXE байт толугу менен жөнөтүлгөнгө чейин коюлат. Бул маанилүү, анткени биздин LED айдоочу учурда, биз жөнөткөндөн кийин LAT төөнөгүч тартуу керек всех маалыматтар, б.а. Биз үчүн жалгыз TXE желеги жетишсиз.

Бул бизге дагы бир желек керек дегенди билдирет. Келгиле, 25.3.7 - "Статус желектерин" карап көрөлү:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
<...>
Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
BUSY желек
BSY желеги аппараттык камсыздоо тарабынан коюлат жана тазаланат (ага жазуу эч кандай таасир этпейт). BSY желеги SPI байланыш катмарынын абалын көрсөтөт.
Ал баштапкы абалга келтирет:
өткөрүп берүү аяктаганда (өткөрүү үзгүлтүксүз болсо, башкы режимден башкасы)
SPI өчүрүлгөндө
негизги режим катасы пайда болгондо (MODF = 1)
Эгерде өткөрүп берүү үзгүлтүксүз болбосо, ар бир маалымат алмашуунун ортосунда BSY желеги тазаланат

Макул, бул пайдалуу болот. Келгиле, Tx буфери кайда жайгашканын билели. Бул үчүн, "SPI маалыматтар реестрин" окуңуз:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Bits 15:0 DR[15:0] Маалымат реестри
Кабыл алынган же берилүүчү маалыматтар.
Берилиштер реестри эки буферге бөлүнөт – бири жазуу үчүн (берүү буфери) жана экинчиси окуу үчүн (кабыл алуу буфери). Маалымат реестрине жазуу Tx буферине жазат, ал эми маалымат реестринен окуу Rx буферинде камтылган маанини кайтарат.

Ооба, TXE жана BSY желектери табылган статус реестри:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

Биз жазабыз:

#define _SPI_DR  0x0C
#define _SPI_SR  0x08

#define BSY         0x0080
#define TXE         0x0002

void dm_shift16(uint16_t value)
{
    _SPI2_(_SPI_DR) = value; //send 2 bytes
    while (!(_SPI2_(_SPI_SR) & TXE)); //wait until they're sent
}

Ооба, биз 16 жолу эки байт өткөрүп беришибиз керек болгондуктан, LED драйверинин чыгууларынын санына жараша, төмөнкүдөй:

void sendLEDdata()
{
    LAT_low();
    uint8_t k = 16;
    do
    {   k--;
        dm_shift16(leds[k]);
    } while (k);

    while (_SPI2_(_SPI_SR) & BSY); // finish transmission

    LAT_pulse();
}

Бирок биз LAT төөнөгүчтү кантип тартууну билбейбиз, андыктан I/Oга кайтып барабыз.

Пиндерди дайындоо

STM32F1де төөнөгүчтөрдүн абалына жооптуу реестрлер адаттан тыш болуп саналат. Атмегага караганда алардын көп экени анык, бирок алар башка STM чиптеринен да айырмаланат. Бөлүм 9.1 GPIOнун жалпы сүрөттөлүшү:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Жалпы максаттагы киргизүү/чыгаруу портторунун ар бири (GPIO) эки 32 биттик конфигурация регистрлери (GPIOx_CRL жана GPIOx_CRH), эки 32 биттик маалымат регистрлери (GPIOx_IDR жана GPIOx_ODR), 32 биттик орнотуу/калыбына келтирүү реестри (GPIOx_BSRR), 16 биттик баштапкы абалга келтирүү реестри (GPIOx_BRR) жана 32- бит бөгөттөө реестри (GPIOx_LCKR).

Биринчи эки регистр адаттан тыш, ошондой эле абдан ыңгайсыз, анткени 16 порт пиндери "бир тууган үчүн төрт бит" форматында чачырап кеткен. Ошол. нөлдөн жетиге чейинки төөнөгүчтөр CRLде, калгандары CRHде. Ошол эле учурда, калган регистрлер порттун бардык пиндеринин биттерин ийгиликтүү камтыйт - көбүнчө жарымы "камдалган".

Жөнөкөйлүк үчүн тизменин аягынан баштайлы.

Бизге бөгөт коюу регистринин кереги жок.

Орнотуу жана баштапкы абалга келтирүү регистрлери абдан күлкүлүү, анткени алар бири-бирин жарым-жартылай кайталайт: бардыгын BSRRде гана жаза аласыз, мында жогорку 16 бит пинди нөлгө, ал эми төмөнкүлөрү 1ге коюлат, же сиз дагы BRR колдонуңуз, анын төмөнкү 16 биттери пинди гана баштапкы абалга келтирет. Мага экинчи вариант жагат. Бул регистрлер маанилүү, анткени алар пиндерге атомдук мүмкүнчүлүк берет:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Atomic Set же Reset
GPIOx_ODR бит деңгээлинде программалоодо үзгүлтүктөрдү өчүрүүнүн кереги жок: бир же бир нече бит APB2 бир атомдук жазуу операциясы менен өзгөртүлүшү мүмкүн. Бул өзгөртүү керек болгон биттин орнотуу/кайра коюу реестрине (GPIOx_BSRR же баштапкы абалга келтирүү үчүн гана, GPIOx_BRR) "1" жазуу аркылуу жетишилет. Башка биттер өзгөрүүсүз калат.

Маалымат регистрлери өзүн-өзү түшүндүрүүчү аталыштарга ээ - IDR = кирүү Багыт реестри, киргизүү реестри; ODR = продукция Багыт реестри, чыгуу реестри. Бизге азыркы долбоордо алардын кереги жок болот.

Акыр-аягы, контролдук регистрлер. Биз экинчи SPI пиндерине, тактап айтканда PB13, PB14 жана PB15ке кызыккандыктан, биз дароо CRHге карайбыз:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

Жана биз 20дан 31ге чейин бит менен бир нерсени жазуу керек экенин көрүп жатабыз.

Биз жогоруда пиндерден эмнени каалай турганыбызды түшүндүк, андыктан бул жерде мен скриншотсуз жасайм, мен жөн гана MODE багытты (эки бит тең 0гө коюлган болсо, киргизүү) жана пин ылдамдыгын (бизге 50 МГц керек, б.а.) көрсөтөт деп айтам. экөө тең “1” пин) жана CNF режимди орнотот: кадимки “түртүү-тартуу” – 00, “альтернативдик” – 10. Демейки боюнча, жогоруда көрүп тургандай, бардык төөнөгүчтөрдүн түбүнөн үчүнчү бит бар (CNF0), аларды режимге коет калкыма киргизүү.

Мен бул чип менен башка нерсени жасоону пландап жаткандыктан, жөнөкөйлүк үчүн мен төмөнкү жана жогорку башкаруу регистрлери үчүн бардык мүмкүн болгон MODE жана CNF маанилерин аныктадым.

Негедир ушундай

#define CNF0_0 0x00000004
#define CNF0_1 0x00000008
#define CNF1_0 0x00000040
#define CNF1_1 0x00000080
#define CNF2_0 0x00000400
#define CNF2_1 0x00000800
#define CNF3_0 0x00004000
#define CNF3_1 0x00008000
#define CNF4_0 0x00040000
#define CNF4_1 0x00080000
#define CNF5_0 0x00400000
#define CNF5_1 0x00800000
#define CNF6_0 0x04000000
#define CNF6_1 0x08000000
#define CNF7_0 0x40000000
#define CNF7_1 0x80000000
#define CNF8_0 0x00000004
#define CNF8_1 0x00000008
#define CNF9_0 0x00000040
#define CNF9_1 0x00000080
#define CNF10_0 0x00000400
#define CNF10_1 0x00000800
#define CNF11_0 0x00004000
#define CNF11_1 0x00008000
#define CNF12_0 0x00040000
#define CNF12_1 0x00080000
#define CNF13_0 0x00400000
#define CNF13_1 0x00800000
#define CNF14_0 0x04000000
#define CNF14_1 0x08000000
#define CNF15_0 0x40000000
#define CNF15_1 0x80000000

#define MODE0_0 0x00000001
#define MODE0_1 0x00000002
#define MODE1_0 0x00000010
#define MODE1_1 0x00000020
#define MODE2_0 0x00000100
#define MODE2_1 0x00000200
#define MODE3_0 0x00001000
#define MODE3_1 0x00002000
#define MODE4_0 0x00010000
#define MODE4_1 0x00020000
#define MODE5_0 0x00100000
#define MODE5_1 0x00200000
#define MODE6_0 0x01000000
#define MODE6_1 0x02000000
#define MODE7_0 0x10000000
#define MODE7_1 0x20000000
#define MODE8_0 0x00000001
#define MODE8_1 0x00000002
#define MODE9_0 0x00000010
#define MODE9_1 0x00000020
#define MODE10_0 0x00000100
#define MODE10_1 0x00000200
#define MODE11_0 0x00001000
#define MODE11_1 0x00002000
#define MODE12_0 0x00010000
#define MODE12_1 0x00020000
#define MODE13_0 0x00100000
#define MODE13_1 0x00200000
#define MODE14_0 0x01000000
#define MODE14_1 0x02000000
#define MODE15_0 0x10000000
#define MODE15_1 0x20000000

Биздин пиндер В портунда жайгашкан (базалык дарек – 0x40010C00), код:

#define _PORTB_(mem_offset) (*(volatile uint32_t *)(0x40010C00 + (mem_offset)))

#define _BRR  0x14
#define _BSRR 0x10
#define _CRL  0x00
#define _CRH  0x04

//используем стандартный SPI2: MOSI на B15, CLK на B13
//LAT пусть будет на неиспользуемом MISO – B14

//очищаем дефолтный бит, он нам точно не нужен
_PORTB_ (_CRH) &= ~(CNF15_0 | CNF14_0 | CNF13_0 | CNF12_0);

//альтернативные функции для MOSI и SCK
_PORTB_ (_CRH) |= CNF15_1 | CNF13_1;

//50 МГц, MODE = 11
_PORTB_ (_CRH) |= MODE15_1 | MODE15_0 | MODE14_1 | MODE14_0 | MODE13_1 | MODE13_0;

Жана, ошого жараша, сиз BRR жана BSRR регистрлери тарабынан кыйратылган LAT үчүн аныктамаларды жаза аласыз:

/*** LAT pulse – high, then low */
#define LAT_pulse() _PORTB_(_BSRR) = (1<<14); _PORTB_(_BRR) = (1<<14)

#define LAT_low() _PORTB_(_BRR) = (1<<14)

(LAT_low жөн гана инерция, ал ар дайым ушундай болгон, кала берсин)

Азыр баары сонун, бирок ал иштебейт. Бул STM32 болгондуктан, алар электр энергиясын үнөмдөйт, демек, керектүү перифериялык түзүлүштөрдүн саатын иштетүү керек.

Саатты иштетүү

Саат, ошондой эле Саат катары белгилүү, саат үчүн жооптуу. Ал эми биз RCC аббревиатурасын байкай алдык. Биз аны документациядан издейбиз: бул баштапкы абалга келтирүү жана саатты башкаруу.

Жогоруда айтылгандай, бактыга жараша, сааттык теманын эң татаал бөлүгүн биз үчүн STM адамдары жасашты, бул үчүн биз аларга терең ыраазычылык билдиребиз (дагы бир жолу мен шилтеме берем Ди Халттын сайты, анын канчалык башаламан экенин ачык-айкын кылуу үчүн). Бизге перифериялык саатты иштетүү үчүн жооптуу регистрлер гана керек (Перифериялык саатты иштетүү регистрлери). Биринчиден, РСКнын базалык дарегин табалы, ал "Эс тутум картасынын" эң башында:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

#define _RCC_(mem_offset) (*(volatile uint32_t *)(0x40021000 + (mem_offset)))

Андан кийин же табактан бир нерсе табууга аракет кылган шилтемени чыкылдатыңыз, же андан да жакшысы, төмөнкү бөлүмдөрдөгү күйгүзүүчү регистрлердин сыпаттамаларынан өтүңүз. регистрлерди иштетүү. RCC_APB1ENR жана RCC_APB2ENR кайдан табабыз:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

Жана алар, ылайык, SPI2, IOPB (I/O Port B) жана альтернативдик функцияларды (AFIO) саатын камтыган биттерди камтыйт.

#define _APB2ENR 0x18
#define _APB1ENR 0x1C

#define IOPBEN 0x0008
#define SPI2EN 0x4000
#define AFIOEN 0x0001

//включаем тактирование порта B и альт. функций
_RCC_(_APB2ENR) |= IOPBEN | AFIOEN;

//включаем  тактирование SPI2
_RCC_(_APB1ENR) |= SPI2EN;

Акыркы кодду табууга болот бул жерде.

Эгер сизде сыноо мүмкүнчүлүгү жана каалоосу болсо, анда DM634ти төмөнкүдөй туташтырыңыз: DAI - PB15, DCK - PB13, LAT - PB14. Биз айдоочуну 5 вольттон кубаттайбыз, жерди туташтырууну унутпаңыз.

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

STM8 PWM

STM8деги PWM

Мен бул макаланы жаңыдан пландаштырып жатканда, мен, мисалы, өтүксүз бут кийимчи болуп калбашы үчүн, бейтааныш чиптин кээ бир функцияларын бир гана маалымат баракчасын колдонуп өздөштүрүүнү чечтим. STM8 бул роль үчүн идеалдуу болгон: биринчиден, менде STM8S103 менен бир нече кытай такталары бар болчу, экинчиден, ал анча популярдуу эмес, ошондуктан Интернетте окуу жана чечим табуу азгырыгы ушул чечимдердин жоктугуна байланыштуу.

Чипте да бар маалымат жадыбалы и маалымдама колдонмо RM0016, биринчисинде pinout жана каттоо даректери бар, экинчисинде - калганынын баары. STM8 коркунучтуу IDEде C тилинде программаланган ST Visual Develop.

Саат жана киргизүү/чыгаруу

Демейки боюнча, STM8 2 МГц жыштыгында иштейт, бул дароо оңдолушу керек.

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
HSI (Жогорку ылдамдыктагы ички) саат
HSI саат сигналы программалоочу бөлгүч (16ден 1ге чейин) менен ички 8 МГц RC осцилляторунан алынат. Ал саат бөлүүчү регистрде (CLK_CKDIVR) орнотулган.
Эскертүү: башталышында саат сигналынын алдыңкы булагы катары 8 бөлгүч менен HSI RC осциллятору тандалат.

Биз маалымат баракчасынан реестрдин дарегин, refmanдагы сыпаттаманы табабыз жана реестрди тазалоо керек экенин көрөбүз:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Биз PWMди иштетип, LEDди туташтырганыбыз үчүн, келгиле, пинутту карап көрөлү:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

Чип кичинекей, көптөгөн функциялар бир эле тээктерге илинген. Чарчы кашаанын ичинде "альтернативдик функция" деп жазылган, ал "опция байттары" менен которулат (параметр байттар) – Atmega сактагычтары сыяктуу бир нерсе. Сиз алардын баалуулуктарын программалык түрдө өзгөртө аласыз, бирок бул зарыл эмес, анткени Жаңы функция кайра жүктөөдөн кийин гана иштетилет. Бул байттарды өзгөртө турган ST Visual Programmer (Visual Develop менен жүктөлүп алынган) колдонуу оңой. Pinout биринчи таймердин CH1 жана CH2 төөнөгүчтөрү төрт бурчтуу кашаанын ичинде жашырылганын көрсөтөт; STVPде AFR1 жана AFR0 биттерин коюу керек, ал эми экинчиси экинчи таймердин CH1 чыгышын PD4тен PC5ке өткөрөт.

Ошентип, 6 төөнөгүч светодиоддорду башкарат: биринчи таймер үчүн PC6, PC7 жана PC3, экинчиси үчүн PC5, PD3 жана PA3.

I/O пиндерин STM8де орнотуу STM32ге караганда жөнөкөй жана логикалуураак:

  • Atmega DDR маалымат багыты реестринен тааныш (Маалымат багыттарынын реестри): 1 = чыгаруу;
  • биринчи башкаруу регистр CR1, чыкканда, түртүү режимин (1) же ачык дренажды (0) орнотот; Мен LEDди чипке катоддор менен туташтыргандыктан, мен бул жерде нөлдөрдү калтырам;
  • экинчи башкаруу регистр CR2, чыкканда, тактык ылдамдыгын орнотот: 1 = 10 МГц

#define PA_DDR     *(volatile uint8_t *)0x005002
#define PA_CR2     *(volatile uint8_t *)0x005004
#define PD_DDR     *(volatile uint8_t *)0x005011
#define PD_CR2     *(volatile uint8_t *)0x005013
#define PC_DDR     *(volatile uint8_t *)0x00500C
#define PC_CR2     *(volatile uint8_t *)0x00500E

PA_DDR = (1<<3); //output
PA_CR2 |= (1<<3); //fast
PD_DDR = (1<<3); //output
PD_CR2 |= (1<<3); //fast
PC_DDR = ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //output
PC_CR2 |= ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //fast

PWM жөндөө

Биринчиден, терминдерди аныктайлы:

  • PWM жыштыгы – таймер белгилөө жыштыгы;
  • Авто кайра жүктөө, AR – таймер эсептей турган автожүктөлүүчү маани (импульс мезгили);
  • Жаңыртуу окуясы, UEV – таймер АРга санаганда пайда болгон окуя;
  • PWM милдет цикли – PWM милдет цикли, көбүнчө “милдет фактору” деп аталат;
  • Маани тартуу/салыштыруу – таймер эсептеген тартуу/салыштыруу үчүн маани бир нерсе кылат (PWM учурда, ал чыгуу сигналын инвертирлейт);
  • Preload Value – алдын ала жүктөлгөн маани. Бааны салыштыруу таймер өтүп жатканда өзгөртө албайт, антпесе PWM цикли үзүлөт. Ошентип, жаңы берилген маанилер буферге жайгаштырылат жана таймер артка санауунун аягына жеткенде жана кайра коюлганда чыгарылат;
  • Четине тегизделген и Ортого тегизделген режимдер – чек араны бойлото жана борбордо түздөө, Атмелдикиндей Тез PWM и Фазалык туура PWM.
  • OCiREF, Чыгуу салыштыруу маалымдама сигналы – маалымдама чыгуу сигналы, чынында, PWM режиминде тиешелүү пинде эмне пайда болот.

Пинуттан көрүнүп тургандай, эки таймердин PWM мүмкүнчүлүктөрү бар - биринчи жана экинчи. Экөө тең 16-бит, биринчисинде көптөгөн кошумча функциялар бар (айрыкча, ал өйдө да, ылдый да санай алат). Экөөбүз тең бирдей иштешибиз керек, андыктан жок нерсени кокустан пайдаланып калбаш үчүн мен анык начар экинчисинен баштоону чечтим. Кээ бир көйгөй, маалымдама колдонмосундагы бардык таймерлердин PWM функционалдуулугунун сүрөттөлүшү биринчи таймер (17.5.7 PWM режими) жөнүндө бөлүмдө берилген, андыктан документ боюнча ар дайым алдыга жана артка секирип туруу керек.

STM8деги PWM Atmegaдагы PWMге караганда маанилүү артыкчылыкка ээ:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Boundary Aligned PWM
Эсептин конфигурациясы ылдыйдан өйдө
Эгерде TIM_CR1 регистриндеги DIR бит тазаланган болсо, ылдыйдан жогоруга эсептөө активдүү болот
мисал
Мисал биринчи PWM режимин колдонот. PWM маалымдама сигналы OCiREF TIM1_CNT < TIM1_CCRi чейин жогору кармалат. Болбосо, ал төмөн деңгээлди талап кылат. Эгерде TIM1_CCRi регистриндеги салыштыруу мааниси автожүктөө маанисинен (TIM1_ARR регистр) чоң болсо, OCiREF сигналы 1де кармалат. Эгерде салыштыруу мааниси 0 болсо, OCiREF нөлдө кармалат....

STM8 таймер учурунда жаңыртуу окуясы биринчи текшерет наркын салыштыруу, ошондо гана шилтеме сигналын чыгарат. Atmega таймери алгач буралып, анан салыштырып, натыйжада compare value == 0 чыгаруу ийне болуп саналат, аны кандайдыр бир жол менен чечиш керек (мисалы, логиканы программалык түрдө инвертирлөө жолу менен).

Ошентип, биз эмне кылгыбыз келет: 8-бит PWM (AR == 255), ылдыйдан өйдө карай санап, чек ара боюнча тегиздөө. Электр лампалары чипке катоддор аркылуу туташтырылгандыктан, PWM 0 (LED күйгүзүлгөн) чейин чыгышы керек. наркын салыштыруу жана 1 кийин.

Кээ бирлери жөнүндө биз буга чейин окуганбыз PWM режими, ошондуктан биз бул фразаны (18.6.8 - TIMx_CCMR1) маалымдама колдонмосунан издөө аркылуу экинчи таймердин керектүү реестрин табабыз:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
110: Биринчи PWM режими – ылдыйдан өйдө санаганда, TIMx_CNT < TIMx_CCR1 учурунда биринчи канал активдүү болот. Болбосо, биринчи канал жигердүү эмес. [мындан ары документте 1-таймерден жаңылыштык көчүрүп чаптоо бар] 111: Экинчи PWM режими – ылдыйдан өйдө санаганда, TIMx_CNT < TIMx_CCR1 болгондо биринчи канал жигердүү эмес. Болбосо, биринчи канал активдүү болот.

Светодиоддор МКга катоддор аркылуу туташтырылгандыктан, экинчи режим бизге ылайыктуу (биринчиси да, бирок биз муну азырынча билбейбиз).

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Bit 3 OC1PE: PIN 1 алдын ала жүктөөнү иштетүү
0: TIMx_CCR1 боюнча алдын ала жүктөө реестри өчүрүлгөн. TIMx_CCR1ге каалаган убакта жаза аласыз. Жаңы маани дароо иштейт.
1: TIMx_CCR1 боюнча алдын ала жүктөө регистри иштетилди. Окуу/жазуу операциялары алдын ала жүктөө реестрине кирүү. Алдын ала жүктөлгөн TIMx_CCR1 мааниси ар бир жаңыртуу окуясында көмүскө реестрге жүктөлөт.
*Эскертүү: PWM режими туура иштеши үчүн, алдын ала жүктөө регистрлери иштетилиши керек. Бул бир сигнал режиминде зарыл эмес (OPM бити TIMx_CR1 регистринде коюлган).

Макул, экинчи таймердин үч каналы үчүн керектүү нерселердин баарын күйгүзөлү:

#define TIM2_CCMR1 *(volatile uint8_t *)0x005307
#define TIM2_CCMR2 *(volatile uint8_t *)0x005308
#define TIM2_CCMR3 *(volatile uint8_t *)0x005309

#define PWM_MODE2   0x70 //PWM mode 2, 0b01110000
#define OCxPE       0x08 //preload enable

TIM2_CCMR1 = (PWM_MODE2 | OCxPE);
TIM2_CCMR2 = (PWM_MODE2 | OCxPE);
TIM2_CCMR3 = (PWM_MODE2 | OCxPE);

AR эки сегиз биттик регистрден турат, бардыгы жөнөкөй:

#define TIM2_ARRH  *(volatile uint8_t *)0x00530F
#define TIM2_ARRL  *(volatile uint8_t *)0x005310

TIM2_ARRH = 0;
TIM2_ARRL = 255;

Экинчи таймер ылдыйдан өйдө карай гана санай алат, чек ара боюнча тегиздөө, эч нерсени өзгөртүүнүн кереги жок. Жыштык бөлгүчтү, мисалы, 256га коелу. Экинчи таймер үчүн бөлгүч TIM2_PSCR регистринде орнотулган жана экинин күчү:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

Корутундуларды жана экинчи таймерди күйгүзүү гана калды. Биринчи маселе регистрлер тарабынан чечилет Тартуу/Салыштыруу иштетүү: алар боюнча асимметриялуу чачыраган эки, үч каналдар бар. Бул жерден биз сигналдын полярдуулугун өзгөртүүгө мүмкүн экенин да биле алабыз, б.а. негизинен, PWM режимин колдонууга мүмкүн болгон 1. Биз жазабыз:

#define TIM2_CCER1 *(volatile uint8_t *)0x00530A
#define TIM2_CCER2 *(volatile uint8_t *)0x00530B

#define CC1E  (1<<0) // CCER1
#define CC2E  (1<<4) // CCER1
#define CC3E  (1<<0) // CCER2

TIM2_CCER1 = (CC1E | CC2E);
TIM2_CCER2 = CC3E;

Акыр-аягы, биз TIMx_CR1 регистринде таймерди баштайбыз:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Келгиле, салыштыруу үчүн чыныгы маанилерди таймерге өткөрүп бере турган AnalogWrite()дин жөнөкөй аналогун жазалы. Реестрлер алдын ала айтылган Регистрлерди басып алуу/салыштыруу, ар бир канал үчүн алардын экөөсү бар: TIM8_CCRxL ичиндеги төмөнкү тартиптеги 2 бит жана TIM2_CCRxH ичиндеги жогорку тартиптеги. Биз 8 биттик PWM түзгөндүктөн, эң аз маанилүү биттерди гана жазуу жетиштүү:

#define TIM2_CCR1L *(volatile uint8_t *)0x005312
#define TIM2_CCR2L *(volatile uint8_t *)0x005314
#define TIM2_CCR3L *(volatile uint8_t *)0x005316

void setRGBled(uint8_t r, uint8_t g, uint8_t b)
{
    TIM2_CCR1L = r;
    TIM2_CCR2L = g;
    TIM2_CCR3L = b;
}

Кунт коюп окурман бизде 100% толтурууга жөндөмсүз PWM бир аз бузулганын байкайт (максималдуу 255 баллда сигнал бир таймер циклине тескерилет). Светодиоддор үчүн бул маанилүү эмес жана кунт коюп окурман аны кантип оңдоону болжолдой алат.

Экинчи таймердеги PWM иштейт, биринчисине өтөбүз.

Биринчи таймердин ошол эле регистрлерде дал ушундай биттери бар (жөн гана экинчи таймерде "запаста" калган биттер биринчисинде бардык өркүндөтүлгөн нерселер үчүн активдүү колдонулат). Ошондуктан, ошол эле регистрлердин даректерин маалымат баракчасынан таап, кодду көчүрүп алуу жетиштүү. Жыштык бөлгүчтүн маанисин өзгөртүңүз, анткени... биринчи таймер эки күчүн эмес, эки регистрде так 16 биттик маанини алууну каалайт Prescaler High и төмөн. Биз баарын кылабыз жана... биринчи таймер иштебейт. Эмне болду?

Маселени 1-таймердин башкаруу регистрлери жөнүндө бүт бөлүмдү карап чыгуу менен гана чечүүгө болот, ал жерден биз экинчи таймерде жок болгонду издейбиз. Бар болот 17.7.30 Тыныгуу реестри (TIM1_BKR), бул бит бар жерде:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Негизги чыгарууну иштетүү

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

Мунун баары азыр анык, код ошол эле жерде.

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

STM8 мультиплекс

STM8де мультиплекстөө

Үчүнчү мини-долбоор сегиз RGB LEDди PWM режиминде экинчи таймерге туташтыруу жана аларды ар кандай түстөрдү көрсөтүү. Бул LED мультиплекстөө концепциясына негизделген, башкача айтканда, эгер сиз светодиоддорду абдан тез күйгүзсөңүз жана өчүрсөңүз, бизге алар дайыма күйүп тургандай сезилет (АЯН сакталууда, көрүү кабылдоо инерциясы). Мен бир жолу кылдым Arduino боюнча ушул сыяктуу бир нерсе.

Жумуштун алгоритми төмөнкүдөй көрүнөт:

  • биринчи RGB LED анодун туташтырган;
  • аны күйгүзүү, катоддорго керектүү сигналдарды жөнөтүү;
  • PWM циклинин аягына чейин күттү;
  • экинчи RGB LED анодун туташтырган;
  • күйгүздү...

Мейли, ж.б. Албетте, кооз иштеши үчүн анод туташтырылган жана ошол эле учурда LED "от күйгүзүлгөн" талап кылынат. Ооба, же дээрлик. Кандай болбосун, биз экинчи таймердин үч каналында маанилерди чыгара турган кодду жазышыбыз керек, UEV жеткенде аларды өзгөртүп, ошол эле учурда учурда активдүү RGB LEDди өзгөртүшүбүз керек.

LED которуштуруу автоматтык болгондуктан, биз "видео эстутум" түзүшүбүз керек, андан үзгүлтүккө учурагыч маалымат алат. Бул жөнөкөй массив:

uint8_t colors[8][3];

Белгилүү бир LED түсүн өзгөртүү үчүн, бул массивге керектүү маанилерди жазуу жетиштүү болот. Ал эми өзгөрмө активдүү LED саны үчүн жооптуу болот

uint8_t cnt;

Demux

Туура мультиплекстөө үчүн бизге, таң калыштуусу, CD74HC238 демультиплексери керек. Demultiplexer – аппараттык камсыздоодо операторду ишке ашыруучу чип <<. Үч киргизүү төөнөгүчтөрү (бит 0, 1 жана 2) аркылуу биз ага үч биттик X санын беребиз жана жооп катары ал чыгаруу номерин ((1<<X). Чиптин калган кириштери бүт дизайнды масштабдоо үчүн колдонулат. Бизге бул чип микроконтроллердин ээлеген төөнөгүчтөрүнүн санын азайтуу үчүн гана эмес, коопсуздук үчүн да керек - кокустан мүмкүн болушунча көбүрөөк светодиоддорду күйгүзбөө жана МКны күйгүзбөө үчүн. Чип бир тыйын турат жана ар дайым үйүңүздүн дары кабинетинде сакталышы керек.

Биздин CD74HC238 каалаган LED анодуна чыңалуу менен камсыз кылуу үчүн жооптуу болот. Толук кандуу мультиплексте, ал P-MOSFET аркылуу мамычага чыңалууну берет, бирок бул демодо түздөн-түз мүмкүн, анткени ылайык, ал 20 мА тартат абсолюттук максималдуу рейтингдер маалымат баракчасында. From CD74HC238 маалымат жадыбалы бизге pinouts жана бул жалган баракча керек:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
H = жогорку чыңалуу деңгээли, L = төмөнкү чыңалуу деңгээли, X – баары бир

Биз E2 жана E1ди жерге, E3, A0, A1 жана A3 пин PD5, PC3, PC4 жана PC5 менен STM8 туташтырабыз. Жогорудагы таблицада төмөнкү жана жогорку деңгээлдер камтылгандыктан, биз бул төөнөгүчтөрдү түртүү төөнөгүчтөрү катары конфигурациялайбыз.

PWM

Экинчи таймердеги PWM мурунку окуядагыдай эле конфигурацияланган, эки айырмасы бар:

Биринчиден, биз үзгүлтүккө иштетишибиз керек Окуяны жаңыртуу (UEV) ал активдүү LEDди которуштуруучу функцияны чакырат. Бул бит өзгөртүү аркылуу ишке ашырылат Жаңыртуу үзгүлтүккө учуратуу аты жазылган реестрде

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
Үзгүлтүккө учуратуу регистр

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Экинчи айырмачылык мультиплекстөө кубулушуна байланыштуу, мисалы Ghosting – диоддордун паразиттик жаркырашы. Биздин учурда, ал UEVде үзгүлтүккө учураган таймер белги коюуну улантып жатканынан улам пайда болушу мүмкүн жана таймер төөнөгүчкө бир нерсе жаза баштаганга чейин үзгүлтүккө учуроочу LEDди которуштурууга үлгүрбөй калат. Муну менен күрөшүү үчүн, логиканы тескери бурушуңуз керек (0 = максималдуу жарыктык, 255 = эч нерсе күйбөйт) жана экстремалдык милдет циклинин маанилеринен качышыңыз керек. Ошол. UEVден кийин диоддор бир PWM циклине толугу менен өчүшүн камсыз кылыңыз.

Уюлдуулукту өзгөртүү:

//set polarity 
    TIM2_CCER1 |= (CC1P | CC2P);
    TIM2_CCER2 |= CC3P;

r, g жана b 255 деп коюудан качыңыз жана аларды колдонууда аларды тескери салууну унутпаңыз.

Үзгүлтүккө учуратат

Үзгүлтүктүн маңызы – белгилүү бир шарттарда чип негизги программаны аткарууну токтотуп, кандайдыр бир тышкы функцияны чакырат. Үзгүлтүктөр тышкы же ички таасирлерден, анын ичинде таймерден улам пайда болот.

Биз биринчи жолу ST Visual Develop долбоорун жаратканда, андан тышкары main.c сырдуу файл менен терезе алдык stm8_interrupt_vector.c, долбоорго автоматтык түрдө кошулат. Бул файлда ар бир үзгүлтүккө функция дайындалат NonHandledInterrupt. Биз өзүбүздүн функциябызды каалаган үзгүлтүккө байлашыбыз керек.

Маалымат баракчасында үзүлүү векторлорунун таблицасы бар, анда бизге керектүүлөрүн табабыз:

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр
13 TIM2 жаңыртуу/ашып кетүү
14 TIM2 тартуу/салыштыруу

Биз UEVдеги LEDди өзгөртүүбүз керек, андыктан №13 үзгүлтүккө муктажбыз.

Демек, биринчиден, файлда stm8_interrupt_vector.c №13 үзгүлтүккө (IRQ13) жооптуу функциянын демейки атын өзүңүзгө өзгөртүңүз:

{0x82, TIM2_Overflow}, /* irq13 */

Экинчиден, биз файл түзүшүбүз керек main.h төмөнкү мазмун менен:

#ifndef __MAIN_H
#define __MAIN_H

@far @interrupt void TIM2_Overflow (void);
#endif

Акыр-аягы, бул функцияны өзүңүзгө жазыңыз main.c:

@far @interrupt void TIM2_Overflow (void)
{
    PD_ODR &= ~(1<<5); // вырубаем демультиплексор
    PC_ODR = (cnt<<3); // записываем в демультиплексор новое значение
    PD_ODR |= (1<<5); // включаем демультиплексор

    TIM2_SR1 = 0; // сбрасываем флаг Update Interrupt Pending

    cnt++; 
    cnt &= 7; // двигаем счетчик LED

    TIM2_CCR1L = ~colors[cnt][0]; // передаем в буфер инвертированные значения
    TIM2_CCR2L = ~colors[cnt][1]; // для следующего цикла ШИМ
    TIM2_CCR3L = ~colors[cnt][2]; // 

    return;
}

Үзгүлтүктөрдү иштетүү гана калды. Бул ассемблер буйругу аркылуу ишке ашырылат rim - Сен аны издөөгө туура келет Программалоо боюнча колдонмо:

//enable interrupts
_asm("rim");

Башка ассемблер буйругу sim – үзгүлтүктөрдү өчүрөт. Жаңы баалуулуктар "видео эстутумга" жазылып жатканда аларды өчүрүү керек, туура эмес учурда пайда болгон үзгүлтүк массивди бузбашы үчүн.

Бардык код - GitHub боюнча.

Маалымат баракчаларын окуу 2: STM32 боюнча SPI; STM8деги PWM, таймерлер жана үзгүлтүктөр

Жок дегенде кимдир бирөө бул макаланы пайдалуу деп тапса, анда мен аны бекер жазган жокмун. Комментарийлерди жана эскертүүлөрдү алганыма кубанычтамын, баарына жооп бергенге аракет кылам.

Source: www.habr.com

Комментарий кошуу