Selaa lähdekoodia

Добавляю состояние модуля.

TelenkovDmitry 4 kuukautta sitten
vanhempi
commit
e8a281c5e2

+ 737 - 737
fw/modules/io/analog_input.c

@@ -1,738 +1,738 @@
-#include "at32f403a_407.h"
-#include "analog_input.h"
-#include "shift_reg.h"
-#include "utility.h"
-#include "FreeRTOS.h"
-#include "task.h"
-#include "settings_api.h"
-#include "adc_transport.h"
-#include "ms5192t.h"
-#include "monitoring.h"
-#include "mux.h"
-#include "filter.h"
-#include <stdio.h>
-
-#undef DBG
-#define DBG if(0)
-
-#if defined (MAI_12)  
-
-#define VOLTAGE_FACTOR      0.182382
-#define CURRENT_FACTOR      0.00091191
-#define CRNT_LIM_V_FACTOR   0.0476
-#define VOLT_ALARM_LIMIT    10000.0
-#define CUR_ALARM_PAUSE     300 // время в секундах на остывание токового шунта
-#define CUR_LIM_LOW_LIMIT   23.0
-#define CUR_LIM_LOW_LIMIT   25.0
-#define CUR_LIM_DELTA_U     0.6
-
-
-uint8_t ai_mux;     // выход сдвигового регистра U1010 (управляет MUX 301, 401)
-                    // мультиплексоры отвечат за коммутацию аналоговых входов и АЦП
-
-uint16_t ai_mode;   // режим измерения аналоговых каналов (ток или напряжение)
-                    // 0000 0000 0000 0000 
-                    // младшие 6 (с 1..6) бит - каналы с 1 по 6 соответственно
-                    // биты 9..14 - каналы с 7 по 12 соответственно
-
-uint16_t ai_alarm;  // слово аварий входов
-
-uint16_t ai_gain[AI_COMMON_NUMBER]; // массив коэффициентов усиленя (modbus)
-
-uint16_t adc_com_raw_data[AI_COMMON_NUMBER]; // сырые данные
-float adc_com_data[AI_COMMON_NUMBER];        // пересчитанные, фильтрованные данные
-
-uint16_t adc_com_fil_data[AI_COMMON_NUMBER]; // Фильтрованные данные (только для отладки)
-
-uint16_t adc_add_raw_data[AI_ADD_NUMBER];
-
-
-led_t ai_alarm_led[12] = {IO_1_R, IO_2_R, IO_3_R, IO_4_R, 
-                          IO_5_R, IO_6_R, IO_7_R, IO_8_R, 
-                          IO_9_R, IO_10_R, IO_11_R, IO_12_R};
-
-led_t ai_input_led[12] = {IO_1_G, IO_2_G, IO_3_G, IO_4_G, 
-                          IO_5_G, IO_6_G, IO_7_G, IO_8_G, 
-                          IO_9_G, IO_10_G, IO_11_G, IO_12_G};
-
-uint16_t ai_state_bit;  // состояние аналоговых входов (вкл/выкл) битовое поле
-
-ai_alarm_t ai_alarm_f[AI_COMMON_NUMBER];    // Вспомогательная структура для 
-                                            //работы с авариями
-
-ai_alarm_t ai_cur_lim;  // Вспомогательная структура для работы с аварией 
-                        // модуля питания внешних датчиков
-
-
-// Авария датчика, значение ниже диапазона (не обрыв)
-// Авария, не обрыв линии (возможно неисправен датчик)
-// Авария датчика, значение выше диапазона (не обрыв)
-uint16_t ai_voltage_alarm;  // аварии в режиме измерения напряжения
-
-// аварии в режиме измерения тока
-uint16_t ai_current_low;    // значение ниже диапазона
-uint16_t ai_current_high;   // значение выше диапазона
-uint16_t ai_current_fail;   // авария (возможно неисправен датчик)
-uint16_t ai_load_sens_alarm;// авария превышения нагрузки на блок питания внешних датчиков
-
-//
-void ai_init(void)
-{
-    // Фильтры (скользящее среднее) для 12-и основных каналов
-    average_filter_init();
-  
-    // Зеленые LED сигнализируют (вкл/выкл) входов.
-    ai_led_update();    
-    
-    // Сдвиговые регистры
-    sh_init();          
-    
-    // Режим измерения
-    ai_set_meas_mode();
-    
-    // Питание внешних датчиков
-    ai_ext_sens_power(settings.ext_sens_power); 
-    
-    // Внешинй ADC
-    ai_adc_init();
-    
-    // Modbus параметры
-    ai_init_modbus_params();
-}
-
-//
-void ai_init_modbus_params(void)
-{
-    for (uint8_t i = 0; i < AI_COMMON_NUMBER; i++) {
-        ai_gain[i] = settings.ai[i].gain_factor;
-    }
-}   
-
-// Управление LED для 12-и основных входов
-void ai_led_update(void)
-{
-    for (int i = 0; i < AI_COMMON_NUMBER; i++) 
-    {
-        if (settings.ai[i].state)
-            leds[ai_input_led[i]].state = LED_ON;
-        else
-            leds[ai_input_led[i]].state = LED_OFF;
-    }
-}
-
-// Установить режим измерения каналов с 1 по 12.
-void ai_set_meas_mode(void)
-{
-    for (int i = 0; i < AI_COMMON_NUMBER; i++)
-    {
-        if (settings.ai[i].mode)
-            ai_set_mode_word((MEAS_CHAN_MODE_t)1, i + 1);
-        else 
-            ai_set_mode_word((MEAS_CHAN_MODE_t)0, i + 1);
-    }
-}   
-
-// Настройка внешнего ADC
-bool ai_adc_init(void)
-{
-    uint8_t ret;
-    unsigned long value;
-    
-    adc_gpio_init();
-    
-    for (uint32_t i = 0; i < 100; i++) {
-        MS5192T_Reset();
-        ret = MS5192T_Init();
-        DBG printf("ADC init status: %s\r\n", ret == 1 ? "OK" : "FAILED");
-        if (ret == 1)
-           break;
-        vTaskDelay(10);
-    }
-        
-    if (!ret) {
-        mon_set_err(ADC_ERR, true);
-        return false;
-    }
-    
-    // Запрос регистра конфигурации для (0x710 - значение по умолчанию)
-    value = MS5192T_GetRegisterValue(MS5192T_REG_CONF, 2, 1);
-    DBG printf("ADC cfg reg: 0x%X: ", value);
-    DBG print_binary_half_word((uint16_t)value);
-    
-    // Коэф-т усиления: 1
-    DBG printf("ADC. Set gain rate 1\r\n");
-    MS5192T_SetGain(MS5192T_GAIN_1);
-    value = MS5192T_GetRegisterValue(MS5192T_REG_CONF, 2, 1);
-    DBG printf("ADC cfg reg: 0x%X: ", value);
-    DBG print_binary_half_word((uint16_t)value);
-    
-    // Униполярный режим
-    DBG printf("Set unipolar input mode...\r\n");
-    MS5192T_SetPolar(MS5192T_CONF_UNIPOLAR);
-    value = MS5192T_GetRegisterValue(MS5192T_REG_CONF, 2, 1);
-    DBG printf("ADC cfg reg: 0x%X: ", value);
-    DBG print_binary_half_word((uint16_t)value);
-    
-    // Регистр статуса
-    value = MS5192T_GetRegisterValue(MS5192T_REG_STAT, 1, 1);
-    DBG printf("ADC status reg: 0x%X: ", value);
-    DBG print_binary_byte((uint8_t)value);
-
-    // Установка внутреннего опорного напряжения
-    MS5192T_SetIntReference(MS5192T_REFSEL_INT); // select internal 1.17V reference
-    value = MS5192T_GetRegisterValue(MS5192T_REG_CONF, 2, 1);
-    DBG printf("ADC cfg reg: 0x%X: ", value);
-    DBG print_binary_half_word((uint16_t)value);
-
-    // Регистр режима (MODE register)
-    value = MS5192T_GetRegisterValue(MS5192T_REG_MODE, 2, 1);
-    DBG printf("ADC mode reg: 0x%X: ", value);
-    DBG print_binary_half_word((uint16_t)value);
-    
-    // Установить update rate
-    DBG printf("Set update rate.\r\n");
-    MS5192T_SetUpdateRate(MS5192T_UP_RATE_500);
-    value = MS5192T_GetRegisterValue(MS5192T_REG_MODE, 2, 1);
-    DBG printf("ADC mode reg: 0x%X: ", value);
-    DBG print_binary_half_word((uint16_t)value);
-    
-    // Калибровка 
-    
-    // 1 - ый канал
-    MS5192T_Calibrate(MS5192T_MODE_CAL_INT_ZERO, MS5192T_CH_AIN1P_AIN1M); 
-    MS5192T_Calibrate(MS5192T_MODE_CAL_INT_FULL, MS5192T_CH_AIN1P_AIN1M); 
-    
-    // 2 - ой канал
-    MS5192T_Calibrate(MS5192T_MODE_CAL_INT_ZERO, MS5192T_CH_AIN2P_AIN2M); 
-    MS5192T_Calibrate(MS5192T_MODE_CAL_INT_FULL, MS5192T_CH_AIN2P_AIN2M); 
-          
-    return true;
-}  
-
-// Оцифровка всех 16-и каналов (входы + дополнительные каналы)
-void ai_processing(void)
-{
-    float filter_factor;
-
-    // 12 основных каналов 
-    for (uint8_t i = 0; i < AI_COMMON_NUMBER/2; i++)
-    {
-        adc_meas_two_channels(&settings.ai[i], &settings.ai[i + 6], 
-                              &adc_com_raw_data[i], &adc_com_raw_data[i + 6]);
-        
-        // ---------------------------------------------------------------------
-        // Фильтрованные данные
-        
-        filter_factor = settings.ai[i].mode == 0 ? VOLTAGE_FACTOR : CURRENT_FACTOR;
-          
-        adc_com_data[i] = (float)adc_com_raw_data[i]*filter_factor*
-                          settings.ai[i].k_factor + settings.ai[i].b_factor;
-        
-        filter_factor = settings.ai[i + 6].mode == 0 ? VOLTAGE_FACTOR : CURRENT_FACTOR;
-        
-        adc_com_data[i + 6] = (float)adc_com_raw_data[i + 6]*filter_factor*
-                              settings.ai[i + 6].k_factor + settings.ai[i + 6].b_factor;
-          
-        // ---------------------------------------------------------------------
-        // Фильтрация. Скользящее среднее. Только для отладки.
-        adc_com_fil_data[i]     = average_int(&average_filter[i], adc_com_raw_data[i]);
-        adc_com_fil_data[i + 6] = average_int(&average_filter[i + 6], adc_com_raw_data[i + 6]);
-    }
-
-    // 4 дополнительных канала
-    for (uint8_t i = 0; i < AI_ADD_NUMBER/2; i++)
-    {
-        adc_meas_two_channels(&settings.ai_add[i], &settings.ai_add[i + 2], 
-                              &adc_add_raw_data[i], &adc_add_raw_data[i + 2]);
-    }
-    
-    
-#if 0    
-    printf("end\r\n");
-    adc_print_data();
-    //adc_print_data_extend();
-    printf("end\r\n");  
-#endif
-}
-
-//
-void adc_meas_two_channels(ai_t *one, ai_t *two, uint16_t *out_one, uint16_t *out_two)
-{
-    uint8_t gain;
-    
-    // 1 - ый канал
-    if (one->state == 0) {
-        DBG printf("[one] channel name: %u off\r\n", one->name);
-        
-    }
-    else {
-        DBG printf("[one] channel name: %u on\r\n", one->name);
-        
-        gain = adc_get_gain(one->gain_factor);
-        MS5192T_SetGain(gain);
-        ai_connect_channel(one->name);
-        vTaskDelay(1);
-        MS5192T_SetChannel(MS5192T_CH_AIN1P_AIN1M);
-        *out_one = MS5192T_SingleConversion();
-    }            
-
-    // 2 - ой канал
-    if (two->state == 0) {
-        DBG printf("[two] channel name: %u off\r\n", two->name);
-    }
-    else {
-        DBG printf("[two] channel name: %u on\r\n", two->name);
-        
-        gain = adc_get_gain(two->gain_factor);
-        MS5192T_SetGain(gain);
-        ai_connect_channel(two->name);
-        vTaskDelay(1);
-        MS5192T_SetChannel(MS5192T_CH_AIN2P_AIN2M);
-        *out_two = MS5192T_SingleConversion();
-    }
-}
-
-//
-uint8_t adc_get_gain(uint8_t tmp) 
-{
-    uint8_t ret;
-    
-    switch (tmp)
-    {
-        case 1  : ret = MS5192T_GAIN_1;   break;
-        case 2  : ret = MS5192T_GAIN_2;   break;
-        case 4  : ret = MS5192T_GAIN_4;   break;
-        case 8  : ret = MS5192T_GAIN_8;   break;
-        case 16 : ret = MS5192T_GAIN_16;  break;
-        case 32 : ret = MS5192T_GAIN_32;  break;
-        case 64 : ret = MS5192T_GAIN_64;  break;
-        case 128: ret = MS5192T_GAIN_128; break;
-        default : ret = MS5192T_GAIN_1;   break;
-    }
-    return ret;
-}
-
-
-//
-void adc_print_data(void)
-{
-    printf("\033[2J"); 
-    printf("\033[H");  
-    
-#if 1    
-    printf("AN_INP_1:  0x%X, %.3f\r\n", adc_com_raw_data[0], adc_com_data[0]);
-    printf("AN_INP_2:  0x%X, %.3f\r\n", adc_com_raw_data[1], adc_com_data[1]);
-    printf("AN_INP_3:  0x%X, %.3f\r\n", adc_com_raw_data[2], adc_com_data[2]);
-    printf("AN_INP_4:  0x%X, %.3f\r\n", adc_com_raw_data[3], adc_com_data[3]);
-    printf("AN_INP_5:  0x%X, %.3f\r\n", adc_com_raw_data[4], adc_com_data[4]);
-    printf("AN_INP_6:  0x%X, %.3f\r\n", adc_com_raw_data[5], adc_com_data[5]);
-    printf("AN_INP_7:  0x%X, %.3f\r\n", adc_com_raw_data[6], adc_com_data[6]);
-    printf("AN_INP_8:  0x%X, %.3f\r\n", adc_com_raw_data[7], adc_com_data[7]);
-    printf("AN_INP_9:  0x%X, %.3f\r\n", adc_com_raw_data[8], adc_com_data[8]);
-    printf("AN_INP_10: 0x%X, %.3f\r\n", adc_com_raw_data[9], adc_com_data[9]);
-    printf("AN_INP_11: 0x%X, %.3f\r\n", adc_com_raw_data[10],adc_com_data[10]);
-    printf("AN_INP_12: 0x%X, %.3f\r\n", adc_com_raw_data[11],adc_com_data[11]);
-    
-    printf("V_ISO_CL:  0x%X, %f\r\n", adc_add_raw_data[0], (double)adc_add_raw_data[0]*VOLTAGE_FACTOR);
-    printf("V_ISO   :  0x%X, %f\r\n", adc_add_raw_data[1], (double)adc_add_raw_data[1]*VOLTAGE_FACTOR);
-    printf("CRNT_LIM_U_BFR_R : 0x%X, %f\r\n", adc_add_raw_data[2],(double)adc_add_raw_data[2]*VOLTAGE_FACTOR);
-    printf("CRNT_LIM_U_ABFR_R: 0x%X, %f\r\n", adc_add_raw_data[3],(double)adc_add_raw_data[3]*VOLTAGE_FACTOR);
-#endif
-}
-
-//
-void adc_print_data_extend(void)
-{
-    printf("\033[2J"); 
-    printf("\033[H");  
-    
-    printf("AN_INP_1: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[0], adc_com_fil_data[0], (double)adc_com_raw_data[0]*0.00001785305/0.0961538, (double)adc_com_fil_data[0]*0.00001785305/0.0961538);
-    printf("AN_INP_2: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[1], adc_com_fil_data[1], (double)adc_com_raw_data[1]*0.00001785305/0.0961538, (double)adc_com_fil_data[1]*0.00001785305/0.0961538);
-    printf("AN_INP_3: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[2], adc_com_fil_data[2], (double)adc_com_raw_data[2]*0.00001785305/0.0961538, (double)adc_com_fil_data[2]*0.00001785305/0.0961538);
-    printf("AN_INP_4: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[3], adc_com_fil_data[3], (double)adc_com_raw_data[3]*0.00001785305/0.0961538, (double)adc_com_fil_data[3]*0.00001785305/0.0961538);
-    printf("AN_INP_5: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[4], adc_com_fil_data[4], (double)adc_com_raw_data[4]*0.00001785305/0.0961538, (double)adc_com_fil_data[4]*0.00001785305/0.0961538);
-    printf("AN_INP_6: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[5], adc_com_fil_data[5], (double)adc_com_raw_data[5]*0.00001785305/0.0961538, (double)adc_com_fil_data[5]*0.00001785305/0.0961538);
-    printf("AN_INP_7: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[6], adc_com_fil_data[6], (double)adc_com_raw_data[6]*0.00001785305/0.0961538, (double)adc_com_fil_data[6]*0.00001785305/0.0961538);
-    printf("AN_INP_8: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[7], adc_com_fil_data[7], (double)adc_com_raw_data[7]*0.00001785305/0.0961538, (double)adc_com_fil_data[7]*0.00001785305/0.0961538);
-    printf("AN_INP_9: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[8], adc_com_fil_data[8], (double)adc_com_raw_data[8]*0.00001785305/0.0961538, (double)adc_com_fil_data[8]*0.00001785305/0.0961538);
-    printf("AN_INP_10: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[9], adc_com_fil_data[9],(double)adc_com_raw_data[9]*0.00001785305/0.0961538, (double)adc_com_fil_data[9]*0.00001785305/0.0961538);
-    printf("AN_INP_11: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[10], adc_com_fil_data[10], (double)adc_com_raw_data[10]*0.00001785305/0.0961538, (double)adc_com_fil_data[10]*0.00001785305/0.0961538);
-    printf("AN_INP_12: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[11], adc_com_fil_data[11], (double)adc_com_raw_data[11]*0.00001785305/0.0961538, (double)adc_com_fil_data[11]*0.00001785305/0.0961538);
-}
-
-
-// 
-void adc_task(void *params)
-{
-    for (;;)
-    {
-        ai_alarm = sh_ai_mode(ai_mode);
-        
-        ai_processing();
-        
-        ai_leds_processing();
-        
-        vTaskDelay(10);
-    }
-}
-
-
-// -------------------------------------------------------------------------- //
-//                      Определение аварий
-
-//
-void adc_alarm_task(void *params)
-{
-    for (;;)
-    {
-#if 1
-        //printf("Analog input mode: ");
-        //print_binary_half_word(ai_mode);
-              
-        ai_voltage_alarm_detect();
-#endif        
-        vTaskDelay(1000);
-    }  
-}
-
-
-// Определение аварий в режиме измерения напряжения
-// ai_voltage_alarm
-void ai_voltage_alarm_detect(void)
-{
-    for (int i = 0; i < AI_COMMON_NUMBER; i++)
-    {
-        // Вход включен и находится в режиме измерения напряжения
-        if (settings.ai[i].state && (settings.ai[i].mode == 0)) 
-        {
-            if (adc_com_data[i] > VOLT_ALARM_LIMIT)
-                ai_voltage_alarm |= 1 << i;
-            else
-                ai_voltage_alarm &= ~(1 << i);
-        }
-    }
-}
-
-
-// Опеределение аварий в режиме измерения тока
-// ai_current_low - авария датчика, значение ниже диапазона (не обрыв)
-// ai_current_high - авария, не обрыв линии (возможно неисправен датчик)
-// ai_current_fail - авария датчика, значение выше диапазона (не обрыв)
-void ai_current_alarm_detect(void)
-{
-    for (int i = 0; i < AI_COMMON_NUMBER; i++)
-    {
-        // Вход включен и находится в режиме измерения тока
-        if (settings.ai[i].state && (settings.ai[i].mode == 1))
-        {
-            if (adc_com_data[i] < 4.0)
-            {
-                // Вход в режиме измерения 4-20 mA
-                if (settings.ai[i].current_mode == 1) 
-                {
-                    if (adc_com_data[i] > 1.0)
-                    {
-                        // Авария датчика, значение ниже диапазона (не обрыв)
-                        ai_current_low |= 1 << i;
-                    }
-                    else
-                    {
-                        // Авария, не обрыв линии (возможно неисправен датчик)
-                        ai_current_fail |= 1 << i;
-                    }
-                }
-                else 
-                {
-                    // Снять флаги с аварий 
-                    // Авария датчика, значение ниже диапазона (не обрыв)
-                    // Авария, не обрыв линии (возможно неисправен датчик)
-                    ai_current_low &= ~(1 << i);
-                    ai_current_fail &= ~(1 << i);
-                }
-            }
-            // Измеряемый ток больше 4 mA
-            else
-            {
-                if (adc_com_data[i] > 20.0)
-                {
-                    // Снять флаги аварий
-                    // Авария, не обрыв линии (возможно неисправен датчик)
-                    ai_current_high &= ~(1 << i);
-                }
-                else
-                {
-                    // Авария датчика, значение выше диапазона (не обрыв)
-                    ai_current_high |= 1 << i;
-                  
-                    if (adc_com_data[i] > 22.0)
-                    {
-                        // Перевести вход в режим измерения напряжения
-                        ai_alarm_f[i].alarm_flag = true;
-                        // Ждать 5 минут (шунт должен остыть)
-                    }
-                }
-            }
-        }
-    }
-}
-
-
-// Контроль питания внешних датчиков
-// TODO добавить событие в журнал
-void ai_ext_sens_current_control(void)
-{
-    float crnt_lim_u_bfr = (float)adc_add_raw_data[2]*CRNT_LIM_V_FACTOR;
-    float crnt_lim_u_abfr = (float)adc_add_raw_data[3]*CRNT_LIM_V_FACTOR;
-      
-    if ((CUR_LIM_LOW_LIMIT < 23.0) || (CUR_LIM_LOW_LIMIT > 25.0))
-        return;
-    
-    if (settings.ext_sens_power == 0)
-        return;
-    
-    if ((crnt_lim_u_bfr - crnt_lim_u_abfr) < CUR_LIM_DELTA_U) 
-    {
-        // Снять флаг аварии
-        ai_load_sens_alarm = 0;
-    }
-    else 
-    {
-        ai_load_sens_alarm = 1;
-        
-        ai_cur_lim.alarm_flag = true;
-    }
-    
-    
-   //adc_add_raw_data[2],(double)adc_add_raw_data[2]*VOLTAGE_FACTOR);
-    //VOLTAGE_FACTOR
-      
-    //printf("CRNT_LIM_U_BFR_R : 0x%X, %f\r\n", adc_add_raw_data[2],(double)adc_add_raw_data[2]*VOLTAGE_FACTOR);
-    //printf("CRNT_LIM_U_ABFR_R: 0x%X, %f\r\n", adc_add_raw_data[3],(double)adc_add_raw_data[3]*VOLTAGE_FACTOR);
-      
-}
-
-
-// Отсчет времени при возникновении аварий на входах.
-// Вызывается раз в секунду.
-void ai_alarm_tim_handler(void)
-{
-    // Обычне каналы
-    for (int i = 0; i < AI_COMMON_NUMBER; i++)
-    {
-        if (ai_alarm_f[i].alarm_flag) {
-            ai_alarm_f[i].cnt++;
-            
-            // Принудительно перевести канал в режим измерения напряжения
-            ai_set_mode_word((MEAS_CHAN_MODE_t)0, i + 1);
-        }
-        else {
-            ai_alarm_f[i].cnt = 0;
-        }
-        
-        if (ai_alarm_f[i].cnt > CUR_ALARM_PAUSE)
-        {
-            ai_alarm_f[i].cnt = 0;
-            ai_alarm_f[i].alarm_flag = false;
-            
-            // Режим измерения канала из настроек. Он мог измениться.
-            ai_set_mode_word((MEAS_CHAN_MODE_t)(settings.ai[i].mode), i + 1);
-        }
-    }
-    
-    // Мониторинг аварии питания внешних датчиков
-    if (ai_cur_lim.alarm_flag) {
-        ai_cur_lim.cnt++;
-        
-        // отключить питание внешних датчиков
-        ai_ext_sens_power(0);
-    }
-    else {
-        ai_cur_lim.cnt = 0;
-    }
-    
-    if (ai_cur_lim.cnt > CUR_ALARM_PAUSE)
-    {
-        ai_cur_lim.cnt = 0;
-        ai_cur_lim.alarm_flag = false;
-        
-        // Питание внешних датчиков из настроек. Настройка могла измениться
-        ai_ext_sens_power(settings.ext_sens_power);
-    }
-    
-}
-
-
-// Подключить канал к АЦП
-// Одновременно могут быть подключены только 2 канала из наборов:
-// 1: AN_INP_1, AN_INP_2, AN_INP_3, AN_INP_4, AN_INP_5, AN_INP_6, V_ISO_CL, 
-//    V_ISO
-//
-// 2: AN_INP_7, AN_INP_8, AN_INP_9, AN_INP_10, AN_INP_11, AN_INP_12, 
-//    CRNT_LIM_U_BFR_R, CRNT_LIM_U_ABFR_R
-void ai_connect_channel(uint8_t channel)
-{
-    if (channel < MUX_401_CH) 
-    {
-        ai_mux &= 0xF0;
-    
-        switch (channel)
-        {
-            case AN_INP_1: ai_mux |= 0x03; break; // U301 Y3
-            case AN_INP_2: ai_mux |= 0x00; break; // U301 Y0
-            case AN_INP_3: ai_mux |= 0x05; break; // U301 Y5
-            case AN_INP_4: ai_mux |= 0x07; break; // U301 Y7
-            case AN_INP_5: ai_mux |= 0x06; break; // U301 Y6
-            case AN_INP_6: ai_mux |= 0x04; break; // U301 Y4
-            case V_ISO_CL: ai_mux |= 0x01; break; // U301 Y1
-            case V_ISO   : ai_mux |= 0x02; break; // U301 Y2
-            default: break;
-        }
-    }
-    else
-    {
-        ai_mux &= 0x87;
-        
-        switch (channel)
-        {
-            case AN_INP_7: ai_mux |= (0x04 << 4); break; // U401 Y4
-            case AN_INP_8: ai_mux |= (0x06 << 4); break; // U401 Y6
-            case AN_INP_9: ai_mux |= (0x07 << 4); break; // U401 Y7
-            case AN_INP_10:ai_mux |= (0x05 << 4); break; // U401 Y5
-            case AN_INP_11:ai_mux |= (0x02 << 4); break; // U401 Y2
-            case AN_INP_12:ai_mux |= (0x01 << 4); break; // U401 Y1
-            case CRNT_LIM_U_BFR_R: ai_mux  |= (0x00 << 4); break; // U401 Y0
-            case CRNT_LIM_U_ABFR_R: ai_mux |= (0x03 << 4); break; // U401 Y3
-            default: break;
-        }
-    }
-    
-    sh_ai_connect(ai_mux);
-    
-    //printf("Analog input connect register: ");
-    //print_binary_byte(ai_mux);
-}
-
-// 
-void ai_set(void)
-{
-    for (int i = 0; i < AI_COMMON_NUMBER; i++) 
-    {
-        if (((settings.ai_state_bits >> i) & 1) != settings.ai[i].state)
-        {
-            settings.ai[i].state = ((settings.ai_state_bits >> i) & 1);
-            if (settings.ai[i].state == 0) {
-                leds[ai_input_led[i]].state = LED_OFF;
-                adc_com_raw_data[i] = 0;
-                adc_com_data[i] = 0;                
-            }
-            else {
-                leds[ai_input_led[i]].state = LED_ON;
-            }
-        }
-    }
-}
-
-// Утсновить режим измерения канала (ток или напряжение)
-void ai_set_mode(MEAS_CHAN_MODE_t mode, uint8_t channel)
-{
-    if (mode == MEAS_CURRENT) 
-    {
-        if (channel < 7)
-            ai_mode |= (1 << (channel - 1));
-        else
-            ai_mode |= (1 << (channel + 1));
-    }
-    else
-        if (channel < 7)
-            ai_mode &= ~(1 << (channel - 1));
-        else
-            ai_mode &= ~(1 << (channel + 1));
-          
-    sh_ai_mode(ai_mode);
-    
-    //printf("Analog input mode: ");
-    print_binary_half_word(ai_mode);
-}
-
-// Формируем слово режима работы каналов (ai_mode)
-void ai_set_mode_word(MEAS_CHAN_MODE_t mode, uint8_t channel)
-{
-    if (mode == MEAS_CURRENT) 
-    {
-        if (channel < 7)
-            ai_mode |= (1 << (channel - 1));
-        else
-            ai_mode |= (1 << (channel + 1));
-    }
-    else
-        if (channel < 7)
-            ai_mode &= ~(1 << (channel - 1));
-        else
-            ai_mode &= ~(1 << (channel + 1));
-}
-
-// Сигнал питания внешних датчиков
-void ai_ext_sens_power(uint16_t state)
-{
-    if (state)
-        ai_mux |= 0x80;
-    else
-        ai_mux &= ~(0x80);
-}
-
-// Управления LED
-void ai_leds_processing(void)
-{
-    // Управление индикацией аварий (12 красных LED) (слово ai_alarm)
-    for (uint8_t i = 0; i < AI_COMMON_NUMBER; i++) {
-        if (ai_alarm & (1 << i)) {
-            leds[ai_alarm_led[i]].state = LED_ON;
-        }
-        else {
-            leds[ai_alarm_led[i]].state = LED_OFF;
-        }
-    }
-}
-
-
-//
-void adc_alarm_detect(void)
-{
-    
-}
-
-// -------------------------------------------------------------------------- //
-//                                  Тесты
-
-//
-void ai_connect_test(void)
-{
-    ai_connect_channel(AN_INP_1);
-    ai_connect_channel(AN_INP_2);
-    ai_connect_channel(AN_INP_3);
-    ai_connect_channel(AN_INP_4);
-    ai_connect_channel(AN_INP_5);
-    ai_connect_channel(AN_INP_6);
-    ai_connect_channel(V_ISO_CL);
-    ai_connect_channel(V_ISO);
-    
-    ai_connect_channel(AN_INP_7);
-    ai_connect_channel(AN_INP_8);
-    ai_connect_channel(AN_INP_9);
-    ai_connect_channel(AN_INP_10);
-    ai_connect_channel(AN_INP_11);
-    ai_connect_channel(AN_INP_12);
-    ai_connect_channel(CRNT_LIM_U_BFR_R);
-    ai_connect_channel(CRNT_LIM_U_ABFR_R);
-}
-
-//
-void ai_mode_test(void)
-{
-    for (uint8_t i = 1; i < 13; i++)
-    {
-        ai_set_mode(MEAS_VOLTAGE, i);
-    }
-}
-
+#include "at32f403a_407.h"
+#include "analog_input.h"
+#include "shift_reg.h"
+#include "utility.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "settings_api.h"
+#include "adc_transport.h"
+#include "ms5192t.h"
+#include "monitoring.h"
+#include "mux.h"
+#include "filter.h"
+#include <stdio.h>
+
+#undef DBG
+#define DBG if(0)
+
+#if defined (MAI_12)  
+
+#define VOLTAGE_FACTOR      0.182382
+#define CURRENT_FACTOR      0.00091191
+#define CRNT_LIM_V_FACTOR   0.0476
+#define VOLT_ALARM_LIMIT    10000.0
+#define CUR_ALARM_PAUSE     300 // время в секундах на остывание токового шунта
+#define CUR_LIM_LOW_LIMIT   23.0
+#define CUR_LIM_LOW_LIMIT   25.0
+#define CUR_LIM_DELTA_U     0.6
+
+
+uint8_t ai_mux;     // выход сдвигового регистра U1010 (управляет MUX 301, 401)
+                    // мультиплексоры отвечат за коммутацию аналоговых входов и АЦП
+
+uint16_t ai_mode;   // режим измерения аналоговых каналов (ток или напряжение)
+                    // 0000 0000 0000 0000 
+                    // младшие 6 (с 1..6) бит - каналы с 1 по 6 соответственно
+                    // биты 9..14 - каналы с 7 по 12 соответственно
+
+uint16_t ai_alarm;  // слово аварий входов
+
+uint16_t ai_gain[AI_COMMON_NUMBER]; // массив коэффициентов усиленя (modbus)
+
+uint16_t adc_com_raw_data[AI_COMMON_NUMBER]; // сырые данные
+float adc_com_data[AI_COMMON_NUMBER];        // пересчитанные, фильтрованные данные
+
+uint16_t adc_com_fil_data[AI_COMMON_NUMBER]; // Фильтрованные данные (только для отладки)
+
+uint16_t adc_add_raw_data[AI_ADD_NUMBER];
+
+
+led_t ai_alarm_led[12] = {IO_1_R, IO_2_R, IO_3_R, IO_4_R, 
+                          IO_5_R, IO_6_R, IO_7_R, IO_8_R, 
+                          IO_9_R, IO_10_R, IO_11_R, IO_12_R};
+
+led_t ai_input_led[12] = {IO_1_G, IO_2_G, IO_3_G, IO_4_G, 
+                          IO_5_G, IO_6_G, IO_7_G, IO_8_G, 
+                          IO_9_G, IO_10_G, IO_11_G, IO_12_G};
+
+uint16_t ai_state_bit;  // состояние аналоговых входов (вкл/выкл) битовое поле
+
+ai_alarm_t ai_alarm_f[AI_COMMON_NUMBER];    // Вспомогательная структура для 
+                                            //работы с авариями
+
+ai_alarm_t ai_cur_lim;  // Вспомогательная структура для работы с аварией 
+                        // модуля питания внешних датчиков
+
+
+// Авария датчика, значение ниже диапазона (не обрыв)
+// Авария, не обрыв линии (возможно неисправен датчик)
+// Авария датчика, значение выше диапазона (не обрыв)
+uint16_t ai_voltage_alarm;  // аварии в режиме измерения напряжения
+
+// аварии в режиме измерения тока
+uint16_t ai_current_low;    // значение ниже диапазона
+uint16_t ai_current_high;   // значение выше диапазона
+uint16_t ai_current_fail;   // авария (возможно неисправен датчик)
+uint16_t ai_load_sens_alarm;// авария превышения нагрузки на блок питания внешних датчиков
+
+//
+void ai_init(void)
+{
+    // Фильтры (скользящее среднее) для 12-и основных каналов
+    average_filter_init();
+  
+    // Зеленые LED сигнализируют (вкл/выкл) входов.
+    ai_led_update();    
+    
+    // Сдвиговые регистры
+    sh_init();          
+    
+    // Режим измерения
+    ai_set_meas_mode();
+    
+    // Питание внешних датчиков
+    ai_ext_sens_power(settings.ext_sens_power); 
+    
+    // Внешинй ADC
+    ai_adc_init();
+    
+    // Modbus параметры
+    ai_init_modbus_params();
+}
+
+//
+void ai_init_modbus_params(void)
+{
+    for (uint8_t i = 0; i < AI_COMMON_NUMBER; i++) {
+        ai_gain[i] = settings.ai[i].gain_factor;
+    }
+}   
+
+// Управление LED для 12-и основных входов
+void ai_led_update(void)
+{
+    for (int i = 0; i < AI_COMMON_NUMBER; i++) 
+    {
+        if (settings.ai[i].state)
+            leds[ai_input_led[i]].state = LED_ON;
+        else
+            leds[ai_input_led[i]].state = LED_OFF;
+    }
+}
+
+// Установить режим измерения каналов с 1 по 12.
+void ai_set_meas_mode(void)
+{
+    for (int i = 0; i < AI_COMMON_NUMBER; i++)
+    {
+        if (settings.ai[i].mode)
+            ai_set_mode_word((MEAS_CHAN_MODE_t)1, i + 1);
+        else 
+            ai_set_mode_word((MEAS_CHAN_MODE_t)0, i + 1);
+    }
+}   
+
+// Настройка внешнего ADC
+bool ai_adc_init(void)
+{
+    uint8_t ret;
+    unsigned long value;
+    
+    adc_gpio_init();
+    
+    for (uint32_t i = 0; i < 100; i++) {
+        MS5192T_Reset();
+        ret = MS5192T_Init();
+        DBG printf("ADC init status: %s\r\n", ret == 1 ? "OK" : "FAILED");
+        if (ret == 1)
+           break;
+        vTaskDelay(10);
+    }
+        
+    if (!ret) {
+        mon_set_err(MON_ADC_EXT, 1);
+        return false;
+    }
+    
+    // Запрос регистра конфигурации для (0x710 - значение по умолчанию)
+    value = MS5192T_GetRegisterValue(MS5192T_REG_CONF, 2, 1);
+    DBG printf("ADC cfg reg: 0x%X: ", value);
+    DBG print_binary_half_word((uint16_t)value);
+    
+    // Коэф-т усиления: 1
+    DBG printf("ADC. Set gain rate 1\r\n");
+    MS5192T_SetGain(MS5192T_GAIN_1);
+    value = MS5192T_GetRegisterValue(MS5192T_REG_CONF, 2, 1);
+    DBG printf("ADC cfg reg: 0x%X: ", value);
+    DBG print_binary_half_word((uint16_t)value);
+    
+    // Униполярный режим
+    DBG printf("Set unipolar input mode...\r\n");
+    MS5192T_SetPolar(MS5192T_CONF_UNIPOLAR);
+    value = MS5192T_GetRegisterValue(MS5192T_REG_CONF, 2, 1);
+    DBG printf("ADC cfg reg: 0x%X: ", value);
+    DBG print_binary_half_word((uint16_t)value);
+    
+    // Регистр статуса
+    value = MS5192T_GetRegisterValue(MS5192T_REG_STAT, 1, 1);
+    DBG printf("ADC status reg: 0x%X: ", value);
+    DBG print_binary_byte((uint8_t)value);
+
+    // Установка внутреннего опорного напряжения
+    MS5192T_SetIntReference(MS5192T_REFSEL_INT); // select internal 1.17V reference
+    value = MS5192T_GetRegisterValue(MS5192T_REG_CONF, 2, 1);
+    DBG printf("ADC cfg reg: 0x%X: ", value);
+    DBG print_binary_half_word((uint16_t)value);
+
+    // Регистр режима (MODE register)
+    value = MS5192T_GetRegisterValue(MS5192T_REG_MODE, 2, 1);
+    DBG printf("ADC mode reg: 0x%X: ", value);
+    DBG print_binary_half_word((uint16_t)value);
+    
+    // Установить update rate
+    DBG printf("Set update rate.\r\n");
+    MS5192T_SetUpdateRate(MS5192T_UP_RATE_500);
+    value = MS5192T_GetRegisterValue(MS5192T_REG_MODE, 2, 1);
+    DBG printf("ADC mode reg: 0x%X: ", value);
+    DBG print_binary_half_word((uint16_t)value);
+    
+    // Калибровка 
+    
+    // 1 - ый канал
+    MS5192T_Calibrate(MS5192T_MODE_CAL_INT_ZERO, MS5192T_CH_AIN1P_AIN1M); 
+    MS5192T_Calibrate(MS5192T_MODE_CAL_INT_FULL, MS5192T_CH_AIN1P_AIN1M); 
+    
+    // 2 - ой канал
+    MS5192T_Calibrate(MS5192T_MODE_CAL_INT_ZERO, MS5192T_CH_AIN2P_AIN2M); 
+    MS5192T_Calibrate(MS5192T_MODE_CAL_INT_FULL, MS5192T_CH_AIN2P_AIN2M); 
+          
+    return true;
+}  
+
+// Оцифровка всех 16-и каналов (входы + дополнительные каналы)
+void ai_processing(void)
+{
+    float filter_factor;
+
+    // 12 основных каналов 
+    for (uint8_t i = 0; i < AI_COMMON_NUMBER/2; i++)
+    {
+        adc_meas_two_channels(&settings.ai[i], &settings.ai[i + 6], 
+                              &adc_com_raw_data[i], &adc_com_raw_data[i + 6]);
+        
+        // ---------------------------------------------------------------------
+        // Фильтрованные данные
+        
+        filter_factor = settings.ai[i].mode == 0 ? VOLTAGE_FACTOR : CURRENT_FACTOR;
+          
+        adc_com_data[i] = (float)adc_com_raw_data[i]*filter_factor*
+                          settings.ai[i].k_factor + settings.ai[i].b_factor;
+        
+        filter_factor = settings.ai[i + 6].mode == 0 ? VOLTAGE_FACTOR : CURRENT_FACTOR;
+        
+        adc_com_data[i + 6] = (float)adc_com_raw_data[i + 6]*filter_factor*
+                              settings.ai[i + 6].k_factor + settings.ai[i + 6].b_factor;
+          
+        // ---------------------------------------------------------------------
+        // Фильтрация. Скользящее среднее. Только для отладки.
+        adc_com_fil_data[i]     = average_int(&average_filter[i], adc_com_raw_data[i]);
+        adc_com_fil_data[i + 6] = average_int(&average_filter[i + 6], adc_com_raw_data[i + 6]);
+    }
+
+    // 4 дополнительных канала
+    for (uint8_t i = 0; i < AI_ADD_NUMBER/2; i++)
+    {
+        adc_meas_two_channels(&settings.ai_add[i], &settings.ai_add[i + 2], 
+                              &adc_add_raw_data[i], &adc_add_raw_data[i + 2]);
+    }
+    
+    
+#if 1    
+    printf("end\r\n");
+    adc_print_data();
+    //adc_print_data_extend();
+    printf("end\r\n");  
+#endif
+}
+
+//
+void adc_meas_two_channels(ai_t *one, ai_t *two, uint16_t *out_one, uint16_t *out_two)
+{
+    uint8_t gain;
+    
+    // 1 - ый канал
+    if (one->state == 0) {
+        //DBG printf("[one] channel name: %u off\r\n", one->name);
+        
+    }
+    else {
+        //DBG printf("[one] channel name: %u on\r\n", one->name);
+        
+        gain = adc_get_gain(one->gain_factor);
+        MS5192T_SetGain(gain);
+        ai_connect_channel(one->name);
+        vTaskDelay(1);
+        MS5192T_SetChannel(MS5192T_CH_AIN1P_AIN1M);
+        *out_one = MS5192T_SingleConversion();
+    }            
+
+    // 2 - ой канал
+    if (two->state == 0) {
+        //DBG printf("[two] channel name: %u off\r\n", two->name);
+    }
+    else {
+        //DBG printf("[two] channel name: %u on\r\n", two->name);
+        
+        gain = adc_get_gain(two->gain_factor);
+        MS5192T_SetGain(gain);
+        ai_connect_channel(two->name);
+        vTaskDelay(1);
+        MS5192T_SetChannel(MS5192T_CH_AIN2P_AIN2M);
+        *out_two = MS5192T_SingleConversion();
+    }
+}
+
+//
+uint8_t adc_get_gain(uint8_t tmp) 
+{
+    uint8_t ret;
+    
+    switch (tmp)
+    {
+        case 1  : ret = MS5192T_GAIN_1;   break;
+        case 2  : ret = MS5192T_GAIN_2;   break;
+        case 4  : ret = MS5192T_GAIN_4;   break;
+        case 8  : ret = MS5192T_GAIN_8;   break;
+        case 16 : ret = MS5192T_GAIN_16;  break;
+        case 32 : ret = MS5192T_GAIN_32;  break;
+        case 64 : ret = MS5192T_GAIN_64;  break;
+        case 128: ret = MS5192T_GAIN_128; break;
+        default : ret = MS5192T_GAIN_1;   break;
+    }
+    return ret;
+}
+
+
+//
+void adc_print_data(void)
+{
+    printf("\033[2J"); 
+    printf("\033[H");  
+    
+#if 1    
+    printf("AN_INP_1:  0x%X, %.3f\r\n", adc_com_raw_data[0], adc_com_data[0]);
+    printf("AN_INP_2:  0x%X, %.3f\r\n", adc_com_raw_data[1], adc_com_data[1]);
+    printf("AN_INP_3:  0x%X, %.3f\r\n", adc_com_raw_data[2], adc_com_data[2]);
+    printf("AN_INP_4:  0x%X, %.3f\r\n", adc_com_raw_data[3], adc_com_data[3]);
+    printf("AN_INP_5:  0x%X, %.3f\r\n", adc_com_raw_data[4], adc_com_data[4]);
+    printf("AN_INP_6:  0x%X, %.3f\r\n", adc_com_raw_data[5], adc_com_data[5]);
+    printf("AN_INP_7:  0x%X, %.3f\r\n", adc_com_raw_data[6], adc_com_data[6]);
+    printf("AN_INP_8:  0x%X, %.3f\r\n", adc_com_raw_data[7], adc_com_data[7]);
+    printf("AN_INP_9:  0x%X, %.3f\r\n", adc_com_raw_data[8], adc_com_data[8]);
+    printf("AN_INP_10: 0x%X, %.3f\r\n", adc_com_raw_data[9], adc_com_data[9]);
+    printf("AN_INP_11: 0x%X, %.3f\r\n", adc_com_raw_data[10],adc_com_data[10]);
+    printf("AN_INP_12: 0x%X, %.3f\r\n", adc_com_raw_data[11],adc_com_data[11]);
+    
+    printf("V_ISO_CL:  0x%X, %f\r\n", adc_add_raw_data[0], (double)adc_add_raw_data[0]*VOLTAGE_FACTOR);
+    printf("V_ISO   :  0x%X, %f\r\n", adc_add_raw_data[1], (double)adc_add_raw_data[1]*VOLTAGE_FACTOR);
+    printf("CRNT_LIM_U_BFR_R : 0x%X, %f\r\n", adc_add_raw_data[2],(double)adc_add_raw_data[2]*VOLTAGE_FACTOR);
+    printf("CRNT_LIM_U_ABFR_R: 0x%X, %f\r\n", adc_add_raw_data[3],(double)adc_add_raw_data[3]*VOLTAGE_FACTOR);
+#endif
+}
+
+//
+void adc_print_data_extend(void)
+{
+    printf("\033[2J"); 
+    printf("\033[H");  
+    
+    printf("AN_INP_1: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[0], adc_com_fil_data[0], (double)adc_com_raw_data[0]*0.00001785305/0.0961538, (double)adc_com_fil_data[0]*0.00001785305/0.0961538);
+    printf("AN_INP_2: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[1], adc_com_fil_data[1], (double)adc_com_raw_data[1]*0.00001785305/0.0961538, (double)adc_com_fil_data[1]*0.00001785305/0.0961538);
+    printf("AN_INP_3: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[2], adc_com_fil_data[2], (double)adc_com_raw_data[2]*0.00001785305/0.0961538, (double)adc_com_fil_data[2]*0.00001785305/0.0961538);
+    printf("AN_INP_4: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[3], adc_com_fil_data[3], (double)adc_com_raw_data[3]*0.00001785305/0.0961538, (double)adc_com_fil_data[3]*0.00001785305/0.0961538);
+    printf("AN_INP_5: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[4], adc_com_fil_data[4], (double)adc_com_raw_data[4]*0.00001785305/0.0961538, (double)adc_com_fil_data[4]*0.00001785305/0.0961538);
+    printf("AN_INP_6: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[5], adc_com_fil_data[5], (double)adc_com_raw_data[5]*0.00001785305/0.0961538, (double)adc_com_fil_data[5]*0.00001785305/0.0961538);
+    printf("AN_INP_7: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[6], adc_com_fil_data[6], (double)adc_com_raw_data[6]*0.00001785305/0.0961538, (double)adc_com_fil_data[6]*0.00001785305/0.0961538);
+    printf("AN_INP_8: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[7], adc_com_fil_data[7], (double)adc_com_raw_data[7]*0.00001785305/0.0961538, (double)adc_com_fil_data[7]*0.00001785305/0.0961538);
+    printf("AN_INP_9: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[8], adc_com_fil_data[8], (double)adc_com_raw_data[8]*0.00001785305/0.0961538, (double)adc_com_fil_data[8]*0.00001785305/0.0961538);
+    printf("AN_INP_10: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[9], adc_com_fil_data[9],(double)adc_com_raw_data[9]*0.00001785305/0.0961538, (double)adc_com_fil_data[9]*0.00001785305/0.0961538);
+    printf("AN_INP_11: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[10], adc_com_fil_data[10], (double)adc_com_raw_data[10]*0.00001785305/0.0961538, (double)adc_com_fil_data[10]*0.00001785305/0.0961538);
+    printf("AN_INP_12: 0x%X 0x%X %f %f\r\n", adc_com_raw_data[11], adc_com_fil_data[11], (double)adc_com_raw_data[11]*0.00001785305/0.0961538, (double)adc_com_fil_data[11]*0.00001785305/0.0961538);
+}
+
+
+// 
+void adc_task(void *params)
+{
+    for (;;)
+    {
+        ai_alarm = sh_ai_mode(ai_mode);
+        
+        ai_processing();
+        
+        ai_leds_processing();
+        
+        vTaskDelay(10);
+    }
+}
+
+
+// -------------------------------------------------------------------------- //
+//                      Определение аварий
+
+//
+void adc_alarm_task(void *params)
+{
+    for (;;)
+    {
+#if 1
+        //printf("Analog input mode: ");
+        //print_binary_half_word(ai_mode);
+              
+        ai_voltage_alarm_detect();
+#endif        
+        vTaskDelay(1000);
+    }  
+}
+
+
+// Определение аварий в режиме измерения напряжения
+// ai_voltage_alarm
+void ai_voltage_alarm_detect(void)
+{
+    for (int i = 0; i < AI_COMMON_NUMBER; i++)
+    {
+        // Вход включен и находится в режиме измерения напряжения
+        if (settings.ai[i].state && (settings.ai[i].mode == 0)) 
+        {
+            if (adc_com_data[i] > VOLT_ALARM_LIMIT)
+                ai_voltage_alarm |= 1 << i;
+            else
+                ai_voltage_alarm &= ~(1 << i);
+        }
+    }
+}
+
+
+// Опеределение аварий в режиме измерения тока
+// ai_current_low - авария датчика, значение ниже диапазона (не обрыв)
+// ai_current_high - авария, не обрыв линии (возможно неисправен датчик)
+// ai_current_fail - авария датчика, значение выше диапазона (не обрыв)
+void ai_current_alarm_detect(void)
+{
+    for (int i = 0; i < AI_COMMON_NUMBER; i++)
+    {
+        // Вход включен и находится в режиме измерения тока
+        if (settings.ai[i].state && (settings.ai[i].mode == 1))
+        {
+            if (adc_com_data[i] < 4.0)
+            {
+                // Вход в режиме измерения 4-20 mA
+                if (settings.ai[i].current_mode == 1) 
+                {
+                    if (adc_com_data[i] > 1.0)
+                    {
+                        // Авария датчика, значение ниже диапазона (не обрыв)
+                        ai_current_low |= 1 << i;
+                    }
+                    else
+                    {
+                        // Авария, не обрыв линии (возможно неисправен датчик)
+                        ai_current_fail |= 1 << i;
+                    }
+                }
+                else 
+                {
+                    // Снять флаги с аварий 
+                    // Авария датчика, значение ниже диапазона (не обрыв)
+                    // Авария, не обрыв линии (возможно неисправен датчик)
+                    ai_current_low &= ~(1 << i);
+                    ai_current_fail &= ~(1 << i);
+                }
+            }
+            // Измеряемый ток больше 4 mA
+            else
+            {
+                if (adc_com_data[i] > 20.0)
+                {
+                    // Снять флаги аварий
+                    // Авария, не обрыв линии (возможно неисправен датчик)
+                    ai_current_high &= ~(1 << i);
+                }
+                else
+                {
+                    // Авария датчика, значение выше диапазона (не обрыв)
+                    ai_current_high |= 1 << i;
+                  
+                    if (adc_com_data[i] > 22.0)
+                    {
+                        // Перевести вход в режим измерения напряжения
+                        ai_alarm_f[i].alarm_flag = true;
+                        // Ждать 5 минут (шунт должен остыть)
+                    }
+                }
+            }
+        }
+    }
+}
+
+
+// Контроль питания внешних датчиков
+// TODO добавить событие в журнал
+void ai_ext_sens_current_control(void)
+{
+    float crnt_lim_u_bfr = (float)adc_add_raw_data[2]*CRNT_LIM_V_FACTOR;
+    float crnt_lim_u_abfr = (float)adc_add_raw_data[3]*CRNT_LIM_V_FACTOR;
+      
+    if ((CUR_LIM_LOW_LIMIT < 23.0) || (CUR_LIM_LOW_LIMIT > 25.0))
+        return;
+    
+    if (settings.ext_sens_power == 0)
+        return;
+    
+    if ((crnt_lim_u_bfr - crnt_lim_u_abfr) < CUR_LIM_DELTA_U) 
+    {
+        // Снять флаг аварии
+        ai_load_sens_alarm = 0;
+    }
+    else 
+    {
+        ai_load_sens_alarm = 1;
+        
+        ai_cur_lim.alarm_flag = true;
+    }
+    
+    
+   //adc_add_raw_data[2],(double)adc_add_raw_data[2]*VOLTAGE_FACTOR);
+    //VOLTAGE_FACTOR
+      
+    //printf("CRNT_LIM_U_BFR_R : 0x%X, %f\r\n", adc_add_raw_data[2],(double)adc_add_raw_data[2]*VOLTAGE_FACTOR);
+    //printf("CRNT_LIM_U_ABFR_R: 0x%X, %f\r\n", adc_add_raw_data[3],(double)adc_add_raw_data[3]*VOLTAGE_FACTOR);
+      
+}
+
+
+// Отсчет времени при возникновении аварий на входах.
+// Вызывается раз в секунду.
+void ai_alarm_tim_handler(void)
+{
+    // Обычне каналы
+    for (int i = 0; i < AI_COMMON_NUMBER; i++)
+    {
+        if (ai_alarm_f[i].alarm_flag) {
+            ai_alarm_f[i].cnt++;
+            
+            // Принудительно перевести канал в режим измерения напряжения
+            ai_set_mode_word((MEAS_CHAN_MODE_t)0, i + 1);
+        }
+        else {
+            ai_alarm_f[i].cnt = 0;
+        }
+        
+        if (ai_alarm_f[i].cnt > CUR_ALARM_PAUSE)
+        {
+            ai_alarm_f[i].cnt = 0;
+            ai_alarm_f[i].alarm_flag = false;
+            
+            // Режим измерения канала из настроек. Он мог измениться.
+            ai_set_mode_word((MEAS_CHAN_MODE_t)(settings.ai[i].mode), i + 1);
+        }
+    }
+    
+    // Мониторинг аварии питания внешних датчиков
+    if (ai_cur_lim.alarm_flag) {
+        ai_cur_lim.cnt++;
+        
+        // отключить питание внешних датчиков
+        ai_ext_sens_power(0);
+    }
+    else {
+        ai_cur_lim.cnt = 0;
+    }
+    
+    if (ai_cur_lim.cnt > CUR_ALARM_PAUSE)
+    {
+        ai_cur_lim.cnt = 0;
+        ai_cur_lim.alarm_flag = false;
+        
+        // Питание внешних датчиков из настроек. Настройка могла измениться
+        ai_ext_sens_power(settings.ext_sens_power);
+    }
+    
+}
+
+
+// Подключить канал к АЦП
+// Одновременно могут быть подключены только 2 канала из наборов:
+// 1: AN_INP_1, AN_INP_2, AN_INP_3, AN_INP_4, AN_INP_5, AN_INP_6, V_ISO_CL, 
+//    V_ISO
+//
+// 2: AN_INP_7, AN_INP_8, AN_INP_9, AN_INP_10, AN_INP_11, AN_INP_12, 
+//    CRNT_LIM_U_BFR_R, CRNT_LIM_U_ABFR_R
+void ai_connect_channel(uint8_t channel)
+{
+    if (channel < MUX_401_CH) 
+    {
+        ai_mux &= 0xF0;
+    
+        switch (channel)
+        {
+            case AN_INP_1: ai_mux |= 0x03; break; // U301 Y3
+            case AN_INP_2: ai_mux |= 0x00; break; // U301 Y0
+            case AN_INP_3: ai_mux |= 0x05; break; // U301 Y5
+            case AN_INP_4: ai_mux |= 0x07; break; // U301 Y7
+            case AN_INP_5: ai_mux |= 0x06; break; // U301 Y6
+            case AN_INP_6: ai_mux |= 0x04; break; // U301 Y4
+            case V_ISO_CL: ai_mux |= 0x01; break; // U301 Y1
+            case V_ISO   : ai_mux |= 0x02; break; // U301 Y2
+            default: break;
+        }
+    }
+    else
+    {
+        ai_mux &= 0x87;
+        
+        switch (channel)
+        {
+            case AN_INP_7: ai_mux |= (0x04 << 4); break; // U401 Y4
+            case AN_INP_8: ai_mux |= (0x06 << 4); break; // U401 Y6
+            case AN_INP_9: ai_mux |= (0x07 << 4); break; // U401 Y7
+            case AN_INP_10:ai_mux |= (0x05 << 4); break; // U401 Y5
+            case AN_INP_11:ai_mux |= (0x02 << 4); break; // U401 Y2
+            case AN_INP_12:ai_mux |= (0x01 << 4); break; // U401 Y1
+            case CRNT_LIM_U_BFR_R: ai_mux  |= (0x00 << 4); break; // U401 Y0
+            case CRNT_LIM_U_ABFR_R: ai_mux |= (0x03 << 4); break; // U401 Y3
+            default: break;
+        }
+    }
+    
+    sh_ai_connect(ai_mux);
+    
+    //printf("Analog input connect register: ");
+    //print_binary_byte(ai_mux);
+}
+
+// 
+void ai_set(void)
+{
+    for (int i = 0; i < AI_COMMON_NUMBER; i++) 
+    {
+        if (((settings.ai_state_bits >> i) & 1) != settings.ai[i].state)
+        {
+            settings.ai[i].state = ((settings.ai_state_bits >> i) & 1);
+            if (settings.ai[i].state == 0) {
+                leds[ai_input_led[i]].state = LED_OFF;
+                adc_com_raw_data[i] = 0;
+                adc_com_data[i] = 0;                
+            }
+            else {
+                leds[ai_input_led[i]].state = LED_ON;
+            }
+        }
+    }
+}
+
+// Утсновить режим измерения канала (ток или напряжение)
+void ai_set_mode(MEAS_CHAN_MODE_t mode, uint8_t channel)
+{
+    if (mode == MEAS_CURRENT) 
+    {
+        if (channel < 7)
+            ai_mode |= (1 << (channel - 1));
+        else
+            ai_mode |= (1 << (channel + 1));
+    }
+    else
+        if (channel < 7)
+            ai_mode &= ~(1 << (channel - 1));
+        else
+            ai_mode &= ~(1 << (channel + 1));
+          
+    sh_ai_mode(ai_mode);
+    
+    //printf("Analog input mode: ");
+    print_binary_half_word(ai_mode);
+}
+
+// Формируем слово режима работы каналов (ai_mode)
+void ai_set_mode_word(MEAS_CHAN_MODE_t mode, uint8_t channel)
+{
+    if (mode == MEAS_CURRENT) 
+    {
+        if (channel < 7)
+            ai_mode |= (1 << (channel - 1));
+        else
+            ai_mode |= (1 << (channel + 1));
+    }
+    else
+        if (channel < 7)
+            ai_mode &= ~(1 << (channel - 1));
+        else
+            ai_mode &= ~(1 << (channel + 1));
+}
+
+// Сигнал питания внешних датчиков
+void ai_ext_sens_power(uint16_t state)
+{
+    if (state)
+        ai_mux |= 0x80;
+    else
+        ai_mux &= ~(0x80);
+}
+
+// Управления LED
+void ai_leds_processing(void)
+{
+    // Управление индикацией аварий (12 красных LED) (слово ai_alarm)
+    for (uint8_t i = 0; i < AI_COMMON_NUMBER; i++) {
+        if (ai_alarm & (1 << i)) {
+            leds[ai_alarm_led[i]].state = LED_ON;
+        }
+        else {
+            leds[ai_alarm_led[i]].state = LED_OFF;
+        }
+    }
+}
+
+
+//
+void adc_alarm_detect(void)
+{
+    
+}
+
+// -------------------------------------------------------------------------- //
+//                                  Тесты
+
+//
+void ai_connect_test(void)
+{
+    ai_connect_channel(AN_INP_1);
+    ai_connect_channel(AN_INP_2);
+    ai_connect_channel(AN_INP_3);
+    ai_connect_channel(AN_INP_4);
+    ai_connect_channel(AN_INP_5);
+    ai_connect_channel(AN_INP_6);
+    ai_connect_channel(V_ISO_CL);
+    ai_connect_channel(V_ISO);
+    
+    ai_connect_channel(AN_INP_7);
+    ai_connect_channel(AN_INP_8);
+    ai_connect_channel(AN_INP_9);
+    ai_connect_channel(AN_INP_10);
+    ai_connect_channel(AN_INP_11);
+    ai_connect_channel(AN_INP_12);
+    ai_connect_channel(CRNT_LIM_U_BFR_R);
+    ai_connect_channel(CRNT_LIM_U_ABFR_R);
+}
+
+//
+void ai_mode_test(void)
+{
+    for (uint8_t i = 1; i < 13; i++)
+    {
+        ai_set_mode(MEAS_VOLTAGE, i);
+    }
+}
+
 #endif

+ 1 - 1
fw/modules/monitor/monitoring.c

@@ -7,7 +7,7 @@ uint32_t mon_state; // Слово состояний модуля (в modbus)
 
 
 // state == true (есть ошибка, нужно установить бит)
-void mon_set_err(err_code_t err_code, bool state)
+void mon_set_err(monitor_err_code_t err_code, uint8_t state)
 {
     if (state)
         mon_state |= err_code;

+ 9 - 4
fw/modules/monitor/monitoring.h

@@ -9,13 +9,18 @@
 // Коды ошибок модуля
 typedef enum
 {
-    ERR_OK  = 0 << 1,
-    ADC_ERR = 1 << 1,
+    MON_ERR_OK  = 0 << 1,
+    MON_RTC     = 1 << 1,
+    MON_EEPROM  = 1 << 2,
+    MON_CHN     = 1 << 3,
+    MON_ADC_EXT = 1 << 4,
+    MON_DAC     = 1 << 5,
+    MON_ADC_INT = 1 << 6,
     
-} err_code_t;
+} monitor_err_code_t;
 
 
-void mon_set_err(err_code_t err_code, bool state);
+void mon_set_err(monitor_err_code_t err_code, uint8_t state);
 
 
 extern uint32_t mon_state; 

+ 11 - 3
fw/user/main.cpp

@@ -42,6 +42,7 @@ extern "C" {
 #include "filter.h"
 #include "modbus_ai_params.h"
 #include "rtc_battery.h"
+#include "monitoring.h"
 }
 #include "terminal_sbs.h"
 #include "terminal_usartbridge.h"
@@ -80,6 +81,8 @@ int main(void)
 
 void init_task(void *argument)
 {
+    uint8_t ret;
+    
 // -------------------------------------------------------------------------- //    
 // Software watchdog
   
@@ -108,7 +111,7 @@ void init_task(void *argument)
     // Настройки параметров порта Modbus
     settings_set_modbus_params(settings.com_settings.mb_port);
     
-#if 0
+#if 1
 // Только для теста    
     settings_set_all_default();
     settings_save(&settings);
@@ -164,8 +167,13 @@ void init_task(void *argument)
     
 // -------------------------------------------------------------------------- //
 // RTC, ADC для измерения напряжения батареи.
-    
-    TM_RTC_Init();
+    ret = TM_RTC_Init();
+
+    if (bpr_data_read(BACKUP_RTC_UPDATE) != 0x1234) 
+        mon_set_err(MON_RTC, 1);
+    else
+        mon_set_err(MON_RTC, 0);
+
     rtc_subtim_init();
     
     adc_battery_init();

BIN
output/fw.bin


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 345 - 339
project/ewarm/iap/iap.dep


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 771 - 763
project/ewarm/module_universal_io.dep


+ 3 - 0
shared/board/common_config.h

@@ -71,6 +71,9 @@
 //
 #define BACKUP_RTC_KEY                  BPR_DATA4
 
+//
+#define BACKUP_RTC_UPDATE               BPR_DATA5
+
 // -------------------------------------------------------------------------- //
 
 // Флаги, статусы

+ 1 - 0
shared/rtc/rtc.c

@@ -128,6 +128,7 @@ void TM_RTC_SetDataTimeUnix(uint32_t unixTime)
     TM_RTC_GetDateTimeFromUnix(&data, unixTime);
     rtc_counter_set(unixTime);
     rtc_wait_config_finish();
+    bpr_data_write(BACKUP_RTC_UPDATE, 0x1234);
 }
 
 

BIN
tools/__pycache__/sys_params.cpython-312.pyc


+ 3 - 2
tools/analog_in.py

@@ -241,11 +241,12 @@ def main():
     '''
 
 
-    ai.sys.get_system_vars()     
+    # ai.sys.get_system_vars()     
     
     # print(ai.get_inputs_state())
     # ai.set_inputs_state(0b1111_1111_1111)
-    # ai.set_inputs_state(0b0000_0000_0001)
+    print(ai.sys.get_module_state())
+    # ai.set_inputs_state(0b0000_0000_0000)
     # ai.set_inputs_state(0b1111_1111_1111)
     # print(ai.get_inputs_state())
     

+ 6 - 0
tools/sys_params.py

@@ -122,6 +122,12 @@ class IO_SysParams:
     def get_bat_votage(self):
         return self.modbus.read_float_holding(SysReg.BAT_VOLTAGE.value)
 
+    def get_module_state(self):
+        '''Состояние модуля'''
+        return self.modbus.read_uint32_holding(SysReg.ERR.value)
+
+
+
     def set_rtc(self):
         """Установить текущее время"""
         t = int((time.time() + self.utc_offset) * 1000)

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä