Инструменты пользователя

Инструменты сайта


ob:o7:first

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
ob:o7:first [2026/04/24 11:31]
саша
ob:o7:first [2026/04/24 16:44] (текущий)
саша
Строка 1: Строка 1:
 ====== Первая программа на языке программирования Оберон ====== ====== Первая программа на языке программирования Оберон ======
  
-В предыдущей заметке было описано, как создать новый проект в среде разработки Рекордино, компилировать модуль-заготовку и затем — сформировать файл прошивки и записать его в память микроконтроллера.+В [[ob:o7:recordino-flash-stm32|предыдущей заметке]] было описано, как создать новый проект в среде разработки Рекордино, компилировать модуль-заготовку и затем — сформировать файл прошивки и записать его в память микроконтроллера.
  
-Теперь разберём детально сам код этого небольшого модуля, чтобы лучше понять идеологию модульного подхода и особенности языка программирования Оберон.+Теперь разберём детально сам код этого небольшого модуля, чтобы лучше понять идеологию модульного подхода и особенности [[https://online.oberon.org/oberon|языка программирования Оберон]].
  
 После запуска проекта открывается следующий код: После запуска проекта открывается следующий код:
Строка 57: Строка 57:
 Программа прошивки состоит из модулей, как из кирпичиков Лего. Программа прошивки состоит из модулей, как из кирпичиков Лего.
  
-**Модуль** всегда начинается с слова //**MODULE**//, после которого следует его название. И заканчивается словом //**END**//, после которого повторяется название, и завершается точкой.+**Модуль** всегда начинается с слова ''MODULE'', после которого следует его название. И заканчивается словом ''END'', после которого повторяется название, и завершается точкой.
  
 <code> <code>
Строка 71: Строка 71:
 В общем случае название модуля может быть любым, название главного модуля редактируется в настройках проекта. Именно для главного модуля будет создаваться прошивка при нажатии на кнопку сборки на панели меню. В общем случае название модуля может быть любым, название главного модуля редактируется в настройках проекта. Именно для главного модуля будет создаваться прошивка при нажатии на кнопку сборки на панели меню.
  
-Секция импорта начинается ключевым словом //**IMPORT**//, после которого через запятую идут названия других модулей — строительных блоков программы. При этом с помощью оператора присваивания //:=// для модулей допускается указывать короткие обозначения.+Секция импорта начинается ключевым словом ''IMPORT'', после которого через запятую идут названия других модулей — строительных блоков программы. При этом с помощью оператора присваивания '':='' для модулей допускается указывать короткие обозначения.
  
 <code> <code>
Строка 88: Строка 88:
 </code> </code>
  
-После секции импорта возможно указывать константы и описывать новые типы данных. Однако в этой простой программе это не используются, поэтому за секцией импорта следует секция глобальных переменных //**VAR**//. После идентификатора (имени) переменной через двоеточие указывается тип данных, который будет хранить переменная.+После секции импорта возможно указывать константы и описывать новые типы данных. Однако в этой простой программе это не используются, поэтому за секцией импорта следует секция глобальных переменных ''VAR''. После идентификатора (имени) переменной через двоеточие указывается тип данных, который будет хранить переменная.
  
 <code> <code>
Строка 113: Строка 113:
 После описания переменных идёт описание процедур и программный код модуля. В этом примере две процедуры: После описания переменных идёт описание процедур и программный код модуля. В этом примере две процедуры:
  
-//Setup// — отвечает за настройку микроконтроллера,    +''Setup'' — отвечает за настройку микроконтроллера,    
  
-//Loop// — содержит главную петлю программы, которая повторяется во время работы микроконтроллера после настройки.+''Loop'' — содержит главную петлю программы, которая повторяется во время работы микроконтроллера после настройки.
  
 <code> <code>
Строка 139: Строка 139:
 </code> </code>
  
-Процедура настройки **Setup** имеет три выражения:+Процедура настройки ''Setup'' имеет три выражения:
  
   - установка начального значения глобальной переменной;   - установка начального значения глобальной переменной;
-  - настройка частоты таймера делается вызовом процедуры //Init// из модуля //SysTick0//. Процедура имеет два аргумента, мы передаём ей частоту работы главного кварца микроконтроллера и желаемую частоту вызова таймера в Герцах (так таймер будет вызываться 1000 раз в секунду); +  - настройка частоты таймера делается вызовом процедуры ''Init'' из модуля ''SysTick0''. Процедура имеет два аргумента, мы передаём ей частоту работы главного кварца микроконтроллера и желаемую частоту вызова таймера в Герцах (так таймер будет вызываться 1000 раз в секунду); 
-  - настройка вывода **PC13** осуществляется с помощью специального модуля //Pins// через процедуру Configure, 6 параметров задают порт, номер вывода, тип вывода (вход/выход), наличие/отсутствие подтяжки, скорость работы, тип подтяжки, и вариант альтернативной функции для вывода. (если ножка будет работать в режиме GPIO, то нужно использовать значение Pins.AF0).+  - настройка вывода **PC13** осуществляется с помощью специального модуля ''Pins'' через процедуру ''Configure'', 6 параметров задают порт, номер вывода, тип вывода (вход/выход), наличие/отсутствие подтяжки, скорость работы, тип подтяжки, и вариант альтернативной функции для вывода. (если ножка будет работать в режиме **GPIO**, то нужно использовать значение ''Pins.AF0'').
  
 <code> <code>
Строка 154: Строка 154:
 </code> </code>
  
 +Процедура ''Loop'' содержит бесконечный цикл ''REPEAT UNTIL FALSE'', в котором находится два выражения:
 +
 +  - условие проверки срабатывание таймера ''SysTick0.OnTimer()'' с кодом, который выполняется, если таймер сработал;
 +  - команда которая отправляет микроконтроллер в спящий режим до срабатывания следующего вызова таймера или иного прерывания ''ARMv7M.WFI''
 +
 +<code>
 +PROCEDURE Loop;
 +    BEGIN
 +        REPEAT
 +            IF SysTick0.OnTimer() THEN
 +                IF msec = 999 THEN msec := 0 ELSE INC(msec) END;
 +                IF msec = 0 THEN
 +                    SYSTEM.PUT(MCU.GPIOCBSRR, {13})
 +                ELSIF msec = 500 THEN
 +                    SYSTEM.PUT(MCU.GPIOCBSRR, {13 + 16})
 +                END;
 +            END;
 +            ARMv7M.WFI
 +        UNTIL FALSE
 +    END Loop;
 +</code>
 +
 +Внутри условия, есть выражение для добавления единицы к счётчику милисекунд ''INC(msec)'', а также условия сброса счётчика в ''0'', когда его значение достигнет константы ''999'':
 +
 +<code>
 +IF msec = 999 THEN msec := 0 ELSE INC(msec) END;
 +</code>
 +
 +Второе условное ветвление, в зависимости от значения глобальной переменной ''msec'' с помощью команды ''SYSTEM.PUT'' устанавливает значение битов регистра ''GPIOC_BSRR'' , так что сначала на вывод **PC13** подаётся напряжение 3,3 Вольта, а затем через половину секунды напряжение устанавливается в 0 Вольт.
 +
 +<code>
 +IF msec = 0 THEN
 +    SYSTEM.PUT(MCU.GPIOCBSRR, {13})
 +ELSIF msec = 500 THEN
 +    SYSTEM.PUT(MCU.GPIOCBSRR, {13 + 16})
 +END;
 +</code>
 +
 +{13} ­— это константа типа SET, которая соответствует двоичному числу с единицей в положении 13.
 +
 +<code>
 +0000 0000 0000 0000 0001 0000 0000 0000
 +</code>
 +
 +Запись такого машинного слова по адресу **MCU.GPIOCBSRR** вызывает документированные изменения напряжений на выводе **PC13**, как описано выше.
 +
 +{13+16} ­— это также константа типа SET, которая соответствует двоичному числу с единицей в положении 29.
 +
 +<code>
 +0001 0000 0000 0000 0000 0000 0000 0000
 +</code>
 +
 +Мы специально записали эту константу в виде суммы 13+16, чтобы было легче читать код. Ведь запись такого машинного слова по адресу **MCU.GPIOCBSRR** вызывает установку нуля на ножке **PC13**.
 +
 +«Почему один регистр управляет и включением и выключением напряжения?» — вероятно спросите вы… Это очень удобно, так как позволяет за одну операцию сразу включить и выключить группы выводов.
 +
 +К примеру вот такая команда за один такт работы микроконтроллера включит напряжение на выводах **PC1** и **PC3**, при этом выключит напряжения начиная с **PC6** и до **PC12**.
 +
 +<code>
 +SYSTEM.PUT(MCU.GPIOCBSRR, {1,3,6+16..12+16})
 +</code>
 +
 +BSSR — расшифровывается как Bit Set/Reset Register (регистр для установки и сброса бит).
 +
 +Подробнее про управление регистрами читайте [[https://wiki.oberon.org/ob/o7/example/put|в заметке в википедии по Оберону]].
 +
 +Управление микроконтроллером — это запись и чтение данных из регистров. Про чтение регистров мы поговорим в следующей заметке, где разберём подключение кнопки к микроконтроллеру.
 +
 +Задавайте вопросы в группе [[https://vk.com/mcuoberon|ВК]] или в [[https://away.vk.com/away.php?rh=c2146088-7486-481c-8f59-c5efc5856fac|телеграм-чате]].
ob/o7/first.1777019488.txt.gz · Последнее изменение: 2026/04/24 11:31 — саша