Интересный глюк DHT11

Krendelyok
Offline
Зарегистрирован: 05.10.2016

Хочу попробовать организовать работу DHT11 и TM1637 на AtTiny13. Вот решил написать свой код ждя датчика DHT11, и обнаружил интересный глюк. Последний сороковой бит с датчика приходит примерно на 60 мкс длиннее, чем все предыдущие)) То есть если приходит логический ноль, то вместо 48 мой счетчик успевает досчитать до 143. А если приходит логическая единица, то вместо 143 счетчик успевает сосчитать до 243. Ничем не смог это объяснить, кроме как кривым датчиком DHT11.  Забавно, что если использовать стандартную библиотеку для этого датчика, то , даже если датчик кривой, то будет создаваться видимость нормальной работы. Но  Ардуина будет отправлять на дисплей данные с датчика, только когда сумма температуры и влажности будет нечетной. Проверьте, пожалуйста, у вас приходят с датчика значения влажности и температуры, когда их сумма должна быть четной? Пришлось программно скорректировать данный глюк:



//#define F_CPU 16000000UL
#include <util/delay.h>
#define PIN_DHT 3

unsigned int time_bit[40]; 
uint8_t data_dht[5];
uint8_t bit_dht;
uint8_t word_dht = 0x00;
//#include <avr/io.h>

void setup(){
 Serial.begin(9600);
}

void start_tmr_ms()
{
  TCNT2 = 0x00;
  TCCR2B = 0x05; //9,375 ���
}

void start_tmr_us()
{
  TCNT2 = 0x00;
  TCCR2B = 0x02; //1,2 ���
}

void start_dht()
{
  DDRB |= (1 << PIN_DHT);
  PORTB |= (1 << PIN_DHT);
  start_tmr_ms();
  while(TCNT2 < 2){} 
  PORTB &= ~(1 << PIN_DHT);
  _delay_ms(18); 
  DDRB &= ~(1 << PIN_DHT);
  PORTB |= (1 << PIN_DHT);
  while(PINB & (1 << PIN_DHT)){}  
  while(~PINB & (1 << PIN_DHT)){} 
  while(PINB & (1 << PIN_DHT)){}

}

void get_data()
{   
 
 
    for(bit_dht = 1; bit_dht < 41; bit_dht++)
    {
    while(~PINB & (1 << PIN_DHT)){} 
    start_tmr_us();
    while(PINB & (1 << PIN_DHT)){} 
   /*Здесь пришлось скорректировать аппаратный (или программный) глюк датчика DHT11.    
    *Почему-то последний сороковой бит (младший бит контрольной суммы) длится примерно на 60 мкс дольше, чем все остальные. 
    *Тоесть если приходит логический ноль, то вместо 48 счетчик успевает досчитать до 143. А если приходит логическая единица, 
    *то вместо 143 счетчик успевает сосчитать до 243. Очень странный глюк. В принципе, если использовать стандартную библиотеку для датчика, 
    *то всё должно работать, несмотря на эту неисправность, но Ардуина будет отправлять на дисплей данные с датчика, только когда сумма 
    *температуры и влажности будет нечетной.
   */   
      if(bit_dht == 40){
        time_bit[bit_dht] = TCNT2 - 100;//Вычитаем 100, если это последний 40 бит 
      }else{
        time_bit[bit_dht] = TCNT2;        
      }
     
    }
   
    
  
}

void decoder_bit(){
 uint8_t bit_number = 0;
 uint8_t word_number = 1;
 for(bit_dht = 1; bit_dht < 41; bit_dht++){  //дербаним наш массив из 40 бит (5 байтов), в котором записана длительность каждого полученного  бита
 
 if(time_bit[bit_dht] > 0x75)                //Если длительность бита больше 28 мкс,
      {
        word_dht = word_dht << 1;            //сдвигаем байт влево и записываем в младший разряд 1
        word_dht |= (1 << 0);
      }else
        {
          word_dht = word_dht << 1;        //Если меньше 28 мкс, сдвигаем влево байт и записываем 0
          word_dht &= ~(1 << 0);
        }   
 
 if(bit_number == 7){                     //Если имеем дело с восьмым битом, записываем полученный байт в массив
  data_dht[word_number] = word_dht;
  word_number += 1;
  bit_number = -1;       //Тут пздц математический парадокс, смотри теорию струн
 }
 bit_number +=1;
}
}

void loop(){
    
    int8_t i;
    start_dht();
    get_data();
   
 for(i = 1; i < 41; i++)
 {
  Serial.println(time_bit[i]); //Вывести список полученных битов (интервалы времени)
 }
  Serial.println();
  decoder_bit();
  for(i = 1; i < 6; i++)
 {
  Serial.println(data_dht[i]); //Вывести список полученных пяти байтов
 }
  _delay_ms(5000);
}

 

Krendelyok
Offline
Зарегистрирован: 05.10.2016

Товарищи, прошу помощи. Колдунство какое-то. Если убираю цикл (строчки 101-104):

// for(i = 1; i < 41; i++)
// {
//  Serial.println(time_bit[i]); //Вывести список полученных битов (интервалы времени)
// }

Начинает периодически выводить неправильную контрольную сумму. Например, 57 вместо 56:


27
0
29
0
56 // контрольная сумма

27
0
29
0
57  // контрольная сумма

27
0
29
0
56  // контрольная сумма

27
0
29
0
57  // контрольная сумма

 

Какой либо закономерности не заметил, просто сюда скопировался чередующийся результат. Как такое вообще возможно? Этот цикл просто выводит на печать содержимое массива, никак его не изменяя. Если этот цикл не удалять, то ошибок нет.

Пробовал оставлять пустой цикл без Serial.println - ошибки остаются. Тоесть функция Serial.println каким то волшебным образом влияет на массив.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Массивы в С нумеруются в отличие от Фортрана не с 1, а с 0.

Соответственно, первый элемент массива имеет номер 0, а последний - 39. В цикле Вы выходите за границу массива - отсюда и проблемы.

Krendelyok
Offline
Зарегистрирован: 05.10.2016

andriano пишет:

Массивы в С нумеруются в отличие от Фортрана не с 1, а с 0.

Соответственно, первый элемент массива имеет номер 0, а последний - 39. В цикле Вы выходите за границу массива - отсюда и проблемы.

Спасибо огромное! Четко и лаконично)) Сделал:

for(bit_dht = 0; bit_dht < 40; bit_dht++)

Всё заработало отлично. Ушла проблема как с длительностью 40 бита, так и с Serial.println))) Страшно представить, что там на уровне ассемблера происходит.