Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

В առաջին մասը Ես փորձեցի պատմել հոբբի էլեկտրոնիկայի ինժեներներին, ովքեր մեծացել են Arduino շալվարից, թե ինչպես և ինչու նրանք պետք է կարդան տվյալների թերթիկներ և այլ փաստաթղթեր միկրոկոնտրոլերների համար: Տեքստը մեծ էր, ուստի ես խոստացա գործնական օրինակներ ցույց տալ առանձին հոդվածում։ Դե, նա իրեն անվանել է կաթնային սունկ...

Այսօր ես ձեզ ցույց կտամ, թե ինչպես օգտագործել տվյալների թերթիկները՝ լուծելու համար բավականին պարզ, բայց անհրաժեշտ բազմաթիվ նախագծեր, առաջադրանքներ STM32 (Blue Pill) և STM8 կարգավորիչների վրա: Բոլոր ցուցադրական նախագծերը նվիրված են իմ սիրելի LED-ներին, մենք դրանք կվառենք մեծ քանակությամբ, ինչի համար ստիպված կլինենք օգտագործել բոլոր տեսակի հետաքրքիր ծայրամասային սարքերը:

Տեքստը կրկին հսկայական է, ուստի հարմարության համար ես պատրաստում եմ բովանդակությունը.

STM32 Blue Pill: 16 LED DM634 վարորդով
STM8. վեց PWM կապի կարգավորում
STM8. 8 RGB LED-ներ երեք պինդերի վրա, ընդհատումներ

Հրաժարում. Ես ինժեներ չեմ, չեմ հավակնում ունենալ էլեկտրոնիկայի խորը գիտելիքներ, հոդվածը նախատեսված է ինձ նման սիրողականների համար։ Իրականում ես ինձ երկու տարի առաջ համարում էի որպես թիրախային լսարան։ Եթե ​​այն ժամանակ ինչ-որ մեկն ինձ ասեր, որ անծանոթ չիպի տվյալների թերթիկները կարդալը սարսափելի չէ, ես երկար ժամանակ չէի ծախսի ինտերնետում որոշ կոդի կտորներ փնտրելու և մկրատով և կպչուն ժապավենով հենակներ հորինելու համար:

Այս հոդվածի ուշադրությունը կենտրոնացված է տվյալների թերթիկների վրա, այլ ոչ թե նախագծերի, ուստի ծածկագիրը կարող է շատ կոկիկ և հաճախ նեղ լինել: Նախագծերն իրենք շատ պարզ են, թեև հարմար են նոր չիպի հետ առաջին ծանոթության համար:

Հուսով եմ, որ իմ հոդվածը կօգնի որևէ մեկին, ով գտնվում է հոբբիի մեջ ընկղմվելու նմանատիպ փուլում:

STM32

16 LED DM634 և SPI-ով

Փոքր նախագիծ՝ օգտագործելով Blue Pill (STM32F103C8T6) և DM634 LED դրայվեր: Օգտագործելով տվյալների թերթիկները, մենք կպարզենք վարորդը, STM IO պորտերը և կկարգավորենք SPI-ն:

DM634

Թայվանական չիպը 16 16-բիթանոց PWM ելքերով, կարելի է միացնել շղթաներով: Ցածր 12-բիթանոց մոդելը հայտնի է ներքին նախագծից Lightpack. Ժամանակին, ընտրելով DM63x-ի և հայտնի TLC5940-ի միջև, ես ընտրեցի DM-ն մի քանի պատճառով. 1) DM-ն ունի ինքնավար PWM՝ սեփական հաճախականության գեներատորով. 2) Մոսկվայում այն ​​կարելի էր էժան գնել, այլ ոչ թե Ալիից ծանրոց սպասել: Եվ, իհարկե, հետաքրքիր էր սովորել, թե ինչպես կառավարել չիպը ինքներդ, այլ ոչ թե օգտագործել պատրաստի գրադարան: Չիպերն այժմ հիմնականում ներկայացված են SSOP3 փաթեթում, դրանք հեշտ է զոդել ադապտերին:

Քանի որ արտադրողը թայվանցի է, տվյալների թերթիկ չիպը գրված է չինական անգլերենով, ինչը նշանակում է, որ զվարճալի կլինի: Սկզբում մենք նայում ենք պինաուտին (Փին միացում) հասկանալու համար, թե որ ոտքը ինչին միացնել, և քորոցների նկարագրությունը (Քորոցի նկարագրություն) 16 կապում:

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
DC լվացարանի աղբյուրներ (բաց արտահոսք)

Սուզվել / Բաց արտահոսքի ելք - արտահոսք; ներհոսող հոսանքի աղբյուր; ելքը միացված է գետնին ակտիվ վիճակում - LED-ները միացված են վարորդին կաթոդներով: Էլեկտրական առումով սա, իհարկե, «բաց արտահոսք» չէ (բաց արտահոսք), բայց տվյալների աղյուսակներում հաճախ հայտնաբերվում է արտահոսքի ռեժիմում գտնվող քորոցների այս նշանակումը:

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Արտաքին դիմադրություններ REXT-ի և GND-ի միջև՝ ելքային հոսանքի արժեքը սահմանելու համար

REXT փին և հողի միջև տեղադրված է հղման դիմադրություն, որը վերահսկում է ելքերի ներքին դիմադրությունը, տես աղյուսակի 9-րդ էջի գրաֆիկը: DM634-ում այս դիմադրությունը կարող է վերահսկվել նաև ծրագրաշարի միջոցով՝ սահմանելով ընդհանուր պայծառությունը (գլոբալ պայծառություն); Ես այս հոդվածում մանրամասների մեջ չեմ մտնի, ես պարզապես այստեղ կտեղադրեմ 2.2 - 3 կՕհմ ռեզիստոր:

Հասկանալու համար, թե ինչպես կառավարել չիպը, եկեք նայենք սարքի ինտերֆեյսի նկարագրությանը.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

Այո, ահա, չինական անգլերենն իր ողջ փառքով: Սա թարգմանելը խնդրահարույց է, եթե ցանկանաք, կարող եք դա հասկանալ, բայց կա ևս մեկ միջոց՝ տեսեք, թե ինչպես է նկարագրված ֆունկցիոնալորեն նման TLC5940 կապը տվյալների թերթիկում.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
... Սարքի մեջ տվյալներ մուտքագրելու համար պահանջվում է ընդամենը երեք փին: SCLK ազդանշանի բարձրացող եզրը տվյալները տեղափոխում է SIN փինից դեպի ներքին ռեգիստր: Բոլոր տվյալները բեռնվելուց հետո կարճ բարձր XLAT ազդանշանը փակում է հաջորդաբար փոխանցված տվյալները ներքին ռեգիստրների մեջ: Ներքին ռեգիստրները դարպասներ են, որոնք գործարկվում են XLAT ազդանշանի մակարդակով: Բոլոր տվյալները նախ փոխանցվում են ամենակարևոր բիթը:

Կանգնեցրեք – սողնակ/սողնակ/կողպեք:
Բարձրացող եզր - զարկերակի առաջատար եզրը
MSB նախ – ամենակարևոր (ամենաձախ) բիթը առաջ:
տվյալների ժամացույցի համար - փոխանցել տվյալները հաջորդաբար (փիթ առ բիթ):

Բառ փակվել հաճախ հանդիպում է չիպերի փաստաթղթերում և թարգմանվում է տարբեր ձևերով, ուստի հասկանալու համար ես ինձ թույլ կտամ

փոքր կրթական ծրագիրLED վարորդը, ըստ էության, հերթափոխի ռեգիստր է: «Հերթափոխ» (հերթափոխություն) անվանման մեջ՝ տվյալների բիթային շարժում սարքի ներսում. ներս խցկված յուրաքանչյուր նոր բիթ առաջ է մղում ամբողջ շղթան իր առջև: Քանի որ ոչ ոք չի ցանկանում դիտել LED-ների քաոսային թարթումը հերթափոխի ընթացքում, գործընթացը տեղի է ունենում բուֆերային ռեգիստրներում, որոնք անջատված են աշխատանքային ռեգիստրներից կափույրով (փակվել) սպասասրահի տեսակ է, որտեղ բիթերը դասավորված են ցանկալի հաջորդականությամբ։ Երբ ամեն ինչ պատրաստ է, կափարիչը բացվում է, և բիթերը անցնում են աշխատանքի՝ փոխարինելով նախորդ խմբաքանակը: Խոսք փակվել միկրոսխեմաների փաստաթղթերում գրեթե միշտ ենթադրում է նման կափույր, անկախ նրանից, թե ինչ համակցություններում է այն օգտագործվում:

Այսպիսով, տվյալների փոխանցումը DM634-ին կատարվում է այսպես. DAI մուտքագրումը սահմանեք հեռավոր LED-ի ամենակարևոր բիտի արժեքին, քաշեք DCK-ը վեր ու վար. սահմանեք DAI մուտքագրումը հաջորդ բիտի արժեքին, քաշեք DCK; և այսպես շարունակ, մինչև բոլոր բիթերը փոխանցվեն (ժամացույցով ներս), որից հետո մենք քաշում ենք LAT. Դա կարելի է անել ձեռքով (bit-bang), բայց ավելի լավ է օգտագործել SPI ինտերֆեյս, որը հատուկ հարմարեցված է դրա համար, քանի որ այն ներկայացված է մեր STM32-ում երկու օրինակով:

Կապույտ հաբ STM32F103

Ներածություն. STM32 կարգավորիչները շատ ավելի բարդ են, քան Atmega328-ը, քան նրանք կարող են սարսափելի թվալ: Ավելին, էներգախնայողության նկատառումներից ելնելով, սկզբում անջատված են գրեթե բոլոր ծայրամասային սարքերը, իսկ ժամացույցի հաճախականությունը 8 ՄՀց է ներքին աղբյուրից։ Բարեբախտաբար, STM ծրագրավորողները գրել են կոդ, որը չիպը հասցնում է «հաշվարկված» 72 ՄՀց-ի, և իմ իմացած բոլոր IDE-ների հեղինակները ներառել են այն սկզբնավորման ընթացակարգում, այնպես որ մենք պետք չէ ժամացույց անել (բայց դուք կարող եք, եթե իսկապես ցանկանում եք). Բայց դուք ստիպված կլինեք միացնել ծայրամասային սարքերը:

Փաստաթղթեր. Blue Pill-ը հագեցած է հայտնի STM32F103C8T6 չիպով, դրա համար կան երկու օգտակար փաստաթուղթ.

Տվյալների աղյուսակում մեզ կարող է հետաքրքրել.

  • Pinouts – chip pinouts – եթե մենք որոշենք ինքներս պատրաստել տախտակները;
  • Հիշողության քարտեզ – հիշողության քարտեզ կոնկրետ չիպի համար: Reference Manual-ն ունի քարտեզ ամբողջ տողի համար, և այն նշում է ռեգիստրներ, որոնք մերը չունի:
  • Pin Definitions Աղյուսակ – թվարկում է քորոցների հիմնական և այլընտրանքային գործառույթները; «Կապույտ հաբ»-ի համար ինտերնետում կարող եք գտնել ավելի հարմար նկարներ՝ քորոցների և դրանց գործառույթների ցանկով: Հետևաբար, մենք անմիջապես google-ում ենք Blue Pill pinout-ը և ձեռքի տակ ենք պահում այս նկարը.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Ն.Բ. համացանցից նկարում սխալ կար, որը նշված էր մեկնաբանություններում, շնորհակալություն դրա համար։ Նկարը փոխարինվել է, բայց սա դաս է. ավելի լավ է տեղեկատվությունը ստուգել ոչ տվյալների թերթիկներից:

Մենք հեռացնում ենք տվյալների թերթիկը, բացում ենք Reference Manual-ը և այսուհետ օգտագործում ենք միայն այն:
Ընթացակարգ. մենք գործ ունենք ստանդարտ մուտքի/ելքի հետ, կարգավորում ենք SPI-ն, միացնում ենք անհրաժեշտ ծայրամասային սարքերը:

Մուտքային ելք

Atmega328-ում I/O-ն իրականացվում է չափազանց պարզ, այդ իսկ պատճառով STM32 տարբերակների առատությունը կարող է շփոթեցնել: Այժմ մեզ միայն անհրաժեշտ են եզրակացություններ, բայց նույնիսկ դրանք ունեն չորս տարբերակ.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
բաց արտահոսք, մղել-քաշել, այլընտրանքային մղել-քաշել, այլընտրանքային բաց արտահոսք

«Քաշել-հրել» (հրել-քաշել) սովորական ելքն է Arduino-ից, փին կարող է վերցնել կամ HIGH կամ LOW արժեքը: Բայց «բաց արտահոսքի» դեպքում կան դժվարություններ, չնայած իրականում այստեղ ամեն ինչ պարզ է.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Ելքի կոնֆիգուրացիա / երբ նավահանգիստը նշանակված է ելքին. / ելքային բուֆերը միացված է. / – բաց արտահոսքի ռեժիմ. «0»-ը ելքային ռեգիստրում միացնում է N-MOS-ը, «1»-ը ելքային ռեգիստրում թողնում է նավահանգիստը Hi-Z ռեժիմում ( P-MOS-ը միացված չէ ) / – push-pull ռեժիմ. «0»-ը ելքային ռեգիստրում ակտիվացնում է N-MOS-ը, «1»-ը ելքային ռեգիստրում ակտիվացնում է P-MOS-ը:

Բոլոր տարբերությունները բաց արտահոսքի միջև (բաց արտահոսք) «հրել-քաշել» -ից (հրել-քաշել) այն է, որ առաջին փինում չի կարող ընդունել HIGH վիճակը. ելքային ռեգիստրում մեկը գրելիս այն անցնում է բարձր դիմադրության ռեժիմի (բարձր Impedance, Hi-Z). Զրո գրելիս քորոցը նույնն է պահում երկու ռեժիմներում՝ և՛ տրամաբանական, և՛ էլեկտրական:

Նորմալ ելքային ռեժիմում փին պարզապես հեռարձակում է ելքային ռեգիստրի բովանդակությունը: «Այլընտրանքում» այն վերահսկվում է համապատասխան ծայրամասային սարքերով (տես 9.1.4).

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Եթե ​​պորտի բիթը կազմաձևված է որպես այլընտրանքային ֆունկցիայի փին, ապա փին ռեգիստրն անջատված է, և փին միացված է ծայրամասային փինին:

Յուրաքանչյուր քորոցի այլընտրանքային ֆունկցիոնալությունը նկարագրված է Քորոցային սահմանումներ Տվյալների թերթիկը ներբեռնված պատկերի վրա է: Հարցին, թե ինչ անել, եթե քորոցն ունի մի քանի այլընտրանքային գործառույթ, պատասխանը տրված է տվյալների թերթիկի տողատակով.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Եթե ​​մի քանի ծայրամասային սարքեր օգտագործում են նույն փին, այլընտրանքային գործառույթների միջև կոնֆլիկտից խուսափելու համար, պետք է միաժամանակ օգտագործվի միայն մեկ ծայրամասային սարք՝ միացնելով ծայրամասային ժամացույցի միացման բիթը (համապատասխան RCC ռեգիստրում):

Վերջապես, ելքային ռեժիմում գտնվող կապումներն ունեն նաև ժամացույցի արագություն: Սա ևս մեկ էներգախնայողության հատկություն է, մեր դեպքում մենք այն դնում ենք առավելագույնի և մոռանում ենք:

Այսպիսով, մենք օգտագործում ենք SPI, ինչը նշանակում է, որ երկու պին (տվյալներով և ժամացույցի ազդանշանով) պետք է լինեն «այլընտրանքային push-pull ֆունկցիա», իսկ մյուսը (LAT) պետք է լինի «կանոնավոր push-pull»: Բայց մինչ դրանք հանձնարարելը, եկեք զբաղվենք SPI-ով։

SPI

Եվս մեկ փոքրիկ կրթական ծրագիր

SPI կամ Serial Peripheral Interface (սերիական ծայրամասային ինտերֆեյս) պարզ և շատ արդյունավետ ինտերֆեյս է MK-ն այլ MK-ների և ընդհանրապես արտաքին աշխարհի հետ կապելու համար: Դրա գործողության սկզբունքը արդեն նկարագրված է վերևում, որտեղ չինական LED վարորդի մասին է (տեղեկատու ձեռնարկում, տես բաժին 25): SPI-ն կարող է գործել հիմնական («վարպետ») և ստրուկ («ստրուկ») ռեժիմներում: SPI-ն ունի չորս հիմնական ալիք, որոնցից ոչ բոլորը կարող են օգտագործվել.

  • MOSI, Master Output / Slave Input. այս փին փոխանցում է տվյալները հիմնական ռեժիմում և տվյալներ ստանում ստրուկ ռեժիմում;
  • MISO, Master Input / Slave Output. ընդհակառակը, այն ստանում է վարպետի մեջ և փոխանցում է ստրուկի մեջ;
  • SCK, Serial Clock. սահմանում է տվյալների փոխանցման հաճախականությունը հիմնականում կամ ստանում է ժամացույցի ազդանշան ստրուկում: Ըստ էության հարվածում է ծեծում;
  • SS, Slave Select. այս ալիքի օգնությամբ ստրուկը գիտի, որ իրենից ինչ-որ բան են ուզում։ STM32-ում այն ​​կոչվում է NSS, որտեղ N = բացասական, այսինքն. վերահսկիչը դառնում է ստրուկ, եթե այս ալիքում հիմք կա: Այն լավ համակցվում է Open Drain Output ռեժիմի հետ, բայց դա այլ պատմություն է:

Ինչպես մնացած ամեն ինչ, SPI-ն էլ STM32-ում հարուստ է ֆունկցիոնալությամբ, ինչը որոշ չափով դժվարացնում է այն հասկանալը: Օրինակ, այն կարող է աշխատել ոչ միայն SPI-ի, այլև I2S ինտերֆեյսի հետ, իսկ փաստաթղթերում դրանց նկարագրությունները խառնված են, անհրաժեշտ է ժամանակին կտրել ավելցուկը։ Մեր խնդիրը չափազանց պարզ է. մենք պարզապես պետք է տվյալներ ուղարկենք՝ օգտագործելով միայն MOSI և SCK: Մենք գնում ենք 25.3.4 բաժին (կիս-դուպլեքս հաղորդակցություն, կիսա-դուպլեքս հաղորդակցություն), որտեղ գտնում ենք. 1 ժամացույց և 1 միակողմանի տվյալների լար (1 ժամացույցի ազդանշան և 1 միակողմանի տվյալների հոսք).

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Այս ռեժիմում հավելվածն օգտագործում է SPI միայն փոխանցման կամ միայն ստացման ռեժիմում: / Միայն փոխանցման ռեժիմը նման է դուպլեքս ռեժիմին. տվյալները փոխանցվում են փոխանցման փինով (MOSI հիմնական ռեժիմում կամ MISO՝ ստրուկ ռեժիմում), իսկ ստացող փին (համապատասխանաբար MISO կամ MOSI) կարող է օգտագործվել որպես սովորական I/O փին: . Այս դեպքում հավելվածը միայն պետք է անտեսի Rx բուֆերը (եթե այն կարդացվի, այնտեղ փոխանցված տվյալներ չեն լինի):

Հիանալի է, MISO փին անվճար է, եկեք միացնենք LAT ազդանշանը դրան: Եկեք նայենք Slave Select-ին, որը STM32-ի վրա կարելի է ծրագրավորել, ինչը չափազանց հարմար է։ Մենք կարդում ենք նույնանուն պարբերությունը 25.3.1 բաժնում SPI Ընդհանուր նկարագրություն.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Ծրագրային կառավարման NSS (SSM = 1) / ստրուկների ընտրության տեղեկատվությունը պարունակվում է SPI_CR1 ռեգիստրի SSI բիթում: Արտաքին NSS փին մնում է անվճար հավելվածի այլ կարիքների համար:

Ժամանակն է գրել գրանցամատյաններին։ Ես որոշեցի օգտագործել SPI2, փնտրել դրա բազային հասցեն տվյալների թերթիկում՝ 3.3 բաժնում Հիշողության քարտեզ.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

Դե, եկեք սկսենք.

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

Բացեք 25.3.3 բաժինը «SPI-ի կազմաձևումը հիմնական ռեժիմում» ինքնաբացատրվող վերնագրով.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

1. Սահմանեք սերիական ժամացույցի հաճախականությունը BR[2:0] բիթերով SPI_CR1 ռեգիստրում:

Գրանցամատյանները հավաքվում են տեղեկատու ձեռնարկի համանուն բաժնում: Հասցեի հերթափոխ (Հասցեի օֆսեթ) CR1 – 0x00-ի համար, լռելյայնորեն բոլոր բիթերը մաքրված են (Վերականգնել արժեքը 0x0000):

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

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):

Քանի որ մենք այստեղ կարդում ենք տվյալների աղյուսակը և չենք նայում սխեմաներին, եկեք ավելի սերտ նայենք CPOL և CPHA բիթերի տեքստի նկարագրությանը 704-րդ էջում (SPI Ընդհանուր նկարագրություն).

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Ժամացույցի փուլ և բևեռականություն
Օգտագործելով SPI_CR1 ռեգիստրի CPOL և CPHA բիթերը, դուք կարող եք ծրագրային կերպով ընտրել ժամանակային չորս հարաբերություններ: CPOL (ժամացույցի բևեռականություն) բիթը վերահսկում է ժամացույցի ազդանշանի վիճակը, երբ տվյալներ չեն փոխանցվում: Այս բիթը վերահսկում է հիմնական և ստրուկ ռեժիմները: Եթե ​​CPOL-ը զրոյացված է, SCK փին հանգստի ռեժիմում ցածր է: Եթե ​​CPOL բիթը սահմանված է, SCK փին բարձր է հանգստի ռեժիմում:
Երբ CPHA (ժամացույցի փուլ) բիթը միացված է, բարձր բիթային թակարդը SCK ազդանշանի երկրորդ եզրն է (ընկնում է, եթե CPOL-ը պարզ է, բարձրանում է, եթե CPOL սահմանված է): Տվյալները հավաքվում են ժամացույցի ազդանշանի երկրորդ փոփոխությամբ: Եթե ​​CPHA բիթը պարզ է, ապա բարձր բիթային թակարդը SCK ազդանշանի բարձրացող եզրն է (ընկնող եզրը, եթե CPOL-ը սահմանված է, բարձրացող ծայրը, եթե CPOL-ը մաքրված է): Տվյալները հավաքվում են ժամացույցի ազդանշանի առաջին փոփոխության ժամանակ:

Կլանելով այս գիտելիքը՝ մենք գալիս ենք այն եզրակացության, որ երկու բիթերն էլ պետք է մնան զրո, քանի որ Մենք ցանկանում ենք, որ SCK ազդանշանը ցածր մնա, երբ այն չի օգտագործվում, և տվյալները փոխանցվեն իմպուլսի բարձրացող եզրին (տես Նկ. Rising Edge DM634 տվյալների թերթիկում):

Ի դեպ, այստեղ մենք առաջին անգամ հանդիպեցինք ST տվյալների թերթիկների բառապաշարի մի առանձնահատկություն. դրանցում գրված է «զրոյացնել բիթը» արտահայտությունը. մի քիչ զրոյացնելԵւ ոչ մի քիչ մաքրելու համար, ինչպես, օրինակ, Atmega-ն:

3. Սահմանեք DFF բիթը՝ որոշելու, թե տվյալների բլոկը 8-բիթանոց է, թե 16-բիթանոց:

Ես հատուկ վերցրեցի 16-բիթանոց DM634, որպեսզի չանհանգստանամ 12-բիթանոց PWM տվյալների փոխանցման հետ, ինչպես DM633-ը: Իմաստ ունի DFF-ը դնել մեկին.

#define DFF         0x0800

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

4. Կազմաձևեք LSBFIRST բիթը SPI_CR1 ռեգիստրում՝ բլոկի ձևաչափը որոշելու համար

LSBFIRST-ը, ինչպես ցույց է տալիս նրա անունը, առաջինը կարգավորում է փոխանցումը ամենաքիչ կարևոր բիթով: Բայց DM634-ը ցանկանում է ստանալ տվյալներ՝ սկսած ամենակարևոր բիթից: Հետևաբար, մենք թողնում ենք այն զրոյացնել:

5. Սարքավորման ռեժիմում, եթե անհրաժեշտ է մուտքագրում NSS փինից, կիրառեք բարձր ազդանշան NSS փին բայթերի փոխանցման ողջ հաջորդականության ընթացքում: NSS ծրագրային ռեժիմում սահմանեք SSM և SSI բիթերը SPI_CR1 ռեգիստրում: Եթե ​​NSS փին պետք է օգտագործվի որպես ելք, ապա պետք է սահմանել միայն SSOE բիթը:

Տեղադրեք SSM և SSI՝ մոռանալու NSS ապարատային ռեժիմի մասին.

#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. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Տվյալների փոխանցման կարգը
Փոխանցումը սկսվում է, երբ բայթը գրվում է Tx բուֆերում:
Տվյալների բայթը բեռնվում է հերթափոխի ռեգիստրում ժամը զուգահեռ ռեժիմ (ներքին ավտոբուսից) առաջին բիթի փոխանցման ժամանակ, որից հետո այն փոխանցվում է հաջորդական MOSI փին ռեժիմ, առաջին կամ վերջին բիթ առաջ՝ կախված CPI_CR1 ռեգիստրում LSBFIRST բիթից: TXE դրոշը սահմանվում է տվյալների փոխանցումից հետո Tx բուֆերից դեպի հերթափոխ ռեգիստր, և նաև առաջացնում է ընդհատում, եթե CPI_CR1 ռեգիստրում TXEIE բիթը սահմանված է:

Թարգմանության մեջ ես ընդգծեցի մի քանի բառ, որպեսզի ուշադրություն հրավիրեմ STM կարգավորիչներում SPI-ի ներդրման մեկ հատկանիշի վրա: Atmega-ում TXE դրոշը (Tx Դատարկ, Tx-ը դատարկ է և պատրաստ է տվյալներ ստանալու համար) սահմանվում է միայն ամբողջ բայթն ուղարկելուց հետո արտաքին. Եվ այստեղ այս դրոշը դրվում է բայթը ներքին հերթափոխի ռեգիստրում տեղադրվելուց հետո: Քանի որ այն հրվում է այնտեղ բոլոր բիթերով միաժամանակ (զուգահեռաբար), և այնուհետև տվյալները փոխանցվում են հաջորդաբար, TXE-ն դրվում է մինչև բայթն ամբողջությամբ ուղարկելը: Սա կարևոր է, քանի որ մեր LED դրայվերի դեպքում, ուղարկելուց հետո մենք պետք է քաշենք LAT փին Ամբողջ տվյալներ, այսինքն. Միայն TXE դրոշը մեզ չի բավականացնի։

Սա նշանակում է, որ մեզ ևս մեկ դրոշ է պետք։ Եկեք նայենք 25.3.7 - «Կարգավիճակի դրոշներ».

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
<...>
Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Զբաղված դրոշ
BSY դրոշը տեղադրվում և մաքրվում է սարքաշարի միջոցով (դրա գրելը որևէ ազդեցություն չունի): BSY դրոշը ցույց է տալիս SPI կապի շերտի վիճակը:
Այն վերակայում է.
երբ փոխանցումն ավարտված է (բացառությամբ հիմնական ռեժիմի, եթե փոխանցումը շարունակական է)
երբ SPI-ն անջատված է
երբ հիմնական ռեժիմի սխալ է տեղի ունենում (MODF=1)
Եթե ​​փոխանցումը շարունակական չէ, BSY դրոշը մաքրվում է յուրաքանչյուր տվյալների փոխանցման միջև

Լավ, սա օգտակար կլինի: Եկեք պարզենք, թե որտեղ է գտնվում Tx բուֆերը: Դա անելու համար կարդացեք «SPI տվյալների գրանցամատյան».

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Bits 15:0 DR[15:0] Տվյալների գրանցում
Ստացված տվյալներ կամ փոխանցվող տվյալներ:
Տվյալների ռեգիստրը բաժանված է երկու բուֆերի՝ մեկը գրելու համար (փոխանցման բուֆեր) և մեկը՝ կարդալու (ստանալու բուֆեր): Տվյալների ռեգիստրում գրելը գրում է Tx բուֆերին, իսկ տվյալների ռեգիստրից կարդալը կվերադարձնի Rx բուֆերում պարունակվող արժեքը:

Դե, և կարգավիճակի ռեգիստրը, որտեղ գտնվում են TXE և BSY դրոշները.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

Մենք գրում ենք:

#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-ում քորոցների վիճակի համար պատասխանատու ռեգիստրները բավականին անսովոր են: Հասկանալի է, որ դրանք ավելի շատ են, քան Atmega-ն, բայց դրանք տարբերվում են նաև մյուս STM չիպերից։ Բաժին 9.1 GPIO-ի ընդհանուր նկարագրությունը.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Ընդհանուր նշանակության I/O պորտերից յուրաքանչյուրը (GPIO) ունի երկու 32-բիթանոց կազմաձևման ռեգիստր (GPIOx_CRL և GPIOx_CRH), երկու 32-բիթանոց տվյալների ռեգիստր (GPIOx_IDR և GPIOx_ODR), 32-բիթանոց կարգավորող/վերակայման ռեգիստր (GPIOx_BSRR), 16-բիթանոց վերակայման ռեգիստր (GPIOx_BRR) և բիթերի արգելափակման ռեգիստր (GPIOx_LCKR):

Առաջին երկու գրանցամատյանները անսովոր են, և նաև բավականին անհարմար, քանի որ 16 պորտի փիները ցրված են դրանց վրա «չորս բիթ մեկ եղբորը» ձևաչափով: Նրանք. Զրո-յոթ կապում են CRL-ում, իսկ մնացածը՝ CRH-ում: Միևնույն ժամանակ, մնացած գրանցամատյանները հաջողությամբ պարունակում են նավահանգստի բոլոր քորոցների բիթերը, որոնք հաճախ մնում են կիսով չափ «պահեստավորված»:

Պարզության համար սկսենք ցուցակի վերջից։

Մեզ արգելափակող ռեգիստր պետք չէ։

Սահմանել և վերակայել ռեգիստրները բավականին զվարճալի են նրանով, որ դրանք մասամբ կրկնօրինակում են միմյանց. ամեն ինչ կարող եք գրել միայն BSRR-ում, որտեղ ավելի բարձր 16 բիթները կզրոյացնեն փին, իսկ ստորինները կդրվեն 1-ի, կամ կարող եք նաև. օգտագործեք BRR, որի ստորին 16 բիթերը վերակայում են միայն քորոցը: Ինձ դուր է գալիս երկրորդ տարբերակը. Այս ռեգիստրները կարևոր են, քանի որ դրանք ապահովում են ատոմային մուտք դեպի կապում.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Ատոմային կարգավորում կամ վերակայում
Կարիք չկա անջատել ընդհատումները GPIOx_ODR-ը բիթային մակարդակում ծրագրավորելիս. մեկ կամ մի քանի բիթ կարելի է փոխել մեկ ատոմային գրելու գործողությամբ APB2: Սա ձեռք է բերվում՝ գրելով «1» կարգավորվող/վերակայման ռեգիստրում (GPIOx_BSRR կամ միայն վերակայման համար՝ GPIOx_BRR), որը պետք է փոխվի: Մնացած բիթերը կմնան անփոփոխ:

Տվյալների ռեգիստրներն ունեն բավականին ինքնըստինքյան անուններ՝ IDR = Մուտքային Ուղղության ռեգիստր, մուտքագրման ռեգիստր; ODR = Արտադրողականություն Ուղղության ռեգիստր, ելքային ռեգիստր։ Ներկայիս նախագծում դրանք մեզ պետք չեն լինի:

Եվ վերջապես հսկիչ ռեգիստրներ։ Քանի որ մենք հետաքրքրված ենք երկրորդ SPI կապումներով, մասնավորապես PB13, PB14 և PB15, մենք անմիջապես նայում ենք CRH-ին.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

Եվ մենք տեսնում ենք, որ մեզ անհրաժեշտ կլինի ինչ-որ բան գրել 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;

Եվ, համապատասխանաբար, կարող եք սահմանումներ գրել LAT-ի համար, որոնք կկտրվեն BRR և BSRR ռեգիստրներով.

/*** 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-ի մարդիկ, ինչի համար մենք շատ շնորհակալ ենք նրանց (ևս մեկ անգամ հղում կտամ. Դի Հալտի կայքը, հասկանալու համար, թե որքան շփոթեցնող է): Մեզ անհրաժեշտ են միայն ռեգիստրներ, որոնք պատասխանատու են ծայրամասային ժամացույցը միացնելու համար (Peripheral Clock Enable Registers): Նախ, եկեք գտնենք RCC-ի բազային հասցեն, այն գտնվում է «Հիշողության քարտեզի» հենց սկզբում.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

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

Եվ այնուհետև կամ կտտացրեք այն հղմանը, որտեղ դուք փորձում եք ինչ-որ բան գտնել ափսեի մեջ, կամ, շատ ավելի լավ, անցեք թույլատրող ռեգիստրների նկարագրությունները բաժիններից: միացնել գրանցամատյանները. Որտեղ մենք կգտնենք RCC_APB1ENR և RCC_APB2ENR.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

Եվ դրանք, համապատասխանաբար, պարունակում են բիթեր, որոնք ներառում են 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. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

STM8 PWM

PWM STM8-ում

Երբ ես նոր էի պլանավորում այս հոդվածը, ես որոշեցի, որպես օրինակ, փորձել տիրապետել անծանոթ չիպի որոշ ֆունկցիոնալությանը, օգտագործելով միայն տվյալների աղյուսակը, որպեսզի չհայտնվեմ կոշկակարի հետ առանց կոշիկների: STM8-ը իդեալական էր այս դերի համար. նախ՝ ես մի քանի չինական տախտակ ունեի STM8S103-ով, և երկրորդ՝ այն այնքան էլ տարածված չէ, և հետևաբար ինտերնետում կարդալու և լուծում գտնելու գայթակղությունը հիմնված է հենց այս լուծումների բացակայության վրա:

Չիպն ունի նաև տվյալների թերթիկ и տեղեկատու ձեռնարկ RM0016, առաջինում կան pinout և ռեգիստրի հասցեներ, երկրորդում՝ մնացած ամեն ինչ։ STM8-ը ծրագրավորված է C-ով սարսափելի IDE-ով ST Visual Develop.

Clocking և I/O

Լռելյայնորեն, STM8-ը գործում է 2 ՄՀց հաճախականությամբ, այն պետք է անմիջապես շտկվի:

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
HSI (բարձր արագությամբ ներքին) ժամացույց
HSI ժամացույցի ազդանշանը ստացվում է ներքին 16 ՄՀց հաճախականությամբ RC տատանվողից՝ ծրագրավորվող բաժանիչով (1-ից 8): Այն սահմանված է ժամացույցի բաժանարար ռեգիստրում (CLK_CKDIVR):
Ծանոթագրություն. սկզբում որպես ժամացույցի ազդանշանի առաջատար աղբյուր ընտրվում է HSI RC օսլիլատորը՝ 8 բաժանարարով:

Մենք գտնում ենք ռեգիստրի հասցեն տվյալների թերթիկում, նկարագրությունը refman-ում և տեսնում ենք, որ ռեգիստրը պետք է մաքրվի.

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Քանի որ մենք պատրաստվում ենք գործարկել PWM-ը և միացնել LED-ները, եկեք նայենք պինութին.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

Չիպը փոքր է, շատ գործառույթներ կասեցված են նույն կապում: Քառակուսի փակագծերում գտնվողը «այլընտրանքային ֆունկցիոնալություն» է, այն փոխարկվում է «օպցիոն բայթերով» (տարբերակ բայթեր) – 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 կարգավորում

Նախ, եկեք սահմանենք տերմինները.

  • PWM հաճախականություն - հաճախականությունը, որով ժմչփը նշում է.
  • Ավտոմատ վերբեռնում, AR – ավտոմատ բեռնվող արժեք, որի չափը կհաշվի ժամանակաչափը (զարկերակային շրջան);
  • Թարմացնել իրադարձությունը, UEV – իրադարձություն, որը տեղի է ունենում, երբ ժամանակաչափը հաշվել է մինչև AR;
  • PWM Duty Cycle – PWM աշխատանքային ցիկլը, որը հաճախ կոչվում է «հերթական գործոն».
  • Գրավել/համեմատել արժեքը – ֆիքսման/համեմատության արժեք, որին հաշվել է ժամանակաչափը ինչ-որ բան կանի (PWM-ի դեպքում այն ​​հակադարձում է ելքային ազդանշանը);
  • Նախաբեռնման արժեքը - նախապես բեռնված արժեք: Համեմատեք արժեքը չի կարող փոխվել, մինչ ժմչփը նշում է, հակառակ դեպքում PWM ցիկլը կխախտվի: Հետևաբար, փոխանցվող նոր արժեքները տեղադրվում են բուֆերի մեջ և դուրս են քաշվում, երբ ժմչփը հասնում է իր հետհաշվարկի ավարտին և վերականգնվում է.
  • Եզրին հավասարեցված и Կենտրոնական հավասարեցված ռեժիմներ - հավասարեցում սահմանի երկայնքով և կենտրոնում, նույնը, ինչ Atmel-ը Արագ PWM и Փուլային ճիշտ PWM.
  • OCiREF, Արդյունք Համեմատել Հղման ազդանշան – հղումային ելքային ազդանշան, փաստորեն, այն, ինչ հայտնվում է PWM ռեժիմում համապատասխան փինում:

Ինչպես արդեն պարզ է պինութից, երկու ժամանակաչափ ունեն PWM հնարավորություններ՝ առաջինը և երկրորդը: Երկուսն էլ 16-բիթանոց են, առաջինն ունի բազմաթիվ լրացուցիչ հնարավորություններ (մասնավորապես, այն կարող է հաշվել և՛ վերև, և՛ ներքև)։ Մեզ երկուսն էլ պետք է հավասարապես աշխատեն, ուստի ես որոշեցի սկսել ակնհայտորեն ավելի աղքատ երկրորդից, որպեսզի պատահաբար չօգտագործեմ մի բան, որը չկա: Որոշ խնդիր այն է, որ տեղեկատու ձեռնարկի բոլոր ժամանակաչափերի PWM ֆունկցիոնալության նկարագրությունը առաջին ժմչփի մասին գլխում է (17.5.7 PWM ռեժիմ), այնպես որ դուք պետք է անընդհատ ետ ու առաջ ցատկեք ամբողջ փաստաթղթում:

PWM-ը STM8-ում ունի կարևոր առավելություն Atmega-ի PWM-ի նկատմամբ.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Սահմանային հավասարեցված 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. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
110. Առաջին PWM ռեժիմ – ներքևից վերև հաշվելիս առաջին ալիքն ակտիվ է, մինչդեռ TIMx_CNT < TIMx_CCR1: Հակառակ դեպքում առաջին ալիքն անգործուն է։ [Այնուհետև փաստաթղթում կա սխալ copy-paste ժմչփ 1-ից] 111. Երկրորդ PWM ռեժիմ – ներքևից վերև հաշվելիս առաջին ալիքը ակտիվ չէ, մինչդեռ TIMx_CNT < TIMx_CCR1: Հակառակ դեպքում առաջին ալիքն ակտիվ է։

Քանի որ LED-ները MK-ին միացված են կաթոդներով, երկրորդ ռեժիմը մեզ հարմար է (առաջինը նույնպես, բայց մենք դա դեռ չգիտենք):

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Բիթ 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;

Մնում է միայն միացնել եզրակացությունները և երկրորդ ժմչփը: Առաջին խնդիրը լուծվում է ռեգիստրների միջոցով Նկարել/Համեմատել Թույլատրելկան երկու, երեք ալիքներ, որոնք ցրված են դրանց վրա ասիմետրիկորեն: Այստեղ մենք կարող ենք նաև սովորել, որ հնարավոր է փոխել ազդանշանի բևեռականությունը, այսինքն. սկզբունքորեն հնարավոր էր օգտագործել PWM Mode 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. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Եկեք գրենք AnalogWrite(-ի պարզ անալոգը), որը համեմատության համար իրական արժեքները կփոխանցի ժամանակաչափին: Գրանցամատյանները կոչվում են կանխատեսելի Գրանցել / Համեմատել գրանցամատյանները, յուրաքանչյուր ալիքի համար դրանք երկուսն են՝ ցածր կարգի 8 բիթները TIM2_CCRxL-ում և բարձրակարգը՝ 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;
}

Ուշադիր ընթերցողը կնկատի, որ մենք ունենք մի փոքր թերի PWM, որը չի կարողանում արտադրել 100% լիցք (առավելագույնը 255 արժեքի դեպքում ազդանշանը շրջվում է մեկ ժամանակաչափի ցիկլի համար): LED-ների համար դա նշանակություն չունի, և ուշադիր ընթերցողն արդեն կարող է կռահել, թե ինչպես դա շտկել:

Երկրորդ ժմչփի վրա PWM-ն աշխատում է, անցնենք առաջինին:

Առաջին ժմչփն ունի նույն բիթերը նույն ռեգիստրներում (ուղղակի այն բիթերը, որոնք մնացել են «պահեստավորված» երկրորդ ժամանակաչափում, առաջինում ակտիվորեն օգտագործվում են բոլոր տեսակի առաջադեմ բաների համար): Ուստի բավական է տվյալների թերթիկում գտնել նույն ռեգիստրների հասցեները և պատճենել կոդը։ Դե, փոխեք հաճախականության բաժանարարի արժեքը, քանի որ... առաջին ժմչփը ցանկանում է ստանալ ոչ թե երկու ռեգիստրի հզորություն, այլ ճշգրիտ 16 բիթանոց արժեք Prescaler High и Ցածր. Մենք ամեն ինչ անում ենք ու... առաջին ժմչփը չի աշխատում։ Ինչ է պատահել?

Խնդիրը կարող է լուծվել միայն՝ նայելով ժմչփ 1-ի կառավարման ռեգիստրների մասին ամբողջ բաժինը, որտեղ մենք փնտրում ենք այն, որը չունի երկրորդ ժմչփը: Կլինի 17.7.30 Ընդմիջման գրանցամատյան (TIM1_BKR), որտեղ կա այս բիթը.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Միացնել հիմնական ելքը

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

Այսքանը հիմա հաստատ է, կոդը առանձին.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

STM8 Multiplex

Multiplexing STM8-ում

Երրորդ մինի-նախագիծը ութ RGB LED-ներ միացնելն է երկրորդ ժմչփին PWM ռեժիմում և ստիպել դրանք տարբեր գույներ ցուցադրել: Այն հիմնված է LED մուլտիպլեքսավորման հայեցակարգի վրա, որն այն է, որ եթե դուք շատ, շատ արագ միացնեք և անջատեք LED-ները, մեզ կթվա, որ դրանք անընդհատ միացված են (տեսողության համառություն, տեսողական ընկալման իներցիա): Ես մի անգամ արել եմ նման բան Arduino-ում.

Աշխատանքային ալգորիթմն ունի հետևյալ տեսքը.

  • միացրեց առաջին RGB LED- ի անոդը;
  • վառեց այն՝ ուղարկելով անհրաժեշտ ազդանշանները կաթոդներին;
  • սպասեց մինչև PWM ցիկլի ավարտը.
  • միացրեց երկրորդ RGB LED- ի անոդը;
  • վառեց այն...

Դե և այլն: Իհարկե, գեղեցիկ շահագործման համար անհրաժեշտ է, որ անոդը միացված լինի և LED-ը միաժամանակ «բռնկվի»: Դե, կամ գրեթե: Ամեն դեպքում, մենք պետք է գրենք կոդ, որը արժեքներ կարտադրի երկրորդ ժմչփի երեք ալիքներում, կփոխի դրանք UEV-ին հասնելու դեպքում և միևնույն ժամանակ կփոխի ներկայումս ակտիվ RGB 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 մեզ անհրաժեշտ են մատիտներ և այս խաբեության թերթիկը.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
H = բարձր լարման մակարդակ, L = ցածր լարման մակարդակ, X – հոգ չէ

Մենք E2 և E1-ը միացնում ենք գետնին, E3, A0, A1 և A3-ը՝ STM5-ի PD3, PC4, PC5 և PC8 կապանքներին: Քանի որ վերը նշված աղյուսակը պարունակում է և՛ ցածր, և՛ բարձր մակարդակներ, մենք կարգավորել ենք այս կապանքները որպես հրում-քաշման կապում:

PWM

Երկրորդ ժմչփի վրա PWM-ը կազմաձևված է նույն կերպ, ինչպես նախորդ պատմության մեջ, երկու տարբերությամբ.

Նախ, մենք պետք է միացնենք ընդհատումը Թարմացնել Իրադարձությունը (UEV), որը կկանչի մի ֆունկցիա, որն անջատում է ակտիվ լուսադիոդը: Դա արվում է բիթը փոխելով Թարմացնել ընդհատումը Միացնել ռեգիստրում խոսուն անունով

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
Ընդհատել միացնել ռեգիստրը

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Երկրորդ տարբերությունը կապված է մուլտիպլեքսավորման երեւույթի հետ, ինչպես, օրինակ ուրվական - դիոդների մակաբուծական փայլ: Մեր դեպքում դա կարող է հայտնվել այն պատճառով, որ ժմչփը, որը 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. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում
13 TIM2 թարմացում/հորդացում
14 TIM2 գրավում/համեմատում

Մենք պետք է փոխենք LED-ը UEV-ում, ուստի մեզ անհրաժեշտ է ընդհատում #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;
}

Մնում է միայն միացնել ընդհատումները: Դա արվում է assembler հրամանի միջոցով rim - դուք պետք է փնտրեք այն Mingրագրավորման ձեռնարկ:

//enable interrupts
_asm("rim");

Ասեմբլերի մեկ այլ հրաման է sim - անջատում է ընդհատումները: Նրանք պետք է անջատվեն, մինչ նոր արժեքներ են գրվում «վիդեո հիշողության մեջ», որպեսզի սխալ պահին առաջացած ընդհատումը չփչացնի զանգվածը:

Ամբողջ կոդը - GitHub-ում.

Կարդացեք տվյալների թերթիկները 2. SPI STM32-ում; PWM, ժամանակաչափեր և ընդհատումներ STM8-ում

Եթե ​​գոնե ինչ-որ մեկին այս հոդվածը օգտակար է համարում, ապա ես այն իզուր չեմ գրել: Ուրախ կլինեմ ստանալ մեկնաբանություններ և դիտողություններ, կփորձեմ պատասխանել ամեն ինչին։

Source: www.habr.com

Добавить комментарий