после щелбанов реле работает, пока отложу разбирательство по теме
это один из моих первых проектов - он простой
есть измельчитель отходов на кухне. он сейчас включается вручную пневмокнопкой, но обязательно нужно вручную заранее включать холодную воду и потом, после выключения диспенсера ее выключать
в преддверии замены основного крана на сенсорный я решил полностью автоматизировать работу диспенсера:
та же пневмокнопка используется для запуска программы
сначала включается клапан подачи воды
через 10 сек включается измельчитель
если нажать снова пневмокнопку (она при нажатии меняет состояние, т.е. нажал раз - включилась, нажал еще раз - выключилась и т.д.)
через таймаут (сейчас 60 сек) программа автоматически останавливается - сначала отключается диспенсер, через 10 сек вода
решил еще встроить контроль тока - чтобы автоматом прервать программу в случае если измельчитель заклинило из-за попавших в него вилок, ножей...))
эту часть предстоит дописать - нужно делать усреднение по переменному току, сейчас логика не корректна (без усреднения)
схема выше
привожу код для atmel studio 6.1
буду признателен за комментарии
основной код в бесконечном цикле main, таймер используется для того, чтобы увеличивать на 1 mclock раз в секунду - используется для задержек
еще настроен watchdog чтобы перезапустить МК в случае зависания
фьюзы выставлены на внутренний генератор 4.8мгц
на закомментареный код не смотрите - изначально писал под МикроС
это один из моих первых проектов - он простой
есть измельчитель отходов на кухне. он сейчас включается вручную пневмокнопкой, но обязательно нужно вручную заранее включать холодную воду и потом, после выключения диспенсера ее выключать
в преддверии замены основного крана на сенсорный я решил полностью автоматизировать работу диспенсера:
та же пневмокнопка используется для запуска программы
сначала включается клапан подачи воды
через 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 Правил Форума
Причина: Нарушение п.2.5 Правил Форума
