©
Беляев М.В.
(Новосибирск, НГПУ)
belyaev@e-mail.ru
В архиве лежит упакованная версия статьи (около 4 кб)
Как следует из заголовка, настоящая заметка является постскриптумом к
предыдущему материалу.
Потребность в постскриптуме возникла в связи с тем, что мной была допущена ошибка. А именно, неверно
утверждение: "если одновременно поменять 0 на обоих входах на 1, то триггер
перейдет в одно из двух основных состояний ... непредсказуемым образом".
В действительности у некоторых (полностью симметричных) триггеров эта
манипуляция может вызвать генерацию. Следовательно и мой вывод о
невозможности генерации в системе 2"И"-"НЕ" тоже неверен.
Деструктивная сила одновременности
Тем не менее, на моих основных выводах эта досадная оплошность не отразилась.
Мое утверждение: "если одновременные события взаимодействуют, то для нормального
функционирования системы такая ситуация должна быть исключена", - даже получило
дополнительное подтверждение. Одновременное наступление взаимодействующих событий не
приводит ни к чему кроме неприятностей. Для триггера большей неприятности,
чем генерация не существует. Мой позитивный подсознательный настрой сыграл со
мной злую шутку - заставил объявить невозможным нежелательный исход.
Триггер казался таким совершенным прибором, но умельцы нашли таки способ
его испортить. К этому ведет двухходовая комбинация:
- перевести триггер в запрещенное состояние (0 на оба входа)
- ОДНОВРЕМЕННО на оба входа подать 1
Вентили одновременно изменяют свое состояние и им это приходится делать раз
за разом. А мы попиваем кофе и радуемся достигнутому результату.
В программах
представленных в предыдущем материале не было возможности установить значения
входов триггеров ОДНОВРЕМЕННО. Внеся соответстующие изменения в операции
ввода, и добавив две переменные и несколько строк кода, мы получаем программу
полностью моделирующую злополучный триггер. И хотя параллельность в
моделируемой системе исключить невозможно (из-за строгой одновременности),
но она прекрасно эмулируется на "двумерном" Си.
Полный листинг программы с подробными комментариями вы можете найти в
Приложении .
Таким образом утверждение В. Любченко:
"Если все выполнено корректно, то в параллельной среде, имеющей трехмерные свойства,
триггер при определенных условиях будет входить в режим генерации, в двумерной же - нет", - по-прежнему остается неверным.
Приложение.
/*-------------------------------------------------
Программная модель "триггера"
- двух перекрестно соединенных логических вентилей
с возможностью одновременной установки входов
Copyright (c) М.В. Беляев, 2001
Для получения генерации в системе 2 "И"-"НЕ" достаточно
любым способом установить оба входа в 0 (нажав 1 и 3, или 5)
и затем ОДНОВРЕМЕННО на оба входа подать 1 (нажать 8).
------------------------------------------------- */
#include <stdio.h>
#include <conio.h>
/* возможные типы вентилей*/
typedef enum
{and_not, or_not, and_, or_} v_types;
v_types vs_type, vr_type; /* типы вентилей S и R */
int S, R; /* входы и */
int Q, P; /* выходы "триггера" */
int same_time; /* флаг одновремен. ввода */
int QR; /* вход Q вентиля R */
int not_end=1; /* управляет завершением */
/*------------------------------------------------- */
v_types SetVType(char *prompt) /* задание типа вентиля */
{
printf("Choose %s ventil type:\n", prompt);
for(;;)
{
puts("0 - and_not, 1 - or_not, 2 - and_, 3 - or_");
switch(getch())
{
case '0': return and_not;
case '1': return or_not;
case '2': return and_;
case '3': return or_;
}
}
}
/*------------------------------------------------- */
void CheckKey() /* управление входами "триггера" */
{
if(kbhit()) /* была ли нажата клавиша? */
{
switch(getch())
{ /* установка входов "триггера"*/
/* последовательная */
case '1':S=0; puts("S=0"); same_time=0; break;
case '2':S=1; puts("S=1"); same_time=0; break;
case '3':R=0; puts("R=0"); same_time=0; break;
case '4':R=1; puts("R=1"); same_time=0; break;
/* одновременная */
case '5':S=0; R=0; puts("S=0 R=0"); same_time=1;break;
case '6':S=1; R=0; puts("S=1 R=0"); same_time=1;break;
case '7':S=0; R=1; puts("S=0 R=1"); same_time=1;break;
case '8':S=1; R=1; puts("S=1 R=1"); same_time=1;break;
case '\033' : not_end = 0; /* ESC - конец работы */
}
}
}
/*------------------------------------------------- */
void print() /* вывод на косоль состояния выходов */
{
printf(" Q= %1d P= %1d\n", QR, P);
}
/*------------------------------------------------- */
int op(v_types v_type, int x, int y) /* логическая операция вентиля */
{
switch (v_type)
{
case and_not: return !(x && y);
case or_not : return !(x || y);
case and_ : return (x && y);
case or_ : return (x || y);
}
}
/*------------------------------------------------- */
/* действие на переходе S -> R */
void VS()
{
int x;
CheckKey(); /* если нажали нужную клавишу - изменить S или R
или сразу S и R */
x = op(vs_type, S, P);
if(x != Q)
{
Q=x; /* вентиль S на выходе дает Q */
if(!same_time) print(); /* вывод на консоль */
}
if(!same_time) QR = Q; /* значение QR обновляется */
}
/*------------------------------------------------- */
/* действие на переходе R -> S */
void VR()
{
int x;
if(same_time) /* если флаг одновременности установлен*/
{
x = op(vr_type, QR, R); /* используется выход QR */
/* (предыдущее состояние) */
QR = Q; /* значение QR обновляется */
}
else x = op(vr_type, Q, R);/* иначе используется выход Q */
if(x != P)
{
P=x; /* вентиль R на выходе дает P */
print();/* вывод на консоль */
}
else same_time=0;
}
/*------------------------------------------------- */
int main()
{
vs_type=SetVType("S"); /* задать тип вентиля S */
printf("S= %1d \n", vs_type);
vr_type=SetVType("R"); /* задать тип вентиля R */
printf("R= %1d \n", vr_type);
/* подсказка - как управлять "триггером" */
puts("\nPress key to change any trigger enter:");
puts("1 - S=0; 2 - S=1; ");
puts("3 - R=0; 4 - R=1\n");
puts("5 - S=0,R=0; 6 - S=1,R=0; ");
puts("7 - S=0,R=1; 8 - S=1,R=1\n");
puts("Now press any key to start");
puts("Press ESC to stop\n");
getch();
while(not_end) /* пока не нажали ESC */
{
VS(); /* S и R работают по очереди */
VR(); /* - это имитация параллельности! */
}
return 0;
}
/*------------------------------------------------- */
|