Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Ответить

Работа с датчиком HDT11

Вс июл 28, 2019 08:04:16

Здравствуйте.

Понадобилось мне добавить в устройство датчик влажности. Купил на али. Написал код. Но не работает. Несколько дней бился, но так и не смог добиться результата.

Имею вот такую программу
Спойлер
Код:

//////////////////////////////////////////////////////////
//               ПАРАМЕТРЫ UART                  //
//////////////////////////////////////////////////////////
#define   BAUD         9600UL                     // Скорость обмена по UART
#define SPEED         ((F_CPU+BAUD*8)/(BAUD*16)-1)
#define      F_CPU   8000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include   <util/delay.h>

//Порт, управляющий нагрузками
#define PIN_LOAD      PINA
#define DDR_LOAD      DDRA
#define PORT_LOAD      PORTA

#define PIN_SENSOR      PINC
#define DDR_SENSOR      DDRC
#define PORT_SENSOR      PORTC

#define PIN_DET1      PC0                     //Считывание 1го положения выключателя
#define PIN_DET2      PC1                     //Считывание 2го положения выключателя
#define PIN_PIR         PC2                     //Обработка датчика движения
#define PIN_DHT11      PC3                     //Считывание значение влажности


#define PIN_LAMP      PA0                     //Управление включением лампой
#define PIN_VENT      PA1                     //Управление включением вентилятора

#define PIN_DEBUG1      PA2                     //Пин для отладки
#define PIN_DEBUG2      PA3                     //Пин для отладки

#define PUSH_SENS1      (1<<PIN_DET1)   //нажата кнопка 1
#define PUSH_SENS2      (1<<PIN_DET2)   //нажата кнопка 2

uint8_t temp;
uint8_t humi;

/*********************************************************
         НАБОР ФУНКЦИЙ ДЛЯ РАБОТЫ ЧЕРЕЗ UART               
*********************************************************/
void init_uart(void){
   UCSRB = (1<<TXEN|1<<RXEN|0<<RXCIE);                     // Настройка UART
   UCSRC = (1<<URSEL|1<<UCSZ1|1<<UCSZ0);
   UBRRL = (uint8_t)(SPEED & 0xFF);
   UBRRH = (uint8_t)(SPEED >> 8);
}

void out_uart(uint8_t data){                     // Передача байта через UART
   while(!(UCSRA&(1<<UDRE)));                     // Ожидание готовности UART к передаче
   UDR = data;                                 // Запись в регистр UDR байта данных начинает процесс передачи
}

uint8_t in_uart(void){                           // Прием байта из UART
   while(!(UCSRA&(1<<RXC)));                     // Ожидание прихода байта
   return UDR;                                 // Возвращение принятого байта

}


uint8_t dht11_read ()
{
   uint8_t datadht[5]; // массив для значений датчика
   datadht[0] = datadht[1] = datadht[2] = datadht[3] = datadht[4] = 0 ; //обнуляем массив
   
   //Инициализация датчика
   DDR_SENSOR   |=(1<<PIN_DHT11);             // выход
   PORT_SENSOR   &=~(1<<PIN_DHT11);             //в низкий уровень
   _delay_ms (18);

   //Переводим порт в режим чтения
   PORT_SENSOR   |=(1<<PIN_DHT11);             //отпускаем линию
   _delay_us (40);
   DDR_SENSOR   &=~(1<<PIN_DHT11);             // вход, режим чтения
   
   //Ждем сигнал готовности датчика к передаче
   while (PIN_SENSOR & (1<<PIN_DHT11)){}      //ждем, датчик должен ответить 0
   _delay_us (60);
   while (!(PIN_SENSOR & (1<<PIN_DHT11))){}   //Ждем отпускания линии датчиком
   _delay_us (60);
   
   //Начало приема данных
   while (PIN_SENSOR & (1<<PIN_DHT11)){}      //эжем начала передачи, начинается с нуля, примерно через 80 мс

   for (uint8_t byte = 0; byte < 5; byte++)
   {
      datadht[byte]=0;
      for (uint8_t bit=0; bit<8; bit++)
      {
         cli (); // запрещаем прерывания
         while (!(PIN_SENSOR & (1<<PIN_DHT11))){}      //ждем когда датчик отпустит шину
         _delay_us (30);                        //задержка высокого уровня при 0 30 мкс
         if ((PIN_SENSOR & (1<<PIN_DHT11))){         //если по истечению времени сигнал на линии высокий, значит передается 1
         datadht[byte]|=1<<(7-bit);         //тогда i-й бит устанавливаем 1
         }
         while (PIN_SENSOR & (1<<PIN_DHT11));         // ждем окончание 1
         sei ();// разрешаем общее прерывание
      }
   }
   humi = datadht[0];

return 0;
}
   
int main(void)
{
   
      //===Инициализация портов====
      //Порт на выход
      DDR_LOAD    |=   (1<<PIN_LAMP|1<<PIN_VENT| 1<<PIN_DEBUG1|1<<PIN_DEBUG2);
      PORT_LOAD   &=   ~(1<<PIN_LAMP|1<<PIN_VENT| 1<<PIN_DEBUG1|1<<PIN_DEBUG2);      //обнуляем выход
      
      //Вход с подтяжкой
      DDR_SENSOR   &=   ~(1<<PIN_DET1|1<<PIN_DET2|1<<PIN_PIR|1<<PIN_DHT11);
      PORT_SENSOR   |=    (1<<PIN_DET1|1<<PIN_DET2|1<<PIN_PIR|1<< PIN_DHT11);
      
      _delay_ms(1000);
      init_uart();
      
   while(1)
    {

      dht11_read ();
      _delay_ms(50);
         out_uart(humi);
          _delay_ms(50);

    }
}



На УАРТ ничего не идет.
Вот что показывает логический анализатор, подключенный на ножку данных датчика
Изображение
Только передний "провал" показывает длительностью 18ms. Потом все импульсы и паузы, либо длительностью 50, либо 100 us.
Причем, посылка делается один раз. Потом просто высокий уровень стоит.
Не пойму, то ли с программой что то, то ли датчик неисправный какой то пришел.
Может кто то сталкивался с таким?
Спасибо.

Re: Работа с датчиком HDT11

Пн июл 29, 2019 09:12:39

можеть чего поможет
DHT11.pdf
(842.29 KiB) Скачиваний: 206

DHT11_b.pdf
(1.45 MiB) Скачиваний: 181

8)

Re: Работа с датчиком HDT11

Пн июл 29, 2019 10:09:59

Спасибо. Попробую ещё раз с этими документами сверить.

А можно вопрос? Это выложено в педагогических целях (то есть вы там увидели явную ошибку) или все таки это как документ, могущий помочь. Просто вроде не одну диаграмму посмотрел. Ну и делал согласно тем диаграммам.

Re: Работа с датчиком HDT11

Пн июл 29, 2019 11:46:21

Я на основе тех даташитов делал - но... ПОД АССЕМБЛЕРОМ...
8)

Воть ссыль на первый вариант макета
https://radiokot.ru/forum/viewtopic.php ... 7#p2198317
Правда ... даавненько то было...
:roll:
Последний раз редактировалось BOB51 Пн июл 29, 2019 13:24:35, всего редактировалось 1 раз.

Re: Работа с датчиком HDT11

Пн июл 29, 2019 11:55:54

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

Re: Работа с датчиком HDT11

Пн июл 29, 2019 11:58:38

В протеусе 8 есть его модель

Re: Работа с датчиком HDT11

Пн июл 29, 2019 12:37:29

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

Re: Работа с датчиком HDT11

Пн июл 29, 2019 13:51:56

От реальности далеко, но проверить код и поглумиться над DHT то что надо.

Re: Работа с датчиком HDT11

Пн июл 29, 2019 14:10:42

У меня под СИ только адуринки...
А у оных вроде как уже готовая библиотека для DHT11...
Хотя... можно и помутить самоделку...
:roll:

Re: Работа с датчиком HDT11

Пт авг 09, 2019 09:08:46

Я делал и работает. На захвате по таймеру, с внутренним RC генератором. А посему ввёл толеранцию, с которой пришлось поиграться. Сейчас оставил 5uS, но не всегда получаю результат, буду увеличивать.
Асм, мега8.

Re: Работа с датчиком HDT11

Ср авг 14, 2019 02:45:33

Что то я не понял ничего. Не могли бы вы поподробнее объяснить?

Re: Работа с датчиком HDT11

Ср авг 14, 2019 21:45:48

Объяснить что именно? Алгоритм? Так по даташиту всё и делал. Таймер1 - 1 тик=1uS. Генерируем стартовый импульс >1000uS - влетаем в прерывание. В обработчике перенастраиваем таймер на захват. Получаем в регистрах ICR длительность импульсов в uS. А дальше разгребаем, пришёл 0 или 1. Это сдвигом пихаем в байт.
Да, у меня DHT22, но протокол тот же.

Re: Работа с датчиком HDT11

Чт авг 15, 2019 05:32:54

Объяснить что именно? Алгоритм? Так по даташиту всё и делал. Таймер1 - 1 тик=1uS. Генерируем стартовый импульс >1000uS - влетаем в прерывание. В обработчике перенастраиваем таймер на захват. Получаем в регистрах ICR длительность импульсов в uS. А дальше разгребаем, пришёл 0 или 1. Это сдвигом пихаем в байт.
Да, у меня DHT22, но протокол тот же.


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


Непонятны эти слова
А посему ввёл толеранцию, с которой пришлось поиграться.
Их бы объяснить. Догадываюсь о чем, но хотелось бы точно.

Добавлено after 4 hours 36 minutes 21 second:
На другом форуме проверили мой код в протеусе. Код рабочий. Скорее всего проблема с датчиками. Китайцы наверно фуфло прислали.

Re: Работа с датчиком HDT11

Чт авг 15, 2019 09:01:28

На таймерах... можно конечно....
Интервал единицы принимаем за целое
Делим на 8.
Таймер настраиваем на 1/8.
Подсчет переполнений за время приема активной
части импульса и табличный селектор для записи значения бита данных,
соответствующего значению количества переполнений в текущий байт данных
а там 1/2 +/-1/8 это 0, а все, что более - 1.
Как-то так...
:roll:
Только длительность интервалов весьма маахонькая - проще
количество программных задержек использовать.
8)

Re: Работа с датчиком HDT11

Чт авг 15, 2019 09:24:33

С таймерами наверно может и хорошо. Вроде как точнее. Хотя мне кажется для такого датчика точность временных задержек не важна. Но и, как минимум, два у меня уже используются для отсчета времени. Третий тоже под вопросом. Да и сложнее это как то. Постоянно переконфигурировать таймер.

Re: Работа с датчиком HDT11

Чт авг 15, 2019 12:18:15

В моем проекте на программных циклах сделано было.
МК не сильно шустрый - 1МГц (0,000001 секунда на команду).
8)
Воть такой варьянт
Спойлер
Код:
;
;         "dht11.txt"  файл обработчика шины датчика влажности/температуры
;                              DHT-11
;
;----------
; заготовка программного модуля для обработки данных датчика DHT-11
; формат данных пять байт :
;     влажность RH целая часть
;     влажность RH дробная часть (у DHT-11=0)
;     температура Т целая часть
;     температура Т дробная часть (у DHT-11=0)
;     контрольная сумма (сумма первых четырех байт
;
; данные передаются старшими битами вперед по однопроводной
; шине подобно протокола микроLAN, разрыв приёма пакета недопустим.
; используются монопольно все регистры текущего регистрового банка.
;
; ---------- константы ----------
;
;
; btrg      equ 40 ; количество бит в пакете (5байт*8бит=40)
; DHTD      equ 5 ; позиционный номер линии данных DHT-11
; port_dht  equ P3 ; переприсвоение порта
;
; ---------- регистры ----------
;
;  .DSEG
; rhdt   equ mlans ; целая часть значения влажности в двоичном коде
; thdt   equ mlans+1 ; целая часть значения температуры в двоичном коде
; регистры текущего банка -
;
;    R7   - байт целых значений влажности
;    R6   - байт дробных значений влажности
;    R5   - байт целых значений температуры
;    R4   - байт дробных значений температуры
;    R3   - байт контрольной суммы
;    R2   - счётчик задержки внутренний
;    R1   - счётчик бит пакета
;    R0   - счётчик задержки внешний
;
; ---------- флаги ----------
;
;  .BSEG
; dht_sf:   .dbit 1 ; флаг семафора запроса/квитирования исполнения
; программы чтнеия данных с DHT-11 (flags2.0)
; dht_rdd:  .dbit 1 ; flags2.1 флаг семафора переключения задач обработчиков
; "запрос чтения данных с DHT-11"
; dht_ptr:  .dbit 1 ; flags2.2 флаг семафора переключения задач обработчиков
; "обработка/вывод на дисплей данных с DHT-11"
;
; ----- собственно утилиты -----
;
  .CSEG
dhtrd:
     setb port_dht.DHTD ; страховка
     clr a
     mov r7,a
     mov r6,a
     mov r5,a
     mov r4,a
     mov r3,a
     mov r1,#btrg ; предподготовка РБ
quest:
     mov r0,#180
     clr port_dht.DHTD
 tm_dht0:
      mov r2,#48
      djnz r2,$
      djnz r0,tm_dht0
     mov r2,#88
     djnz r2,$ ;генерация импульса запроса датчика 18mS
    setb port_dht.DHTD ; переводим линию данных на ввод с подтяжкой к 1
 quest1:
    mov r2,#17
    djnz r2,$ ; ждём ~34uS
 wt_dht0:
    ; error control
    mov a,port_dht
    jb ACC.DHTD,wt_dht0 ; ждем начало ответа датчика
   mov r2,#20
   djnz r2,$ ; ждём ~40uS
 wt_dht1:
    ; error control
    mov a,port_dht
    jnb ACC.DHTD,wt_dht1 ; ждем окончание состояния 0 импульса ответа
   mov r2,#35
   djnz r2,$ ; ждём ~70uS
 wt_dht2:
    ; error control
    mov a,port_dht
    jb ACC.DHTD,wt_dht2 ; ждем окончание состояния 1 импульса ответа
   mov r2,#23
   djnz r2,$ ; ждём ~46uS
 wt_dht3:
    ; error control
    mov a,port_dht
    jnb ACC.DHTD,wt_dht3 ; ждем окончание состояния 0 первого импульса строба
   clr c
 first:
   mov r2,#8
   djnz r2,$ ; задержка 16uS
 paket_dht:
   mov a,port_dht ; ждем окончание импульса значения текущего бита данных
   jnb ACC.DHTD,mount ; 3uS
   mov a,port_dht
   jnb ACC.DHTD,mount ; 3uS
   mov a,port_dht
   jnb ACC.DHTD,mount ; 3uS
   mov a,port_dht
   jnb ACC.DHTD,mount ; 3uS
   mov a,port_dht
   jnb ACC.DHTD,mount ; 3uS
   mov a,port_dht
   jnb ACC.DHTD,mount ; 3uS итоговое ожидание 1 в пределах 19-31uS
   setb c ; если окончание уровня 1 прошло в пределах 19-31uS обрабатывается 0, иначе это 1
 wt_dht4:
    mov a,port_dht
    jb ACC.DHTD,wt_dht4 ; ждем окончание состояния 1 импульса ответа
 mount:
   mov a,r3
   rlc a
   mov r3,a
   mov a,r4
   rlc a
   mov r4,a
   mov a,r5
   rlc a
   mov r5,a
   mov a,r6
   rlc a
   mov r6,a
   mov a,r7
   rlc a
   mov r7,a
   clr c ; страховой сброс С
    ; обработка текущего бита завершена (16uS)
   mov r2,#14
   djnz r2,$ ; ждём ~28uS (в итоге вместе с обработкой массива вписались в 44uS)
 wt_dht5:
     ; error control
    mov a,port_dht
    jnb ACC.DHTD,wt_dht5 ; ждем окончание состояния 0 очередного импульса строба (~47-54uS)
   djnz r1,first ; декремент счетчика бит в пакете и если не равно 0 повтор от first
   ; последующее в задержке опроса 16+2=18uS (в сумме интервал 21-34uS)
 ;----------
    ; храним результат в буфер
     mov mlans,r7 ; значение RH
     mov (mlans+1),r6 ; десятые RH (вероятен 0)
     mov (mlans+2),r5 ; значение Т
     mov (mlans+3),r4 ; десятые Т (вероятен 0)
     mov (mlans+4),r3 ; контрольная сумма предыдущего
 ;----------
 ret ; обработка пакета, включая импульс завершения завершена
;
; error control - обработчик "сторожевой собаки" ошибки протокола/физического интерфейса датчика
;
;----------
;

это "чистый ассемблер" для MCS51.
Под АВР ку в "чистом асме" переделать не проблема, а вот с Сишным ассемблером (ассемблерные вставки)
я не работаю - там несколько своя специфика.
8)

Re: Работа с датчиком HDT11

Чт авг 15, 2019 21:54:09

Объясняю про толеранцию. В начале библы определяем, что толеранция= допустим,10uS. Когда произошёл захват, т.е. в обработчике прерывания по захвату впихиваем в память содержимое регистра ICR. В основном цикле берём из памяти младший байт - это длительность полученного от датчика импульса в микросекундах. Допустим, ловим импульс 80uS. Проверяем, если длительность <80-10 -это ошибка, если >80+10 - тоже ошибка. Т. е. Фактически ловим импульс 80+-10uS. Может датчик и выдаёт твёрдые интервалы, но с точки зрения внутреннего RC генератора эти интервалы очень растяжимое понятие.
PS. кстати, почему для отсчёта времени надо 2 таймера? Всю работу с временем может делать один самый глупый таймер на борту.
У меня таймер0 считает время, таймер1 занимается датчиком влажности, таймер2 молотит шим.

Добавлено after 26 minutes 10 seconds:
На таймерах... можно конечно....
Интервал единицы принимаем за целое
Делим на 8.
Таймер настраиваем на 1/8.
Подсчет переполнений за время приема активной
части импульса и табличный селектор для записи значения бита данных,
соответствующего значению количества переполнений в текущий байт данных
а там 1/2 +/-1/8 это 0, а все, что более - 1.
Как-то так...
:roll:
Только длительность интервалов весьма маахонькая - проще
количество программных задержек использовать.
8)

Да нет, я я запускаю таймер на захват(после старта) 1 тик= 1uS. И выпрыгиваю в главный цикл, где проверяю флаг, который устанавливается в прерывании по захвату. Соответственно, достаю из RAMа число (оно в микросекундах) и решаю 0 это или 1. И опять в главный цикл. Т.е. не зависаю на 4 mS на датчике.
Т.к.полученное число в микросекундах, просто по ДШ сравниваем (а чё это было) - 0, 1, или ещё какая херь.

Re: Работа с датчиком HDT11

Пт авг 16, 2019 06:58:49

О
PS. кстати, почему для отсчёта времени надо 2 таймера? Всю работу с временем может делать один самый глупый таймер на борту.


Таймеры считаю время для разных функций. Почему? - потому что мне так было проще. Наверно можно и на одном, но не хотел заморачиваться этим, т.к. вроде и так хватало)

Добавлено after 7 hours 1 minute 29 seconds:
dgrett, перечитал еще ваше сообщение несколько раз. Возможно позже и попробую на таймере замутить. Но позже.. Пока хочется хоть как то замутить

Re: Работа с датчиком HDT11

Пт авг 16, 2019 11:31:00

ЗамУчивайте:)

Добавлено after 1 hour 13 minutes 8 seconds:
Но! Т.к. протокол основан на измерении длительности импульсов(1-Wire), то сам атмел велел использовать таймер1 в режиме захвата, имхо.

Добавлено after 11 minutes 31 second:
tux, я в сях ноль полный, но я вижу, что стартовый импульс у вас 1 секунда, а это в 1000 раз больше чем надо. И в других местах тоже mS вместо uS. Подтяжка к плюсу, надеюсь, имеется?

Re: Работа с датчиком HDT11

Сб авг 17, 2019 11:51:47

1 секунда это не стартовый импульс. Это просто задержка после включения. В мс потом только стартовый импульс, который по даташиту равен 18мс. Потом везде микросекунды.

Добавлено after 2 minutes 12 seconds:
Ну и как я уже писал выше - программу проверили в симуляторе, алгоритм рабочий, проблема с вероятностью 99% где то в железе
Ответить