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

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


ob:o7:first

Различия

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

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

Предыдущая версия справа и слева Предыдущая версия
Следующая версия
Предыдущая версия
ob:o7:first [2026/04/24 10:37]
саша
ob:o7:first [2026/04/24 16:44] (текущий)
саша
Строка 1: Строка 1:
 ====== Первая программа на языке программирования Оберон ====== ====== Первая программа на языке программирования Оберон ======
  
-В предыдущей заметке было описано, как создать новый проект в среде разработки Рекордино, компилировать модуль-заготовку и затем — сформировать файл прошивки и записать его в память микроконтроллера.+В [[ob:o7:recordino-flash-stm32|предыдущей заметке]] было описано, как создать новый проект в среде разработки Рекордино, компилировать модуль-заготовку и затем — сформировать файл прошивки и записать его в память микроконтроллера.
  
-Теперь разберём детально сам код этого небольшого модуля, чтобы лучше понять идеологию модульного подхода и особенности языка программирования Оберон.+Теперь разберём детально сам код этого небольшого модуля, чтобы лучше понять идеологию модульного подхода и особенности [[https://online.oberon.org/oberon|языка программирования Оберон]].
  
 После запуска проекта открывается следующий код: После запуска проекта открывается следующий код:
Строка 9: Строка 9:
 <code> <code>
  
 +    MODULE Main; 
 +     
 +    
     IMPORT SYSTEM,      IMPORT SYSTEM, 
         ARMv7M := MicroARMv7M,          ARMv7M := MicroARMv7M, 
Строка 49: Строка 51:
     Setup;     Setup;
     Loop     Loop
 +     
 +END Main. 
 </code> </code>
  
 Программа прошивки состоит из модулей, как из кирпичиков Лего. Программа прошивки состоит из модулей, как из кирпичиков Лего.
  
-**Модуль** всегда начинается с слова **MODULE**, после которого следует его название. И заканчивается словом **END**, после которого повторяется название, и завершается точкой.+**Модуль** всегда начинается с слова ''MODULE'', после которого следует его название. И заканчивается словом ''END'', после которого повторяется название, и завершается точкой.
  
 <code> <code>
  
  
-    MODULE Main;+MODULE Main;
  
-    END Main.+END Main.
          
  
Строка 68: Строка 71:
 В общем случае название модуля может быть любым, название главного модуля редактируется в настройках проекта. Именно для главного модуля будет создаваться прошивка при нажатии на кнопку сборки на панели меню. В общем случае название модуля может быть любым, название главного модуля редактируется в настройках проекта. Именно для главного модуля будет создаваться прошивка при нажатии на кнопку сборки на панели меню.
  
-Секция импорта начинается ключевым словом **IMPORT**, после которого через запятую идут названия других модулей — строительных блоков программы. При этом с помощью оператора присваивания **:=** для модулей допускается указывать короткие обозначения.+Секция импорта начинается ключевым словом ''IMPORT'', после которого через запятую идут названия других модулей — строительных блоков программы. При этом с помощью оператора присваивания '':='' для модулей допускается указывать короткие обозначения.
  
 <code> <code>
  
  
-    MODULE Main;+MODULE Main;
    
-       IMPORT SYSTEM,  +   IMPORT SYSTEM,  
-           ARMv7M := MicroARMv7M, (* общее для всех контроллеров архитектуры ARMv7 *) +       ARMv7M := MicroARMv7M, (* общее для всех контроллеров архитектуры ARMv7 *) 
-           SysTick0 := MobxARMv7MSTM32SysTick0, (* пример таймера на прерываниях *) +       SysTick0 := MobxARMv7MSTM32SysTick0, (* пример таймера на прерываниях *) 
-           MCU := MicroSTM32F4, (* ардеса регистров для микроконтроллеров STM32F4* *) +       MCU := MicroSTM32F4, (* ардеса регистров для микроконтроллеров STM32F4* *) 
-           Pins := MicroSTM32F4Pins, (* модуль для настройки портов ввода/вывода *) +       Pins := MicroSTM32F4Pins, (* модуль для настройки портов ввода/вывода *) 
-           Sys := MicroSTM32F4System; (* модуль для базовой настройки STM32F4* *)+       Sys := MicroSTM32F4System; (* модуль для базовой настройки STM32F4* *)
        
        
 </code> </code>
  
-После секции импорта возможно указывать константы и описывать новые типы данных. Однако в этой простой программе это не используются, поэтому за секцией импорта следует секция глобальных переменных **VAR**. После идентификатора (имени) переменной через двоеточие указывается тип данных, который будет хранить переменная.+После секции импорта возможно указывать константы и описывать новые типы данных. Однако в этой простой программе это не используются, поэтому за секцией импорта следует секция глобальных переменных ''VAR''. После идентификатора (имени) переменной через двоеточие указывается тип данных, который будет хранить переменная.
  
 <code> <code>
  
-    VAR +VAR 
-        msec: INTEGER;+    msec: INTEGER;
        
 </code> </code>
Строка 97: Строка 100:
  
 <code> <code>
 +MODULE Main;
          
-    BOOLEAN   логические значения TRUE и FALSE +    IMPORT SYSTEM,  
-    CHAR      литеры стандартного набора литер +            ARMv7M := MicroARMv7M, (* общее для всех контроллеров архитектуры ARMv7 *) 
-    INTEGER   целые числа +            SysTick0 := MobxARMv7MSTM32SysTick0, (* пример таймера на прерываниях *) 
-    REAL      действительные числа +            MCU := MicroSTM32F4, (* ардеса регистров для микроконтроллеров STM32F4* *) 
-    BYTE      целые числа от до 255 +            Pins := MicroSTM32F4Pins, (* модуль для настройки портов ввода/вывода *) 
-    SET       набор целых чисел между 0 и пределом, зависящим от реализации+            Sys := MicroSTM32F4System; (* модуль для базовой настройки STM32F4* *)
                  
 </code> </code>
Строка 109: Строка 113:
 После описания переменных идёт описание процедур и программный код модуля. В этом примере две процедуры: После описания переменных идёт описание процедур и программный код модуля. В этом примере две процедуры:
  
-**Setup** — отвечает за настройку микроконтроллера,    +''Setup'' — отвечает за настройку микроконтроллера,    
  
-**Loop** — содержит главную петлю программы, которая повторяется во время работы микроконтроллера после настройки.+''Loop'' — содержит главную петлю программы, которая повторяется во время работы микроконтроллера после настройки.
  
 <code> <code>
  
-    MODULE Main; +MODULE Main; 
-    ...+...
  
-        PROCEDURE Setup; +    PROCEDURE Setup; 
-        BEGIN +    BEGIN 
-            ... +        ... 
-        END Setup;+    END Setup;
          
-        PROCEDURE Loop; +    PROCEDURE Loop;
-        BEGIN +
-            ... +
-        END Loop; +
     BEGIN     BEGIN
-        Setup; +        ... 
-        Loop +    END Loop; 
-    END Main. + 
 +BEGIN 
 +    Setup; 
 +    Loop 
 +END Main. 
          
 </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> 
 +PROCEDURE Setup; 
 +BEGIN 
 +  msec := 0; 
 +  SysTick0.Init(Sys.HCLK, 1000); 
 +  Pins.Configure(Pins.C,13,Pins.output,Pins.pushPull,Pins.medium,Pins.noPull,Pins.AF0); 
 +END Setup; 
 +</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.1777016238.txt.gz · Последнее изменение: 2026/04/24 10:37 — саша