#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 #undef DBG #define DBG if(0) #if defined (MAI_12) #define VOLTAGE_FACTOR 0.182382 #define CURRENT_FACTOR 0.00091191 #define VOLT_ALARM_LIMIT 10000.0 //uint16_t ai_state_bit; 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; // состояние аналоговых входов (вкл/выкл) битовое поле // Авария датчика, значение ниже диапазона (не обрыв) // Авария, не обрыв линии (возможно неисправен датчик) // Авария датчика, значение выше диапазона (не обрыв) uint16_t ai_voltage_alarm; // аварии в режиме измерения напряжения // аварии в режиме измерения тока uint16_t ai_current_low; // значение ниже диапазона uint16_t ai_current_high; // значение выше диапазона uint16_t ai_current_fail; // авария (возможно неисправен датчик) // 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 - авария датчика, значение выше диапазона (не обрыв) // TODO Реализовать принудительное переключение в режим измерения напряжения на 5 минут 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) { // Перевести вход в режим измерения напряжения // Ждать 5 минут (шунт должен остыть) } } } } } } // Подключить канал к АЦП // Одновременно могут быть подключены только 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