Atmega 328p (без кварца) + nrf24 + dht22

jondiv
Offline
Зарегистрирован: 10.09.2014
Здравствуйте!
Хочу сделать свою метиостанцию.
Есть елементы:
Atmega 328p
nrf24
DHT22
 
Atmega 328p - я перепрошил по уроку "Arduino ATmega328 Без кварца without crystal quartz bootloader" от автора Dmitry OSIPOV ( https://www.youtube.com/watch?v=wuEzIKybvXw ).
Подключил на макетной плате:
 
Скетч:
 
#include <SPI.h>
#include "RF24.h"
#include "DHT.h"
#include <avr/sleep.h>
#include <avr/wdt.h>

#define DHTPIN 4 //Пин подключения DHT
#define DHTTYPE DHT22 //Прописываем тип датчика температуры
DHT dht(DHTPIN, DHTTYPE);
int dhtVcc = 5;
int ledVcc = 7;
int ledC  = 0;

RF24 radio(9, 10);
const uint64_t pipes[2] = {0xF0F0F0F000LL, 0xF0F0F0F0FFLL};// адреса каналов приема и передачи

volatile boolean wdt_tripped = 1;
int count =0;
int isact=1;

void setup(){

  pinMode(dhtVcc, OUTPUT);
  pinMode(ledVcc, OUTPUT);
  
  
  wdt_disable();
  wdt_reset();
  wdt_enable(WDTO_8S);   //пробуждение каждые 8 сек
  
  initRF();
  
  dht.begin();
}

void loop() {
  wdt_interrupt_mode();

  
  if (wdt_tripped) {
    wdt_tripped = 0;
    count++;
    ledC++;
    if(ledC == 15 || isact==1){
      ledC = 0;
      ledOn();
    }
    if (count == 150 || isact==1) {
      isact = 0;
      digitalWrite(dhtVcc, HIGH);
      delay(500);
      int temp_new;
      int humi_new;
      temp_new=dht.readTemperature();//Читаем показания датчиков
      humi_new=dht.readHumidity();
      digitalWrite(dhtVcc, LOW);
      delay(500);
      String stringVar = String(temp_new)+":"+String(humi_new);
      sendRF(stringVar); 
    }
  }
  system_sleep();   //МК засыпает
}

// мигание светодиодом
void ledOn(){
  digitalWrite(ledVcc, HIGH);
    delay(100);
  digitalWrite(ledVcc, LOW);
}

void initRF(){
  radio.begin();
  radio.setDataRate(RF24_250KBPS); // Скорость передачи
  //radio.setPALevel(RF24_PA_MAX); 
  radio.setChannel(100); // Номер канала от 0 до 127
  radio.setRetries(15,15); // Кол-во попыток и время между попытками
  radio.openWritingPipe(pipes[1]);  // Открываем канал передачи
  //radio.openReadingPipe(1, pipes[0]); // Открываем один из 6-ти каналов приема
  //radio.startListening(); // Начинаем слушать эфир 
  radio.powerDown();
}

void sendRF(String str){
  char data[50];
  str.toCharArray(data, 50);
  radio.powerUp();  //подаём питание на NRF24
  delay(10); 
  radio.write(&data, 32); 
  delay(10);
  radio.powerDown(); //отключаем питание RF24 штатно
}

//режим сна для МК
void system_sleep() {
  delay(2);                            // Wait for serial traffic
  _SFR_BYTE(ADCSRA) &= ~_BV(ADEN);     // Switch ADC off
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_mode();                        // System sleeps here
  sleep_disable();
  _SFR_BYTE(ADCSRA) |= _BV(ADEN);      // Switch ADC on
}
void wdt_interrupt_mode() {
  wdt_reset();
  WDTCSR |= _BV(WDIE); // Restore WDT interrupt mode
}
ISR(WDT_vect) {
  wdt_tripped = 1; // set global volatile variable
}
Все вроде бы работает, температуру получает, данные отправляет.
Пробую оставить на длительное время. И тут начинает ардуинка не стабильно работать, то не отправит ничего, то отправит, потом 
такое ощущение что arduino залипает и не уходит в сон, не отправляет ничего, и все, как будто зависло, отключаю батарейки, включаю заново, опять все пошло, жду некоторое время опять зависло. 
подскажите что можно сделать?
 
dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

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

jondiv
Offline
Зарегистрирован: 10.09.2014

Светодиод я подключал, по скечу int ledVcc = 7; он мигает, все хорошо. На протяжении 2х-3х часов все норм. Данные передаются каждые 20 мин, светодиод мигает каждые 2 минуты. Работает от 3х пальчиковых батареек. Может при пробуждении каждые 20мин, сажать батарейки? пробовал еще подключать аккум на 3.7В (520mAh), тоже самое, потом пробовал аккум на 4,8В (700mAh) тоже через некоторое время зависон, и да зависон выражается еще на светодиоде который подключен к 7 пин, он как-бы мерцает(мигает)

sav13
sav13 аватар
Offline
Зарегистрирован: 17.06.2013

А вы еще четвертым парамером напряжение батареи посылайте.

/**
* Функция определения напряжения питания устройства
*/
static int vccRead(byte us =250) {
  ADMUX = 1<<REFS0; // опорное напряжение - Vcc
  ADMUX |= 0x0E;    // объект измерения - внутренний источник
                    // стабилизированного напряжения 1.1В
  delayMicroseconds(us);
 
  ADCSRA |= 1<<ADSC;         // запуск АЦ-преобразования
  while(ADCSRA & (1<<ADSC)); // и ожидание его завершения
  word x = ADC;
  return x ? (1100L * 1023) / x : -1;
}

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

alexvs
Offline
Зарегистрирован: 22.07.2014

А если оставить питание от USB и заюзать Serial.println() для отладки?  Глядишь - найдете после чего виснет.

Alexey-kipia
Alexey-kipia аватар
Offline
Зарегистрирован: 14.03.2016


Всем привет!

Ребят на этом форуме с неделю так, что плохо тут ориентирусь.

Из последних тем по DHT 22 нашел эту. Есть вопрос по DHT. Я с Arduin-кой играюсь всего неделю, а с DHT 22 тоже раньше не имел дел.

За пару дней накидал Скетч с использованием DHT. Стал прогонять в Proteus-е и нашел временной провал в программе который мне сильно мешает.

boolean DHT::read(bool force) {
  // Check if sensor was read less than two seconds ago and return early
  // to use last reading.
  uint32_t currenttime = millis();
  if (!force && ((currenttime - _lastreadtime) < 2000)) {
    return _lastresult; // return last correct measurement
  }
  _lastreadtime = currenttime;

  // Reset 40 bits of received data to zero.
  data[0] = data[1] = data[2] = data[3] = data[4] = 0;

  // Send start signal.  See DHT datasheet for full signal diagram:
 http://www.adafruit.com/datasheets/Digital%20humidity%20and%20temperature%20sensor%20AM2302.pdf

  // Go into high impedence state to let pull-up raise data line level and
  // start the reading process.
  digitalWrite(_pin, HIGH);
//  return;
  delay(250);
Последняя строка:  delay(250);
Хочу уменьшить до минимума. Если я правильно понял из Datasheet-а:
Step 1: MCU send out start signal to AM2302 and AM2302 send response signal to MCU Your specialist in innovating humidity & temperature sensors Data-bus's free status is high voltage level. When communication between MCU and AM2302 begins, MCU will pull low data-bus and this process must beyond at least 1~10ms to ensure AM2302 could detect MCU's signal, then MCU will pulls up and wait 20-40us for AM2302's response.
То для начала - старта обмена контроллер должен притянуть шину на нуль на время 1-10 милисекунд. Потом датчик отвечает ну и т.д. и т.п. В коде сидит 250 милисекунд задержка. Зачем автор так сделал не пойму.
Подскажите кто, что знает. Или направте ссылочкой почитать алгоритм чтения. Я не нашел. Много пересмотрел, но натыкался на мусор либо на вышеуказанный Datasheet. Библиотека отсюда - https://github.com/adafruit/DHT-sensor-library
 
bwn
Offline
Зарегистрирован: 25.08.2014

Alexey-kipia, завели бы свою тему. Неприлично как то.(((.

А на DHT сия проблема есть. И используя библиотеку ее похоже не решить.
Единственное, что нашел:

01	// Mega
02	uint8_t data[5]; 
03	const byte DHT1_pin = 22;
04	const byte DHT2_pin = 24;
05	const unsigned int interval = 1000;
06	 
07	void setup(){
08	  Serial.begin(9600); 
09	}
10	 
11	void loop(){
12	  int hum1  = 0, temp1 = 0;
13	  int hum2  = 0, temp2 = 0;
14	  static unsigned long prevMillis = 0;
15	  if(millis() - prevMillis > interval){
16	    prevMillis += 1000;
17	    if(readingDHT(DHT1_pin)){         //если контрольная сумма верна
18	      hum1 = (data[0] << 8) | data[1];//считаем Н и Т первого датчика
19	      temp1 = ((data[2] & 0x7F) << 8) | data[3];
20	      if(data[2] & 0x80)  temp1 *= -1;
21	    }else{
22	      //ошибка DHT1
23	    }
24	    if(readingDHT(DHT2_pin)){
25	      hum2 = (data[0] << 8) | data[1];
26	      temp2 = ((data[2] & 0x7F) << 8) | data[3];
27	      if(data[2] & 0x80)  temp2 *= -1;    
28	    }else{
29	      //ошибка DHT2
30	    }
31	    Serial.print("hum1 = "); Serial.print(hum1 /10);
32	    Serial.print('.'); Serial.println(hum1 %10);
33	    Serial.print("tem1 = ");Serial.print(temp1 /10);
34	    Serial.print('.'); Serial.println(temp1 %10);
35	    Serial.print("hum2 = ");Serial.print(hum2 /10);
36	    Serial.print('.'); Serial.println(hum2 %10);
37	    Serial.print("tem2 = ");Serial.print(temp2 /10);
38	    Serial.print('.'); Serial.println(temp2 %10);
39	    Serial.println();
40	  }
41	}
42	//=============================================== 
43	boolean readingDHT(byte pin) {
44	  boolean state = HIGH;   //состояние линии
45	  byte counter = 0, j = 0;
46	  const byte count = 5;
47	  for(byte i=0; i<5; i++){
48	    data[i] = 0;
49	  }
50	  pinMode(pin, OUTPUT);
51	  digitalWrite(pin, LOW);
52	  delay(1);           //более 800mks нужно чтобы рабудить датчик DHT21-22
53	  //delay(18);        //для DHT11 
54	  //cli();                    //отключить прерывания если нужно
55	  pinMode(pin, INPUT);     //начинаем слушать датчик
56	  for(byte i = 0; i < 83; i++){//читаем 83 сост линии
57	    counter = 0;
58	    while (digitalRead(pin) == state) {//state==1 первый проход
59	      counter++;
60	      delayMicroseconds(4);//if 4 mkc count==3-7
61	      if (counter > 20)  break;
62	    }//end while
63	    state = !state;//digitalRead(_pin);
64	    if (counter > 20) break;    
65	    if ((i > 3) && !(i & 1)) {//i%2 записать каждый бит в байты хранения
66	      data[j >> 3] <<= 1;  //читаем с 5(i=4) состояния(1,0,1,0,?,0,?,0,...?)
67	      if (counter > count)  data[j>>3] |= 1;//counter>3-10 дальше ошибки
68	      j++;
69	    }
70	  }//end for
71	  //sei();            //включить прерывания  
72	  uint8_t sum = data[0] + data[1] + data[2] + data[3];
73	  if(sum == data[4]) return 1;
74	  else               return 0;
75	}

Сам не пробовал, руки не дошли. Номера строк тереть надо, они в оригинале уже были.

Alexey-kipia
Alexey-kipia аватар
Offline
Зарегистрирован: 14.03.2016

Не совсем понял, сори.

Мне не нужен код. Библиотека, что я привел работает нормально. Мне не понятно зачем автор влупил задержку 250 милисекунд в том месте, что я указал. Такое ощущение, что он перепутал милисекунды с микро секундами. Я уже надумал вариант обхода этой проблемы. Применим подсчет времени работы программы. Зайдем, сохраним считвнное время. При следующем входе будем проверять прошедшее время. Если истекло, пойдем дальше. Функция millis(); . Просто странно. Автор применил эту функцию на входе в подпрограмму и тупо влепил остановку программы через несколько действий. Я решу эту проблему, но хочется знать для чего эта выдержка у Автора?

Alexey-kipia
Alexey-kipia аватар
Offline
Зарегистрирован: 14.03.2016

В Proteus-е нормально работает даже если вообще убираю эту задержку :-)

Alexey-kipia
Alexey-kipia аватар
Offline
Зарегистрирован: 14.03.2016

bwn пишет:

Alexey-kipia, завели бы свою тему. Неприлично как то.(((.

А на DHT сия проблема есть. И используя библиотеку ее похоже не решить.
Единственное, что нашел:

01	// Mega
02	uint8_t data[5]; 
03	const byte DHT1_pin = 22;
04	const byte DHT2_pin = 24;
05	const unsigned int interval = 1000;
06	 
07	void setup(){
08	  Serial.begin(9600); 
09	}
10	 
11	void loop(){
12	  int hum1  = 0, temp1 = 0;
13	  int hum2  = 0, temp2 = 0;
14	  static unsigned long prevMillis = 0;
15	  if(millis() - prevMillis > interval){
16	    prevMillis += 1000;
17	    if(readingDHT(DHT1_pin)){         //если контрольная сумма верна
18	      hum1 = (data[0] << 8) | data[1];//считаем Н и Т первого датчика
19	      temp1 = ((data[2] & 0x7F) << 8) | data[3];
20	      if(data[2] & 0x80)  temp1 *= -1;
21	    }else{
22	      //ошибка DHT1
23	    }
24	    if(readingDHT(DHT2_pin)){
25	      hum2 = (data[0] << 8) | data[1];
26	      temp2 = ((data[2] & 0x7F) << 8) | data[3];
27	      if(data[2] & 0x80)  temp2 *= -1;    
28	    }else{
29	      //ошибка DHT2
30	    }
31	    Serial.print("hum1 = "); Serial.print(hum1 /10);
32	    Serial.print('.'); Serial.println(hum1 %10);
33	    Serial.print("tem1 = ");Serial.print(temp1 /10);
34	    Serial.print('.'); Serial.println(temp1 %10);
35	    Serial.print("hum2 = ");Serial.print(hum2 /10);
36	    Serial.print('.'); Serial.println(hum2 %10);
37	    Serial.print("tem2 = ");Serial.print(temp2 /10);
38	    Serial.print('.'); Serial.println(temp2 %10);
39	    Serial.println();
40	  }
41	}
42	//=============================================== 
43	boolean readingDHT(byte pin) {
44	  boolean state = HIGH;   //состояние линии
45	  byte counter = 0, j = 0;
46	  const byte count = 5;
47	  for(byte i=0; i<5; i++){
48	    data[i] = 0;
49	  }
50	  pinMode(pin, OUTPUT);
51	  digitalWrite(pin, LOW);
52	  delay(1);           //более 800mks нужно чтобы рабудить датчик DHT21-22
53	  //delay(18);        //для DHT11 
54	  //cli();                    //отключить прерывания если нужно
55	  pinMode(pin, INPUT);     //начинаем слушать датчик
56	  for(byte i = 0; i < 83; i++){//читаем 83 сост линии
57	    counter = 0;
58	    while (digitalRead(pin) == state) {//state==1 первый проход
59	      counter++;
60	      delayMicroseconds(4);//if 4 mkc count==3-7
61	      if (counter > 20)  break;
62	    }//end while
63	    state = !state;//digitalRead(_pin);
64	    if (counter > 20) break;    
65	    if ((i > 3) && !(i & 1)) {//i%2 записать каждый бит в байты хранения
66	      data[j >> 3] <<= 1;  //читаем с 5(i=4) состояния(1,0,1,0,?,0,?,0,...?)
67	      if (counter > count)  data[j>>3] |= 1;//counter>3-10 дальше ошибки
68	      j++;
69	    }
70	  }//end for
71	  //sei();            //включить прерывания  
72	  uint8_t sum = data[0] + data[1] + data[2] + data[3];
73	  if(sum == data[4]) return 1;
74	  else               return 0;
75	}

Сам не пробовал, руки не дошли. Номера строк тереть надо, они в оригинале уже были.

А чего темы плодить? Просто тематически.

Забиваешь DHT22 и не получаешь ничего путнего. Просто каждый заводит свою тему: DHT22, 22DHT, DH22T.

А суть одна - решение проблем с датчиком или Библиотекой :-)

Alexey-kipia
Alexey-kipia аватар
Offline
Зарегистрирован: 14.03.2016

Ну в общем на данный момент просмотрел весь класс DHT и не увидел привязки к этой выдержке. Перед вызовом подпрограммы - объекта boolean DHT::read(bool force) нет ни одной манипуляции с входом - выходом типа старта опроса и тем самым нет нужды в выдержке. Просто коментируем и получаем 250 милисекунд свободного времени в собственной программе. Тем более, что есть переферия требующая обработки максимум в 10 милисекунд. :-)

alexvs
Offline
Зарегистрирован: 22.07.2014

Вот другой автор и соответственно другая реализация библиотеки https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib