ß                         Программирование структуры системы мониторинга

 

Адрес документа:

http://shabronov_s2.dyn-dns.ru/temp/gr_mi38_37_mp6_sh/gr_mi38_37_mp6_sh.doc    инд 2-95-л6

 

В данной лекции рассматривается  программирование структуры системы мониторинга. Примеры измерения температуры цифрового датчика. Однопоточное и много поточное выполнение алгоритма. Особенности потоков - скрытые явные.

 

Содержание:

Алгоритм  мониторинга

Что называется алгоритмом?  Понятие алгоритма является довольно древним и относится к одному из главных, а также базовых понятий в математике, программировании и в  нашей действительности.

 Что такое алгоритм?  

 На картинках ниже показаны циклические действия  по алгоритму:

    

Алгоритм  точные сформулированные указания, порядок определенных действий, которые должны обеспечить достижение поставленной цели.
 Термин происходит от латинского написания имени известного восточного математика 787-850 годов Мухаммеда аль-Хорезми - Algorithmi. Этот ученный был первым, кто сформулировал точные правила для записи натуральных чисел, а также правила для подведения отсчётов в столбик. Довольно интересным фактом является и то, что, несмотря на древние корни, само понятие было точно сформулировано лишь в начале ХХ века. Ныне алгоритм является основной составляющей современного бизнеса, любого учебного процесса или же исследования. Именно поэтому каждому современному человеку просто необходимо точно знать, что означает алгоритм.

Ниже на рисунке представлена блок схема алгоритма мониторинга.  Рядом показано главное (основное) слово программы, отображающее основные этапы алгоритма.  

Стрелками указано, какому блоку соответствует слово программы.

«Золотое» правило - программируем «сверху». В начале пишем по алгоритму основное слово  MAIN. И в нем описываем действия «ПО  КРУПНОМУ».

Наш изучаемый  мониторинг состоит  из одного цикла  BEGIN …<тело программы > …. UNTIL

В  «теле программы» находятся основные «слова» отвечающие за мониторинг. Имеется  один условный переход - проверка граничных условий. Второй условный переход – повторение измерений. Разберем блоки и слова алгоритма.

 

 

Например, проверка запуска. Вход по паролю и т.д.

            M_GRN_EKRAN  - отображение на экране

            M_GRN_WRITE   - запись границы в файле

 

А если на стеке 0 – то программа возвращается к слову BEGIN и начинает выполнять повторно  получение данных из источника.  И все повторяется вновь.

 

Ниже представлен алгоритм мониторинга с использованием конструкции BEGIN   WHILE     REPEAT

 

Отличие в том, что проверка условий выхода проверяется вначале, а затем получение данных и их обработка.

Это все тот же  пример простого цикла.  Все действия программы выполняются последовательно.   Далее рассмотрим конкретную программу для цифрового датчика.

 

Отвлечение руководителя анекдот - на лекции не озвучивать;

·   Как вам удалось сохранить брак? - Просто в наше время было принято чинить вещи, а не выбрасывать их.

 

Программа мониторинга;

Используем  цифровой датчика Dallas  Semicondutor  ds1820 и ds18b20. Они отличаются разной точностью измерения.

Внешний вид датчиков:

    

 

Схема подключения датчиков протокола 1-wire:

Применение DS2490 для сопряжения USB и однопроводной шины

 

 

Внешний вид адаптера 1-wire USB- ds2490    и рядом с ним датчик ds1820

  DS9490R

 

 

Для работы с usb- 1-wire производители подготовили dll-библиотеку  ibusb32.dll   (скачать)  И обязательно требуется установить драйверы для работы с USB- адаптером адрес1 адрес2 

Ниже представлен текст программы. Скопировать блокнотом, создать файл с расширением f. Скомпилировать программой компилятора forth. В папке с  исполняемым файлом, должен находиться и файл ibusb32.dll. А так же эта библиотека может находиться и в области  :\Windows\SYSTEM32\  Но если Вы с правами гостя на компьютере, записать в данный каталог не получиться.

 

\ начало  текста

\ программа чтения датчика температур  Dallas Semiconductor   ds1820 в  одном потоке 

 

 WINAPI:   TMEndSession   IBUSB32.dll

 WINAPI:   TMExtendedStartSession    IBUSB32.dll

 WINAPI:   TMGetVersion              ibusb32.dll

 WINAPI:   TMSetup                   IBUSB32.dll

 WINAPI:   TMOneWireCom              IBUSB32.dll 

 WINAPI:   TMOneWireLevel            IBUSB32.dll

 WINAPI:   TMBlockIO                 IBUSB32.dll  

 WINAPI:   TMTouchReset              IBUSB32.dll

 WINAPI:   TMNext                    IBUSB32.dll 

 WINAPI:   SetConsoleCursorPosition  KERNEL32.DLL

 WINAPI:   SetConsoleTextAttribute   KERNEL32.DLL

 WINAPI:   MessageBeep               USER32.DLL ( пищание системного динамика )

 WINAPI:   Beep                      KERNEL32.DLL ( звучит звуковое устройство т-МС  F-ГЦ -- )

 WINAPI:   GetLocalTime              KERNEL32.DLL ( читаем локальное т.е. установленное на компьютере время )

 

 

\  резервируем переменные и константы для работы

0   VALUE  handle1  ( глобальная переменная описателя устройства сопряжения )

0   VALUE  BUF1     (  глобальная переменная для сохранения адресов буферов переменных )

0   VALUE  BUF2     (  глобальная переменная для сохранения адресов буферов данных датчиков )

0   VALUE  In       (  глобальная переменная для временого хранения индекса )

0x8 CONSTANT NDAT ( максимальное количество датчиков на одном адаптере )

0   VALUE  IDAT       (  глобальная переменная для  обнаруженных датчиков на линии  )

0   VALUE  Nizm       (  глобальная переменная для  подсчета количества измерений  )

: NAME_DAN  S" file_temperatur_dan.xls" ; ( имя файла данных температур )

0   VALUE  FR1 (  указатель для файла данных )

: NAME_TRW  S" file_temperatur_trw.xls" ; ( имя файла данных тревог )

0   VALUE  FR2 (  указатель для файла тревог )

DECIMAL

  30 CONSTANT T_TRWG (  гр  температура выше которой выдается тревога )

 

\ описываем требуемые слова для работы главного слова мониторинга

CREATE  SYSTEMTIME  0x10 ALLOT ( память под данные для системного времени )

\ для наглядного вызова часов минут и тд области памяти в выделенной области обозначены через отдельные слова

: wYear            0 + ;

: wMonth           2 + ;

: wDayOfWeek       4 + ;

: wDay             6 + ;

: wHour            8 + ;

: wMinute        0xA + ;

: wSecond        0xC + ;

: wMilliseconds  0xE + ;

 

: TIME&DATE1 ( -- wsec sec min hr day mt year )

  SYSTEMTIME GetLocalTime DROP

  SYSTEMTIME wMilliseconds  W@  ( мили секунда )

  SYSTEMTIME wSecond        W@  ( секунда )

  SYSTEMTIME wMinute        W@  ( минута )

  SYSTEMTIME wHour          W@  ( час )

  SYSTEMTIME wDay           W@  ( день )

  SYSTEMTIME wMonth         W@  ( месяц )

  SYSTEMTIME wYear          W@  ( год )

;

 

: TIME ( cc мм чч  -->    время системы  в стек )

     SYSTEMTIME GetLocalTime DROP

     SYSTEMTIME wSecond W@  ( секунда )

     SYSTEMTIME wMinute W@  ( минута )

     SYSTEMTIME wHour W@    ( час )

     ;

 

: TEXT-ATTR ( fg bg -- установка цвета знака fg фона bg )   0x10 * + H-STDOUT SetConsoleTextAttribute DROP ;

: UST_ATR_LIM_CMD     0xF  8    TEXT-ATTR ( fg bg -- установка цветности вариант  )   ;

: UST_ATR_LIM1_CMD    0xF  5    TEXT-ATTR ( fg bg -- установка цветности вариант 1 тревоги ) ;

: UST_ATR_LIM2_CMD    0xF  0xA  TEXT-ATTR ( fg bg -- установка цветности вариант 2 тревоги )   ;

: UST_ATR_NORM_CMD    0x7  0    TEXT-ATTR ( fg bg -- установка цветности исходное  для терминала )  ;

 

: GotoXY ( x y --  установка координаты курсора в консоли. )

  0x10000 * +   H-STDOUT SetConsoleCursorPosition DROP

;

: ZWUK (   Т-мс F-гц --- )   Beep DROP  ;

: BEEP_M2 (  цыганочка с входом вар2  )

 0x60 0x900   ZWUK    0x60 0x800   ZWUK   0x60 0x700   ZWUK   0x60 0x600   ZWUK   0x60 0x500   ZWUK  ;

 

: FIX ( M --> ) 0x100 /MOD   GotoXY ( x y -- ) ;

: .RF ( форматирование без выдачи это литерал числа )

  >R DUP >R ABS    S>D <# #S R> SIGN #>     R> OVER - 0 MAX SPACES    ;

: .R ( n1 n2 --   форматный вывод n1 по размеру n2 )   .RF  TYPE ;

: PAUSE1 ( N --> пауза в N  миллисекунд 0> )  Sleep DROP ;

: ?KEY1  ( K --> код клавиши ) KEY? IF KEY    ELSE 0  THEN ;

: ZWUK_TRW1 ( три тревожных звонка ) 3 0 DO 0x80 PAUSE1  0x40 MessageBeep  DROP  ( ВЫДАЕТСЯ ЗВУК ПИЩАЛКИ ДИНАМИКА ) LOOP ;

 

\  контрольные слова для отладки программы

: STOP1 BEGIN ?KEY1 DUP 0x1B = IF BYE THEN 0x20 = UNTIL ;

CREATE KKS_B  0 ,

: KKS ( распечатаь штатными средствами и предупреждение о исчерпании стека )

  BASE @ KKS_B ! ( систему счисления  на сохранение )

  CR ."  ctk,N--> " DECIMAL

  DEPTH DUP 1 < IF  DUP 0= IF  .  S"  Стек пустой!" ( при 0 )

                           ELSE  DROP S" ОШИБКА - СТЕК ИСЧЕРПАН !!! "

                           THEN   ANSI>OEM TYPE

                ELSE  DUP  .  HEX ."  = "   .SN

                THEN      S"   --> верх " ANSI>OEM TYPE

       KKS_B @ BASE ! ( вернули систему счисления  )      ;

 

 

 

 

: M_PODGOTOVKA_KOL ( поиск количества датчиков на шине )

  handle1 0= IF EXIT THEN (  выходим из подсчета если нет описателя т.е. устройство не работает )

  NDAT 0 DO ( поиск в цикле до максимального значения датчиков цикл типа do..loop  )

     BUF1   handle1   TMNext    1 =  ( процедура dll - поиск номера следующего датчика )

   IF ( да - найден новый датчик )

          BUF1 0x27 +  (  A1 -- ) BUF2 I 0x10 * + 8 CMOVE ( Abuf1 -  сохранили для дальнейшей работы МАС адрес датчика )

   ELSE   I TO IDAT ( записали данные кол-ва )  LEAVE ( выход т.к. поиск окончен )

   THEN

        LOOP

  CR S" На шине 1-wire устройства с мас:" ANSI>OEM TYPE   ( выводим сообщение о найденных устройствах )

  IDAT 0 DO  CR HEX BUF2 I 0x10 * + ( A -- ) 8 0 DO DUP I +   C@  3 .R  LOOP DROP  LOOP

 ( печатаем номера )

\  BUF2  100 DUMP  ( посмотреть дамп с содержимым кодов датчиков )  KKS STOP1         

;

 

: M_PODGOTOVKA_DRV ( -- подключение драйверов для работы с цифровым датчиком  и сообщение если драйвер подключить не удалось )

 \   STARTLOG ( ВКЛЮЧИТЬ ФАЙЛ ОТЧЕТА SPF.LOG )

 \   ENDLOG (  выключить файл отчета )   

NAME_DAN   R/W CREATE-FILE DROP ( FR -- ) TO FR1

 (  cоздали файл для записи и чтения  и сохранили указатель на файл )

NAME_TRW   R/W CREATE-FILE DROP ( FR -- ) TO FR2

 (  cоздали файл тревог для записи и чтения  и сохранили указатель на файл )

 

0x100         ALLOCATE THROW TO BUF1

( заняли временную память и записали адрес ее  начало в локальную перменную BUF1 )

0x10 NDAT *  ALLOCATE THROW TO BUF2

( заняли временную помять  для номера датчика и его данных  на каждый датчик по 0x100 байт )

BUF1  TMGetVersion     1 = IF  ( OK ) BUF1 ASCIIZ>  CR  TYPE ELSE ( err )  S" нет файла драйвера ibusb32.dll" ANSI>OEM CR TYPE  THEN

     0  1  1   TMExtendedStartSession   TO handle1 ( начали сессию и определили описатель )

      \  устанавливаются параметры для максимальной длинны линии

          handle1   TMSetup  ( 1-OK  3= ERR )  1 <> IF 0 TO  handle1 THEN ( проверка на установку  1 )

    6 0   handle1   TMOneWireCom    6 <> IF 0 TO  handle1 THEN ( проверка на установку 2 )

  2 1 0   handle1   TMOneWireLevel 0<> IF  0 TO  handle1 THEN ( проверка на установку 3 ) 

    M_PODGOTOVKA_KOL ( подсчет количества датчиков на шине )

handle1 0= IF  ( действия при отсутствии устройства на usb )

                FR1 CLOSE-FILE ( fileid -- ior  закрыли файл )  DROP   NAME_DAN  DELETE-FILE  ( c-addr u -- ior удалили файл  ) DROP

                FR2 CLOSE-FILE ( fileid -- ior  закрыли файл )  DROP   NAME_TRW  DELETE-FILE  ( c-addr u -- ior удалили файл  ) DROP               

               

                UST_ATR_LIM_CMD

                ZWUK_TRW1

                CR S" ВНИМАНИЕ! Драйвер программой не настроен!!! " ANSI>OEM TYPE 

                CR S" Возможные причины: " ANSI>OEM TYPE                 

                CR S" Нет устройства и драйвера USB в компьютере. " ANSI>OEM TYPE                 

                CR S" Включите диспетчер устройств и проконтролируйет исправность. " ANSI>OEM TYPE                 

                CR S" Контакты с технической поддержкой по тс 913-905-8839   shabronov@ngs.ru " ANSI>OEM TYPE                 

                CR S" Ищите, и обрящете, толцыте, и отверзется Евангелии от Луки гл. 11, ст. 9 " ANSI>OEM TYPE                 

                CR S" Программа прекращает работу! Нажмите любую клавишу " ANSI>OEM TYPE                 

                CR 0 0xA DO  I .  0x400 PAUSE1  BEEP_M2  ?KEY1 0<> IF BYE THEN    -1 +LOOP                

                UST_ATR_NORM_CMD    BYE ( выход из работы программы )

          THEN      

 ;

 

: M_PODGOTOVKA ( подготовка )

    S"  Чтение данных температуры цифрового датчика ds1820 "  ANSI>OEM TYPE 

 CR S"  Выход из программы клавиша - ESC "                    ANSI>OEM TYPE 

    M_PODGOTOVKA_DRV ( -- подключение драйверов для работы с цифровым датчиком  и сообщение если драйвер подключить не удалось )

;

 

 

: M_DAN_READ ( получение данных )

 IDAT 0 DO  ( цикл  читаем данные по МАС имс датчиков )

     BUF1 0x100 0xFF FILL   ( заполняем кодом FF для передачи )

     handle1  TMTouchReset  DROP  ( сигнал сброса  )

     0x55 BUF1 C!    ( запись команды назначить имс )

     BUF2 I 0x10 * +  ( A1 )  BUF1 1+ ( A1 A2 -- )  8 CMOVE (  передали МАС имс датчика )

     0x44 BUF1 9 + C!     ( команда конвертации температуры после МАСа )

     0xA   BUF1     handle1  TMBlockIO  DROP ( выдали команду  последовательность из 0xA байт )

     0x400   PAUSE1 ( ждем 1024 милисекунды т 1секунду  )

     0xBE BUF1 9 + C!   (  команда чтения озу датчика вместо конвертации пишем )   

     0xA 8 +   BUF1     handle1  TMBlockIO DROP ( выдали команду последовательности 18 байт )

     BUF1 0xA +  ( A1 - находятся 2а байта данных температуры или FFFF если нет данных )

     BUF2 I 0x10 * + 8 +  ( A1 A2 -  адрес для хранения 2х байт данных температуры )

     2 CMOVE ( - передали данные на временное  хранение для отображения и записи в файл )

      LOOP

;

 

 

\ ---------------------------------------------

 

CREATE PKZ_M1 ( МАСИВ ПОД ЗНАЧЕНИЯ ПЕРЕРАСЧЕТА )

\ 0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F

  0 C, 1 C, 1 C, 2 C, 3 C, 3 C, 4 C, 5 C, 6 C, 6 C, 6 C, 7 C, 7 C, 8 C, 9 C, 9 C,

 

 

: M_DAN_EKRAN_T1 ( At Ndel=0x10/0x2  - отображение для ds18b20  ds1820 код делителя 0x10 и 0x2 )

   S"  Т, гр = " ANSI>OEM TYPE

   SWAP (  Ndel At -- )

   DUP   C@  SWAP 1+ C@ 0x100 * + ( T -- )  DUP 0xFFF >

    IF ( ОТРИЦАТЕЛЬНАЯ ВЫДАЧА  число более FFF т/е отрицательное )

        DUP  0xFFFF SWAP -   ( отнимаем для 16 разрядной адресации )

               [CHAR] -  ( знак минуса )

    ELSE DUP   [CHAR] +  (  знак плюса   ) THEN EMIT

    ( Ndel T T  --> показываем целое значение )

    DECIMAL  ROT  / 2 .R  [CHAR] .   ( показали целое и точку ) EMIT

   (  T --> )  0xF AND (  ТОЛЬКО ЦЕЛАЯ ЧАСТЬ ) PKZ_M1 + C@  1 .R  ( ПОКАЗЫВВЕМ )

;

 

 

: M_DAN_EKRAN ( отображение на экране )

       ( цикл  показываем данные и МАС имс датчиков 1e 8 байт мас далее 2а байта данные )

   0x400 ( точка после меню )  IDAT 0x100 * +   FIX   ( устанавливаем отображение на экране фиксировано по количеству датчиков )

   S" Nизм = "  ANSI>OEM TYPE  DECIMAL  Nizm DUP .   1+ TO Nizm (  учет количества измерений )

      IDAT 0 DO  CR HEX BUF2 I 0x10 * + ( A -- ) 8 0 DO DUP I +   C@  3 .R  LOOP

         DUP C@ 0x28 = IF DUP   8 + ( A At -- ) 0x10  M_DAN_EKRAN_T1 ( At Ndel=0x10 - отображение для ds18b20 - т.е. где первый код имс = 0x28 ) THEN

         DUP C@ 0x10 = IF DUP   8 + ( A At -- ) 0x2   M_DAN_EKRAN_T1 ( At Ndel=2    - отображение для ds1820 - т.е. где первый код имс = 0x10  ) THEN

         DROP ( убрали адрес )

            LOOP  ( печатаем номера и температуры  )

;

 

: M_DAN_WRITE_T1 ( At Ndel=0x10 - запись в файл для ds18b20 - т.е. где первый код имс = 0x28 )

   SWAP (  Ndel At -- )

   DUP   C@  SWAP 1+ C@ 0x100 * + ( T -- )  DUP 0xFFF >

    IF ( ОТРИЦАТЕЛЬНАЯ ВЫДАЧА  число более FFF т/е отрицательное )

        DUP  0xFFFF SWAP -   ( отнимаем для 16 разрядной адресации )

               S" -" ( знак минуса )

    ELSE DUP   S" +"  (  знак плюса   ) THEN  ( Ndel T T  A1 N1 )  FR1  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали знак )

    ( Ndel T T  --> показываем целое значение )

    DECIMAL  ROT  /    2 .RF  FR1  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали число целых )

          S" ," (  зпт )    FR1  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали запятую разделитель )

   ( Т ) 0xF AND (  ТОЛЬКО ЦЕЛАЯ ЧАСТЬ ) PKZ_M1 + C@  1 .RF  ( записываем )

                             FR1  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали дробную часть )

   S" _" 0x9 2 PICK C!       FR1  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали разделитель таб код 0x9 )

;

 

: M_DAN_WRITE_FILE ( запись данных в файле )

  IDAT 0 DO  ( запись по строчно данных темперутур и разделением как на экране а подготавливаем данные в BUF1 )

   BUF2 I 0x10 * + ( A -- )

         DUP C@ 0x28 = IF DUP   8 + ( A At -- ) 0x10  M_DAN_WRITE_T1 ( At Ndel=0x10 - запись в файл для ds18b20 - т.е. где первый код имс = 0x28 ) THEN

         DUP C@ 0x10 = IF DUP   8 + ( A At -- ) 0x2   M_DAN_WRITE_T1 ( At Ndel=2    - запись в файл для ds1820 - т.е. где первый код имс = 0x10  ) THEN

         DROP ( убрали адрес )

       LOOP

    S" __" ( A1 N=1 )  0xD 2 PICK C!  ( код ВК )  0xA 2 PICK 1+ C! FR1   WRITE-FILE ( c-addr u fileid -- ior ) DROP ( 2а байта перевода строки )

;

 

: M_DAN_TRW ( At Ndel=2    - 0/-1 контроль предела для ds1820 только для Ттрв > 0 гр  )

   SWAP (  Ndel At -- )    DUP   C@  SWAP 1+ C@ 0x100 * + (  Ndel T   --> проверка целого значения )

    SWAP  /   ( Tцел_изм  -- ) T_TRWG   > (  pz -- ) 

   ;

 

: M_USLOVIJ (  0/-1 – проверка условий )

   0 (  PZ -- признак в стеке что нет превышения температур  ставим заранее и убираем если будет превышение в проверке условия )

   IDAT 0 DO  (  цикл проверки по каждому датчику если превышен то выход по тревоге )

   BUF2 I 0x10 * + ( PZ A -- )

       DUP C@ 0x28 = IF DUP   8 + ( A At -- ) 0x10  M_DAN_TRW ( At Ndel=0x10 - 0/-1 контроль предела для ds18b20 ) IF ( PZ A -- )  2DROP -1 LEAVE  THEN  THEN

       DUP C@ 0x10 = IF DUP   8 + ( A At -- ) 0x2   M_DAN_TRW ( At Ndel=2    - 0/-1 контроль предела для ds1820  ) IF ( PZ A -- )  2DROP -1 LEAVE  THEN  THEN

      ( PZ A -- )  DROP ( PZ --  убрали адрес )

     LOOP ( PZ -- )     ;

 

: M_GRN_EKRAN ( отображение на экране )

   CR  S" Текущее время/чч:мм:cc/ :" ANSI>OEM TYPE 

   TIME ( cc мм чч  -->    время системы  в стек )

   DECIMAL  3 .R  S" :" TYPE   3 .R S" :"  TYPE  3 .R

   S"  Превышен заданных предел гр = " ANSI>OEM TYPE  

   T_TRWG  3 .R

;

:  M_GRN_EKRAN_CLS ( очистка сообщений на экране )

  CR  0x50 SPACES ( передаем 0x40 пробеллов на экран где было сообщение )

  ;

 

: M_DAN_WRITE_T2 ( At Ndel=0x10 - запись в файл fr2 для ds18b20 - т.е. где первый код имс = 0x28 )

   SWAP (  Ndel At -- )

   DUP   C@  SWAP 1+ C@ 0x100 * + ( T -- )  DUP 0xFFF >

    IF ( ОТРИЦАТЕЛЬНАЯ ВЫДАЧА  число более FFF т/е отрицательное )

        DUP  0xFFFF SWAP -   ( отнимаем для 16 разрядной адресации )

               S" -" ( знак минуса )

    ELSE DUP   S" +"  (  знак плюса   ) THEN  ( Ndel T T  A1 N1 )  FR2  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали знак )

    ( Ndel T T  --> показываем целое значение )

    DECIMAL  ROT  /    2 .RF  FR2  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали число целых )

          S" ," (  зпт )    FR2  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали запятую разделитель )

   ( Т ) 0xF AND (  ТОЛЬКО ЦЕЛАЯ ЧАСТЬ ) PKZ_M1 + C@  1 .RF  ( записываем )

                             FR2  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали дробную часть )

   S" _" 0x9 2 PICK C!       FR2  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали разделитель таб код 0x9 )

;

 

 

: M_GRN_WRITE (  запись границы в файле )

  \ записываем время события и температуры датчиков но файл c описателем FR2

   DECIMAL TIME ( cc мм чч  -->    время системы  в стек )

   3 .RF                FR2  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали час )

   S" :"  (  знак    )  FR2  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали знак )    

   3 .RF                FR2  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали минуты )

   S" :"  (  знак    )  FR2  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали знак )

   3 .RF                FR2  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали секунды )           

   S" _" 0x9 2 PICK C!  FR2  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали разделитель таб код 0x9 )  

 

  IDAT 0 DO  ( запись по строчно данных темперутур и разделением как на экране а подготавливаем данные в BUF1 )

   BUF2 I 0x10 * + ( A -- )

         DUP C@ 0x28 = IF DUP   8 + ( A At -- ) 0x10  M_DAN_WRITE_T2 ( At Ndel=0x10 - запись в файл fr2 для ds18b20 - т.е. где первый код имс = 0x28 ) THEN

         DUP C@ 0x10 = IF DUP   8 + ( A At -- ) 0x2   M_DAN_WRITE_T2 ( At Ndel=2    - запись в файл fr2 для ds1820 - т.е. где первый код имс = 0x10  ) THEN

         DROP ( убрали адрес )

       LOOP

    S" __" ( A1 N=1 )  0xD 2 PICK C!  ( код ВК )  0xA 2 PICK 1+ C! FR2   WRITE-FILE ( c-addr u fileid -- ior ) DROP ( 2а байта перевода строки )

 ;

 

: M_OUT_WORK (  0/-1 проверка условий выхода )   ?KEY1   0x1B = (  -1 при нажатик клавиши ESC ) ;

 

: M_ZAVERCHEN ( завершение  )

    FR1 CLOSE-FILE ( fileid -- ior  закрыли файл )  DROP

    FR2 CLOSE-FILE ( fileid -- ior  закрыли файл )  DROP   

    BUF2 FREE DROP (  освободили память )

    BUF1 FREE DROP (  освободили память )

    handle1  TMEndSession  DROP ( и закрыли ее 0=err 1ok )

    BYE

;

 

\  главное слово мониторинга

: MAIN  (  главное слово   )

M_PODGOTOVKA ( подготовка )

BEGIN

     M_DAN_READ ( получение данных )

     M_DAN_EKRAN ( отображение на экране )

     M_DAN_WRITE_FILE ( запись данных в файле )

     M_USLOVIJ (  0/-1 – проверка условий )

  IF ( да – индикация. Граница  нарушена )

     M_GRN_EKRAN ( отображение на экране )

     M_GRN_WRITE (  запись границы в файле )

  ELSE ( нет -  все нормально )

     M_GRN_EKRAN_CLS ( очистка сообщений на экране )

  THEN

    M_OUT_WORK (  0/-1 проверка условий выхода )

    ( 0/-1 –  значение в стеке  )

UNTIL  ( выход из цикла если будет -1 или  к begin)

     M_ZAVERCHEN ( завершение  )

 ;

 

\  подготавливаем переменные  и текст программы записываем в исполняемый файл.

0  TO SPF-INIT?  (   в переменную записываем код 0 – означает что инициализация выполняется )

 '  NOOP MAINX !  ( в переменную записываем адрес выхода )

 '  MAIN   TO <MAIN>  ( в переменную записываем  старт программы со слова MAIN   ) 

S" test2.exe" SAVE (  сохраняем файл исполнения  с именем  test2.exe )

BYE (  выходим из режима редактирования и компиляция, т.е. все бай-бай )

\  текст программы окончен.

 

 

Если адаптер не установился или его нет, то выдается сообщение, в противном случае отображаются показания датчиков, показано ниже на рисунке.

 

 

 

Отвлечение руководителя анекдот  - на лекции не озвучивать;

  • Цветы для девушки - то же самое, что и носки для мужика - сначала обязательно надо понюхать.  

 

Один поток и много потоков. Что лучше?

Программа, приведенная в качестве мониторинга, выполнена в режиме одного потока. Это означает:

Но это все очень условное разделение. Исходить надо из требований к процессу измерения и реализации получаемых данных.

Получаемые данные, отображают какое-то явление или процесс.

Например:

 

Что бы выполнить требования в измерениях  с разными временами обращения используют разные потоки. А обмен данных между ними выполняют через выделенные области памяти.  Ниже блок схема измерения, в котором 5-ть потоков.

 

 

 

Для понимания возможностей и работы потоков в мониторинге рассмотрим  программу с 2-мя  дополнительными потоками. Используем  программу мониторинга и ее  основу алгоритма. А вместо датчика температуры и показаний температуры, используем как параметр -  время нажатия одной клавиши – например = клавиша= 1 .  код = 0x30

Программа измеряет время двойного нажатия данной клавиши в миллисекундах. Отображает значение и пишет время события с данными в файл.  Алгоритм  представлен ниже на рисунке.

 

CREATE BUF1  0x100  ALLOT ( заняли память в 0x100 байт для обмена данными между потоками )

CREATE  FR1 0 ,  (  переменная для идентификатора потока  что бы его можно было остановить )

: POTOK (  слово определяющее поток  начало с «двоеточия» )

* * *  * * *  * * *  * * *

( в теле потока могут быть любые новые слова программы )

* * *    * * *  * * *     * * *

;  (  последний знак  - «тчк-зпт» )

  POTOK ( Aисполнения ) ТASK:  exPOTOK !  (  cохранили  адрес  слова определяющее поток  для  отдельного старта )

 

* * *          * * *   

:  PODGOTOVKA (   в теле подготовки  запускаем новый поток )

BUF1  exPOTOK START  ( FR -- )  FR1 !  (  сохранили идентификатор созданного потока )  

; 

FR1 @  STOP (  останов потока )

 

 

\ начало  текста

\ программа учета времени двойного нажатия клавиши 1 и ее отображения.  

 

 WINAPI:   SetConsoleCursorPosition  KERNEL32.DLL

 WINAPI:   SetConsoleTextAttribute   KERNEL32.DLL

 WINAPI:   MessageBeep               USER32.DLL ( пищание системного динамика )

 WINAPI:   Beep                      KERNEL32.DLL ( звучит звуковое устройство т-МС  F-ГЦ -- )

 WINAPI:   GetLocalTime              KERNEL32.DLL ( читаем локальное т.е. установленное на компьютере время )

 WINAPI:   GetTickCount              KERNEL32.DLL  (  время c начала загрузки мс в системе )

 

\  резервируем переменные и константы для работы

0   VALUE  BUF1     (  глобальная переменная для сохранения адресов буферов переменных )

0   VALUE  BUF2     (  глобальная переменная для сохранения адресов буферов данных датчиков )

0   VALUE  In       (  глобальная переменная для временого хранения индекса )

0x8 CONSTANT NDAT ( максимальное количество датчиков на одном адаптере )

0   VALUE  IDAT       (  глобальная переменная для  обнаруженных датчиков на линии  )

0   VALUE  Nizm       (  глобальная переменная для  подсчета количества измерений  )

: NAME_DAN  S" file_dan.xls" ; ( имя файла данных температур )

CREATE   FR1   0 ,  0 , (  указатель для файла данных и указатель для потока в 4+ ячейке  )

 

 

DECIMAL

  5000 CONSTANT T_TRWG (  время превышения нажатия в миллисекундах )

0  VALUE  PZ_N ( переменая нажатия 0 нет 1 одно нажатие 2 - два нажатия )  

0   VALUE  FR3 (  указатель для  потока времени нажатия ) 

 

 

: TIME_SOST_WORKS ( -- wsec  )

\ время работы с момента старта в мс 

  GetTickCount ( мили секунда ) ;

 

 

\ описываем требуемые слова для работы главного слова мониторинга

CREATE  SYSTEMTIME  0x10 ALLOT ( память под данные для системного времени )

\ для наглядного вызова часов минут и тд области памяти в выделенной области обозначены через отдельные слова

: wYear            0 + ;

: wMonth           2 + ;

: wDayOfWeek       4 + ;

: wDay             6 + ;

: wHour            8 + ;

: wMinute        0xA + ;

: wSecond        0xC + ;

: wMilliseconds  0xE + ;

 

: TIME&DATE1 ( -- wsec sec min hr day mt year )

  SYSTEMTIME GetLocalTime DROP

  SYSTEMTIME wMilliseconds  W@  ( мили секунда )

  SYSTEMTIME wSecond        W@  ( секунда )

  SYSTEMTIME wMinute        W@  ( минута )

  SYSTEMTIME wHour          W@  ( час )

  SYSTEMTIME wDay           W@  ( день )

  SYSTEMTIME wMonth         W@  ( месяц )

  SYSTEMTIME wYear          W@  ( год )

;

 

: TIME ( cc мм чч  -->    время системы  в стек )

     SYSTEMTIME GetLocalTime DROP

     SYSTEMTIME wSecond W@  ( секунда )

     SYSTEMTIME wMinute W@  ( минута )

     SYSTEMTIME wHour W@    ( час )

     ;

 

: TEXT-ATTR ( fg bg -- установка цвета знака fg фона bg )   0x10 * + H-STDOUT SetConsoleTextAttribute DROP ;

: UST_ATR_LIM_CMD     0xF  8    TEXT-ATTR ( fg bg -- установка цветности вариант  )   ;

: UST_ATR_LIM1_CMD    0xF  5    TEXT-ATTR ( fg bg -- установка цветности вариант 1 тревоги ) ;

: UST_ATR_LIM2_CMD    0xF  0xA  TEXT-ATTR ( fg bg -- установка цветности вариант 2 тревоги )   ;

: UST_ATR_NORM_CMD    0x7  0    TEXT-ATTR ( fg bg -- установка цветности исходное  для терминала )  ;

 

: GotoXY ( x y --  установка координаты курсора в консоли. )

  0x10000 * +   H-STDOUT SetConsoleCursorPosition DROP

;

: ZWUK (   Т-мс F-гц --- )   Beep DROP  ;

: BEEP_M2 (  цыганочка с входом вар2  )

 0x60 0x900   ZWUK    0x60 0x800   ZWUK   0x60 0x700   ZWUK   0x60 0x600   ZWUK   0x60 0x500   ZWUK  ;

 

: FIX ( M --> ) 0x100 /MOD   GotoXY ( x y -- ) ;

: .RF ( форматирование без выдачи это литерал числа )

  >R DUP >R ABS    S>D <# #S R> SIGN #>     R> OVER - 0 MAX SPACES    ;

: .R ( n1 n2 --   форматный вывод n1 по размеру n2 )   .RF  TYPE ;

: PAUSE1 ( N --> пауза в N  миллисекунд 0> )  Sleep DROP ;

: ?KEY1  ( K --> код клавиши ) KEY? IF KEY    ELSE 0  THEN ;

: ZWUK_TRW1 ( три тревожных звонка ) 3 0 DO 0x80 PAUSE1  0x40 MessageBeep  DROP  ( ВЫДАЕТСЯ ЗВУК ПИЩАЛКИ ДИНАМИКА ) LOOP ;

 

\  контрольные слова для отладки программы

: STOP1 BEGIN ?KEY1 DUP 0x1B = IF BYE THEN 0x20 = UNTIL ;

CREATE KKS_B  0 ,

: KKS ( распечатаь штатными средствами и предупреждение о исчерпании стека )

  BASE @ KKS_B ! ( систему счисления  на сохранение )

  CR ."  ctk,N--> " DECIMAL

  DEPTH DUP 1 < IF  DUP 0= IF  .  S"  Стек пустой!" ( при 0 )

                           ELSE  DROP S" ОШИБКА - СТЕК ИСЧЕРПАН !!! "

                           THEN   ANSI>OEM TYPE

                ELSE  DUP  .  HEX ."  = "   .SN

                THEN      S"   --> верх " ANSI>OEM TYPE

       KKS_B @ BASE ! ( вернули систему счисления  )      ;

 

 

: WORK_IZM_NAGIMA ( A=BUF1 -- поток  который измеряет время нажатия клавиши )

   ( Abuf1 -- aдрес где время храниться  )

   BEGIN

   PZ_N 1 = IF  DUP 4 +  DUP @ 0= IF -1 SWAP !   TIME_SOST_WORKS  ( -- wsec  ) OVER !  ELSE DROP THEN   THEN

   PZ_N 2 = IF  DUP 4 + 0!  0 TO PZ_N  TIME_SOST_WORKS  ( -- wsec  ) OVER @  -   OVER 8 + !

              -1 OVER 3 4 * + !    ( установили признак для записи в файл данных )

               THEN

        0 UNTIL

;

 

' WORK_IZM_NAGIMA TASK: exWORK_IZM_NAGIMA  (  подготовлено слово для запуска потока  измерения )

 

 

: WORK_FILE_NAGIMA_T1 ( Abuf1 --- Abuf1 ---   запись данных в файл )

\  измеренные данные времени нажатия находяться в области 8 + от начала их и выдаем но в начале текущее время

  \ записываем время события и температуры датчиков но файл c описателем FR2

   DECIMAL TIME ( cc мм чч  -->    время системы  в стек )

   3 .RF                FR1 @  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали час )

   S" :"  (  знак    )  FR1 @  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали знак )    

   3 .RF                FR1 @  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали минуты )

   S" :"  (  знак    )  FR1 @ WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали знак )

   3 .RF                FR1 @  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали секунды )           

   S" _" 0x9 2 PICK C!  FR1 @  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали разделитель таб код 0x9 )  

  \ --------------------------------------------------------------------------

   DUP 8 + @  9  .RF  FR1 @  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали число  миллисекунд )

   S" _" 0x9 2 PICK C!  FR1 @  WRITE-FILE ( c-addr u fileid -- ior ) DROP (  записали разделитель таб код 0x9 )  

   S" __" ( A1 N=1 )  0xD 2 PICK C!  ( код ВК )  0xA 2 PICK 1+ C! FR1 @   WRITE-FILE ( c-addr u fileid -- ior ) DROP ( 2а байта перевода строки )

 

;

 

 

: WORK_FILE_NAGIMA ( A=BUF1 -- поток  который  записывае в файл время нажатия клавиши )

   ( Abuf1 -- aдрес где все  храниться  )

   BEGIN

       DUP  3 4 * + DUP @     (   признак для записи в файл данных -1/0  )

       IF 0! ( сбрасываем и переходим к записи в файл )

             WORK_FILE_NAGIMA_T1 ( Abuf1 --- Abuf1 ---   запись данных в файл )

       ELSE DROP THEN      

        0 UNTIL

;

 

' WORK_FILE_NAGIMA TASK: exWORK_FILE_NAGIMA  (  подготовлено слово для запуска потока записи в файл )

 

 

 

 

 

: M_PODGOTOVKA (  К - подготовка )

    S"  Учет времени двойного нажатия клавиши 1 "  ANSI>OEM TYPE 

 CR S"  Выход из программы клавиша - ESC "                    ANSI>OEM TYPE 

 

 

  \   STARTLOG ( ВКЛЮЧИТЬ ФАЙЛ ОТЧЕТА SPF.LOG )

 \   ENDLOG (  выключить файл отчета )   

 

NAME_DAN   R/W CREATE-FILE  DROP ( FR -- )  FR1 !

 (  cоздали файл для записи и чтения  и сохранили указатель на файл )

0x10         ALLOCATE THROW TO BUF1

( заняли временную память и записали адрес ее  начало в локальную перменную BUF1 )

0x10 NDAT *  ALLOCATE THROW TO BUF2

BUF1 exWORK_IZM_NAGIMA   START  TO FR3  ( запустили поток для измерения времени нажатия )

BUF1 exWORK_FILE_NAGIMA  START  FR1 4 + !   ( запустили поток для измерения времени нажатия )

?KEY1 (  K - код нажатия выдали сразу же )    

;

 

 

: M_DAN_READ ( K - K  получение данных )

  DUP [CHAR] 1 = IF PZ_N 1+ TO PZ_N THEN ( при нажатии увеличиваем значение признака )

  ;

\ ---------------------------------------------

 

: M_DAN_EKRAN ( K -- K  отображение на экране )

  DUP 0= IF EXIT THEN

  0x200 FIX S" Нажата клавиша : " ANSI>OEM TYPE     DUP  EMIT

  S"  время нажатия,мс = " ANSI>OEM TYPE    BUF1 8 + @  9 .R

  ;

 

 

: M_DAN_WRITE_FILE ( запись данных в файле )

;

 

: M_DAN_TRW ( At Ndel=2    - 0/-1 контроль предела для ds1820 только для Ттрв > 0 гр  )

 

   ;

 

: M_USLOVIJ (  0/-1 – проверка условий )

  0

 

 ;

 

: M_GRN_EKRAN ( отображение на экране )

\  0x300 FIX  DUP 0<> IF DUP EMIT THEN

 ;

:  M_GRN_EKRAN_CLS ( очистка сообщений на экране )

   ;

 

 

: M_GRN_WRITE (  запись границы в файле )

 ;

 

: M_OUT_WORK ( k1 - K2 0/-1 проверка условий выхода )

    DROP    ?KEY1 DUP    0x1B = (  K  PZ=-1  при нажатик клавиши ESC ) ;

 

: M_ZAVERCHEN ( завершение  )

    FR1 @ CLOSE-FILE ( fileid -- ior  закрыли файл )  DROP

    BUF2 FREE DROP (  освободили память )

    BUF1 FREE DROP (  освободили память )

    BYE

;

 

\  главное слово мониторинга

: MAIN  (  главное слово   )

M_PODGOTOVKA ( K - подготовка )

BEGIN ( K -- код нажатия на стеке )

     M_DAN_READ ( k -- получение данных )

     M_DAN_EKRAN ( отображение на экране )

     M_DAN_WRITE_FILE ( запись данных в файле )

     M_USLOVIJ (  0/-1 – проверка условий )

    

  IF ( да – индикация. Граница  нарушена )

     M_GRN_EKRAN ( отображение на экране )

     M_GRN_WRITE (  запись границы в файле )

  ELSE ( нет -  все нормально )

     M_GRN_EKRAN_CLS ( очистка сообщений на экране )

  THEN

    M_OUT_WORK (  Kkl 0/-1 проверка условий выхода )

UNTIL  ( выход из цикла если будет -1 или  к begin)

     M_ZAVERCHEN ( K завершение  )

 ;

 

\  подготавливаем переменные  и текст программы записываем в исполняемый файл.

0  TO SPF-INIT?  (   в переменную записываем код 0 – означает что инициализация выполняется )

 '  NOOP MAINX !  ( в переменную записываем адрес выхода )

 '  MAIN   TO <MAIN>  ( в переменную записываем  старт программы со слова MAIN   ) 

S" test2.exe" SAVE (  сохраняем файл исполнения  с именем  test2.exe )

BYE (  выходим из режима редактирования и компиляция, т.е. все бай-бай )

\  текст программы окончен.

 

 

Отвлечение руководителя анекдот  - на лекции не озвучивать;

·  Скромность красит человека. В серенький цвет.

 

Список задач на поточное  программирование;           

 

Модификация – 1-й уровень понимания.

  1. В программе температурных датчиков ввести в меню  кнопку, которая при отсутствии датчиков, выполняет переход к диспетчеру устройств.
  2. В программе 2-го нажатия клавиши изменить выбор клавиши на клавишу =0= 
  3. В программе 2-го  нажатия клавиши выдавать звуковое подтверждения 1го нажатия
  4. В программе 2-го  нажатия клавиши  выдавать звуковое подтверждение 2-го нажатия
  5. В программе 2-го нажатия клавиши  выдавать количество нажатий всего

Новые свойства – 2-ой уровень понимания.

  1. В программе температурных датчиков не останавливать программу, продолжать выполнение, но отображать  ошибку.
  2. В программе температурных датчиков не останавливать программу, а вместо данных выдавать эквивалент – время секунд компьютера.
  3. В программе температурных датчиков не останавливать программу, а вместо данных выдавать датчиком случайных чисел температуры в интервале  20. 40 градусов
  4. В программе  2-го нажатия клавиши изменить измерение. Ввести контроль на превышение 2-го нажатия. Если более 5 секунд один раз нажата – выдавать сообщение и сбрасывать начало измерения.
  5. В программе 2-го нажатия   ввести 3-ий поток для измерения 2х клавиш нажатия. Т.е. контролировать не только клавишу 1 но и клавишу 2 Запись оставить в  прежнем варианте

Изменения алгоритма – 3-ий уровень понимания и создания.

  1. Программу температурных датчиков выполнить с 3-мя потоками. Основной с показаниями данных , измерение температур,  и запись данных в файл.
  2. Изменить тип внешних устройств.   Опрос фотодатчика подключенного к 1-wire. Предложить схему.  Алгоритм и программу.
  3. Программа мониторинга данных из файла данных на своем компьютере. По локальной сети. Из данных в интернете.

Задача практической полезности

  1. Программа для мониторинга  =идентификации= почерка нажатия клавиш. Цель программы идентифицировать  клавиатурный почерк

 

Внимание! Задачи  выполняются  и передаются руководителю на электронную почту  с соблюдением правил оформления.  Архив должен содержать; титульный лист – 1 файл, Текст задачи – на каждую задачу свой текстовый файл. Исполняемый файл. Имя текстового файла задачи должно соответствовать имени исполняемого файла.

 

На практических занятиях каждый обучаемый в группе должен выполнить выше, приведенные задачи. Решение и обоснование выбора решения, стиль отображения, ошибки в работе программы -  определяют оценку обучаемого.  Количество задач и их оценивание задано по условию =ИЛИ= Т.е. если предполагается  ответ на 5 то все предыдущие уровни предоставлять не надо.

 

Отвлечение руководителя анекдот  - на лекции не озвучивать;

·         Критика должна быть конструктивной. Оскорбления должны быть аргументированы. "Ты дурак, потому что ты идиот" - так, например.

Литература:

Внимание! – программы клавиатурного почерка могут иметь коммерческий статус или отсутствовать на сайтах  по предлагаемым, на этих сайтах  ссылкам.  Поиск и использование программ  не входит в тему данной лекции.

 

  Отвлечение руководителя анекдот - на лекции не озвучивать;

·         Ленивые всё делают быстро. Чтобы поскорее отделаться от работы.       И делают качественно. Чтобы потом не переделывать.

 

Выводы:

 

Подготовлено 10-3-2016

Автор Шабронов Андрей Анатольевич тс. 913-905-8839  shabronov@ngs.ru

Ред-2 -11-3-2016