Измерение веса руды по току статора. Практика. Часть 2. Программная реализация на МК

в 6:34, , рубрики: алгоритм измерения веса руды на МК, Алгоритмы, Анализ и проектирование систем, измерение веса на МК, Измерение веса руды по току статора, программа для МК, программирование микроконтроллеров, разработка

Последняя часть из цикла «Измерение веса полезных ископаемых». В данной статье будет показана программная реализация на МК.

Вспомним основы данного метода измерение веса полезных ископаемых по току статора шахтной подъемной установки (ШПУ), оборудованной высоковольтным асинхронным двигателем с фазным ротором.

Вместо предисловия

Так как реальное устройство не проектировалось и не изготавливалось, то для симулирования данного процесса использовался программный комплекс Proteus. Данный симулятор поддерживает множество различных МК и из списка им поддерживаемых выбиралась аппаратная платформа для реализации алгоритма и проверки всего метода.

Предисловие

Для удобства проведения испытаний при симулировании, исходная схема в протеусе, показанная в первой части, претерпела изменения. Рассмотрим изменения.
Измерение веса руды по току статора. Практика. Часть 2. Программная реализация на МК - 1
Первый лист схемы. Картинка кликабельна.

Изменения коснулись в размножение сигнала напряжения, разрыва токовой цепи, введения индуктивной составляющей в цепь нагрузки.
Измерение веса руды по току статора. Практика. Часть 2. Программная реализация на МК - 2
Второй лист схемы. Картинка кликабельна.

Используется компонент ComPim, для связи с ком портом системы. МК фирмы Microchip. Входные сигналы с первого листа. Приборы (вольтметр, амперметр) для визуального контроля параметров напряжения и тока. Переключатели, используются для проведения автоматического вычисления средней точки каналов тока и напряжения.

Введение

При написании программы для МК PIC18F2580 использовалась бесплатная IDE MpLab X v 2.26, компилятор XC8 v1.20.
Во время разработки программы, пришлось написать собственные математические функции:

  • извлечение квадратного корня из целого 32-х битного числа,
  • извлечение квадратного корня из числа с плавающей точкой одинарной точности,
  • умножение целых беззнаковых чисел 16 бит,
  • умножение целых знаковых чисел 16 бит.

Стандартные функции, которые компилятор использует, не подходили в плане быстродействия, это касается умножения 16х16. А библиотечной функции извлечения квадратного корня из целого 32-х битного числа вообще не нашлось.

Также в проекте использовались пользовательские типы переменных. Они введены для удобства использования.

Пользовательские типы переменных описаны в хидере user_type.h

Инициализация МК

Инициализация МК вынесена в отдельный модуль в проекте. Производится согласно даташиту на МК. В хидере модуля инициализации включены конфигурационные биты (фьюзы). Для данных МК эти фьюзы можно зашить в прошивку, в .hex файл.

Вот хидер.

#include <xc.h>

/*
 Установка конфигурационных битов МК
*/
#pragma config IESO = OFF
#pragma config OSC = HSPLL      //HS oscillator, PLL enabled (Clock Frequency = 4 x FOSC1)
#pragma config MCLRE = ON       //MCLR pin enabled; RE3 input pin disabled
#pragma config XINST = OFF      //Instruction set extension and Indexed Addressing mode disabled (Legacy mode)
#pragma config PBADEN = OFF     //PORTB<4:0> pins are configured as digital I/O on Reset

/*
 Прототипы функций инициализация периферии МК
 */
void INT_init(void);
void T0_init(void);
void ADC_init(void);
void USART_init(int BAUD);
void T2_init(void);
void PIC_init(void);

Инициализируем необходимую периферию собственной функцией.

Прерывания в данном МК имеют приоритет. Уровней всего два: высокий и низкий. Прерывание от таймера 0, по которому отсчитываем временные интервалы (семплы) для измерений сигналов напряжения и тока, имеет высокий приоритет, так как он критичный ко времени, остальные низкий.

Обработка сигналов с АЦП

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

   if (Count_sample<SAMPLE){       //Если не достигли нужного количества измерений
        ADCON0bits.GO_DONE=1;       //Запускаем преобразование АЦП
        while(ADCON0bits.GO_DONE);  //Ждем окончание
        ADCON0bits.CHS0=0;          //Подключаем первый канал
        I_adc.byte.HB=ADRESH;
        I_adc.byte.LB=ADRESL;       //Считываем код АЦП
        I_int=(INT)I_adc.Val-I_0.Val;
        /*
         * Так как программные реализации умножения используют алгоритм без
         * использования аппаратного умножителя, пользуемся пользовательской
         * функцией для умножения с привлечением аппаратного умножителя 8х8
         * При симулировании программы встроенным симулятором, скорость
         * выполнения операции умножения 16х16=32 бита возросла почти в четыре раза,
         * количество инструкций уменьшилось
         * с 854 до 288 для беззнакового и до 302 для знакового произведения,
         * при чем пользовательская функция выполняется
         * практически в одном и том же диапазоне инструкций, независимо от значения
         * переменных входящих в произведение
         */
        I_sum+=(SLONG)mul_int(I_int,I_int);
        ADCON0bits.GO_DONE=1;       //Запускаем преобразование АЦП
        while(ADCON0bits.GO_DONE);  //Ждем окончание
        ADCON0bits.CHS0=1;          //Подключаем второй канал к модулю АЦП
        U_adc.byte.HB=ADRESH;
        U_adc.byte.LB=ADRESL;       //Считываем код АЦП
        U_int=(INT)U_adc.Val-U_0.Val;
        U_sum+=(SLONG)mul_int(U_int,U_int);
        P_act+=(SLONG)mul_sint(U_int,I_int);
        Count_sample++;
    }   
    if (Count_sample>=SAMPLE){      //Завершаем измерения, останавливаем таймер
        Count_sample=0;
        Flag_izm=1;
        T0CONbits.TMR0ON=0;
    }

В основном цикле, по флагу Flag_izm производим дополнительные промежуточные вычисления.

if (Flag_izm){                              //Производим расчеты
            Flag_izm=0;
            if (Count_main_sample<MAIN_SAMPLE){
                U_d+=(SLONG)U_sum;
                U_sum=0;
                I_d+=(SLONG)I_sum;
                I_sum=0;
                P_m+=(SLONG)P_act;
                P_act=0;
Count_main_sample++;
            }
}

Протокол ModBus RTU

В данной реализации связь с «внешним» миром осуществляется с использованием USART МК, поверх данного интерфейса применен промышленный протокол ModBus RTU. Реализация данного протокола довольна проста и не ресурсоемка. Прием сообщений производится в прерывании от приемника USART.

    /*обработчик прерывания от приемника уарт*/
    if (PIR1bits.RCIF){
        if (RCSTAbits.FERR || RCSTAbits.OERR) {         /*В случае ошибки приемника*/
            RCSTAbits.CREN=0;                           /*Отключаем приемник для сброса ошибки*/
            RCSTAbits.CREN=1;                           /*Включаем приемник для продолжения работы УАРТ*/
        }
        MODBUS.rxtimer=0;                               /*Сбрасываем таймер конца фрейма по приему очереднего байта*/
        if(MODBUS.rxcnt>(BUF_SZ-2)) MODBUS.rxcnt=0;
            MODBUS.buffer[MODBUS.rxcnt++]=RCREG1;        /*Записываем очередной байт в массив данных ModBus*/
        PIR1bits.RCIF=0;                                /*Сбрасываем флаг прерывания от приемника УАРТ*/
    }

Обработка сообщений от мастера происходит в основном цикле, когда критичные ко времени измерения закончены.

if (Flag_izm){                              //Производим расчеты
…
if (MODBUS.rxgap){                  //Если пришло сообщение
                    MODBUS_SLAVE(&MODBUS);          //обрабатываем его
                    MODBUS.rxgap=0;
                } 
}

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

/*
 * Функция отправки сообщения мастеру
 */
void TX_FRAME(UART_DATA *MODBUS)
{
      RCSTAbits.CREN=0;
      TXSTAbits.TXEN=1;
      INTCONbits.GIEH=0;                                             /* во время передачи отключим прерывания*/
      INTCONbits.GIEL=0;
      while(MODBUS->txcnt<MODBUS->txlen){
         TXREG=MODBUS->buffer[MODBUS->txcnt++];
         while(!PIR1bits.TXIF) NOP();
      }
      INTCONbits.GIEH=1;
      INTCONbits.GIEL=1;
      MODBUS->txlen=0;
      RCSTAbits.CREN=1;
}

Заполнение таблицы регистров ModBus

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

Начнем с первого регистра (нулевого). В него положим значение действующего напряжения в формате Real, то есть значение будет занимать два 16-ти битных регистра Modbus. Далее значение тока, активной мощности, полной мощности, косинуса.

                res_table[0].Val=U_real.word.LW;    //Заполняем таблицу регистров
                res_table[1].Val=U_real.word.HW;    //Модбас, для ответа мастеру
                res_table[2].Val=I_real.word.LW;
                res_table[3].Val=I_real.word.HW;
                res_table[4].Val=P_real.word.LW;
                res_table[5].Val=P_real.word.HW;
                res_table[6].Val=P_pol.word.LW;
                res_table[7].Val=P_pol.word.HW;
                res_table[8].Val=Cos_p.word.LW;
                res_table[9].Val=Cos_p.word.HW;

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

Для отображения данных от устройства, на данном этапе, воспользуемся OPC сервером. Его внутренних инструментов достаточно для отображения данных, записи значений в регистры и т.д.

Автоматическое определение средней точки каналов и расчет коэффициентов

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

Для автоматического вычисления АЦП0 каналов, необходимо снять с них полезный сигнал, т.е. разорвать токовую петлю, в которую включен датчик тока ACS712 и подключить на вход напряжения среднюю точку с ОУ. Далее алгоритм, произведет вычисление среднеквадратичного значение сигнала, и по команде от мастера, мы вычисленные значения занесем в АЦП0 для каждого канала и запишем эти значения в EEPROM. После этого, подключим исследуемые сигналы напряжения и тока.

if (MODBUS.write){
            if (res_table[10].Val==1){          //Команда на автоматическое
                U_0.Val=(WORD)U_real.Val;       //вычисление АЦП0
                I_0.Val=(WORD)I_real.Val;
                eeprom_write(0,U_0.byte.HB);    //Записываем в еепром значения
                eeprom_write(1,U_0.byte.LB);    //АЦП0  по каналам
                eeprom_write(2,I_0.byte.HB);
                eeprom_write(3,I_0.byte.LB);
            }
}

Для вычисления коэффициентов воспользуемся следующим порядком действий. После вычисления средней точки каналов, подключения реальных сигналов на аналоговые входы, алгоритм вычисляет среднеквадратичное значение напряжения и тока в единицах АЦП. Для перевода их в физические величины необходимо измерить данные сигналы приборами, вольтметром и амперметром. Измеренные приборами значения записываем в нужные регистры Модбас, и по команде от мастера производим вычисление коэффициентов. Для уменьшения длины посылки по Модбас, в данной реализации, значение с приборов переводится к целочисленному значению путем умножения значения напряжения на 10, а значение тока на 100. Полученные данные записываются в регистры, и по команде от мастера производится расчет коэффициентов. Рассчитанные коэффициенты записываются в EEPROM.

        if (MODBUS.write){
            if (res_table[10].Val==2){          //Команда на вычисление коэффициентов
                K_u.Val=U_real.Val/res_table[11].Val;   //тока и напряжения
                K_u.Val*=10.0;
                K_i.Val=I_real.Val/res_table[12].Val;
                K_i.Val*=100.0;
                eeprom_write(4,K_u.byte.MB);    //Записываем коэффициенты
                eeprom_write(5,K_u.byte.UB);
                eeprom_write(6,K_u.byte.HB);
                eeprom_write(7,K_u.byte.LB);
                eeprom_write(8,K_i.byte.MB);
                eeprom_write(9,K_i.byte.UB);
                eeprom_write(10,K_i.byte.HB);
                eeprom_write(11,K_i.byte.LB);
            }
            res_table[10].Val=0;
            MODBUS.write=0;
        }

Расчет веса

Вес руды можно высчитывать непосредственно из формулы, приведенной в первой части повествования.
Измерение веса руды по току статора. Практика. Часть 2. Программная реализация на МК - 3
Измерение веса руды по току статора. Практика. Часть 2. Программная реализация на МК - 4

Где:

  • F0 – сила развиваемая двигателем при подъеме пустого сосуда,
  • F – сила, измеренная при подъеме груженного сосуда,
  • g – ускорение свободного падения в точки взвешивания.

В данной реализации измерение массы не производится, так как симулирование в Протеусе не предусматривает такую возможность.
Симуляция в протеусе позволяет понять жизнеспособность основной идеи: «Измерение веса руды во время транспортировки в подъемном сосуде по току статора».

Архив с проектом в MpLab X и файлом проекта протеуса находится здесь.

Видео, наглядно показывающее обработку сигналов напряжения и тока, вычисление активной мощности, косинуса фи и полной мощности показано ниже.

Заключение

Измерение веса добытых полезных ископаемых в промышленности имеет большое значение в технологическом учете, оценки эффективности производимых работ и т.д.

Для измерения массы руды используется много различных видов и типов весовых устройств.

В данном цикле статей была рассмотрена возможность измерения веса руды, по измерению развиваемого момента приводного двигателя ШПУ во время транспортировки груза в подъемном сосуде. Данный способ используется в ШПУ снабженными двигателями постоянного тока, где вычисление массы производится по току якоря при постоянном возбуждении.

P.S.

Так как добыча полезных ископаемых в мире производится в больших объемах, и предпосылок на снижение нет, то этот способ измерения весы руды для технологического учета имеет право на жизнь. И может в недалеком будущем мы увидим промышленные устройства для измерения массы груза в подъемном сосуде, основанные на данном принципе.

Автор: Helixa

Источник


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js