Files
Balsam_167/Source/Internal/DAC.c
Andrey f741741cf8 Сохранить русские комментарии и настройки проекта в UTF-8
Добавить пояснения к исходникам, заголовкам TI, настройкам CCS и существующим проверкам. Зафиксировать правила кодировки, обзор модулей и аудит комментариев.
2026-10-12 12:24:48 +03:00

587 lines
52 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. Русские пояснения сохранены в UTF-8. */
/* Подключает "DSP2833x_Device.h": поставляемое TI описание Device для семейства C2833x. */
#include "DSP2833x_Device.h" // DSP281x Headerfile Include File
/* Подключает "DSP2833x_SWPrioritizedIsrLevels.h": поставляемое TI описание SWPrioritizedIsrLevels для семейства C2833x. */
#include "DSP2833x_SWPrioritizedIsrLevels.h"
/* Подключает "filter_bat2.h": накопительный фильтр измерительных каналов. */
#include "filter_bat2.h"
/* Подключает "measure.h": обработка датчиков, вычисление величин и миллисекундный такт системы. */
#include "measure.h"
/* Подключает "RS485.h": приём и передача SCI-A/SCI-B, упаковка команд и FIFO первого порта. */
#include "RS485.h"
/* Подключает "message.h": обработка Modbus, заводские параметры и сохранение настроек. */
#include "message.h"
/* Подключает "DAC.h": выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
#include "DAC.h"
/* Подключает "package.h": адреса устройств, типы плат и псевдонимы технологических регистров. */
#include "package.h"
/* Подключает "tools.h": настройка внешней памяти и служебные задержки. */
#include "tools.h"
/* Подключает "peripher.h": перемычки режима платы, дискретные входы и выходы. */
#include "peripher.h"
/* Подключает "log_to_mem.h": двухбанковый регистратор событий нагрузки во внешней RAM. */
#include "log_to_mem.h"
/* Задаёт dCLK_1 = GpioDataRegs.GPBSET.bit.GPIO63=1; данные dCLK_1. */
#define dCLK_1() GpioDataRegs.GPBSET.bit.GPIO63=1
/* Задаёт dCLK_0 = GpioDataRegs.GPBCLEAR.bit.GPIO63=1; данные dCLK_0. */
#define dCLK_0() GpioDataRegs.GPBCLEAR.bit.GPIO63=1
/* Задаёт dCS_1 = GpioDataRegs.GPBSET.bit.GPIO59=1; данные dCS_1. */
#define dCS_1() GpioDataRegs.GPBSET.bit.GPIO59=1
/* Задаёт dCS_0 = GpioDataRegs.GPBCLEAR.bit.GPIO59=1; данные dCS_0. */
#define dCS_0() GpioDataRegs.GPBCLEAR.bit.GPIO59=1
/* Объявляет WAKEpowse — данные WAKEpowse. */
unsigned long WAKEpowse;
/* Объявляет IMPowse — данные IMPowse. */
unsigned long IMPowse;
/* Объявляет period_dac — период ЦАП; time_dac — time ЦАП. */
unsigned int period_dac, time_dac;
/* Все выходы УМП и рампа принадлежат одному обработчику Timer1.
* Основной цикл больше не выдаёт START: иначе он может увидеть короткий
* спад команды, который пропустит расчёт ЦАП с периодом 5 мс. */
/* Задаёт LOAD_IDLE = 0U; состояние ожидания команды пуска. */
#define LOAD_IDLE 0U
/* Задаёт LOAD_RUN = 1U; состояние работающей нагрузки и нарастания тока. */
#define LOAD_RUN 1U
/* Задаёт LOAD_RELOAD = 2U; состояние выдержки перед повторным запуском. */
#define LOAD_RELOAD 2U
/* Задаёт LOAD_FAULT = 3U; состояние остановки после исчерпания попыток. */
#define LOAD_FAULT 3U
/* Задаёт LOAD_MAX_ATTEMPTS = 5U; предел повторных пусков нагрузки — пять. */
#define LOAD_MAX_ATTEMPTS 5U
/* Задаёт LOAD_VOLTAGE_MIN = 30U; минимальное разрешённое напряжение нагрузки — 30 В. */
#define LOAD_VOLTAGE_MIN 30U
/* Задаёт LOAD_PULSE_MS = 1000U; длительность удержания импульса START/STOP — 1000 мс. */
#define LOAD_PULSE_MS 1000U
/* Объявляет load_state — текущее состояние автомата нагрузки; load_attempts — накопленное число пусков в текущем цикле, максимум пять; load_inhibit — признак запрета повторного запуска до требуемого перехода входов. */
static unsigned int load_state, load_attempts, load_inhibit;
/* Объявляет load_count_dac — load число ЦАП; load_count_ramp — load число ramp; load_init_count — load init число. */
static unsigned int load_count_dac, load_count_ramp, load_init_count;
/* Объявляет load_zero_sent — данные load_zero_sent; load_stop_asserted — признак установленного выхода STOP; load_initialized — данные load_initialized. */
static unsigned int load_zero_sent, load_stop_asserted, load_initialized;
/* Объявляет load_go — начальный ток за вычетом базовых 4 мА, ограниченный диапазоном 0..5; load_end — конечный ток за вычетом 4 мА, ограниченный сверху значением 16. */
static float load_go, load_end;
/* 16-битные поля общие с CAN ISR. Снимок и увеличение возраста выполняются
* под короткой блокировкой IRQ; отправка SPI под блокировкой не выполняется. */
/* Объявляет load_voltage — последнее выбранное напряжение CAN, масштаб 1 В на слово; load_voltage_age — возраст последнего достоверного выбранного напряжения CAN в миллисекундах; load_voltage_seen — признак получения выбранного измерения напряжения CAN. volatile требует фактического чтения или записи при каждом доступе. */
static volatile unsigned int load_voltage, load_voltage_age, load_voltage_seen;
/* Объявляет load_simulation — данные load_simulation. volatile требует фактического чтения или записи при каждом доступе. */
static volatile unsigned int load_simulation;
/* Сбрасывает все переменные автомата нагрузки до разрешения прерываний; COFF не обнуляет всю .ebss. */
void Load_control_init(void)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Записывает load_state значением LOAD_IDLE; load_attempts = 0; load_inhibit = 0; текущее состояние автомата нагрузки. */
load_state = LOAD_IDLE; load_attempts = 0; load_inhibit = 0;
/* Записывает load_count_dac значением 0; load_count_ramp = 0; load_init_count = 1; load число ЦАП. */
load_count_dac = 0; load_count_ramp = 0; load_init_count = 1;
/* Записывает load_zero_sent значением 0; load_stop_asserted = 0; load_initialized = 0; данные load_zero_sent. */
load_zero_sent = 0; load_stop_asserted = 0; load_initialized = 0;
/* Записывает load_go значением 0; load_end = 0; начальный ток за вычетом базовых 4 мА, ограниченный диапазоном 0..5. */
load_go = 0; load_end = 0;
/* Записывает load_voltage значением 0; load_voltage_age = 0; load_voltage_seen = 0; последнее выбранное напряжение CAN, масштаб 1 В на слово. */
load_voltage = 0; load_voltage_age = 0; load_voltage_seen = 0;
/* Записывает load_simulation значением 0; данные load_simulation. */
load_simulation = 0;
/* Записывает IMPowse значением 0; WAKEpowse = 0; period_dac = 0; time_dac = 0; данные IMPowse. */
IMPowse = 0; WAKEpowse = 0; period_dac = 0; time_dac = 0;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Возраст сбрасывает только нужное напряжение, а не любой CAN-пакет.
* УМП 5: ЗПТ1, индекс 305; УМП 6: ЗПТ2, индекс 8. Масштаб 1 В/ед.
* Маски слотов сохраняют адреса даже для пропущенных слов кадра. */
/* Принимает напряжение выбранной нагрузки из достоверных слов CAN и сбрасывает возраст только нужного измерения. */
void Load_voltage_can(unsigned int header, unsigned int a,
/* Объявляет b — данные b. */
unsigned int b, unsigned int c)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Объявляет address — адрес. Начальное значение задаётся справа от знака равенства. */
unsigned int address = header & 0x1FFFU;
/* Объявляет selected — данные selected; i — данные i; mask — маска; data — данные. Начальное значение задаётся справа от знака равенства. */
unsigned int selected, i, mask = 0x8000U, data[3];
/* Проверяет if (Desk != dsk_LOAD или (load_simulation & 1U)) return; последующий оператор выполняется только при истинном условии. */
if (Desk != dsk_LOAD || (load_simulation & 1U)) return;
/* Проверяет if (Mode == adr_LOA1) selected = 305U; последующий оператор выполняется только при истинном условии. */
if (Mode == adr_LOA1) selected = 305U;
/* Проверяет else if (Mode == adr_LOA2) selected = 8U; последующий оператор выполняется только при истинном условии. */
else if (Mode == adr_LOA2) selected = 8U;
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
else return;
/* Записывает data[0] значением a; data[1] = b; data[2] = c; данные. */
data[0] = a; data[1] = b; data[2] = c;
/* Цикл for (i = 0; i < 3; i++, address++, mask >>= 1) ; задаёт начальное значение, условие продолжения и шаг перебора. */
for (i = 0; i < 3; i++, address++, mask >>= 1) {
/* Проверяет if ((header & mask) и address == selected); последующий оператор выполняется только при истинном условии. */
if ((header & mask) && address == selected) {
/* Записывает load_voltage значением data[i]; последнее выбранное напряжение CAN, масштаб 1 В на слово. */
load_voltage = data[i];
/* Записывает load_voltage_age значением 0; возраст последнего достоверного выбранного напряжения CAN в миллисекундах. */
load_voltage_age = 0;
/* Записывает load_voltage_seen значением 1; признак получения выбранного измерения напряжения CAN. */
load_voltage_seen = 1;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* STOP удерживается весь сброс, включая отправку кода 4 мА в ЦАП.
* Повторный пуск разрешён только после этой отправки и 1000 мс STOP.
* Это подтверждение программной отправки, не измерение физического тока. */
/* Снимает START и разрешение нагрузки, удерживает STOP 1000 мс и сбрасывает состояние нарастания тока. */
static void load_stop(unsigned int state)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Сбрасывает аппаратный сигнал через clear_START_DPTB();. */
clear_START_DPTB();
/* Устанавливает аппаратный сигнал через set_STOP_DPTB();. */
set_STOP_DPTB();
/* Сбрасывает аппаратный сигнал через clear_RES_OUT_2();. */
clear_RES_OUT_2();
/* Записывает load_stop_asserted значением 1; признак установленного выхода STOP. */
load_stop_asserted = 1;
/* Записывает load_state значением state; текущее состояние автомата нагрузки. */
load_state = state;
/* Записывает load_count_ramp значением 0; load число ramp. */
load_count_ramp = 0;
/* Записывает load_zero_sent значением 0; данные load_zero_sent. */
load_zero_sent = 0;
/* Записывает IMPowse значением LOAD_PULSE_MS; данные IMPowse. */
IMPowse = LOAD_PULSE_MS;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Ограничивает начальный и конечный ток, снимает STOP, выдаёт START и считает новую попытку пуска. */
static void load_start(void)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Уставки фиксируются для каждой попытки. Внутренний ноль = 4 мА.
* Исправлена опечатка старого ограничения: ограничиваем конец рампы,
* а не заменяем начальную уставку на 16 (что давало скачок до 20 мА). */
/* Записывает load_go значением (float)DAC_go - 4.0; начальный ток за вычетом базовых 4 мА, ограниченный диапазоном 0..5. */
load_go = (float)DAC_go - 4.0;
/* Записывает load_end значением (float)DAC_stop - 4.0; конечный ток за вычетом 4 мА, ограниченный сверху значением 16. */
load_end = (float)DAC_stop - 4.0;
/* Проверяет if (load_go < 0) load_go = 0; последующий оператор выполняется только при истинном условии. */
if (load_go < 0) load_go = 0;
/* Проверяет if (load_go > 5) load_go = 5; последующий оператор выполняется только при истинном условии. */
if (load_go > 5) load_go = 5;
/* Проверяет if (load_end > 16) load_end = 16; последующий оператор выполняется только при истинном условии. */
if (load_end > 16) load_end = 16;
/* Проверяет if (load_end <= load_go) load_end = load_go + 1; последующий оператор выполняется только при истинном условии. */
if (load_end <= load_go) load_end = load_go + 1;
/* Записывает ump_dac_go10 значением (unsigned int)((load_go + 4.0) * 10.0); ump ЦАП go 10. */
ump_dac_go10 = (unsigned int)((load_go + 4.0) * 10.0);
/* Записывает ump_dac_stop10 значением (unsigned int)((load_end + 4.0) * 10.0); ump ЦАП stop 10. */
ump_dac_stop10 = (unsigned int)((load_end + 4.0) * 10.0);
/* Записывает load_count_ramp значением 0; load число ramp. */
load_count_ramp = 0;
/* Изменяет счётчик в выражении load_attempts++; на один для следующего шага. */
load_attempts++;
/* STOP отпускаем непосредственно перед START, разрешение — после него.
* Задание остаётся 4 мА до первого шага новой рампы. */
/* Сбрасывает аппаратный сигнал через clear_STOP_DPTB();. */
clear_STOP_DPTB();
/* Записывает load_stop_asserted значением 0; признак установленного выхода STOP. */
load_stop_asserted = 0;
/* Устанавливает аппаратный сигнал через set_START_DPTB();. */
set_START_DPTB();
/* Устанавливает аппаратный сигнал через set_RES_OUT_2();. */
set_RES_OUT_2();
/* Записывает IMPowse значением LOAD_PULSE_MS; данные IMPowse. */
IMPowse = LOAD_PULSE_MS;
/* Записывает load_state значением LOAD_RUN; текущее состояние автомата нагрузки. */
load_state = LOAD_RUN;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Вычисляет такты ЦАП; для недопустимого сохранённого тайм-аута CAN возвращает 600 мс. */
void Setup_DAC_time(void)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Записывает WAKEpowse значением 3L * DAC_FREQ +1; данные WAKEpowse. */
WAKEpowse = 3L * DAC_FREQ +1;
/* Записывает period_dac значением READY_FREQ / DAC_FREQ; период ЦАП. */
period_dac = READY_FREQ / DAC_FREQ;
/* Записывает time_dac значением LOAD_TIME * DAC_FREQ; time ЦАП. */
time_dac = LOAD_TIME * DAC_FREQ;
/* Старые EEPROM имеют ноль в новом параметре: используем 600 мс.
* 1..60000 мс можно менять через регистр 0x52 и сохранять штатно. */
/* Проверяет if ((unsigned int)LOAD_CAN_TIMEOUT == 0U или; последующий оператор выполняется только при истинном условии. */
if ((unsigned int)LOAD_CAN_TIMEOUT == 0U ||
/* Записывает LOAD_CAN_TIMEOUT значением 600; сохраняемый тайм-аут свежести напряжения CAN в миллисекундах, регистр 0x52. */
(unsigned int)LOAD_CAN_TIMEOUT > 60000U) LOAD_CAN_TIMEOUT = 600;
/* Записывает LOAD_STATUS значением 0; LOAD_ATTEMPTS = 0; слово состояния защиты нагрузки для чтения, регистр 0x7C. */
LOAD_STATUS = 0; LOAD_ATTEMPTS = 0;
/* Записывает load_initialized значением 1; данные load_initialized. */
load_initialized = 1;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Начинает функцию dOUT; назначение модуля — выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
void dOUT(int x)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Проверяет if(x) GpioDataRegs.GPBSET.bit.GPIO60=1; последующий оператор выполняется только при истинном условии. */
if(x) GpioDataRegs.GPBSET.bit.GPIO60=1;
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
else GpioDataRegs.GPBCLEAR.bit.GPIO60=1;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Начинает функцию wast; назначение модуля — выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
void wast()
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Объявляет i — данные i. */
int i;
/* Цикл for(i=0;i<25;i++);; задаёт начальное значение, условие продолжения и шаг перебора. */
for(i=0;i<25;i++);
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Начинает функцию dSEND; назначение модуля — выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
void dSEND(unsigned int word)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Объявляет i — данные i. */
int i;
/* Вызывает dCS_0 с аргументами (); DSP28x_usDelay(1L) в текущей последовательности операций. */
dCS_0(); DSP28x_usDelay(1L);
/* Цикл for(i=0;i<16;i++); задаёт начальное значение, условие продолжения и шаг перебора. */
for(i=0;i<16;i++)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Вызывает dCLK_1 с аргументами () в текущей последовательности операций. */
dCLK_1();
/* Записывает word значением word<<1; DSP28x_usDelay(1L); слово. */
dOUT((word & 0x8000)?1:0); word = word<<1; DSP28x_usDelay(1L);
/* Вызывает dCLK_0 с аргументами (); DSP28x_usDelay(1L) в текущей последовательности операций. */
dCLK_0(); DSP28x_usDelay(1L);
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Вызывает dCS_1 с аргументами () в текущей последовательности операций. */
dCS_1();
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Начинает функцию Init_DAC; назначение модуля — выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
void Init_DAC(void)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Вызывает dSEND с аргументами (0x9002|0x0000) в текущей последовательности операций. */
dSEND(0x9002|0x0000);
/* Переключает аппаратный сигнал через toggle_RES_OUT_1();. */
toggle_RES_OUT_1();
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Начинает функцию anal_output; назначение модуля — выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
static void anal_output(long vrot, long maxx, int calibration)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Объявляет out — данные out. */
long out;
/* Объявляет x — данные x. */
static int x;
/* Записывает out значением DAC_min() + vrot * DAC_max() / maxx - vrot * DAC_min() / maxx ; данные out. */
out = DAC_min() + vrot * DAC_max() / maxx - vrot * DAC_min() / maxx ;
/* Записывает x значением 0; данные x. */
x=0;// !x; тщетно бытие
/* Проверяет if(calibration и cCalibrDac) out=DAC_cal(); последующий оператор выполняется только при истинном условии. */
if(calibration && cCalibrDac) out=DAC_cal();
/* Записывает out значением out & 0xFFF; данные out. */
out = out & 0xFFF;
/* Проверяет if(x) dSEND(out|0x0000|0x0000); последующий оператор выполняется только при истинном условии. */
if(x) dSEND(out|0x0000|0x0000);
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
else dSEND(out|0x8000|0x0000);
/* Записывает modbus[123] значением out; массив технологических регистров; слово int на C28x занимает 16 бит. */
modbus[123] = out;
/* Записывает modbus[0x1C] значением 40L + vrot * 200 / maxx - vrot * 40 / maxx ; массив технологических регистров; слово int на C28x занимает 16 бит. */
modbus[0x1C] = 40L + vrot * 200 / maxx - vrot * 40 / maxx ;
/*
if(!no_write)
{
Test_mem_limit(4);
Log_to_mem(modbus[0x7B]);
Log_to_mem(modbus[0x63]);
Log_to_mem(modbus[0x1C]);
Log_to_mem(modbus[0x1D]);
}
*/
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Сохранён публичный интерфейс; защитный сброс вызывает внутреннюю
* функцию с calibration=0, чтобы ручная калибровка не подменила 4 мА. */
/* Начинает функцию Anal_output; назначение модуля — выход ЦАП и автомат защиты нагрузки с проверкой напряжения и свежести CAN. */
void Anal_output(long vrot, long maxx)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Проверяет if (maxx > 0) anal_output(vrot, maxx, 1); последующий оператор выполняется только при истинном условии. */
if (maxx > 0) anal_output(vrot, maxx, 1);
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* В такте Timer1 проверяет команды, напряжение и давность CAN; управляет STOP, повторным пуском и током ЦАП. */
void Load_runner(void)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Объявляет saved — данные saved; commands — данные commands; voltage — данные voltage; fresh — данные fresh; timeout — данные timeout. */
unsigned int saved, commands, voltage, fresh, timeout;
/* Объявляет start — данные start; reset — сброс; active — данные active. Начальное значение задаётся справа от знака равенства. */
unsigned int start, reset, active = 0;
/* Объявляет sinus — данные sinus. Начальное значение задаётся справа от знака равенства. */
float sinus = 0;
/* ISR работает 1 кГц, но GPIO/ЦАП нельзя обслуживать до загрузки
* параметров. Это также исключает прежнее деление на time_dac=0. */
/* Проверяет if (!load_initialized или !READY или !period_dac или !time_dac) return; последующий оператор выполняется только при истинном условии. */
if (!load_initialized || !READY || !period_dac || !time_dac) return;
/* Записывает saved значением __disable_interrupts(); данные saved. */
saved = __disable_interrupts();
/* Записывает commands значением (unsigned int)Commands; данные commands. */
commands = (unsigned int)Commands;
/* Записывает voltage значением (load_simulation & 2U) ? 0U : load_voltage; данные voltage. */
voltage = (load_simulation & 2U) ? 0U : load_voltage;
/* Записывает timeout значением (unsigned int)LOAD_CAN_TIMEOUT; данные timeout. */
timeout = (unsigned int)LOAD_CAN_TIMEOUT;
/* Проверяет if (!timeout или timeout > 60000U) timeout = 600U; последующий оператор выполняется только при истинном условии. */
if (!timeout || timeout > 60000U) timeout = 600U;
/* До первого пакета значение 0 не считается свежим измерением.
* Насыщение возраста исключает ложное восстановление после переполнения. */
/* Записывает fresh значением load_voltage_seen && load_voltage_age < timeout; данные fresh. */
fresh = load_voltage_seen && load_voltage_age < timeout;
/* Проверяет if (load_voltage_age < 65535U) load_voltage_age++; последующий оператор выполняется только при истинном условии. */
if (load_voltage_age < 65535U) load_voltage_age++;
/* Вызывает __restore_interrupts с аргументами (saved) в текущей последовательности операций. */
__restore_interrupts(saved);
/* Записывает start значением commands & 0x80U; reset = commands & 0x40U; данные start. */
start = commands & 0x80U; reset = commands & 0x40U;
/* Проверяет if (IMPowse) IMPowse--; последующий оператор выполняется только при истинном условии. */
if (IMPowse) IMPowse--;
/* Отсутствие команды пуска — начало нового сеанса, сбрасывает ошибку.
* RESET всегда старше START; отпускание RESET при оставшемся START
* не даёт неожиданного повторного пуска: сначала требуется START=0. */
/* Проверяет if (!start); последующий оператор выполняется только при истинном условии. */
if (!start) {
/* Проверяет if (load_state != LOAD_IDLE) load_stop(LOAD_IDLE); последующий оператор выполняется только при истинном условии. */
if (load_state != LOAD_IDLE) load_stop(LOAD_IDLE);
/* Записывает load_attempts значением 0; load_inhibit = 0; накопленное число пусков в текущем цикле, максимум пять. */
load_attempts = 0; load_inhibit = 0;
/* Проверяет else if (reset); последующий оператор выполняется только при истинном условии. */
} else if (reset) {
/* Проверяет if (load_state != LOAD_FAULT и load_state != LOAD_IDLE); последующий оператор выполняется только при истинном условии. */
if (load_state != LOAD_FAULT && load_state != LOAD_IDLE)
/* Вызывает load_stop. Снимает START и разрешение нагрузки, удерживает STOP 1000 мс и сбрасывает состояние нарастания тока. */
load_stop(LOAD_IDLE);
/* Записывает load_inhibit значением 1; признак запрета повторного запуска до требуемого перехода входов. */
load_inhibit = 1;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Проверяет if (reset и !load_stop_asserted) load_stop(LOAD_IDLE); последующий оператор выполняется только при истинном условии. */
if (reset && !load_stop_asserted) load_stop(LOAD_IDLE);
/* Повторный START допускается после сброса ЦАП, окончания STOP и
* восстановления нужного CAN-напряжения. Таймаут сам не тратит попытку. */
/* Проверяет if (start и !reset и !load_inhibit и !WAKEpowse и fresh и; последующий оператор выполняется только при истинном условии. */
if (start && !reset && !load_inhibit && !WAKEpowse && fresh &&
/* Продолжает список аргументов, полей или выражение load_zero_sent && !IMPowse &&; порядок элементов сохраняется. */
load_zero_sent && !IMPowse &&
/* Продолжает список аргументов, полей или выражение (load_state == LOAD_IDLE || load_state == LOAD_RELOAD)) load_start();; порядок элементов сохраняется. */
(load_state == LOAD_IDLE || load_state == LOAD_RELOAD)) load_start();
/* Проверяет if (load_state == LOAD_RUN и !IMPowse) clear_START_DPTB(); последующий оператор выполняется только при истинном условии. */
if (load_state == LOAD_RUN && !IMPowse) clear_START_DPTB();
/* Проверяет if (++load_count_dac >= period_dac); последующий оператор выполняется только при истинном условии. */
if (++load_count_dac >= period_dac) {
/* Записывает load_count_dac значением 0; load число ЦАП. */
load_count_dac = 0;
/* Проверяет if (WAKEpowse); последующий оператор выполняется только при истинном условии. */
if (WAKEpowse) {
/* Элемент постоянной таблицы --WAKEpowse;; порядок значений совпадает с порядком индексов потребителя. */
--WAKEpowse;
/* Проверяет if (WAKEpowse и !(WAKEpowse % (DAC_FREQ / 2))); последующий оператор выполняется только при истинном условии. */
if (WAKEpowse && !(WAKEpowse % (DAC_FREQ / 2))) {
/* Записывает load_init_count значением 1; load init число. */
Init_DAC(); load_init_count = 1;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
} else {
/* Записывает active значением load_state == LOAD_RUN; данные active. */
active = load_state == LOAD_RUN;
/* Проверяет if (active); последующий оператор выполняется только при истинном условии. */
if (active) {
/* При таймауте сохраняем положение И отправленное задание,
* не делаем STOP и не продолжаем разгон без обратной связи. */
/* Проверяет if (fresh); последующий оператор выполняется только при истинном условии. */
if (fresh) {
/* Проверяет if (load_count_ramp > time_dac / 2) load_count_ramp++; последующий оператор выполняется только при истинном условии. */
if (load_count_ramp > time_dac / 2) load_count_ramp++;
/* Проверяет if (++load_count_ramp > time_dac) load_count_ramp = time_dac; последующий оператор выполняется только при истинном условии. */
if (++load_count_ramp > time_dac) load_count_ramp = time_dac;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Записывает sinus значением ((load_end - load_go) / 16.0 * load_count_ramp) +; данные sinus. */
sinus = ((load_end - load_go) / 16.0 * load_count_ramp) +
/* Продолжает список аргументов, полей или выражение (load_go / 16.0 * time_dac);; порядок элементов сохраняется. */
(load_go / 16.0 * time_dac);
/* Проверяем следующий шаг ДО передачи ЦАП. 6 мА допустимы,
* строго >6 мА и <30 В требуют немедленного STOP.
* Первая попытка входит в лимит 5; шестого START не будет. */
/* Проверяет if (fresh и voltage < LOAD_VOLTAGE_MIN и; последующий оператор выполняется только при истинном условии. */
if (fresh && voltage < LOAD_VOLTAGE_MIN &&
/* Продолжает список аргументов, полей или выражение sinus * 16.0 > 2.0 * time_dac) {; порядок элементов сохраняется. */
sinus * 16.0 > 2.0 * time_dac) {
/* Вызывает load_stop. Снимает START и разрешение нагрузки, удерживает STOP 1000 мс и сбрасывает состояние нарастания тока. */
load_stop(load_attempts >= LOAD_MAX_ATTEMPTS ?
/* Продолжает список аргументов, полей или выражение LOAD_FAULT : LOAD_RELOAD);; порядок элементов сохраняется. */
LOAD_FAULT : LOAD_RELOAD);
/* Записывает active значением 0; sinus = 0; данные active. */
active = 0; sinus = 0;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
} else {
/* Записывает load_count_ramp значением 0; load число ramp. */
load_count_ramp = 0;
/* Записывает load_init_count значением (load_init_count + 1) & 0x3FFU; load init число. */
load_init_count = (load_init_count + 1) & 0x3FFU;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Во время защиты и пуска ручной код калибровки запрещён.
* Калибровка сохранена только при снятом START и свободном STOP.
* Нулевой код задания здесь означает ток 4 мА по DAC_min(). */
/* Записывает ump_dac_ramp значением load_count_ramp; ump ЦАП ramp. */
ump_dac_ramp = load_count_ramp;
/* Записывает ump_dac_duration значением time_dac; ump ЦАП duration. */
ump_dac_duration = time_dac;
/* Записывает ump_dac_position значением (unsigned int)sinus; ump ЦАП position. */
ump_dac_position = (unsigned int)sinus;
/* Проверяет if (active и !fresh); последующий оператор выполняется только при истинном условии. */
if (active && !fresh) {
/* Удерживаем ЦАП. Даже cInitDac не меняет ток в паузе CAN. */
/* Проверяет else if ((!load_init_count или cInitDac) и !load_stop_asserted); последующий оператор выполняется только при истинном условии. */
} else if ((!load_init_count || cInitDac) && !load_stop_asserted) {
/* Записывает load_init_count значением 1; cInitDac = 0; load init число. */
Init_DAC(); load_init_count = 1; cInitDac = 0;
/* Выполняет альтернативу, если предыдущее условие if оказалось ложным. */
} else {
/* Вызывает anal_output с аргументами ((int)sinus, time_dac, в текущей последовательности операций. */
anal_output((int)sinus, time_dac,
/* Продолжает список аргументов, полей или выражение !start && !load_stop_asserted);; порядок элементов сохраняется. */
!start && !load_stop_asserted);
/* A manual calibration frame is not a confirmed 4 mA reload.
* START must wait for a forced baseline frame after it. */
/* Проверяет if (!active) load_zero_sent = !(!start и !load_stop_asserted и cCalibrDac); последующий оператор выполняется только при истинном условии. */
if (!active) load_zero_sent = !(!start && !load_stop_asserted && cCalibrDac);
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Диагностика доступна обычным Modbus/CAN, независимо от логгера:
* бит 0 — ошибка пяти пусков; бит 1 — нет свежего напряжения;
* бит 2 — сброс перед повтором; бит 3 — работа рампы.
* Ошибка удерживается со STOP, пока оператор не снимет START. */
/* Записывает LOAD_STATUS значением (load_state == LOAD_FAULT ? 1U : 0U) |; слово состояния защиты нагрузки для чтения, регистр 0x7C. */
LOAD_STATUS = (load_state == LOAD_FAULT ? 1U : 0U) |
/* Продолжает список аргументов, полей или выражение (!fresh ? 2U : 0U) |; порядок элементов сохраняется. */
(!fresh ? 2U : 0U) |
/* Продолжает список аргументов, полей или выражение (load_state == LOAD_RELOAD ? 4U : 0U) |; порядок элементов сохраняется. */
(load_state == LOAD_RELOAD ? 4U : 0U) |
/* Продолжает список аргументов, полей или выражение (load_state == LOAD_RUN ? 8U : 0U) |; порядок элементов сохраняется. */
(load_state == LOAD_RUN ? 8U : 0U) |
/* Продолжает список аргументов, полей или выражение (load_simulation << 4);; порядок элементов сохраняется. */
(load_simulation << 4);
/* Записывает LOAD_ATTEMPTS значением load_attempts; число попыток пуска для чтения, регистр 0x7D. */
LOAD_ATTEMPTS = load_attempts;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Local versioned block, shared by RTU and service CAN. Probe its signature
* before writes: old firmware returns exception 2 instead of starting tests.
* Simulation is RAM-only, zeroed at boot, and never copied into EEPROM.
* bit 0 ignores ZPT reception (age reaches the configured timeout);
* bit 1 substitutes 0 V only for protection, leaving real logged CAN intact. */
/* Фиксирует управляющие входы перед выполнением автомата защиты нагрузки. */
unsigned int Load_protection_prepare(unsigned int function, unsigned int address,
/* Объявляет value — данные value; out — данные out. Хранит указатель на данные. */
unsigned int value, unsigned int *out, unsigned int *error)
/* Открывает составной блок или описание полей; следующие строки принадлежат этому уровню вложенности. */
{
/* Объявляет saved — данные saved. Начальное значение задаётся справа от знака равенства. */
unsigned int saved = __disable_interrupts();
/* Записывает error значением 2; ошибка. */
*error = 2;
/* Проверяет if (Desk == dsk_LOAD и address == 0x1300U и function == 3 и value == 8); последующий оператор выполняется только при истинном условии. */
if (Desk == dsk_LOAD && address == 0x1300U && function == 3 && value == 8) {
/* Записывает out[0] значением 0x5550U; out[1] = 1; данные out. */
out[0] = 0x5550U; out[1] = 1;
/* Записывает out[2] значением load_simulation; out[3] = (unsigned int)LOAD_CAN_TIMEOUT; данные out. */
out[2] = load_simulation; out[3] = (unsigned int)LOAD_CAN_TIMEOUT;
/* Записывает out[4] значением (unsigned int)LOAD_STATUS; out[5] = load_attempts; данные out. */
out[4] = (unsigned int)LOAD_STATUS; out[5] = load_attempts;
/* Записывает out[6] значением load_voltage; out[7] = load_voltage_seen ? load_voltage_age : 65535U; данные out. */
out[6] = load_voltage; out[7] = load_voltage_seen ? load_voltage_age : 65535U;
/* Записывает error значением 0; ошибка. */
*error = 0;
/* Вызывает __restore_interrupts с аргументами (saved) в текущей последовательности операций. */
__restore_interrupts(saved);
/* Завершает Load_protection_prepare и возвращает 8. */
return 8;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Проверяет if (Desk == dsk_LOAD и function == 6); последующий оператор выполняется только при истинном условии. */
if (Desk == dsk_LOAD && function == 6) {
/* Проверяет if (address == 0x1302U и value <= 3U); последующий оператор выполняется только при истинном условии. */
if (address == 0x1302U && value <= 3U) {
/* Записывает load_simulation значением value; данные load_simulation. */
load_simulation = value;
/* Записывает error значением 0; ошибка. */
*error = 0;
/* Проверяет else if (address == 0x1303U и value >= 1U и value <= 60000U); последующий оператор выполняется только при истинном условии. */
} else if (address == 0x1303U && value >= 1U && value <= 60000U) {
/* Записывает LOAD_CAN_TIMEOUT значением value; *error = 0; сохраняемый тайм-аут свежести напряжения CAN в миллисекундах, регистр 0x52. */
LOAD_CAN_TIMEOUT = value; *error = 0;
/* Проверяет else if (address == 0x1302U или address == 0x1303U) *error = 3; последующий оператор выполняется только при истинном условии. */
} else if (address == 0x1302U || address == 0x1303U) *error = 3;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}
/* Записывает out[0] значением address; out[1] = value; данные out. */
out[0] = address; out[1] = value;
/* Вызывает __restore_interrupts с аргументами (saved) в текущей последовательности операций. */
__restore_interrupts(saved);
/* Завершает Load_protection_prepare и возвращает 2. */
return 2;
/* Закрывает текущий блок или список полей; следующие операторы относятся к внешнему уровню. */
}