Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал

В эхний хэсэг Би Arduino өмднөөс өссөн хобби электроникийн инженерүүдэд микроконтроллерын мэдээллийн хуудас болон бусад баримт бичгийг хэрхэн, яагаад унших ёстойг хэлэхийг оролдсон. Текст нь том хэмжээтэй болсон тул би тусдаа нийтлэлд практик жишээг харуулахаа амласан. За тэр өөрийгөө сүүний мөөг гэж...

Өнөөдөр би STM32 (Цэнхэр эм) болон STM8 хянагч дээрх олон төсөл, даалгавруудыг шийдвэрлэхэд маш энгийн боловч шаардлагатай мэдээллийн хуудсыг хэрхэн ашиглахыг танд үзүүлэх болно. Бүх демо төслүүд миний дуртай LED-д зориулагдсан тул бид тэдгээрийг их хэмжээгээр гэрэлтүүлэх болно, үүний тулд бид бүх төрлийн сонирхолтой дагалдах хэрэгслийг ашиглах шаардлагатай болно.

Текст дахин том болсон тул тав тухтай байлгах үүднээс би контентыг хийж байна:

STM32 Blue Pill: DM16 драйвертай 634 LED
STM8: Зургаан PWM зүүг тохируулж байна
STM8: Гурван зүү дээр 8 RGB LED, тасалдал

Анхааруулга: Би инженер биш, электроникийн талаар гүнзгий мэдлэгтэй гэж дүр эсгэдэггүй, нийтлэл нь над шиг сонирхогчдод зориулагдсан болно. Ер нь би хоёр жилийн өмнө өөрийгөө зорилтот үзэгчид гэж боддог байсан. Хэрэв хэн нэгэн надад танил бус чип дээрх мэдээллийн хуудсыг уншихад аймаар биш гэж хэлсэн бол би Интернетээс зарим код хайж, хайч, наалдамхай тууз бүхий суга таяг зохион бүтээхэд их цаг зарцуулахгүй байх байсан.

Энэ нийтлэлийн гол зүйл бол төслүүд биш, мэдээллийн хуудаснууд дээр байгаа тул код нь маш цэвэрхэн биш, ихэвчлэн давчуу байж магадгүй юм. Төслүүд нь өөрөө маш энгийн боловч шинэ чиптэй анх танилцахад тохиромжтой.

Миний нийтлэл хоббитой ижил төстэй үе шатанд байгаа хэн нэгэнд тусална гэж найдаж байна.

STM32

DM16 болон SPI бүхий 634 LED

Цэнхэр эм (STM32F103C8T6) болон DM634 LED драйвер ашигладаг жижиг төсөл. Мэдээллийн хуудсыг ашиглан бид драйвер, STM IO портуудыг тодорхойлж, SPI-г тохируулах болно.

DM634

16 битийн PWM гаралттай Тайваний чипийг гинжээр холбож болно. Доод түвшний 16 битийн загварыг дотоодын төслөөс мэддэг Хөнгөн багц. Нэгэн цагт DM63x болон алдартай TLC5940 хоёрын хооронд сонголт хийхдээ би хэд хэдэн шалтгааны улмаас DM-ийг сонгосон: 1) Aliexpress дээрх TLC нь хуурамч, гэхдээ энэ нь тийм биш юм; 2) DM нь өөрийн давтамж үүсгэгчтэй бие даасан PWM-тэй; 3) Алигийн илгээмжийг хүлээхээс илүүтэйгээр Москвад хямд үнээр худалдаж авах боломжтой. Мөн бэлэн номын сан ашиглахаас илүү чипийг өөрөө удирдаж сурах нь мэдээж сонирхолтой байсан. Одоо чипсийг ихэвчлэн SSOP24 багцад танилцуулж байгаа бөгөөд тэдгээрийг адаптерт гагнахад хялбар байдаг.

Үйлдвэрлэгч нь Тайвань учраас мэдээллийн хуудас чип нь хятад англи хэл дээр бичигдсэн бөгөөд энэ нь хөгжилтэй байх болно гэсэн үг юм. Эхлээд бид зүүг харна (Pin холболт) аль хөлийг юунд холбохыг ойлгох, зүүг тайлбарлах (Зүү Тодорхойлолт). 16 зүү:

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
DC угаалтуурын эх үүсвэр (Нээлттэй ус зайлуулах хоолой)

Угаалтуур / Нээлттэй ус зайлуулах гарц - ус зайлуулах; орж ирж буй гүйдлийн эх үүсвэр; гаралт нь идэвхтэй төлөвт газард холбогдсон - LED нь катодоор драйвертай холбогддог. Цахилгааны хувьд энэ нь мэдээжийн хэрэг "нээлттэй ус зайлуулах суваг" биш юм (нээлттэй ус зайлуулах хоолой), гэхдээ мэдээллийн хуудсанд ус зайлуулах горимд байгаа тээглүүрүүдийн энэ тэмдэглэгээ ихэвчлэн олддог.

Мэдээллийн хуудас 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 драйвер нь үндсэндээ ээлжийн бүртгэл юм. "Шилжилт" (ээлж) нэрээр - төхөөрөмжийн доторх өгөгдлийн битийн хөдөлгөөн: дотор нь түлхэгдсэн шинэ бит бүр нь бүхэл гинжийг урдуур нь түлхэж өгдөг. Ээлжийн үеэр LED эмх замбараагүй анивчихыг хэн ч ажиглахыг хүсдэггүй тул процесс нь ажлын регистрээс дампуураар тусгаарлагдсан буфер регистрүүдэд явагддаг.түгжээ) нь битүүдийг хүссэн дарааллаар нь байрлуулсан хүлээлгийн өрөө юм. Бүх зүйл бэлэн болсны дараа хаалт нээгдэж, битүүд ажилдаа орж, өмнөх багцыг солино. Үг түгжээ бичил схемийн баримт бичигт ямар хослол ашиглаж байгаагаас үл хамааран ийм хаалтыг бараг үргэлж илэрхийлдэг.

Тиймээс, DM634 руу өгөгдөл дамжуулах нь дараах байдлаар явагдана: DAI оролтыг холын LED-ийн хамгийн чухал битийн утгад тохируулж, DCK-ийг дээш доош татах; DAI оролтыг дараагийн битийн утгад тохируулж, DCK-г татах; гэх мэт бүх битийг дамжуулах хүртэл (орж ирсэн), үүний дараа бид LAT-ыг татна. Үүнийг гараар хийж болно (жаахан тэсрэлт), гэхдээ манай STM32 дээр хоёр хувь хэвлэгдсэн байгаа тул тусгайлан тохируулсан SPI интерфейсийг ашиглах нь дээр.

Цэнхэр эм STM32F103

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

Баримт бичиг: Цэнхэр эм нь алдартай STM32F103C8T6 чипээр тоноглогдсон бөгөөд үүнд хоёр хэрэгтэй баримт бичиг бий.

Мэдээллийн хүснэгтэд бид дараахь зүйлийг сонирхож магадгүй юм.

  • Pinouts - чип pinouts - хэрэв бид хавтанг өөрсдөө хийхээр шийдсэн тохиолдолд;
  • Санах ойн газрын зураг - тодорхой чипийн санах ойн зураг. Лавлагааны гарын авлагад бүхэл бүтэн шугамын газрын зураг байгаа бөгөөд манайд байхгүй регистрүүдийг дурдсан байдаг.
  • Зүүний тодорхойлолтуудын хүснэгт – тээглүүрүүдийн үндсэн болон өөр функцуудыг жагсаах; "Цэнхэр эм" -ийн хувьд та тээглүүр, тэдгээрийн функцуудын жагсаалт бүхий Интернетээс илүү тохиромжтой зургуудыг олох боломжтой. Тиймээс бид нэн даруй Google-ээс Blue Pill pinout-ийг хайж, энэ зургийг гартаа байлгана.

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

Бид мэдээллийн хуудсыг устгаж, лавлах гарын авлагыг нээж, одооноос эхлэн зөвхөн үүнийг ашигладаг.
Процедур: бид стандарт оролт/гаралтын асуудлыг шийдэж, SPI-г тохируулж, шаардлагатай дагалдах хэрэгслийг асаана.

Оролт гаралт

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-ийг идэвхжүүлдэг.

Нээлттэй ус зайлуулах хоолойн бүх ялгаа (нээлттэй ус зайлуулах хоолой) "түлхэх"-ээс (түлхэх татах) нь эхний зүү нь ӨНДӨР төлөвийг хүлээн авах боломжгүй юм: гаралтын регистрт нэгийг бичих үед энэ нь өндөр эсэргүүцлийн горимд ордог (өндөр эсэргүүцэл, Сайн байна уу). Тэг бичих үед зүү нь логик болон цахилгааны аль алинд нь хоёуланд нь адилхан ажилладаг.

Ердийн гаралтын горимд зүү нь гаралтын регистрийн агуулгыг шууд дамжуулдаг. "Хувилбар" хэсэгт үүнийг холбогдох захын төхөөрөмжөөр удирддаг (9.1.4-ийг үзнэ үү):

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
Хэрэв портын битийг өөр функцийн зүү болгон тохируулсан бол пин регистрийг идэвхгүй болгож, зүү нь захын зүүтэй холбогдсон байна.

Зүү тус бүрийн өөр функцийг доор тайлбарласан болно Зүү тодорхойлолт Мэдээллийн хуудас нь татаж авсан зураг дээр байна. Хэрэв зүү нь хэд хэдэн өөр функцтэй бол яах вэ гэсэн асуултын хариултыг мэдээллийн хуудасны зүүлт тайлбараар өгсөн болно.

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

Эцэст нь, гаралтын горимд байгаа зүү нь мөн цагийн хурдтай байдаг. Энэ бол эрчим хүч хэмнэх өөр нэг онцлог шинж чанар бөгөөд манай тохиолдолд бид үүнийг хамгийн дээд хэмжээнд нь тохируулаад мартдаг.

Тиймээс: бид SPI ашиглаж байгаа бөгөөд энэ нь хоёр тээглүүр (өгөгдөл болон цагийн дохиотой) "өөр түлхэх татах функц", нөгөө нь (LAT) нь "ердийн түлхэх татах" байх ёстой гэсэн үг юм. Гэхдээ тэднийг томилохоосоо өмнө SPI-тэй харьцъя.

ТХТ

Өөр нэг жижиг боловсролын хөтөлбөр

SPI эсвэл Serial Peripheral Interface (цуваа захын интерфейс) нь MK-г бусад MK-ууд болон ерөнхийдөө гадаад ертөнцтэй холбох энгийн бөгөөд маш үр дүнтэй интерфейс юм. Түүний үйл ажиллагааны зарчмыг дээр дурдсан бөгөөд Хятадын LED драйверын талаар (лавлах гарын авлагад 25-р хэсгийг үзнэ үү). SPI нь мастер ("мастер") болон боол ("боол") горимд ажиллах боломжтой. SPI нь дөрвөн үндсэн сувагтай бөгөөд эдгээрийг бүгдийг нь ашиглаж болохгүй:

  • MOSI, Мастер гаралт / Боол оролт: энэ зүү нь мастер горимд өгөгдлийг дамжуулж, боол горимд өгөгдлийг хүлээн авдаг;
  • MISO, Мастер оролт / Боол гаралт: эсрэгээр нь эзэнд хүлээн авч, боолд дамжуулдаг;
  • SCK, Serial Clock: мастер дахь өгөгдөл дамжуулах давтамжийг тохируулдаг эсвэл боол дахь цагийн дохиог хүлээн авдаг. Үндсэндээ цохилтын цохилт;
  • SS, Slave Select: энэ сувгийн тусламжтайгаар боол түүнээс ямар нэг зүйл хүсч байгааг мэддэг. STM32 дээр үүнийг NSS гэж нэрлэдэг бөгөөд N = сөрөг, өөрөөр хэлбэл. Хэрэв энэ сувагт газар байгаа бол хянагч боол болно. Энэ нь Нээлттэй ус зайлуулах гаралтын горимтой сайн хослуулсан боловч энэ нь өөр түүх юм.

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

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
Энэ горимд програм нь зөвхөн дамжуулах эсвэл зөвхөн хүлээн авах горимд SPI-г ашигладаг. / Зөвхөн дамжуулах горим нь хоёр талт горимтой төстэй: өгөгдөл нь дамжуулах пин дээр дамждаг (MOSI мастер горимд эсвэл MISO нь боол горимд), хүлээн авах пин (MISO эсвэл MOSI тус тус) ердийн оролт гаралтын зүү болгон ашиглаж болно. . Энэ тохиолдолд програм нь зөвхөн Rx буферийг үл тоомсорлох шаардлагатай (хэрэв уншсан бол тэнд дамжуулагдсан өгөгдөл байхгүй болно).

Гайхалтай, MISO зүү үнэгүй, LAT дохиог түүнд холбоно. STM32 дээрх программчлалын дагуу удирдах боломжтой Slave Select-ийг харцгаая, энэ нь маш тохиромжтой. Бид 25.3.1 SPI-ийн ерөнхий тайлбар хэсэгт ижил нэртэй догол мөрийг уншина.

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
Програм хангамжийн хяналтын NSS (SSM = 1) / Slave сонгох мэдээлэл SPI_CR1 регистрийн SSI битэд агуулагддаг. Гадаад NSS зүү нь бусад хэрэглээний хэрэгцээнд үнэ төлбөргүй хэвээр байна.

Бүртгэлд бичих цаг болжээ. Би SPI2-г ашиглахаар шийдсэн бөгөөд түүний үндсэн хаягийг мэдээллийн хуудаснаас хайж олоорой - Санах ойн газрын зургийн 3.3 хэсгээс:

Мэдээллийн хуудас 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-ийн ерөнхий тайлбар) нарийвчлан авч үзье.

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
Цагийн үе ба туйлшрал
SPI_CR1 регистрийн CPOL болон CPHA битүүдийг ашиглан та дөрвөн цаг хугацааны хамаарлыг программчлан сонгож болно. CPOL (цагны туйлшрал) бит нь өгөгдөл дамжуулахгүй байх үед цагийн дохионы төлөвийг хянадаг. Энэ бит нь мастер болон slave горимыг хянадаг. Хэрэв CPOL дахин тохируулагдсан бол амрах горимд SCK зүү бага байна. Хэрэв CPOL бит тохируулагдсан бол амрах горимын үед SCK зүү өндөр байна.
CPHA (цагийн фаз) битийг тохируулах үед өндөр битийн зангууны strobe нь SCK дохионы хоёр дахь ирмэг болно (CPOL тодорхой бол буурч, CPOL тохируулагдсан бол нэмэгддэг). Өгөгдөл нь цагийн дохионы хоёр дахь өөрчлөлтөөр баригддаг. Хэрэв CPHA бит тодорхой бол өндөр битийн трап strobe нь SCK дохионы өсөх ирмэг болно (CPOL тохируулагдсан бол унасан ирмэг, CPOL арилсан бол өсөх ирмэг). Цагийн дохионы эхний өөрчлөлтөд өгөгдөл баригддаг.

Энэхүү мэдлэгийг шингээж авсны дараа бид хоёр бит хоёулаа тэг хэвээр байх ёстой гэсэн дүгнэлтэд хүрсэн Ашиглагдаагүй үед SCK дохио бага хэвээр байх ба импульсийн өсөлтийн ирмэг дээр өгөгдөл дамжуулахыг бид хүсч байна (Зураг XNUMX-ийг үз). Rising Edge DM634 мэдээллийн хуудсанд).

Дашрамд хэлэхэд, бид ST мэдээллийн хуудасны үгсийн сангийн онцлог шинжийг энд анх олж харсан: тэдгээрт "битийг тэг болгох" гэсэн хэллэг бичигдсэн байдаг. бага зэрэг дахин тохируулах, үгүй ​​ээ бага зэрэг цэвэрлэхжишээлбэл, Атмега гэх мэт.

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 буферт байт бичигдсэн үед дамжуулалт эхэлнэ.
Өгөгдлийн байт нь ээлжийн бүртгэлд ачаалагддаг Зэрэгцээ горим (дотоод автобуснаас) эхний битийг дамжуулах явцад, дараа нь дамжуулагдана дараалсан CPI_CR1 регистрийн LSBFIRST битийн тохиргооноос хамааран эхний эсвэл сүүлчийн бит урагшлах MOSI зүү горим. Өгөгдөл дамжуулсны дараа TXE тугийг тохируулна Tx буферээс шилжилтийн бүртгэл рүү, мөн CPI_CR1 регистрийн TXEIE бит тохируулагдсан бол тасалдлыг үүсгэдэг.

STM хянагч дахь SPI хэрэгжилтийн нэг онцлогт анхаарлаа хандуулахын тулд би орчуулгын цөөн хэдэн үгийг онцолсон. Atmega дээр TXE туг (Tx хоосон, Tx хоосон бөгөөд өгөгдөл хүлээн авахад бэлэн байна) зөвхөн байтыг бүхэлд нь илгээсний дараа тохируулна гарч. Энд энэ тугийг дотоод ээлжийн бүртгэлд байт оруулсны дараа тохируулна. Тэнд бүх битүүдийг нэгэн зэрэг (зэрэгцээ) түлхэж, дараа нь өгөгдлийг дараалан шилжүүлдэг тул байтыг бүрэн илгээхээс өмнө TXE-г тохируулна. Энэ нь чухал учир нь Манай LED драйверын хувьд бид илгээсний дараа LAT зүүг татах хэрэгтэй всех өгөгдөл, өөрөөр хэлбэл Зөвхөн TXE туг бидэнд хангалттай биш байх болно.

Энэ нь бидэнд өөр туг хэрэгтэй гэсэн үг. 25.3.7 - "Статус туг"-ыг харцгаая:

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
<…>
Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
ЗАВГҮЙ туг
BSY тугийг техник хангамжаар тохируулж, цэвэрлэдэг (түүн рүү бичих нь ямар ч нөлөө үзүүлэхгүй). BSY туг нь SPI холбооны давхаргын төлөвийг заана.
Энэ нь дахин тохируулагдана:
шилжүүлэг дуусах үед (хэрэв дамжуулалт тасралтгүй байгаа бол мастер горимоос бусад)
SPI идэвхгүй болсон үед
мастер горимын алдаа гарах үед (MODF = 1)
Хэрэв дамжуулалт тасралтгүй явагдахгүй бол өгөгдөл дамжуулах бүрийн хооронд BSY туг арилгадаг

За, энэ хэрэг болно. Tx буфер хаана байгааг олж мэдье. Үүнийг хийхийн тулд "SPI мэдээллийн бүртгэл" -ийг уншина уу:

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
Бит 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
}

LED драйверын гаралтын тооноос хамааран бид 16 дахин хоёр байт дамжуулах шаардлагатай тул дараах байдалтай байна.

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 дээр тээглүүрүүдийн төлөвийг хариуцдаг бүртгэлүүд нь ер бусын байдаг. Тэд Atmega-аас илүү олон байгаа нь ойлгомжтой, гэхдээ тэдгээр нь бусад 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 болгож тохируулж болно. Доод 16 бит нь зөвхөн зүүг дахин тохируулдаг BRR ашиглах. Би хоёр дахь сонголтод дуртай. Эдгээр бүртгэлүүд нь тээглүүрүүдэд атомын хандалтыг хангадаг тул чухал юм.

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

Өгөгдлийн бүртгэлүүд нь маш ойлгомжтой нэртэй байдаг - IDR = Оролт Чиглэлийн бүртгэл, оролтын бүртгэл; ODR = гаралтын Чиглэлийн бүртгэл, гаралтын бүртгэл. Одоогийн төсөлд тэд бидэнд хэрэггүй болно.

Эцэст нь хяналтын бүртгэлүүд. Бид PB13, PB14, PB15 гэх хоёр дахь SPI зүүг сонирхож байгаа тул бид шууд ИТХ-ыг харна.

Мэдээллийн хуудас 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

Манай зүү нь B порт дээр байрладаг (үндсэн хаяг - 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_бага, үргэлж ийм байсан, хэвээрээ л байг)

Одоо бүх зүйл сайхан байна, гэхдээ энэ нь ажиллахгүй байна. Энэ нь STM32 учраас тэд цахилгаан хэмнэдэг бөгөөд энэ нь шаардлагатай нэмэлт төхөөрөмжүүдийн цагийг идэвхжүүлэх шаардлагатай гэсэн үг юм.

Цагийн горимыг асаана уу

Цаг гэж нэрлэгддэг цаг нь цагийг хариуцдаг. Мөн бид RCC товчлолыг аль хэдийн анзаарсан. Бид үүнийг баримт бичигт хайдаг: энэ бол Reset and Clock Control юм.

Дээр дурдсанчлан, аз болоход цагны сэдвийн хамгийн хэцүү хэсгийг STM-ийн хүмүүс хийсэн бөгөөд үүнд бид маш их талархаж байна (би дахин нэг удаа холбоос өгөх болно. Ди Халтын вэбсайт, энэ нь ямар их будлиантай болохыг тодорхой болгохын тулд). Бидэнд зөвхөн захын цагийг идэвхжүүлэх үүрэгтэй регистрүүд хэрэгтэй (Захын цагийг идэвхжүүлэх бүртгэл). Эхлээд RCC-ийн үндсэн хаягийг олъё, энэ нь "Санах ойн газрын зураг" -ын хамгийн эхэнд байна.

Мэдээллийн хуудас 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 порт 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 нь C хэл дээр аймшигтай IDE программчлагдсан ST Visual Develop.

Цаг болон I/O

Анхдагч байдлаар, 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-тай татаж авсан) ашиглах нь илүү хялбар байдаг. Анхны таймерын CH1 ба CH2 зүү нь дөрвөлжин хаалтанд нуугдаж байгааг харуулж байна; STVP-д AFR1 ба AFR0 битүүдийг тохируулах шаардлагатай бөгөөд хоёр дахь нь хоёр дахь таймерын CH1 гаралтыг PD4-ээс PC5 руу шилжүүлэх болно.

Тиймээс 6 зүү нь LED-ийг удирдах болно: эхний таймер нь PC6, PC7 ба PC3, хоёр дахь нь PC5, PD3, PA3.

STM8 дээр I/O зүүг өөрөө тохируулах нь 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 тохиргоо

Эхлээд нэр томъёог тодорхойлъё:

  • ХОУХШ-ийн давтамж – таймер шажигдах давтамж;
  • Автоматаар дахин ачаалах, AR – таймер тоолох хүртэл автоматаар ачаалагдах утга (импульсийн хугацаа);
  • Шинэчлэх үйл явдал, UEV – таймер AR хүртэл тоолох үед тохиолдох үйл явдал;
  • PWM үүргийн мөчлөг – ХОУХШ-ийн үүргийн мөчлөгийг ихэвчлэн “ажлын хүчин зүйл” гэж нэрлэдэг;
  • Утгыг авах/харьцуулах – таймер тоолсон авах/харьцуулах утга ямар нэг зүйл хийх болно (PWM-ийн хувьд энэ нь гаралтын дохиог эргүүлдэг);
  • Урьдчилан ачаалах утга - урьдчилан ачаалагдсан утга. Үнэ цэнийг харьцуулах Цаг хэмжигч ажиллаж байх үед өөрчлөх боломжгүй, эс тэгвээс 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 дараа.

Зарим талаар бид аль хэдийн уншсан ХОУХШ-ний горим, тиймээс бид энэ хэллэгийг лавлах гарын авлагаас хайх замаар хоёр дахь таймерын шаардлагатай бүртгэлийг олдог (18.6.8 - TIMx_CCMR1):

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
110: Эхний PWM горим – доороос дээш тоолох үед TIMx_CNT < TIMx_CCR1 байхад эхний суваг идэвхтэй байна. Үгүй бол эхний суваг идэвхгүй байна. [цаашид баримт бичигт таймер 1-ээс алдаатай хуулж буулгасан байна] 111: Хоёр дахь PWM горим – доороос дээш тоолох үед TIMx_CNT < TIMx_CCR1 байхад эхний суваг идэвхгүй байна. Үгүй бол эхний суваг идэвхтэй байна.

LED нь катодоор MK-тай холбогдсон тул хоёр дахь горим нь бидэнд тохирсон (эхнийх нь ч гэсэн, гэхдээ бид үүнийг хараахан мэдэхгүй).

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
Bit 3 OC1PE: 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;

Үлдсэн зүйл бол дүгнэлт болон хоёр дахь таймерыг өөрөө асаах явдал юм. Эхний асуудлыг регистрээр шийддэг Зураг авах/харьцуулах Бататгах: тэдгээрийн хооронд тэгш бус байдлаар тархсан хоёр, гурван суваг байдаг. Эндээс бид дохионы туйлшралыг өөрчлөх боломжтой гэдгийг мэдэж болно, i.e. зарчмын хувьд 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 бол дохио нь нэг таймерын мөчлөгт урвуу болно). LED-ийн хувьд энэ нь хамаагүй бөгөөд анхааралтай уншигч үүнийг хэрхэн засахаа аль хэдийн таамаглаж чадна.

Хоёр дахь таймер дээрх 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 мультиплексийн үзэл баримтлал дээр суурилдаг бөгөөд хэрэв та LED-ийг маш хурдан асааж унтраавал тэдгээр нь байнга асаалттай байгаа мэт санагдах болно (харааны тууштай байдал, харааны мэдрэмжийн инерци). Би нэг удаа тэгсэн Arduino дээр иймэрхүү зүйл.

Ажлын алгоритм нь дараах байдалтай байна.

  • анхны RGB LED-ийн анодыг холбосон;
  • үүнийг асааж, катод руу шаардлагатай дохиог илгээх;
  • PWM мөчлөгийн төгсгөл хүртэл хүлээсэн;
  • хоёр дахь RGB LED-ийн анодыг холбосон;
  • асаалаа...

За, гэх мэт. Мэдээжийн хэрэг, үзэсгэлэнтэй ажиллахын тулд анодыг холбож, LED-ийг нэгэн зэрэг "гал асаах" шаардлагатай. За, эсвэл бараг л. Ямар ч тохиолдолд бид хоёр дахь таймерын гурван сувагт утгыг гаргах код бичиж, UEV-д хүрэх үед тэдгээрийг өөрчлөх, мөн одоо идэвхтэй RGB LED-ийг өөрчлөх шаардлагатай.

LED сэлгэн залгах нь автомат учраас бид тасалдал зохицуулагч өгөгдөл хүлээн авах "видео санах ой" үүсгэх хэрэгтэй. Энэ бол энгийн массив:

uint8_t colors[8][3];

Тодорхой LED-ийн өнгийг өөрчлөхийн тулд энэ массив руу шаардлагатай утгыг бичихэд хангалттай. Мөн хувьсагч нь идэвхтэй LED-ийн тоог хариуцах болно

uint8_t cnt;

Демукс

Зөв үржүүлэхийн тулд бидэнд CD74HC238 демультиплексер хэрэгтэй. Demultiplexer - техник хангамжид операторыг хэрэгжүүлдэг чип <<. Гурван оролтын зүү (0, 1, 2 битүүд) дамжуулан бид гурван битийн X тоог өгдөг бөгөөд хариуд нь гаралтын дугаарыг идэвхжүүлдэг (1<<X). Чипийн үлдсэн оролтууд нь дизайныг бүхэлд нь масштаблахад ашиглагддаг. Энэ чип нь зөвхөн микроконтроллерийн эзэлдэг тээглүүрүүдийн тоог багасгахаас гадна аюулгүй байдлын үүднээс шаардлагатай бөгөөд ингэснээр аль болох олон LED-ийг санамсаргүйгээр асаахгүй, MK-г шатаахгүй. Чип нь нэг пенни үнэтэй бөгөөд гэрийн эмийн шүүгээнд үргэлж хадгалагдах ёстой.

Манай CD74HC238 нь хүссэн LED-ийн анод руу хүчдэл өгөх үүрэгтэй. Бүрэн хэмжээний мультиплексийн хувьд энэ нь P-MOSFET-ээр дамжуулан баганыг хүчдэлээр хангах боловч энэ үзүүлэн дээр үүнийг шууд хийх боломжтой. дагуу 20 мА татдаг үнэмлэхүй дээд үнэлгээ мэдээллийн хуудсанд. -аас Мэдээллийн хуудас CD74HC238 бидэнд pinouts болон энэ хуурамч хуудас хэрэгтэй:

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
H = өндөр хүчдэлийн түвшин, L = бага хүчдэлийн түвшин, X - хамаагүй

Бид E2 ба E1-ийг газардуулга, E3, A0, A1, A3-ыг STM5-ийн PD3, PC4, PC5, PC8 шонтой холбоно. Дээрх хүснэгтэд бага болон дээд түвшний аль алиныг нь агуулж байгаа тул бид эдгээр зүүг түлхэх зүү болгон тохируулдаг.

PWM

Хоёрдахь таймер дээрх PWM нь өмнөх түүхтэй ижил аргаар тохируулагдсан бөгөөд хоёр ялгаа нь:

Эхлээд бид тасалдлыг идэвхжүүлэх хэрэгтэй Үйл явдлыг шинэчлэх (UEV) нь идэвхтэй LED-ийг сэлгэх функцийг дуудах болно. Энэ нь битийг өөрчлөх замаар хийгддэг Шинэчлэх тасалдлыг идэвхжүүлэх нэр бүхий бүртгэлд

Мэдээллийн хуудас 2 унших: STM32 дээрх SPI; STM8 дээрх PWM, таймер ба тасалдал
Бүртгэлийг идэвхжүүлэх тасалдал

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Хоёр дахь ялгаа нь мультиплексийн үзэгдэлтэй холбоотой, тухайлбал хий үзэгдэл - диодын шимэгч гэрэл. Манай тохиолдолд энэ нь UEV дээр тасалдал үүсгэсэн таймер үргэлжлүүлэн шажигдаж, таймер зүү дээр ямар нэгэн зүйл бичиж эхлэхээс өмнө тасалдал зохицуулагч LED-ийг солих цаг байхгүйгээс болж гарч ирж магадгүй юм. Үүнтэй тэмцэхийн тулд та логикийг эргүүлэх хэрэгтэй (0 = хамгийн их гэрэлтүүлэг, 255 = юу ч асахгүй) ба хэт их ажлын мөчлөгийн утгуудаас зайлсхийх хэрэгтэй. Тэдгээр. UEV-ийн дараа LED нь нэг 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, таймер ба тасалдал

Хэрэв ядаж хэн нэгэн энэ нийтлэлийг хэрэгтэй гэж үзвэл би үүнийг дэмий хоосон бичээгүй болно. Би сэтгэгдэл, тайлбарыг хүлээж авахдаа баяртай байх болно, би бүх зүйлд хариулахыг хичээх болно.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх