======Простой генератор случайных чисел====== Иногда в программе для микроконтроллера требуется создавать случайные числа. Возьмем пример из книги Мартина Райзера и Никлауса Вирта [[https://people.inf.ethz.ch/wirth/ProgInOberonWR.pdf|Программирование на Обероне]]. С него начинается введение в программирование на Обероне со страницы 9. Также этот пример входит в комплект примеров системы Блэкбокс (модуль ObxRandom). Немного адаптируем его под последний диалект Оберона, который мы используем для микроконтроллеров, а именно — сделаем явное преобразование типов между REAL и INTEGER с помощью встроенных в [[https://visual.sfu-kras.ru/oberon|язык]] процедур FLT и FLOOR. FLT преобразует переменную типа INTEGER в переменную типа REAL FLOOR округляет REAL до меньшего целочисленного значения INTEGER MODULE Random; VAR z: INTEGER; (* global variable *) PROCEDURE Uniform* (): REAL; CONST a = 16807; m = 2147483647; q = m DIV a; r = m MOD a; VAR gamma: INTEGER; BEGIN gamma := a * (z MOD q) - r * (z DIV q); IF gamma > 0 THEN z := gamma ELSE z := gamma + m END; RETURN FLT(z) * (1.0 / FLT(m)) (* value of the function *) END Uniform; PROCEDURE InitSeed* (seed: INTEGER); BEGIN z := seed END InitSeed; BEGIN z := 314159 (* initial value of seed *) END Random. Теперь попробуем применить этот модуль, напишем небольшую программу для микроконтроллера STM32F401CC. В этой программе модуль Random используется, чтобы установить задержку до переключения состояния светодиода. MODULE Main; IMPORT SYSTEM, ARMv7M := MicroARMv7M, SysTick0 := MobxARMv7MSTM32SysTick0, MCU := MicroSTM32F4, Pins := MicroSTM32F4Pins, Sys := MicroSTM32F4System, Rnd := Random; VAR delay: INTEGER; ledOn: BOOLEAN; PROCEDURE Setup; BEGIN delay := 0; SysTick0.Init(Sys.HCLK, 1000); Pins.Configure(Pins.C, 13, Pins.output, Pins.pushPull, Pins.medium, Pins.noPull, Pins.AF0); SYSTEM.PUT(MCU.GPIOCBSRR, {13 + 16}); ledOn := FALSE; (* тут может быть инициализация от какого-то источника случайных чисел *) (* Rnd.InitSeed(someIntSource); *) delay := FLOOR(Rnd.Uniform() * 1000.0); END Setup; PROCEDURE Loop; BEGIN REPEAT IF SysTick0.OnTimer() THEN IF delay <= 0 THEN IF ledOn THEN SYSTEM.PUT(MCU.GPIOCBSRR, {13}) ELSE SYSTEM.PUT(MCU.GPIOCBSRR, {13 + 16}) END; ledOn := ~ledOn; delay := FLOOR(Rnd.Uniform() * 1000.0); ELSE DEC(delay) END; END; ARMv7M.WFI UNTIL FALSE END Loop; BEGIN Setup; Loop END Main. Получаем результат. https://vkvideo.ru/video-198725476_456239054 Последовательность не будет повторяться, если инициализировать генератор от некоторого другого источника. Например, встроенный датчик температуры. Но это уже будет другая статья. Спасибо за чтение. Задавайте вопросы в группе или в телеграм канале: https://t.me/recordinoChat Успехов!