#1 2015-03-01 19:25:49

rfl
Учасник
З Киев
Зареєстрований: 2015-03-01
Повідомлень: 6

Тестирование электромеханических реле - помогите отладить код

Здравствуйте.

В целях обучения программированию на Ардуино написал скрипт проверки электромеханических реле. Код - работает, т.е. вполне можно проверить работоспособность ОДНОГО реле.
Суть проверки: реле с заданным интервалом включается/отключается, МК проверяет наличие сигнала, проходящего через контакты электромеханического реле. Результаты проверки, пока что, можно смотреть только через Serial Monitor.

На создание скрипта натолкнула обнаруженная неисправность в китайских реле, которые проработали от силы 1000 включений (Бракованные реле Songle 10А отличается по цвету (немного светлее) от тех, что работают без сбоев).

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

Также, есть такие вопросы:
1. Как вывести из функции данные о более чем 1-ом параметре (кол-во ошибок при включении, кол-во ошибок при выключении, и др.).  Я вижу несколько способов: глобальные переменные, массив. Что правильнее, и если массив - то как это реализовать?
2. Как перезаписывать в переменную текстовые данные? Я сделал попытку, записывать в переменную relay_status значения ON|OFF, но из этого ничего не получилось: или ошибка, или все время выводится OFF.


Буду признателен за любую помощь!


Код скрипта:

// Тест реле


// Определение номеров входов и выходов
#define PIN_MK_LED 13 // Светодиод интегрированный в Ардуино
#define PIN_RELAY_1_SW 22 // Управление реле 1
#define PIN_RELAY_2_SW 23 // Управление реле 2
#define PIN_RELAY_1_CONTACT 30 // Вход с контакта реле 1
#define PIN_RELAY_2_CONTACT 31 // Вход с контакта реле 2

// Другие константы
#define SERIAL_MONITOR_SW 1 // Включен (1) или выключен (0) Serial Monitor
#define SERIAL_MONITOR_SPEED 57500 // Скорость работы Serial Monitor

#define RELAY_SWITCH_DELAY 500 // Скорость работы Serial Monitor


// Определение переменных

// Светодиод интегрированный в Ардуино
unsigned long mk_led_interval_on = 200; // мс
unsigned long mk_led_interval_off = 800; // мс


void setup() 
  {
  if (SERIAL_MONITOR_SW == 1)
    Serial.begin(SERIAL_MONITOR_SPEED);
  
  pinMode(PIN_MK_LED, OUTPUT);
  pinMode(PIN_RELAY_1_SW, OUTPUT);
  pinMode(PIN_RELAY_1_CONTACT, INPUT);
  digitalWrite(PIN_RELAY_1_SW, LOW);
  }

void loop() 
  {
  // Светодиод мигает - МК работает
  mk_led_blink(mk_led_interval_on, mk_led_interval_off);
  
  relay_test(PIN_RELAY_1_SW, PIN_RELAY_1_CONTACT, RELAY_SWITCH_DELAY);
  //relay_test(PIN_RELAY_2_SW, PIN_RELAY_2_CONTACT, RELAY_SWITCH_DELAY);
  }
  
// Тест реле
void relay_test(byte pin_switch, byte pin_contact, unsigned long interval)
  {
 
  static unsigned long interval_timer = 0; // Интервал переключения
  static unsigned long sw_delay_timer = 0; //
  static unsigned long sw_delay = 0; //  
  static unsigned long sw_counter = 0; //
  static byte sw_status = LOW;
  static byte cont_expected_status = LOW;
  static byte cont_real_status = 0;
  static char relay_status[] = "OFF";
  static byte error = 0;
  static unsigned long error_counter = 0;
  static unsigned long error_counter_on = 0;
  static unsigned long error_counter_off = 0;
  
  if (millis() - interval_timer > interval)
    { 
    sw_counter++;
      
    error = 0;
    if (sw_delay_timer > 0)
      {
      error_counter++;
      error = 1;
      if (sw_status == HIGH)
        error_counter_on++;
      else
        error_counter_off++;
      }
      
    if (SERIAL_MONITOR_SW == 1)
      {
      Serial.print("Relay pin: "); 
      Serial.print(pin_switch); 
      Serial.println(";");
      Serial.print("contact pin: "); 
      Serial.print(pin_contact); 
      Serial.println(";");
      Serial.print("relay status: ");
      Serial.print(sw_status);
      Serial.println(";");
      Serial.print("error: "); 
      Serial.print(error);
      Serial.println(";");
      Serial.print("TOTAL: ON/OFF relay counter - ");
      Serial.print(sw_counter);
      Serial.print("; error ON - ");
      Serial.print(error_counter_on);
      Serial.print("; error OFF - ");
      Serial.print(error_counter_off);
      Serial.println();
      Serial.println();
      }
      
    interval_timer = millis();
    if (sw_status == LOW)
      {
      sw_status = HIGH;
      char relay_status[] = "ON";
      }
    else
      {
      sw_status = LOW;
      char relay_status[] = "OFF";
      }
    digitalWrite(pin_switch, !digitalRead(pin_switch)); 
    }
    
  if (digitalRead(pin_contact) == LOW && sw_delay_timer == 0)
    {
    sw_delay_timer = millis();
    }
  if (digitalRead(pin_contact) == HIGH && sw_delay_timer > 0)
    {
    sw_delay = millis() - sw_delay_timer;
    sw_delay_timer = 0;
    }
  }
  
// Светодиод мигает - МК работает
// interval_on .... - кол-во милисекунд, на которое будет включен светодиод
// interval_off ... - кол-во милисекунд, на которое будет выключен светодиод
void mk_led_blink(unsigned long interval_on, unsigned long interval_off)
  {
  static unsigned long mk_led_switch_interval = 0; // Интервал переключения
  static unsigned long mk_led_switch_timer = 0; // Время когда последний раз переключали диод
  static byte mk_led_status = LOW; //
  if (millis() - mk_led_switch_timer > mk_led_switch_interval) 
    {
    mk_led_switch_timer = millis();
    if (mk_led_status == LOW)
      {
      mk_led_status = HIGH;
      mk_led_switch_interval = interval_on;
      }
    else
      {
      mk_led_status = LOW;
      mk_led_switch_interval = interval_off;
      }
    digitalWrite(PIN_MK_LED, mk_led_status);
    }
  }

Схема упрощена, к Ардуино реле подключено не напрямую - подключен модуль реле на оптопаре. Подключив реле напрямую к МК, как указано на схеме, ВЫ рискуете спалить вывод МК!
R1-R2 10K
Схема подключения

Остання редакція rfl (2015-03-01 19:27:25)

Неактивний

#2 2015-03-02 13:53:03

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Тестирование электромеханических реле - помогите отладить код

typedef struct {
  unsigned long error;
  unsigned long error_counter_on;
  unsigned long error_counter_off;
} td_error_status;


обьявление
volatile td_error_status error_status;

extern volatile  td_error_status error_status;

volatile  если в несколько потоков будете работать ( вероятно не ваш вариант )

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

доступ к данным
error_status.error_counter++;

для экономии времени запускайте тест на всех реле реле одновременно,  а анализ и выдачу результата только по тем ножка (вход)  которые нужны.
я бы так делал.

"2. Как перезаписывать в переменную текстовые данные? Я сделал попытку, записывать в переменную relay_status значения ON|OFF, но из этого ничего не получилось: или ошибка, или все время выводится OFF."   не совсем понятно, что Вы имеете в виду?

Неактивний

#3 2015-03-02 19:34:30

rfl
Учасник
З Киев
Зареєстрований: 2015-03-01
Повідомлень: 6

Re: Тестирование электромеханических реле - помогите отладить код

NoName пише:

volatile  если в несколько потоков будете работать ( вероятно не ваш вариант )

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

доступ к данным
error_status.error_counter++;

для экономии времени запускайте тест на всех реле реле одновременно,  а анализ и выдачу результата только по тем ножка (вход)  которые нужны.
я бы так делал.

"2. Как перезаписывать в переменную текстовые данные? Я сделал попытку, записывать в переменную relay_status значения ON|OFF, но из этого ничего не получилось: или ошибка, или все время выводится OFF."   не совсем понятно, что Вы имеете в виду?

Спасибо, что откликнулись! Не подскажете, где можно подробнее почитать про указатели и voliate с несколькими потоками? Или примеры реализации скриптов?

А по поводу перезаписи текстовых данных: хотелось бы выводить текст статуса реле (ON|OFF), а не 1 и 0... Для этого, я и предполагал использовать переменную, которую если реле включено записывается "ON", выключено - "OFF".

Неактивний

#4 2015-03-03 11:59:40

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Тестирование электромеханических реле - помогите отладить код

смысл хранить ON/OFF нет оставьте 1 и 0  а при  выводе
if (var == 0 )
Serial.print("OFF");
else
Serial.print("ON");
где то так

классика:
184663d1348402602


у Вас сейчас отличная задача ) не сложная и полезная.
все получится, даже если будете по одному реле делать тест. 

если не учитывать контроль времени - то все реле замкнули
data =  P1IN ( порт  на вход ) 


базовый принцип:
data сами соберете, но ет не сложный тест, без учета контроля времени срабатывания  реле (поставьте паузу для гарантированного срабатывание )

for ( foo =0; foo < max ; foo ++ )
if  ( (data & (0x01 << foo)) == (0x01 << foo) )   relay[foo] = 1; else relay[foo] = 0;


for ( foo =0; foo < max ; foo ++ )
{

Serial.print("Relay ");
Serial.print( foo );


if (relay[foo]  == 0 )
Serial.print(" ERROR");
else
Serial.print(" OK");

Serial.print("\r\n");

}

Неактивний

#5 2015-03-04 02:41:44

rfl
Учасник
З Киев
Зареєстрований: 2015-03-01
Повідомлень: 6

Re: Тестирование электромеханических реле - помогите отладить код

Переписал скрипт с использованием структур. Все протестировал - работает: определяет, если после сигнала на переключение реле не произошло переключение контактов, и в этом случае заносит это событие в счетчик ошибок. Надеюсь, этот код кому-нибудь пригодится для теста реле или изучения работы структур smile

Просьба покритиковать код, возможно что-то можно было бы улучшить/оптимизировать? Для всех ли переменных объявлены правильные типы?
Из того, что я бы сделал сам, да не знаю как:
- заменить строку relay_data *relay_arr[] = {d_relay_1, d_relay_2}, в которой массивы собираются в один, каким-нибудь автоматическим процессом, чтобы в случае добавления/отключения релешек не нужно было править эту строку вручную.

Код скрипта проверки реле:

// Тест реле

// Константы
#define SERIAL_MONITOR_SW 1 // Включен (1) или выключен (0) Serial Monitor
#define SERIAL_MONITOR_SPEED 57600 // Скорость работы Serial Monitor

#define RELAY_SWITCH_MAX 20UL  // Кол-во включений/выключений реле
#define RELAY_SWITCH_DELAY 500UL // Скорость работы переключения реле - пауза между переключениями в мс
#define RELAY_OFF_DEFAULT HIGH // Состояние выключенного реле (HIGH|LOW)

#define SERIAL_FREQ 5000UL // Пауза в мс между выводами информации в Serial Monitor

// Структура параметров реле
struct relay_data 
  {
  byte pin_relay_control; // Номер выхода управления реле
  byte pin_relay_contact; // Номер входа для чтения показаний с контакта реле
  unsigned long interval_sw; // Таймер интервала переключения реле
  unsigned long interval_sw_timer; // Интервал переключения реле
  unsigned long sw_counter; // Счетчик кол-ва переключений реле
  byte status_control; // Статус управления реле. LOW - включить, HIGH - отключить реле
  byte status_contact; // Статус контакта реле. LOW - нет сигнала, HIGH - есть сигнал
  byte sw_status_counter; // Счетчик изменения статусов
  unsigned long error_counter; // Общее кол-во ошибок
  unsigned long error_counter_on; // Кол-во ошибок включения
  unsigned long error_counter_off; // Кол-во ошибок выключения
  };

// Параметры по умолчанию для реле 1 (последовательность согласно структуре в struct)
relay_data d_relay_1[1] =
  {
  {22,30,500,0,0,RELAY_OFF_DEFAULT,HIGH,2,0,0,0},
  };
relay_data &relay_1 = d_relay_1[0];

// Параметры по умолчанию для реле 2 (последовательность согласно структуре в struct)
relay_data d_relay_2[1] =
  {
  {23,31,550,0,0,RELAY_OFF_DEFAULT,HIGH,2,0,0,0},
  };
relay_data &relay_2 = d_relay_2[0];  

relay_data *relay_arr[] = {d_relay_1, d_relay_2};
byte relay_count = sizeof(*relay_arr);


void setup() 
  {
    
  if (SERIAL_MONITOR_SW == 1)
    {
    Serial.begin(SERIAL_MONITOR_SPEED);
    Serial.println("Relay tester");
    Serial.println();
    Serial.print("Count relay for test: ");
    Serial.println(relay_count);
    Serial.println();
    Serial.println("SETUP: set in/out pin:");
    }
    
  for (int i = 0; i < relay_count; i++)
    {
    relay_data &rel_cur_arr = *relay_arr[i];
    
    pinMode(rel_cur_arr.pin_relay_control, OUTPUT);
    digitalWrite(rel_cur_arr.pin_relay_control, RELAY_OFF_DEFAULT);
    pinMode(rel_cur_arr.pin_relay_contact, INPUT);
    
    if (SERIAL_MONITOR_SW == 1)
      {
      Serial.print("Relay ");
      Serial.print((i + 1));
      Serial.print(": pin_relay_control-");
      Serial.print(rel_cur_arr.pin_relay_control);
      Serial.print("; pin_relay_contact-");
      Serial.print(rel_cur_arr.pin_relay_contact);
      Serial.println(".");
      }
      
    }
  //  pinMode(PIN_MK_LED, OUTPUT);
  }

  
void loop() 
  {
  relay_test();
  relay_data_serial();
  }
  


// Функция тестирования реле
void relay_test()
  {
  for (int i = 0; i < relay_count; i++)
    {
    relay_data &rel_cur_arr = *relay_arr[i];
    
    if (rel_cur_arr.sw_counter <= RELAY_SWITCH_MAX)
      {
      
      if (millis() - rel_cur_arr.interval_sw_timer > rel_cur_arr.interval_sw)
        {
        rel_cur_arr.interval_sw_timer = millis();
        
        //Serial.print(rel_cur_arr.pin_relay_control);
        //Serial.print(" - ");
        //Serial.print(rel_cur_arr.sw_status_counter);
        //Serial.println("");
        
        // Счетчик ошибок
        if (rel_cur_arr.sw_status_counter < 2)
          {
          rel_cur_arr.error_counter++;
          if (rel_cur_arr.status_control == RELAY_OFF_DEFAULT)
            rel_cur_arr.error_counter_off++;      
          else
            rel_cur_arr.error_counter_on++;
          }
        rel_cur_arr.sw_status_counter = 0;
          
        // Включение/отключение реле
        if (rel_cur_arr.sw_counter == RELAY_SWITCH_MAX) // Отключение реле после отработки максимального кол-ва переключений
          rel_cur_arr.status_control = RELAY_OFF_DEFAULT;
        else // Изменение состояния реле (Вкл/Выкл)
          rel_cur_arr.status_control = !rel_cur_arr.status_control;
        digitalWrite(rel_cur_arr.pin_relay_control, rel_cur_arr.status_control);
          
        rel_cur_arr.sw_counter++;
        }
        
      // Проверка состояний контактов
      rel_cur_arr.status_contact = digitalRead(rel_cur_arr.pin_relay_contact);
      if (rel_cur_arr.status_contact == LOW)
        rel_cur_arr.sw_status_counter = 1;
      if (rel_cur_arr.status_contact == HIGH && rel_cur_arr.sw_status_counter == 1)
        rel_cur_arr.sw_status_counter = 2;
      }
    }
  }
  
// Функция вывода информации о результатах тестирования реле в Serial Monitor
void relay_data_serial()
  {
  if (SERIAL_MONITOR_SW == 1)
    {
    static unsigned long interval_timer = 0;
    static byte relay_num = 0;
    static byte reley_test_end_counter = 0;
    static byte reley_test_end = 0;
    
    if (millis() - interval_timer > SERIAL_FREQ && reley_test_end == 0)
      {
      Serial.println();
      interval_timer = millis();
      
      for (int i = 0; i < relay_count; i++)
        {
        relay_data &rel_cur_arr = *relay_arr[i];
        
        // Поиск окончания проверки
        if (rel_cur_arr.sw_counter >= RELAY_SWITCH_MAX)
          reley_test_end_counter++;
          
        relay_num = i + 1;
        Serial.print("Relay ");
        Serial.print(relay_num);
        Serial.print(" (pin control ");
        Serial.print(rel_cur_arr.pin_relay_control);
        Serial.println("):");
        Serial.print("On/off switch: ");
        Serial.print((rel_cur_arr.sw_counter - 1));
        Serial.print("; Error counters On: ");
        Serial.print(rel_cur_arr.error_counter_on);
        Serial.print(", Off: ");
        Serial.print(rel_cur_arr.error_counter_off);
        Serial.println();
        }
        
      if (reley_test_end_counter > relay_count)
        reley_test_end = 1;
      }
    }
  }

Неактивний

#6 2015-03-04 10:26:47

NoName
Customer
З Київ
Зареєстрований: 2014-07-08
Повідомлень: 1,446

Re: Тестирование электромеханических реле - помогите отладить код

браво )
а теперь сделать диалог в терминалке )
если ентер без ввода то по умолчанию.

введите кол тестов:  (def 200  ):_
введите время переключения:  (def 500  ):_

выполнение теста : [===                 ]   30%.   ошибок 0,  abort, press  Q

по завершению, развернутый статус.

(вывод  без перехода на новую строку  \r )  не все терминалки поддерживают , но  будет красиво.  ориентируйтесь на VT100


и лампочек не хватает )
если тест длительный, визуальная индикация нужна, мне по крайней мере ) 
например - зеленый нет ошибок, красный есть проблемы

Неактивний

#7 2015-03-05 02:27:55

rfl
Учасник
З Киев
Зареєстрований: 2015-03-01
Повідомлень: 6

Re: Тестирование электромеханических реле - помогите отладить код

Спасибо за оценку, но от улучшений этого скрипта я откажусь, так как есть на что потратить время, да и как по мне, интереснее выводить не на терминал, а через web-сервер. Этим скриптом я учился работать со структурами.
А по поводу лампочки - её можно взять из первого скрипта: функция mk_led_blink() как раз и задумывалась для индикации работы: интегрированный в дуину led медленно мигает, когда идет процесс без ошибок, быстро - если ошибка, и просто светит, если тест закончился без ошибок.

Неактивний

#8 2015-03-08 22:55:52

v11april
Учасник
Зареєстрований: 2015-03-08
Повідомлень: 1

Re: Тестирование электромеханических реле - помогите отладить код

rfl - есть результаты тестов? Если можно, выложите пожалуйста, интересует ширпотреб, SRA или SRD.     PDF это одно, а реальность?

Неактивний

#9 2015-03-10 02:53:51

rfl
Учасник
З Киев
Зареєстрований: 2015-03-01
Повідомлень: 6

Re: Тестирование электромеханических реле - помогите отладить код

А в реальности, по тестам, реле одного и того же производителя: от очень плохо, до вполне приемлемо. Реле Songle SRD-05VDC-SL-C - два реле (в модуле для Ардуино) выдержали около 1000 переключений и стали переключаться через раз, а другие и после 20 000 не выдавали ни одной ошибки. Стоит отметить, что корпус бракованных реле - более светлый, а у тех, что работают хорошо - темнее. Так что помимо модели, нужно учитывать подделки.

Также, если планируете тестить реле - тестируйте их под реальной нагрузкой, хотя бы под половниинной предельной мощностью. Я тестировал практически без нагрузки, через контактные площадки реле проходило 5В и несколько мкА! У меня тест реле скорее на программирование, чем на реальную тестовую лабораторию (схема), но если её немного "допилить" (схему), то можно тестировать по настоящему.

Неактивний

Швидке повідомлення

Введіть повідомлення і натисніть Надіслати

Підвал форуму