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

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


ob:o7:generator

Простой генератор случайных чисел

Иногда в программе для микроконтроллера требуется создавать случайные числа. Возьмем пример из книги Мартина Райзера и Никлауса Вирта Программирование на Обероне. С него начинается введение в программирование на Обероне со страницы 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

Успехов!

ob/o7/generator.txt · Последнее изменение: 2026/08/31 17:56 — iadenisov