Реле заклинило во включенном состоянии - в чем причина?

Все прочитали, вроде даже поняли, взяли паяльник - а нифига не получается? Скорее сюда! Поможем. Чем можем...
Ответить
Электрический кот
Сообщения: 1040
Зарегистрирован: Вс сен 25, 2011 19:09:33

Сообщение axillent »

после щелбанов реле работает, пока отложу разбирательство по теме
это один из моих первых проектов - он простой

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

в преддверии замены основного крана на сенсорный я решил полностью автоматизировать работу диспенсера:
та же пневмокнопка используется для запуска программы
сначала включается клапан подачи воды
через 10 сек включается измельчитель
если нажать снова пневмокнопку (она при нажатии меняет состояние, т.е. нажал раз - включилась, нажал еще раз - выключилась и т.д.)
через таймаут (сейчас 60 сек) программа автоматически останавливается - сначала отключается диспенсер, через 10 сек вода

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

схема выше
привожу код для atmel studio 6.1
буду признателен за комментарии

основной код в бесконечном цикле main, таймер используется для того, чтобы увеличивать на 1 mclock раз в секунду - используется для задержек
еще настроен watchdog чтобы перезапустить МК в случае зависания
фьюзы выставлены на внутренний генератор 4.8мгц
на закомментареный код не смотрите - изначально писал под МикроС
Спойлер

Код: Выделить всё

/*
  PORT B 0 - кнопка включения диспенсера
  PORT B 1 - включение клапана подачи воды
  PORT B 2 - включение диспенсера
  PORT B 3 - буззер
  
  
  логика
  
  - отслеживаем переключение выключателя
  - вклчение следует циклу - сначала вода, потом диспенсер, потом вода после отключения диспенсера
  - при изменении статуса кнопки при работающем диспенсере - немедленное выключение, вода отключается через паузу
  
  датчик тока:
  - ошибка если в статусе выключено ток превысит некий порог
  - ошибка с остановом если ток будет ниже одного порога или выше другого
  
  бипер:
  - коротко - при запуске
  - длинно - перед включением воды
  - 2 х длинно - перед включением диспенсера
  - 5 х длинно - превышение максимального тока
  - 3 х коротко - ток слишком низкий после включения
  - серия из 2 х коротко если тоак превышен в состоянии выключено
  
  
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <util/delay.h>

#define CALIBRATION1    234
#define CALIBRATION2    207
#define DELAY1 10       // задержка между подачей воды и включением диспенсера, сек
#define DELAY2 60      // значение таймаута для автоматического отключения диспенсера, сек

// 512 - значение при нудевом токе (acs712 дает VCC/2 при нуле)
// датчик acs712-5a имеет чувствительность 185мв/А - 1024 / 5в * 0,185 = 38 единиц на ADC на один ампер
#define CURRENT_OFF_MAXIMUM	512 + 38/2			// 0,5А - максимальное значение датчика тока в состоянии диспенсер выключен
#define CURRENT_ON_MINIMUM	0					// минимальное значение тока в состоянии диспенсер включен
#define CURRENT_ON_MAXIMUM	512 + 38*5			// 5A - максимальное значение тока в состоянии диспенсер включен

//sbit  button_dis at PINB.B0;
//sbit  valve      at PORTB.B1;
//sbit  dispenser  at PORTB.B2;
//sbit  buzzer     at PORTB.B3;
//sbit  testbit    at PORTB.B4;

// Declare your global variables here
volatile unsigned int mclock;
volatile unsigned char mclock2;
unsigned int clock_stamp;
uint8_t button_off_status;
enum status_list { status0=0, status1=1, status2=2, status3=3, status4=4 } status;

ISR (TIM0_OVF_vect)
{
     TCNT0 = CALIBRATION1; // калибровано на вызов функции раз в секунду
     mclock2--;
     if(mclock2 == 0) {
          mclock++;
          mclock2 = CALIBRATION2;
     }
}
/*
void WD_ISR() iv IVT_ADDR_WDT {
}*/
#define ADC_VREF_TYPE 0x00

// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
	ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
	// Delay needed for the stabilization of the ADC input voltage
	_delay_us(10);
	// Start the AD conversion
	ADCSRA|=0x40;
	// Wait for the AD conversion to complete
	while ((ADCSRA & 0x10)==0);
	ADCSRA|=0x10;
	return ADCW;
}


void init();
void beep(unsigned char islong, unsigned char count);
void delay_sec10(unsigned char delay);
void valve_off();
void valve_on();
void dispenser_off();
void dispenser_on();
uint8_t check_button() { return PINB & (1<<PB0); }

int main(){

	unsigned int current;

     mclock = 0;
     TCNT0 = CALIBRATION1;
     mclock2 = CALIBRATION2;
     
     init();
     status = status0;
     button_off_status = check_button();

     wdt_reset();
	 sei();

     beep(0, 1);
     
     //SREG_I_bit = 1;   // interrupt enable
     
     while (1)
      {
		  
		// измеряем ток
		current = read_adc(2);
		
      // проверяем не выключяли ли принудительно кнопку
      switch(status) {
      case status0:          // игнорируем состояние когда и так все выключено
        break;
      default:
        if(button_off_status == check_button()) {
            status = status3;
            //testbit = 1;
        }
      }
	  
	  // проверка по току
	  switch(status) {
		case status0:
			// проверяем что ток меньше порога - диспенсер выключен
			if(current > CURRENT_OFF_MAXIMUM) {
				beep(0, 2);
			}
			break;
		case status2:
			// проверяем минимум и максимум - диспенсер включен
			if(current > CURRENT_ON_MAXIMUM) {
				dispenser_off();
				beep(1, 5);
				status = status3;
			} else 
			if(current < CURRENT_ON_MINIMUM) {
				dispenser_off();
				beep(0, 3);
				status = status3;
			}
			break;
		default:
			break;
	  }

      switch(status) {
      case status1:    // вода уже была открыта, ждем паузу перед включением диспенсера
        if(mclock - clock_stamp > DELAY1) {
            beep(1, 2);
            delay_sec10(20);
            dispenser_on();
            clock_stamp = mclock;
            status = status2;
        }
        break;
      case status2:     // ждем истечения паузы и принудительно выключаем диспенсер, потом воду
        if(mclock - clock_stamp > DELAY2) {
            status = status3;
        }
        break;
      case status3:     // выключаем диспенсер, через паузу - воду
        dispenser_off();
        delay_sec10(100); // 10 сек
        valve_off();
        status = status0;
        button_off_status = check_button();  // текущее значение кнопки делаем значением выключено
        //testbit = 0;
        break;
      case status0:     // все выключено, ловим нажатие
      default:
        if(check_button() != button_off_status) {
            status = status1;
            beep(1, 1);
            valve_on();
            clock_stamp = mclock;
        }
      }
      //asm wdr
      delay_sec10(4);
      }
}


void init() {
  CLKPR=0x80;
  CLKPR=0x00;
  //Port B initialization
  // Func5=In Func4=Out Func3=Out Func2=Out Func1=Out Func0=In
  // State5=T State4=T State3=0 State2=0 State1=0 State0=T
  DDRB=0b001110;
  PORTB=0x01;

  // Clock source: System Clock

//  TCCR0A=0x00;
  TCCR0B=0x05;  // делим на 1024 частоту процессора
//  TCNT0=0x00;
//  OCR0A=0x00;
//  OCR0B=0x00;

  // Timer/Counter 0 Interrupt(s) initialization
  TIMSK0=0x02;


	// ADC initialization
	// ADC Clock frequency: 150,000 kHz
	// ADC Bandgap Voltage Reference: Off
	// ADC Auto Trigger Source: Free Running
	// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
	DIDR0&=0x03;
	DIDR0|=0x00;
	ADMUX=ADC_VREF_TYPE & 0xff;
	ADCSRA=0xA5;
	ADCSRB&=0xF8;

  // Watchdog Timer initialization
  // Watchdog Timer Prescaler: OSC/1024k
  // Watchdog Timer interrupt: On
  //WDTCR=0x39;
  //WDTCR=0x69;

  // Watchdog Timer initialization
  // Watchdog Timer Prescaler: OSC/32k
  // Watchdog Timer interrupt: On
   //WDTCR=0x1C;
   //WDTCR=0x4C;
   wdt_enable(WDTO_2S);
}

void beep(unsigned char islong, unsigned char count) {
    for(;count > 0; count--) {
        PORTB |= (1 << PB3);
        delay_sec10((islong) ? 10 : 2);
        PORTB &= ~(1 << PB3);
        delay_sec10((islong) ? 5 : 1);
    }
}
// задержка в десятых долях секунд со сбросом watchdog
void delay_sec10(unsigned char delay) {
     for(;delay > 0; delay--) {
         _delay_ms(98);
         wdt_reset();
     }
}

/*
  PORT B 0 - кнопка включения диспенсера
  PORT B 1 - включение клапана подачи воды
  PORT B 2 - включение диспенсера
  PORT B 3 - буззер
*/
void dispenser_off() { PORTB &= ~(1 << PB2); }
void dispenser_on()  { PORTB |= (1 << PB2); }
void valve_off() { PORTB &= ~(1 << PB1); }
void valve_on() { PORTB |= (1 << PB1); }
Последний раз редактировалось Gudd-Head Чт июн 13, 2013 14:38:35, всего редактировалось 1 раз.
Причина: Нарушение п.2.5 Правил Форума
Реклама
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1119
Зарегистрирован: Ср май 01, 2013 22:37:08
Откуда: Украина

Сообщение Alter Ego »

axillent писал(а):решил еще встроить контроль тока - чтобы автоматом прервать программу в случае если измельчитель заклинило
Ненадежный метод. Если есть возможность, лучше установить датчик вращения - датчик Холла
и приклеенный куда-нибудь магнит.
Реклама
Электрический кот
Сообщения: 1040
Зарегистрирован: Вс сен 25, 2011 19:09:33

Сообщение axillent »

Alter Ego писал(а): Ненадежный метод
штатный способ защиты - предохранитель с востановлением
вполне работает

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

я хочу продублировать штатную защиту по току, может быть буду срабатывать чуть раньше
Ответить

Вернуться в «Практика»