Детектор сигаретного дыма на ATtiny13A и MQ-2

inhelp
inhelp аватар
Offline
Зарегистрирован: 23.09.2012

Простенький детектор сигаретного дыма на ATtiny13A и датчике и MQ-2. 

При запахе сигаретного дыма, загораются светодиоды. При слабом уровне горит 1, среднем - 2 и максимальном 3, если воздух чист  --- ничего не горит ))).

void setup() {   
  DDRB = 0b10111;
}
 void loop() {
  int sensorValue = ADC_READ();
   int range = map(sensorValue, 100, 135, 0, 3);
   switch (range) {
   case 1:    
     PORTB &= ~(1<<0);
     PORTB &= ~(1<<1);
     PORTB &= ~(1<<2);
     break;
   case 2:   
     PORTB |= (1<<0); 
     PORTB &= ~(1<<1);
     PORTB &= ~(1<<2);
     break;
   case 3:    
     PORTB |= (1<<0);
     PORTB |= (1<<1);
     PORTB &= ~(1<<2);
     break;
   case 4:   
      PORTB |= (1<<0);
      PORTB |= (1<<1);
      PORTB |= (1<<2);
     break;
     } 
   }
 int ADC_READ()
{
  ADMUX = 3; // ADC pin
  ADCSRA |= 1<<ADEN;
  ADCSRA |= 1<<ADSC;
  while(!(ADCSRA & (1<<ADIF)));
  ADCSRA |= 1<<ADIF; 
  byte low  = ADCL;
  byte high = ADCH;
  ADCSRA &= ~(1 << ADEN); 
  return (high << 8) | low;
}

За оптимизацию кода отдельное спасибо HWman

Binary sketch size: 802 bytes

 

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Забавно, range мапится в значение от 0 до 3, а switch от 1 до 4 работает, неувязочка, однако.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Так ещё меньше весить будет:

int main( void )
{  
  DDRB = 0b10111;
while(1){
  int sensorValue = ADC_READ();
  int range = ((sensorValue - 79) / 14); //int range = map(sensorValue, 100, 135, 1, 4);
   switch (range) {
   case 1:    // your hand is on the sensor
     PORTB &= ~(1<<0);
     PORTB &= ~(1<<1);
     PORTB &= ~(1<<2);
     break;
   case 2:    // your hand is close to the sensor
     PORTB |= (1<<0); 
     PORTB &= ~(1<<1);
     PORTB &= ~(1<<2);
     break;
   case 3:    // your hand is a few inches from the sensor
     PORTB |= (1<<0);
     PORTB |= (1<<1);
     PORTB &= ~(1<<2);
     break;
   case 4:    // your hand is nowhere near the sensor
      PORTB |= (1<<0);
      PORTB |= (1<<1);
      PORTB |= (1<<2);
     break;
   }
  return 0;
 }
}
 int ADC_READ()
{
  ADMUX = 3; // ADC pin
  ADCSRA |= 1<<ADEN;
  ADCSRA |= 1<<ADSC;
  while(!(ADCSRA & (1<<ADIF)));
  ADCSRA |= 1<<ADIF; 
  byte low  = ADCL;
  byte high = ADCH;
  ADCSRA &= ~(1 << ADEN);  // отключаем АЦП
  return (high << 8) | low;
}

Размер скетча в двоичном коде: 268 байт (из 1 024 байт максимум)

inhelp
inhelp аватар
Offline
Зарегистрирован: 23.09.2012

kisoft пишет:
Забавно, range мапится в значение от 0 до 3, а switch от 1 до 4 работает, неувязочка, однако.

сорри, правильно так

int range = map(sensorValue, 100, 135, 0, 4);

не тот скетч залил ...

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Вот интересно, если я определил тип данных int, целое число вроде, ну и по расчётах должно выйти 1.5 тогда какое число запишется в переменную 1 или 2? В школе помню учили что 1.5 это равно 2, а как же микропроцессоров учили в школе?

 

step962
Offline
Зарегистрирован: 23.05.2011

HWman пишет:

Вот интересно, если я определил тип данных int, целое число вроде, ну и по расчётах должно выйти 1.5 тогда какое число запишется в переменную 1 или 2? В школе помню учили что 1.5 это равно 2, а как же микропроцессоров учили в школе?

"микропроцессоров" учили целочисленной двоичной арифметике.

Грубо:

29/5=5 и 4 в остатке (а не 5,8 -> 6)

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Ясно, спасибо :)

toc
Offline
Зарегистрирован: 09.02.2013

Ардуино IDE оптимизирует код? Вычисляет константы при компиляции? Если нет, то можно ещё с десяток байт флеш памяти съэкономить если их вычислить все, то есть заменить:

~(1<<0)    на  0b11111110

~(1<<1)    на  0b11111101    и так далее. Наглядность пострадает, хотя с какой стороны смотреть.

В case 4 можно написать одной строкой: PORTB |= 0b00000111;

и в 1 тоже по аналогии.

 

inhelp
inhelp аватар
Offline
Зарегистрирован: 23.09.2012

Спасибо, информативно ...

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013
int main( void )
{  
  DDRB = 0b10111;
while(1){
 unsigned int sensorValue = ADC_READ();
 unsigned int range = ((sensorValue - 79) / 14); //int range = map(sensorValue, 100, 135, 1, 4);
   switch (range) {
   case 1:    // your hand is on the sensor
     PORTB &= ~0b111;
     break;
   case 2:    // your hand is close to the sensor
     PORTB |= (1<<0); 
     PORTB &= ~(1<<1);
     PORTB &= ~(1<<2);
     break;
   case 3:    // your hand is a few inches from the sensor
     PORTB |= (1<<0);
     PORTB |= (1<<1);
     PORTB &= ~(1<<2);
     break;
   case 4:    // your hand is nowhere near the sensor
      PORTB |= 0b111;
     break;
   }
  return 0;
 }
}
  int ADC_READ()
{
  ADMUX = 3; // ADC pin
  ADCSRA |= 1<<ADEN;
  ADCSRA |= 1<<ADSC;
  while(!(ADCSRA & (1<<ADIF)));
  ADCSRA |= 1<<ADIF; 
  byte low  = ADCL;
  byte high = ADCH;
  ADCSRA &= ~(1 << ADEN);  // отключаем АЦП
  return (high << 8) | low;
}

 

Размер скетча в двоичном коде: 232 байт (из 1 024 байт максимум).
Как-то так? Или чёт напартачил, я засветил что изменил

toc
Offline
Зарегистрирован: 09.02.2013

если заказчик согласен изменить схему, то можно ещё значительно уменьшить объём программы, заменив весь блок swith на две строки.

всего два светодиода л1 и л2.  при нулевом уровне все выключены. уровень 1 включён л1, уровень 2 включён л2, уровень 3 включены оба.

byte range = ..... //  тут допустимые значения 0..3

PORTB &= 0b11111100;  // обнулили 2 бита

PORTB |= range;  // включили светодиодики

toc
Offline
Зарегистрирован: 09.02.2013

вариант для схемы с тремя светиками

byte range = ..... // тут допустимые значения 0..3

PORTB &= 0b11111000; // обнулили 3 бита

while(range--)
   PORTB |= 1<<range; // включили светодиодики

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Я вот что думаю, а есть ли смысл делать код неузнаваемым для ардуиновцев? памяти ещё ого-го остаётся...

Ну для наглядности - не спорю, хорошо, оптимизация это всегда хорошо, на нужно же думать и о других...

DjeFF
Offline
Зарегистрирован: 02.09.2013

Всем привет. Помогите, пожалуйста, чайнику! Нужно собрать детектор табачного дыма, есть платформа Arduino Uno и датчик MQ2. Как мне доработать данный код, чтоб на выходи получить аналоговый сигнал (или загорался диод) при среднем и максимальном уровни дыма. Так же, просьба объяснить к каким контактам нужно подключать диод? Спасибо!

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013






#define led1 10 // 1 светодиод
#define led2 11 // 2 светодиод
#define led3 12 // 3 светодиод
#define analogInPin A0 // датчик
void setup() {  
 pinMode(analogInPin, INPUT);   
 pinMode(led1, OUTPUT);  
 pinMode(led2, OUTPUT);  
 pinMode(led3, OUTPUT);  
}
void loop() {
  int sensorValue = analogRead(analogInPin);
  int range = map(sensorValue, 100, 135, 1, 4);
  switch (range) {
  case 1:    
    digitalWrite(led1, LOW); 
    digitalWrite(led2, LOW); 
    digitalWrite(led3, LOW); 
    break;
  case 2:   
    digitalWrite(led1, HIGH);
    digitalWrite(led2, LOW); 
    digitalWrite(led3, LOW); 
    break;
  case 3:    
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, LOW); 
    break;
  case 4:   
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, HIGH);
    break;
  } 
}

 

DjeFF
Offline
Зарегистрирован: 02.09.2013

inhelp пишет:

kisoft пишет:
Забавно, range мапится в значение от 0 до 3, а switch от 1 до 4 работает, неувязочка, однако.

сорри, правильно так

int range = map(sensorValue, 100, 135, 0, 4);

не тот скетч залил ...

Спасибо большое. А еще вопросик, вот выше писали, что значение int range надо поменять, это критично или можно оставить как вы прислали?

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Честно говоря нет времени разбираться, но смысл в том, что если range, от 0 до 3, то и switch, должен работать от 0 до 3, а если использовать switch от 1 до 4 то достаточно к range добавить 1. Но как правильно - Вам виднее

ingener.solovyev
Offline
Зарегистрирован: 12.02.2013

Интересный и очень актуальный проект. Но интересна чуствительность данного устройства.

У нас в офисе курят в туалете (хотя и ЗАПРЕЩЕНО), высота потолка под 3 метра. Если устройство будет под потолком, сработает ли оно?

Araris
Araris аватар
Онлайн
Зарегистрирован: 09.11.2012

ingener.solovyev пишет:

Интересный и очень актуальный проект. Но интересна чуствительность данного устройства.

У нас в офисе курят в туалете (хотя и ЗАПРЕЩЕНО), высота потолка под 3 метра. Если устройство будет под потолком, сработает ли оно?

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

С избирательностью у датчиков серии MQ не очень, хотя за такие деньги что бы мы хотели ?

Araris
Araris аватар
Онлайн
Зарегистрирован: 09.11.2012

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

ingener.solovyev
Offline
Зарегистрирован: 12.02.2013

Araris пишет:

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

Тогда имеет смысл делать замер воздуха 1 раз в сутки, рано утром. Туалет убирают вечером, за ночь проветривается. Часов в 4-5 утра воздух эталонный на след сутки.

Araris
Araris аватар
Онлайн
Зарегистрирован: 09.11.2012

Возможно для данного случая так лучше, практика покажет.

DjeFF
Offline
Зарегистрирован: 02.09.2013

HWman пишет:







#define led1 10 // 1 светодиод
#define led2 11 // 2 светодиод
#define led3 12 // 3 светодиод
#define analogInPin A0 // датчик
void setup() {  
 pinMode(analogInPin, INPUT);   
 pinMode(led1, OUTPUT);  
 pinMode(led2, OUTPUT);  
 pinMode(led3, OUTPUT);  
}
void loop() {
  int sensorValue = analogRead(analogInPin);
  int range = map(sensorValue, 100, 135, 1, 4);
  switch (range) {
  case 1:    
    digitalWrite(led1, LOW); 
    digitalWrite(led2, LOW); 
    digitalWrite(led3, LOW); 
    break;
  case 2:   
    digitalWrite(led1, HIGH);
    digitalWrite(led2, LOW); 
    digitalWrite(led3, LOW); 
    break;
  case 3:    
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, LOW); 
    break;
  case 4:   
    digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, HIGH);
    break;
  } 
}

 

Привет, подскажите, а можно настроить датчик чтоб он был еще более чувствительным? Сейчас диод, подключенный к выходу 10, загорается если на него выдыхать дым в течении пол минуты. Какие значения поменять для эксперимента с чувствительностью? Спасибо!

Araris
Araris аватар
Онлайн
Зарегистрирован: 09.11.2012

Выведите в окно терминала Serial.println(analogRead(analogInPin)); и посмотрите, как значения меняются в присутствии дыма, поэкспериментируйте, посмотрите, какие идут цифры с пина (датчика). А дальше сами увидите.

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Подключи датчик к дуинке и подключи датчик, и смотри что показывает датчик в разных ситуациях:





void setup() {
  Serial.begin(9600);
}
void loop() {
  // read the input on analog pin 0:
  int Value = analogRead(A0);
  Serial.println(Value);
  delay(500);
}

Потом выставишь сколько тебе нужно в:







 int range = map(sensorValue, 100, 135, 1, 4) // 1 негорят, 4 горят все три светодиода

 

inhelp
inhelp аватар
Offline
Зарегистрирован: 23.09.2012

Какой резистор у Вас подключен к датчику, если переменный то в каком положении ??? От этого и зависит чуствительность... 

 

DjeFF
Offline
Зарегистрирован: 02.09.2013

Постоянный резистор на 220 Ом, поэксперементировал с значениями датчика, вроде стало чувствительней, всем большое спасибо за помощь

HWman
HWman аватар
Offline
Зарегистрирован: 26.02.2013

Пожалуйста, удачных проектов :)

INIKXXI
Offline
Зарегистрирован: 11.08.2014

А кто-нибудь сделал хотя бы прототип ? Хотелось бы ознакомиться.

alex62
Offline
Зарегистрирован: 27.05.2015

Кроме датчика MQ, есть ли другие?

Дим
Offline
Зарегистрирован: 05.05.2017

Можно схему подключения?