Архів блогу

субота, 10 жовтня 2020 р.

Конспект №0 по мікроконтролерам STM8


Творчі пориви в напрямку створення електронних пристроїв змушують зосереджувати увагу на мікроконтролерах та програмуванні.  Для більш якісного засвоєння матеріалу вирішив писати такий собі конспект. Це не буде інструкцією, закликом до чого небудь чи хизування. Має бути просто конспект зі своїми спостереженнями і висновками, які мій мозок вивів на основі опрацьованої інформації з інтернету, або іншими словами результат самонавчання. Не факт, правда, що отримана інформація була вірною чи висновки зроблені з неї є вірними.

Загалом для роботи з мікроконтролерами потрібно знати 3 предмета:

-         англійська мова, благо є гугл;

-         програмування, є повно уроків в інтеренеті;

-         радіоелектроніка, гадаю свої 20 років дружби з паяльником можна врахувати в орієнтовне знайомство з предметом.

До списку не входить багато чого з таких речей як: користування комп’ютером, читання, писання, використання, налаштовування  програмних та апаратних засобів розробки.

Для роботи з сімейством STM8 обраний набір STVD +Cosmic C compiler. Програми робочі, безкоштовні, без обмежень в кількості коду.  ST Visual develop https://www.st.com/en/development-tools/stvd-stm8.html  - фірмове IDE (інтегроване середовище розробки) від STM, але в ньому можна працювати лиш з Асемблером, тому в якості зовнішнього модуля підключається Cosmic C compiler, щоб мати змогу писати-компілювати програми на мові Сі. Cosmic надає безкоштовну ліцензію на використання свого програмного забезпечення для мікроконтролерів  STM8 після реєстрації на їх сайті http://www.cosmicsoftware.com/, також там вказано, що всі продукти  Cosmic включають один рік технічної підтримки та оновлень, як буде після року користування то побачимо...

В якості піддослідних чіпів обрались STM8S103F3P6 на платі та STM8S001, STM8L001 в якості дрібних і дешевих  восьмилапок.

В мікроконтролері є така штука як регістри і якщо ми хочемо чогось від контролера то потрібно спілкуватись з регістрами:  записувати або читати дані, які знаходяться в комірках(розрядах) регістрів. Коли регістр 8-ми бітний в ньому є 8 комірок пам’яті котрі можуть записувати 1 біт інформації тобто 0 або 1. Відповідно для запису – читання бітів регістра використовуються логічні операції з бітами. Бітові операції в мові програмування Сі потрібно знати, як 2+2 з першого класу школи. Особисто мені не завадить нагадування, що є що і куди саме його впихнути потрібно, тому алгебра логіки та бітові операції в Сі:

https://folkprog.net/pobitovie-operatsii-v-c/

https://ph0en1x.net/81-howto-work-with-ports-register-bits-in-microcontroller.html

https://pikabu.ru/story/nemnogo_o_portakh_i_bitovyikh_operatsiyakh_4316272

http://www.atmega8.ru/wiki/view/doc.20.html

https://diodov.net/logicheskie-operatsii-programmirovanie-mikrokontrollerov-avr/

https://diodov.net/pobitovye-operatsii-programmirovanie-mikrokontrollerov-avr-na-c/

https://habr.com/ru/post/406889/

 

Символ

назва

дія (приклад)

&

Побітове логічне «І»

AND», множення)

010 &  101 результат  000

 100 &  101 результат 100

Побітова операція логічного «І» відбувається з кожним розрядом (кожною цифрою)  чисел відповідно таблиці істинності

Х  У   &

0  0   0

0  1   0

1  0   0

1  1   1

&&

Логічне «І», “AND”

Використовується для перевірки умови істинності чи хиби

If( 101 && 010 ) – вираз дасть значення істини і код оператора умови if буде виконано.

x && y – буде істинним допоки один із операндів не стане 0, при чому кажуть якщо перший з операндів стане 0 то другий і наступні опранди до уваги не беруться і перевірятись не будуть в зв’язку з відсутнісю необхідності відповідно таблиці істинності логічного «І», тобто весь вираз прийме стане хибним.

&

отримання адреси

y = &xтака операція призначає адресу комірки пам’яті (номер квартири) де зберігається значення х (гроші) змінній Y, тобто  Y тепер знає номер квартири де лежать гроші і при зверненні до у залюбки каже його(номер).

*

звернення за адресою

z=*yвикористовується для доступу до грошей з квартири номер якої знає у. Враховуючи попередній приклад  вийде, що зет приймає значення ікс через звернення до ігрека  z == x.

|

побітове логічне  «АБО», “OR

(додавання)

101 | 010 буде 111 згідно таблиці істинності

х  у  |

0  0  0

0  1  1

1  0  1

1  1  1

||

логічне «АБО», “OR”

 001 || 000 дасть результаті  значення істини, якщо хоча б один з операндів не 0 то вираз буде істиною згідно таблиці істинності для логічного «АБО». Використовується у  if(001||000)

!

логічне заперечення «НІ», “NOT

(інверсія)

!0 дасть в результаті  1

!1 дасть в результаті  0

If(1!=0 ) – вираз істинний і читається, як -один не дорівнює нулю.

Операція використовується в порівняннях як і  &&, ||.

~

побітове логічне заперечення «НІ», “NOT

~ 010 буде дорівнювати  101. Дана операція - унарна, така, що  проводиться тільки  над одним числом.

^

побітове виключне «АБО»,XOR

х    у    ^    Одиниця в результаті виходить тільки тоді,

0    0    0    коли значення бітів в тих само розрядах

1    0    1    чисел різне. Тобто  1 «АБО» 0 дасть 1 в

0    1    1    результаті, а   1«АБО» 1 та 0 «АБО» 0 дадуть 

1    1    0    логічну хибу чи просто 0.

<< 

логічний зсув вліво

010<<1  дасть 100 

010<<3  дасть 000

Операція зміщує вліво  біти лівої частини (числа 010) на кількість позицій вказану справа виразу.

0b00000000 | (1<<5) – тут же одиниця встановлюється на 5-ту позицію 

0b00000000 | 0b00100000 ==  0b00100000

0b00000000 | (1<<0)   ==  0b00000001

Біти рахуються з 0 !!!!

Зсув числа вліво рівноцінно множенню на 2, на скільки позицій зсунули, на стільки двійок і множити:

2 == 0b00000010

0b00000010 <<  2 == 0b00001000 == 2 *2 *2 == 8

0b00000010 <<  5 == 0b01000000 == 2*2*2*2*2*2 == 64

>> 

логічний зсув вправо

010>>1 001

010>>2 000

Аналогічно зсуву вліво тільки в іншу сторону і при зсуві вправо відбувається ділення на 2  

64 == 0b01000000

 0b01000000 >>  4  ==  0b00000100 == 64/2/2/2/2 == 4

 

 

 

 











































































Оператори порівняння  >, <, >=, <=, ==, != разом з логічними операторами !, &&, || в якості результату завжди дають 0 або 1, істину або хибу, чисел не утворюють!!!

Бітові оператори  &, |, ~, ^, <<, >> в результаті використання можуть утворювати числа відповідно до своєї дії, тобто числа відмінні від просто логічної істини  чи логічної хиби.   

Це звісно не вся інформація по операціям в Сі, тому читаємо, наприклад :

http://www.c-cpp.ru/books

https://learnc.info/c/

https://narodstream.ru/programmirovanie_n_c/

«ВВЕДЕНИЕ В ЯЗЫК СИ» (c) Курсков С.Ю., составление, 2006-2012

Б.В. Керниган, Д.М. Ричи.  «Язык С». 

Оскільки Stm8 – мікроконтролери 8-ми бітні, то й регістри мають 8 бітів, або 8 комірок, є звісно виключення коли 2 8-ми бітні регістри поєднуються в один 16-ти бітний, як то лічильники в таймерах, але контролер від цього 16-ти бітним не стає.

Регістри, їх біти описані в даташИтаманУала  референс мануалі, а те які саме з них реалізовані в конкретному контролері вказано вже в даташиті на контролер.

Наприклад регістр DDR (data direction register-регістр напрямку даних) має 8 бітів кожен з яких відповідає лінії порта вводу-виводу даних. Портом можна, також, називати лапку (вивід, контакт) контролера, але краще не треба. Н випадку різних корпусів, різних серій, не всі порти можуть мати всі фізичні виводи, тобто порт B (PB) є весь в наявності, а виводи має тільки PB4 та PB5. В документах від СТМ є рекомендації переключати віртуальні виводи, які не використовуються(не мають фізичного виводу, лапки) в режим виводу даних (output), конфігурації  ПУШ-ПУЛЛ, та подати низький рівень сигналу на них. Цитата з даташити на STM8S001J3:

«The PA2, PB0, PB1, PB2, PB3, PB6, PB7, PC1, PC2, PC7, PD0, PD2, PD4, PD7, PE5 and PF4 GPIOs should be configured after device reset in output push-pull mode with output
low-state to reduce the devices consumption and to improve its EMC immunity. The GPIOs
mentioned above are not connected to pins, and they are in input-floating mode after a
device reset
»

За допомогою регістра ДДР можна сконфігурувати лапку порта на роботу входом чи виходом. Тут же на допомогу ДДР приходять регістри CR1 та CR2. При роботі входом лапка приймає високоімпедансний стан плаваючий, або притягнутий до плюса живлення, коли ж призначити її виходом то додатково потрібно вказати чи вихід буде відкритим колектором чи буде пуш пул.

Регістри можна представити, як дисковий кодовий замок в якому першим диском ми вибираємо регістр, іншими 8 –ма дисками(або 16-ма, чи 32-ма)  вибираємо код, тобто, функціонал який нам потрібен.

Писати в регістр можна так

PB_DDR = 0b11111111 //всі лінії порта Д встановлено виходом (всі 8 лапок)

PB_DDR =0xFF                // результат від такого запису буде ідентичним попередньому.

Наскільки я зрозумів простим присвоюванням (опрація «=») можна конфігурувати порт на початку програми, в процесі ж роботи програми, коли потрібно записати якісь біти в регістр порта використовуються логічні операції та логічний зсув бітів

PB_DDR |= (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)

Так як нумерація бітів починається з нульового біту то відповідно для нього використовується зсув вліво на нульове положення.  Результат такої операції буде ідентичний попереднім двом.

 Хоча на перший погляд і не зрозуміло, чому б не писати через присвоєння завжди: PB_DDR= 0b00000001. Кажуть, що у випадку логічних операцій з конкретними бітами інші біти регістра не змінюються тому користуються таким способом. А ще, я собі думаю, що в процесі виконання програми не можна знати точно де яке значення знаходиться 0 чи 1 тому й використовується зсув разом з логічними операціями для отримання, так би мовити, гарантованого результату незалежно від вмісту регістра.

 Отож бітова магія!

Записуємо одиничку:

PB_DDR = 0b00000000;         // початкове значення порта, після скидання контролера всі виводи (лапки)

                       //  порта налаштовані,  як входи.

PB_DDR  = 0b00100000;        //  лапка PB5 налаштована на вихід.

PB_DDR = 0x20;                       // те саме.

PB_DDR = PB_DDR| (1<<5);  //знову те саме тільки за допомогою логічного «АБО» та логічного зсуву         

                                                      //одинички вліво на позицію з номером 5  (012345)

PB_DDR |= (1<<5);                  // те саме, але скороченим записом.

 

Записуємо нулик (стираємо одиничку обнуляємо ):

PB_DDR = 0b11111111;  // весь порт налаштовано виходом.

PB_DDR & = ~ (1<<7);      // скидаємо в 0 сьомий біт (вивід PB7 стає входом).

PB_DDR == 0b01111111; // результат попередньої дії.

 

Логіка тут наступна:  (1<<7) – робимо зсув одиниці вліво на сьому позицію. Стоп, нам же треба  НУЛЬ, добре чіпляємо хвостика логічного заперечення  ~ (1<<7)  і отримуємо НУЛЬ, але в нас на 7-му місці ОДИНИЦЯ і якщо один додати нуль отримаємо ОДИНИЦЮ,  а це означає необхідність виконати дію множення & = і в результаті отримаємо бажаний НУЛЬ в бажаномі місці.

Всі дії описано відповідно до пріоритету виконання операцій в Сі, спочатку круглі дужки, потім інверсія, потім складений оператор множення з присвоєнням.

 

Зміна стану біта на протилежний:

PB_DDR=0b00000000;     //початковий стан.

PB_DDR^= (1<<5);             // змінюємо  5-й біт порта на протилежний.

PB_DDR==0b00100000;   // результат операції.

PB_DDR^= (1<<5);              // повторно змінюємо.

PB_DDR==0b00000000;    // результат повторної зміни.

 

За пріоритетом спершу виконуються дужки, потім побітове «АБО» разом з присвоюванням. Коли змінюється нуль на одиницю то має бути типу такої дії 0^1 що в результаті дасть 1, яка в свою чергу має стати на 5-ту позицію (5-й розряд).  У випадку  наявної одиниці 1^1 буде 0 який і запишеться в 5-й розряд. Все чинно-ладно по таблиці істинності побітового виключного «АБО».

 

Дані дії треба прийняти, як є. Незважаючи на деяку нелогічність, яка може ЗДАТИСЬ з пріоритетами, діями та результатами.

 

Для зміни декількох, або всіх бітів, необхідно перечислити в правій частині операції всі зсуви потрібних бітів через побітове «АБО»

PB_DDR |= (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)

PB_DDR &= (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)

PB_DDR ^= (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)

 

Потрібно не тільки писати, змінювати, а ще ж читати біти в розрядах портів. В STM8 є свої регістри які потрібно прочитати, щоб отримати інформацію про стан входів порта вводу-виводу даних. Читати потрібно регістри ODR (output data register, Px_ODR) та IDR (input data register, Px_IDR) З назви видно, що регістр  ODR потрібен коли пін працює, як вихід, а IDR коли пін є входом. При цьому в ODR можна писати і читати з нього дані (зручна штука коли, наприклад, програма щось виконала, але результат невідомий наперед, то його можна просто прочитати з регістра порта і зробити щось чи не робити, як то в генераторі випадкових чисел щось випало і треба зробити інтерпретацію вихідних даних, дати відповідь), а регістр IDR тільки читати, що в свою чергу дуже навіть логічно )).

  Як пишеться тут: https://diodov.net/pobitovye-operatsii-programmirovanie-mikrokontrollerov-avr-na-c/

https://obanracer.ru/chtenie-portov-avr-v-si-izuchenie-sistemy-komand-mikrokontrollera-avr.html

Перевірка, читання бітів в регістрі проводиться з операторами if-else, while.

            Перевірка на 0:

            if (0== (PB_ODR&( 1<<5)))                //порівнюємо 0 із п’ятим розрядом порта B, який в свою чергу

                        // перевіряється на 0 зсувом 1 на 5-ту позицію та побітовим  «І» з

                        //значенням, яке знаходиться в регістрі PB_ODR. Відповідно коли 

                        //там 1 то й результатом лог«І» буде одиниця, а коли одиницю      

                       //прирівняєм з 0 то отримаємо логічну брехню (хибу).

 if (~ (PB_ODR&( 1<<5)))     //інша форма запису того самого виразу.

     {

Some code                          // якийсь код

}

            else{

                     Other code                    // інший якийсь код

                    }


 

Особисте спостереження на основі користування ARDUINO при використанні if дуже доречним буде додавання else, для того, щоб програма випадково не потрапила в «незрозумілий стан» і подальший код гарненько виконувався.

Перевірка на 1:

if (0!= (PB_ODR&( 1<<5)))

{

Some code                          // якийсь код

}

            else{

                     Other code                    // інший якийсь код

                        }

if (PB_ODR&( 1<<5))            // інша форма запису того самого виразу.

 

Все те саме окрім порівняння 0!=, яке читається -нуль не дорівнює. Коли нуль не дорівнює одиниці значення істинне і виконується код   «Some code», коли ж в регістрі в п’ятому розряді знаходиться 0 то операція & в (PB_ODR&( 1<<5)) дасть 0, а 0!=0 це вже хибне ствердження, а тому буде виконуватись код «Other code».

 

Очікування 0:

while (PB_IDR & (1<<0))     //як видно операція порівняння не змінилась,

                                      // цикл while буде виконувати Some code до тих пір, допоки на PB0

                                                    //буде одиниця, як тільки порт отримає 0, цикл завершиться, якщо  

                                                    //програма має ще код після while то продовжиться його виконання.

{

Some code

}

Очікування 1:

while (!(PB_IDR & (1<<0)))   //while буде крутитись, а відповідно виконувати Some code допоки на PB0 буде 0.

{

Some code

}

while (~(PB_IDR & (1<<0)))    //те саме тільки для порівняння використовується операція побітового заперечення, тобто 

                                                       //поки PB0 буде 0 до тих пір вираз буде істинним, а відповідно цикл буде виконувати  Some code.

{

Some code

}

 

  Надалі не завадить література:

«Основы микропроцессорной техники: Микроконтроллеры STMС.Н. Торгаев. Томск 2014

«Начало работы с микроконтроллерами STM8» Матюшов Н.В.

RM0016, Reference manual STM8S Series and STM8AF Series 8-bit microcontrollers разом з даташитами на конкретний чіп.

1 коментар:

  1. Achima Abelard, ваш коментар надзвичайно важливий для нас. Не соромтесь видаляти рекламну контактну інформацію разом із машинним перекладом та й загалом цілим коментарем, який ніяким боком не відноситься до теми написаного. Щиро вдячний MegaSkilledTechnician!

    ВідповістиВидалити