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

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


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://vkvideo.ru/video-198725476_456239054

Последовательность не будет повторяться, если инициализировать генератор от некоторого другого источника. Например, встроенный датчик температуры. Но это уже будет другая статья. Спасибо за чтение. Задавайте вопросы в группе или в телеграм канале: https://t.me/recordinoChat

Успехов!

<iframe src=«https://vkvideo.ru/video_ext.php?oid=-198725476&id=456239054&hash=» width=«640» height=«360» frameborder=«0» allowfullscreen=«1» style=«background-color: #000» allow=«autoplay; encrypted-media; fullscreen; picture-in-picture»></iframe>

ob/o7/generator.1777306543.txt.gz · Последнее изменение: 2026/04/27 19:15 — саша