PDA

Просмотр полной версии : Некорректная работа таблицы отображения данных (хранилища)



zaurm
30.04.2026, 13:35
Добрый день!

Прошу помощи.
Две одинаковые панели СП310-Р с одинаковым софтом.
В программе реализовано циклическое хранилище и таблица отображения данных.
Одна панель работает правильно.

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

Существует еще одна странность.
После нажатия кнопки очистки хранилище на неисправной панели не очищается и при записи на флешку записывается со всеми предыдущими значениями.

Ранее этот софт был отлажен и на одной панели работает так, как и задумано.

Кто-нибудь сталкивался с подобным поведением панели?

Панель работала несколько месяцев, данные записывались каждые 15 секунд.
Могли ли износиться ячейки флеш-памяти с указателями?

zaurm
30.04.2026, 14:02
UPD.:

Беглый расчет показывает, что количество циклов записи указателей превысил 100 тысяч раз, что для флеш-памяти может быть весьма критично.

Сдвиг адреса хранилища на 4 байта вернул панель к жизни (PWF 4096 > 4100).

Тогда возникает следующий вопрос — как можно преодолеть такой износ памяти, если такое, конечно, возможно.

kondor3000
30.04.2026, 15:44
UPD.:

Беглый расчет показывает, что количество циклов записи указателей превысил 100 тысяч раз, что для флеш-памяти может быть весьма критично.

Сдвиг адреса хранилища на 4 байта вернул панель к жизни (PWF 4096 > 4100).

Тогда возникает следующий вопрос — как можно преодолеть такой износ памяти, если такое, конечно, возможно.

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

zaurm
30.04.2026, 17:53
kondor3000, благодарю за ответ.

В общих чертах это понятно.
У меня данные появляются для сохранения каждые 7—8 секунд.
Самое простое и рациональное — это замена «Архивации в панели» на «Архивацию на USB»
Но мне при этом архив требуется отображать в «Таблице отображения данных».
И тут начинаются костыли.

Например.
Небольшой журнал в оперативной памяти.
Затем данные из него переписывать по адресам, по которым располагается журнал в долговременной памяти.
Все зависит от того, как реализована функция «Архивация в панели».
Если она на каждый регистр, данные из которого переносит, делает инкремент указателя,
то не имеет значения, как часто или редко мы перегружаем данные из ОЗУ в ПЗУ.
Указатель будет изнашиваться пропорционально переданному в журнал объему данных.

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

kondor3000
30.04.2026, 18:01
Всё делается проще, расширенный режим панели и смещайте адреса как хотите.
У Petera спросите https://owen.ru/forum/showthread.php?t=22915&p=482344&viewfull=1#post482344

zaurm
30.04.2026, 18:18
Буду разбираться, благодарю.

Ссылка по данной теме:
https://owen.ru/forum/showthread.php?t=25381

petera
30.04.2026, 22:04
kondor3000, благодарю за ответ.

В общих чертах это понятно.
У меня данные появляются для сохранения каждые 7—8 секунд.
Самое простое и рациональное — это замена «Архивации в панели» на «Архивацию на USB»
Но мне при этом архив требуется отображать в «Таблице отображения данных».
И тут начинаются костыли.

Например.
Небольшой журнал в оперативной памяти.
Затем данные из него переписывать по адресам, по которым располагается журнал в долговременной памяти.
Все зависит от того, как реализована функция «Архивация в панели».
Если она на каждый регистр, данные из которого переносит, делает инкремент указателя,
то не имеет значения, как часто или редко мы перегружаем данные из ОЗУ в ПЗУ.
Указатель будет изнашиваться пропорционально переданному в журнал объему данных.

Насколько помню, самостоятельно из скрипта записать данные в расположенную свыше 4096 байт долговременную память нельзя.
Во первых, пусть Вас не вводит в заблуждение название "Архивирование на USB"
На самом деле архивирование происходит в панели в регистрах, выделенных под хранилище
89063
И только когда заполнится хранилище, т.е. когда число выборок данных достигнет значения "Число строк для одной записи"
89064
в этот момент все хранилище будет записано в файл на USB
Если Вы вдруг решили сделать "Число строк для одной записи" равным 1, то учтите Ваша USB долго не протянет...
Нужно накапливать некоторое достаточное количество данных в хранилище панели.
Есть нюанс- если выбрать режим записи файла, например "Фиксированное имя" или "Название по дате", то каждый раз данные архива будут дописываться в конец одного и того же файла. Но в структуре элемента "Архивирования" есть ошибка, в нем есть флаг заполнения хранилища и когда он установлен, то происходит запись накопленного архива на USB, однако при этом флаг не сбрасывается и это вызывает появление повторных записей в архиве. Нужно ОБЯЗАТЕЛЬНО включить галку "Очистить регистры после экспорта"
89065
Т.к. хранилище оперативного архива в месте с "указателями" можно располагать в области PSW, то никакого износа "указателя" не будет.
Таблицу отображения данных, с включенным циклическим буфером, можно легко привязать к адресу оперативного хранилища "Архивирования на USB"
Либо делать ф.кнопкой импорт файла/файлов с USB по адресу таблицы отображения данных, при этом циклический буфер у таблицы должен быть выключен.

Как отобразить каталог файлов на USB, как выбрать имя файла из каталога, например для импорта архива в таблицу см. пример проекта тут https://owen.ru/forum/showthread.php?t=22915&p=479083&viewfull=1#post479083
89066
Путь сохранеия архивов на USB - Archives\TEST
режим сохранения - Имя по умолчанию
таким образом в папке Archives будут накапливаться файлы
TEST0001.csv
TEST0002.csv
.......................
TEST9999.csv
89069
Имеется возможность посмотреть список файлов на USB
89071 89074



Ссылка на видио https://disk.yandex.ru/i/eg8oA-8P5tz7og
Ссылка на рутубе https://rutube.ru/video/dd691ad7f2acc3b003072866e487c539/

https://www.youtube.com/watch?v=xqcLijmtdGI

zaurm
30.04.2026, 23:27
petera, грандиозное спасибо. Как и в прошлом году с этим же проектом,
так и сейчас — исчерпывающая помощь на профессиональном уровне.

zaurm
04.05.2026, 21:52
petera, отдельно выражаю Вам благодарность за набор средств под названием DeBug.
Без этого инструмента браться за любой более-менее сложный проект не имеет смысла.
С самого начала активно использую, сэкономлено уйма сил и времени.

Касательно темы. Изменение пользовательского опыта на постоянное включение внешнего
накопителя и работа с ним, как с внутренним журналом, не предусмотрено ТЗ и было отвергнуто.
Поэтому решил реализовать свою функцию «Архивирование в панели» так:
1. Запись в сам журнал, расположенный во внутренней энергонезависимой памяти, осуществляется в темпе
поступления измерений (7,5 сек.).
2. Обновление указателей циклического буфера осуществляются с интервалом 1,5-2 часа, т. к. именно они
изнашиваются при постоянной записи в журнал функцией «Архивирование в панели». Время рассчитано исходя
из срока службы панели — 10 лет и макс. количество циклов записи — 75 тыс.
Обновление указателей происходит либо по времени, либо по событиям:
а) переключение в окно «Архив»; б) кнопка экспорта журнала на USB-накопитель; в) например, кнопка «Обновить»,
которую предполагаю добавить в окно «Архив».

Остается такое ограничение — «Таблица отображения данных» обновляется не в темпе поступления информации.
Это либо согласовывается с заказчиком, либо при использовании активного окна «Архив» запись переходит в непрерывный режим
при повышенном износе памяти. И по таймеру 3-5 минут окно автоматически переключается на основное.
Отказался от варианта придумывать костыли с буфером в ОЗУ и выводом данных во второй таблице, наложенной поверх первой.

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

petera
05.05.2026, 11:32
petera, отдельно выражаю Вам благодарность за набор средств под названием DeBug.
Без этого инструмента браться за любой более-менее сложный проект не имеет смысла.
С самого начала активно использую, сэкономлено уйма сил и времени.
.....

под названием DeBug скрывается этот пост https://owen.ru/forum/showthread.php?t=26783&p=251022&viewfull=1#post251022
Использование макроса "DEBUG Print" можно упростить если сохранить текст функции

#include <stdarg.h>
//#define DEBUG_ENB 1
void realdprintf (char const *file, int line, char const *func, int delay, char const *format, ...);

#if DEBUG_ENB
#define DEBUG(...) realdprintf(__FILE__, __LINE__, __func__, __VA_ARGS__)

void realdprintf (char const *file, int line, char const *func, int delay, char const *format, ...)
{
#define winNo 5002
#define LTOTAL 8
#define CTOTAL 40
#define INPUT PSW[136]
#define SCRADDR PSW[139]
#define TIC (*(DWORD*) (PSW + 38))
#define TABS 8
#define OK 0
#define LEFT 1
#define RIGHT 2
#define KbdStatus(bitno) ((INPUT) & (1 << (bitno)))
#define FORWARD 1
#define BACKWARD -1

char *pBuffScr;
char *pBuffPrint = Malloc((LTOTAL -1) * CTOTAL);
BYTE *saveREGS = Malloc(LTOTAL * CTOTAL);
WORD saveREG1, saveREG2;
static int Xpos = 0, Ypos = 0;
register int t, len2;
int len1, len3, dir;
unsigned long tm;
va_list arg;

/* Save working registers */
saveREG1 = INPUT;
saveREG2 = SCRADDR;
/* Calculate the initial address of the screen buffer */
SCRADDR = PSW[10] - LTOTAL * CTOTAL/2;
pBuffScr = (char*) &PSW[SCRADDR];
/* Save the registers of the screen buffer area */
memcpy(saveREGS, pBuffScr, LTOTAL * CTOTAL);
/* Clear screen buffer */
memset(pBuffScr, ' ', LTOTAL * CTOTAL);

/* Print to screen line #1 */
len1 = sprintf(pBuffScr, "> %s line %d in %s ", func, line, file);
len2 = CTOTAL + Max(0, len1-CTOTAL);

/* remaining print lines in the buffer */
va_start(arg, format);
len3 = vsnprintf (pBuffPrint, LTOTAL * CTOTAL - len2 - 1, format, arg);
va_end(arg);
pBuffPrint[len3] = '\0';

/* Display buffer on screen */
t= 0;
do {
switch(pBuffPrint[t]) {
case '\a': //Bell
Beep();
break;
case '\t': //Tab
len2 = len2 - len2 % TABS + TABS;
break;
case '\n': //LF
len2 = len2 - len2 % CTOTAL + CTOTAL;
break;
default:
pBuffScr[len2] = pBuffPrint[t];
len2++;
}
t++;
} while (pBuffPrint[t] !=0 && len2 < (LTOTAL * CTOTAL));

/* Call the debug window and control its position */
dir = FORWARD;
tm = TIC;
while(!(KbdStatus(OK) || (delay !=0 && (TIC-tm) >= delay*10)) ) {
if (KbdStatus(RIGHT)) {
tm = TIC;
CloseWindow(winNo);
Xpos = Xpos + 100;
}
if (KbdStatus(LEFT)) {
tm = TIC;
CloseWindow(winNo);
Xpos = Xpos - 100;
if (Xpos < 0) {
Xpos = 0;
Ypos = Ypos + dir * 100;
}
if (Ypos == 400) dir = BACKWARD;
if (Ypos == 0) dir = FORWARD;
}
OpenWindow(winNo, Xpos, Ypos);
INPUT = 0;
Delay(10);
}
CloseWindow(winNo);

/* Restore working registers */
memcpy(pBuffScr, saveREGS, LTOTAL * CTOTAL);
INPUT = saveREG1;
SCRADDR = saveREG2;
/* Deallocate memory blocks */
Free(pBuffPrint);
Free(saveREGS);
}

#else
#define DEBUG(...)
#endif

в файл ".\ARMTool\Include\Debug_prn.h"
89097
Тогда достаточно в глобальный макрос проектов добавить всего две строчки

#define DEBUG_ENB 1
#include <Debug_prn.h>
89096