Иногда в программе для микроконтроллера требуется создавать случайные числа. Возьмем пример из книги Мартина Райзера и Никлауса Вирта Программирование на Обероне. С него начинается введение в программирование на Обероне со страницы 9. Также этот пример входит в комплект примеров системы Блэкбокс (модуль ObxRandom).
Немного адаптируем его под последний диалект Оберона, который мы используем для микроконтроллеров, а именно — сделаем явное преобразование типов между REAL и INTEGER с помощью встроенных в язык процедур 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://t.me/recordinoChat
Успехов!