Современные технологии автоматизации» («СТА») —  журнал для квалифицированных специалистов по промышленной автоматизации Форум СТА — современные технологии автоматизации Домашняя страница
Домашняя страница форума CTA Домашняя страница форума CTA > II. АСУТП и SCADA > Архив
  Активные темы Активные темы
  FAQ FAQ  Искать в форуме   Зарегистрироваться Зарегистрироваться  Вход в систему Вход в систему

Проблема с Stored

 Ответить Ответить
Автор
Сообщение
Vel_ Смотреть выпадающим
Действительный член
Действительный член


Присоединился: 25 Апрель 2006
Категория: Russian Federation
Online Status: Offline
Публикации: 116
Свойства публикации Свойства публикации   Ответить, цитируя автора - Vel_ Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Тема сообщения: Проблема с Stored
    Опубликовано: 25 Апрель 2006 09:49

Поясните, если кто сталкивался с подобной проблемой!

Для сохранения настроек регулятора в область памяти под батарейкой и последующего востановления после перезагрузки контроллера ADAM5510 используется Stored.obj, написанный на С++. Переменные сохраняются и востанавливаются, но возникает проблема. если превысить количество сохраняемых переменных (примерно > 40 типа Float)(Хотя Stored.obj должен сохранять 1000 байт (250 пер. типа Float), то сразу после загрузки программы в контроллер, PLCNET OPC Server еще конфигурируется, но через некоторое время конфигурирование происходит с ошибками (имена сетевых переменных, их количество и т.д.). При этом, если успеть сконфигурировать PLCNET OPC Server, то в дальнейшем данные при работе OPC считываются без проблем.

Vel
Наверх
Vel_ Смотреть выпадающим
Действительный член
Действительный член


Присоединился: 25 Апрель 2006
Категория: Russian Federation
Online Status: Offline
Публикации: 116
Свойства публикации Свойства публикации   Ответить, цитируя автора - Vel_ Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 26 Апрель 2006 06:07

Для пояснения исходник Stored.obj на С

#include <dos.h>

// константы
#define MAX_STOREDDATA   1000       // макс. размер буфера сохраняемых
        // переменных (в байтах)
// типы
typedef unsigned char BYTE;
//typedef unsigned char BOOL;
typedef enum { FALSE=0, TRUE=1 } BOOL;

// внешние объявления
extern _pascal STOREDMEM;           // начало области сохраняемых переменных
extern _pascal STOREDEND;           // конец области сохраняемых переменных
//extern _pascal BYTE RESTORE_STATUS; // статус программы RESTORE

// восстановление области STORED
void _pascal RestoreMem(void)
{
  int i,fsize;
  BYTE *pdata;

      // начало блока данных
      pdata=(BYTE*)&STOREDMEM;
      // размер блока данных (с ограничением по максимуму)
      fsize=(int)(&STOREDEND)-(int)(&STOREDMEM);
      if (fsize>MAX_STOREDDATA)
 fsize=MAX_STOREDDATA;
      // читаем блок данных
    // цикл
    for (i = 0x0; i < fsize; i++)
    {
 // запись
 *(pdata + i) = peekb(0x3000, i+0x1000);
    }

  // чтобы эта функция больше не вызывалась, записываем 0 в байт
  // статуса программы.
  //RESTORE_STATUS=0;
  // даже если восстановление не было успешным, в любом случае устанавливаем
  // признак выполнения операции восстановления (чтобы разрешить последующую
  // работу SaveMem)
  //IsRestored=TRUE;
}

// сохранение области STORED
void _pascal SaveMem(void)
{
  int i,fsize;
  BYTE *pdata;
  // начало блока данных
  pdata=(BYTE*)&STOREDMEM;
  // размер блока данных (с ограничением по максимуму)
  fsize=(int)(&STOREDEND)-(int)(&STOREDMEM);
  if (fsize>MAX_STOREDDATA)
    fsize=MAX_STOREDDATA;
  // запись выполняется, если:
  //  - до этого уже отработата ф-я RestoreMem
  //  - данные еще ни разу не были записаны или они изменились
    // цикл
    for (i = 0x0; i < fsize; i++)
     {
 // запись
 pokeb(0x3000, i + 0x1000, *(pdata + i));
     }

    // запись была выполнена хотя бы раз
   // IsSaved=TRUE;
}

Vel
Наверх
Vel_ Смотреть выпадающим
Действительный член
Действительный член


Присоединился: 25 Апрель 2006
Категория: Russian Federation
Online Status: Offline
Публикации: 116
Свойства публикации Свойства публикации   Ответить, цитируя автора - Vel_ Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 03 Май 2006 12:32

Проблема оказывается не в Stored.obj, а в компиляторе UL16. Если ставишь 80x86 C/CPP-compatible compiler, то тут и начинаются "чудеса".

K10.map - 80x86 processors family compiler

 Start  Stop   Length Name               Class

 00000H 084DBH 084DCH SYSTEM             CODE
 084DCH 086D7H 001FCH CONST              DATA
 086D8H 09B74H 0149DH DATA               DATA
 09B75H 0A3D3H 0085FH VARLIST            DATA
 0A3D4H 0A3D4H 00000H STORED             DATA
 0A3E0H 0B3DFH 01000H STACK              STACK

Program entry point at 0000:73EF

K10.map - 80x86 C/CPP-compatible compiler

 Start  Stop   Length Name               Class

 00000H 04831H 04832H _TEXT              CODE
 04840H 04840H 00000H _FARDATA           FAR_DATA
 04840H 04840H 00000H _FARBSS            FAR_BSS
 04840H 04840H 00000H _OVERLAY_          OVRINFO
 04840H 04840H 00000H _1STUB_            STUBSEG
 04840H 05705H 00EC6H _DATA              DATA
 05706H 05709H 00004H DATA               DATA
 0570AH 05719H 00010H _CONST             DATA
 0571AH 057D7H 000BEH CONST              DATA
 057D8H 057D8H 00000H _CVTSEG            DATA
 057D8H 057D8H 00000H _SCNSEG            DATA
 057D8H 05A7BH 002A4H VARLIST            DATA
 05A7CH 05ABCH 00041H STORED             DATA
 05ABEH 05B75H 000B8H _CONST             CONST
 05B76H 05B7BH 00006H _INIT_             INITDATA
 05B7CH 05B7CH 00000H _INITEND_          INITDATA
 05B7CH 05B7CH 00000H _EXIT_             EXITDATA
 05B7CH 05B7CH 00000H _EXITEND_          EXITDATA
 05B7CH 05BBBH 00040H _BSS               BSS
 05BBCH 05BBCH 00000H _BSSEND            BSSEND
 05BC0H 06C3FH 01080H _STACK             STACK

Program entry point at 0000:0000 (а точка входа - NILL)

И размер у выходного ехе без срр на 2,5 килобайта меньше.

Переделываю программу на чистом asm. Посже опубликую результат.

Vel
Наверх
Vel_ Смотреть выпадающим
Действительный член
Действительный член


Присоединился: 25 Апрель 2006
Категория: Russian Federation
Online Status: Offline
Публикации: 116
Свойства публикации Свойства публикации   Ответить, цитируя автора - Vel_ Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 04 Май 2006 06:51

Проблема решена!

Расширил функциональность подпрограммы: теперь ведется контроль перекомпиляции проекта, для этого в проекте должна быть создана глобальная переменная Stored и ей присваевается значение по умолчанию (отличное от предыдущего проекта). При перекомпиляции сохраняемые переменные берут значения по умолчанию (раньше требовался код FBD для установки значений). Программа Restore автоматически останавливается и останавливает программу Save. Сохраняется 998 байт (проверено сохранением и востановлением 249 переменных Float). obj стал 552 байта вместо 838.

Требования:

1) Должна быть создана глобальная переменная Stored и ей присваевается значение по умолчанию (отличное от предыдущего проекта).

2) Первой в проекте UL должена быть программа Restore "EXT" (статус - Start  ( Auto Run ) с функцией RESTOREMEM.

3) Вторая программа Save "EXT" (статус - Stop) с функцией SAVEMEM.

4) Где нибудь в программе должен быть вызов GCALL программы Save (по времени или как хотите).

5) obj собирается командой \TASM.EXE storedn.asm

6) В папке проекта UL создается *.lnk файл с атрибутом "Только чтение"  и содержанием:

C:\K11\K11.OBJ+
C:\K11\STOREDN.OBJ
C:\K11\K11.EXE

7) В проекте Ul, в опциях указать "80x86 processors family compiler", а не "80x86 C/CPP-compatible compiler".

В итоге все прекрасно работает, *.exe файл на 2,5 Кб меньше.

Вывод: не использовать "80x86 C/CPP-compatible compiler" и писать подпрограммы на asm.

Vel
Наверх
Vel_ Смотреть выпадающим
Действительный член
Действительный член


Присоединился: 25 Апрель 2006
Категория: Russian Federation
Online Status: Offline
Публикации: 116
Свойства публикации Свойства публикации   Ответить, цитируя автора - Vel_ Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 04 Май 2006 06:52

;г=========================================================================ї
; і Объектный файл для UltraLogik 16
; і Сохраняемые переменные
; і (вариант 1)
; L=========================================================================

; Объединить несколько сегментов в группу,
; адресуемую с помощью одного сегментного регистра: Group
DGROUP  group VARLIST,DATA,STORED

; ===========================================================================
; Указание на сегмент: Externs
     extrn RESTORE_STATUS:far ; переменная - статус работы программы RESTORE
     extrn SAVE_STATUS:far    ; переменная - статус работы программы SAVE
     extrn STORED_VAR:far     ; переменная - контроль перекомпиляции проекта
 extrn STOREDMEM:far  ; Начало сегмента сохраняемых переменных
 extrn STOREDEND:far  ; Окончание сегмента сохраняемых переменных

; ===========================================================================
; Сегмент :code
SYSTEM  segment byte public 'CODE' use16
  assume ds:DGROUP, cs:SYSTEM
  
Seg_DGROUP    dw seg DGROUP
; Функция восстановления сохряняемых переменных
  public RESTOREMEM
RESTOREMEM proc near

 push    ax       ; сохранить предыдущий ax в стек
        push    es       ; сохранить предыдущий es в стек
        push    si       ; сохранить предыдущий si в стек
        push    ds       ; сохранить предыдущий ds в стек
        push    dx       ; сохранить предыдущий dx в стек
        push    bx       ; сохранить предыдущий bx в стек
       
     mov     ax, 3000h    ; в ах адресс начала области с питанием от батарейки
     mov     es, ax       ; в es адресс из ах "начало области с питанием от батарейки"
     mov     ds, word ptr cs:Seg_DGROUP ; устанавливаем ds:DGROUP
 mov ax, word ptr ds:STORED_VAR  ; получаем значение переменной STORED типа integer (глобальная) в которой
                                        ; "значение по умолчанию" сравнивается с данными по адресу 30000-30001
     xor     si, si       ; обнуление регистра si
     cmp  ax, word ptr es:[si]   ; сравниваем ax с (STORED из памяти под батарейкой)
 je  Metka_0             ; если равны, то переход на Metka_0
    ; иначе
 jmp Exit             ; безусловный переход: выход из подпрограммы

Metka_0:
 mov ax, offset STOREDEND  ; адресс конца блока (сегмента) сохраняемых перен. в регистр ax
 sub ax, offset STOREDMEM  ; вычитаем из ах адресс начала блока (сегмента)
                               ; сохраняемых перен. и получаем в ах количество
                               ; байт (размер) области сохраняемых перен.
 mov dx, ax       ; записываем в dx полученный в ах результат вычислений
 cmp dx, 3E8h     ; сравниваем dx с (1000)
 jle Metka_1      ; если dx меньше или равнен (1000), то переход на Metka_1
 mov dx, 3E8h     ; если dx больше (1000), то dx ограничиваем до (1000)

Metka_1:
 jmp Metka_3        ; безусловный переход:

Metka_2:
 mov al, byte ptr es:[si+2]   ; один байт в al, из области с питанием от батарейки
 mov bx, offset STOREDMEM  ; в bx - адресс начала блока (сегмента) сохраняемых перенных
 add bx, si      ; сложение bx и si, в bx следующий адресс блока (сегмента)
                 ; сохраняемых перенных, для записи бита из области STORED
 mov byte ptr ds:[bx], al  ; запись бита в ячейку блока (сегмента) сохраняемых перенных
 inc si          ; инкремент: увеличивает приемник (регистр) на 1
                 ; (перевод на следующий бит)

Metka_3:
 cmp si, dx      ; сравниваем si с dx
 jl Metka_2     ; если si меньше dx, то переход на метку Metka_2

Exit:
        mov    byte ptr ds:SAVE_STATUS, 0     ; останавливаем программу SAVE
        mov    byte ptr ds:RESTORE_STATUS, 0  ; останавливаем программу RESTORE
       
        pop    bx       ; восстановить bx основной программы
        pop    dx       ; восстановить dx основной программы
 pop    ds       ; восстановить ds основной программы
 pop    si       ; восстановить si основной программы
        pop    es       ; восстановить es основной программы
        pop    ax       ; восстановить ax основной программы
       
 call SAVEMEM    ; вызов программы сохранения в область под батарейкой

  retn         ; вернуться в основную программу
RESTOREMEM endp

; ---------------------------------------------------------------------------

  public SAVEMEM
SAVEMEM  proc near

 push    ax       ; сохранить предыдущий ax в стек
        push    ds       ; сохранить предыдущий ds в стек
 push    di       ; сохранить предыдущий di в стек
        push    es       ; сохранить предыдущий es в стек
        push    cx       ; сохранить предыдущий cx в стек
        push    bx       ; сохранить предыдущий bx в стек
  
     mov     ax, 3000h   ; в ах адресс начала области с питанием от батарейки
     mov     es, ax      ; в es адресс из ах "начало области с питанием от батарейки"  
     mov     ds, word ptr cs:Seg_DGROUP ; устанавливаем ds:DGROUP
 mov ax, word ptr ds:STORED_VAR  ; получаем значение переменной STORED типа integer (глобальная)
 xor     di, di      ; обнуление регистра di
 mov word ptr es:[di], ax  ; записываем в область под батарейкой значение STORED_VAR
 mov ax, offset STOREDEND   ; адресс конца блока (сегмента) сохраняемых перен. в регистр ax
 sub ax, offset STOREDMEM   ; вычитаем из ах адресс начала блока (сегмента)
                                ; сохраняемых перен. и получаем в ах количество
                                ; байт (размер) области сохраняемых перен.
 mov cx, ax         ; записываем в cx полученный в ах результат вычислений
 cmp cx, 3E8h       ; сравниваем cx с (1000)
  jle Metka_4       ; если cx меньше или равнен (1000), то переход на Metka_4
 mov cx, 3E8h      ; если cx больше (1000), то cx ограничиваем до (1000)

Metka_4:
 jmp Metka_6   ; безусловный переход:  short (короткий переход) если

Metka_5:
 mov bx, offset STOREDMEM ; в bx - адресс начала блока (сегмента) сохраняемых перенных
 add bx, di             ; получаем адресс бита в сегменте сохр. переменных
 mov dl, byte ptr ds:[bx]    ; значение бита из сегмента сохр. перем. в dl
 mov byte ptr es:[di+2], dl  ; в es+смещение (адрес в области с питанием от
                          ; батарейки) записываем бит из сегмента сохр. перем.
 inc di                 ; инкремент: увеличивает приемник (регистр) на 1
                         ; (перевод на следующий бит)

Metka_6:
 cmp di, cx     ; сравниваем di с cx для условного перехода jl
 jl Metka_5    ; если di меньше cx, то переход на Metka_5

 pop    bx       ; восстановить bx основной программы
 pop    cx       ; восстановить cx основной программы
 pop    es       ; восстановить es основной программы  
 pop    di       ; восстановить di основной программы
 pop    ds       ; восстановить ds основной программы
 pop    ax       ; восстановить ax основной программы

 retn           ; вернуться в основную программу
SAVEMEM  endp

SYSTEM  ends


; ===========================================================================
VARLIST  segment byte public 'DATA' use16
  assume ds:DGROUP
VARLIST  ends

; ===========================================================================
DATA  segment byte public 'DATA' use16
  assume ds:DGROUP
DATA  ends

; ===========================================================================
STORED  segment byte public 'DATA' use16
  assume ds:DGROUP
STORED  ends

  end

Vel
Наверх
sermon Смотреть выпадающим
Новичок
Новичок


Присоединился: 07 Сентябрь 2005
Категория: Russian Federation
Online Status: Offline
Публикации: 35
Свойства публикации Свойства публикации   Ответить, цитируя автора - sermon Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 04 Май 2006 09:24
Спасибо, примем к сведению.
Хотя у меня штатный stored.obj (на C++) работает нормально, может переменных не так много. Правда, на UL32.
Наверх
Mast Смотреть выпадающим
Новичок
Новичок


Присоединился: 12 Май 2006
Категория: Kazakhstan
Online Status: Offline
Публикации: 5
Свойства публикации Свойства публикации   Ответить, цитируя автора - Mast Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 18 Май 2006 14:38
Первоначально опубликовано Vel_

Проблема решена!

Расширил функциональность подпрограммы: теперь ведется контроль перекомпиляции проекта, для этого в проекте должна быть создана глобальная переменная Stored и ей присваевается значение по умолчанию (отличное от предыдущего проекта). При перекомпиляции сохраняемые переменные берут значения по умолчанию (раньше требовался код FBD для установки значений). Программа Restore автоматически останавливается и останавливает программу Save. Сохраняется 998 байт (проверено сохранением и востановлением 249 переменных Float). obj стал 552 байта вместо 838.

Я для управления програмой Restore при первом запуске использовал тумблер от NODE ID :

        mov dx,0138h ; Порт переключателей NODE ID
        in al,dx
        and al,80h      ; Верхний переключатель
        jz @Exit          ; Выход из программы Restore

Использование тумблера позволяет выбирать сохраняемые переменные берут значения по умолчанию или востанавливаются из энергонезависимой памяти

 

Наверх
Vel_ Смотреть выпадающим
Действительный член
Действительный член


Присоединился: 25 Апрель 2006
Категория: Russian Federation
Online Status: Offline
Публикации: 116
Свойства публикации Свойства публикации   Ответить, цитируя автора - Vel_ Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 19 Май 2006 05:05

А если сетевой адресс контроллера задается DIP переключателем, то будут создаваться определенные "неудобства".

В моей программе вы заранее определяете, взять зачения из энергонезависимой области (оставить старое значение Stored в проекте) или записать значения по умолчанию (записать новое значение Stored в проект).

Vel
Наверх
Mast Смотреть выпадающим
Новичок
Новичок


Присоединился: 12 Май 2006
Категория: Kazakhstan
Online Status: Offline
Публикации: 5
Свойства публикации Свойства публикации   Ответить, цитируя автора - Mast Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 19 Май 2006 12:01
Первоначально опубликовано Vel_

А если сетевой адресс контроллера задается DIP переключателем, то будут создаваться определенные "неудобства".

В моей программе вы заранее определяете, взять зачения из энергонезависимой области (оставить старое значение Stored в проекте) или записать значения по умолчанию (записать новое значение Stored в проект).

На счет неудобств согласен , но зато есть возможность перезапустить программу с установками по умолчанию в любой момент времени , что бывает иногда необходимо . 

Наверх
Vel_ Смотреть выпадающим
Действительный член
Действительный член


Присоединился: 25 Апрель 2006
Категория: Russian Federation
Online Status: Offline
Публикации: 116
Свойства публикации Свойства публикации   Ответить, цитируя автора - Vel_ Ответить, цитируя автора -  ОтветитьОтвет Прямая ссылка на эту публикацию Опубликовано: 22 Май 2006 05:19

В моей программе на ходу тоже можно установить значения по умолчанию. Для этого переменной Stored в проекте установите атрибуты "сохраняемая" и "сетевая". В дальнейшем можете по сети установить новое значение переменной Stored и перезагрузить (сбросить) контроллер. Все!

Vel
Наверх
 Ответить Ответить

Переход на форум Права доступа на форуме Смотреть выпадающим

Bulletin Board Software by Web Wiz Forums® version 9.64
Powered by Web Wiz Forums Free Express Edition
Copyright ©2001-2009 Web Wiz