Микроконтроллеры

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Микроконтроллеры » Архив » Работа с датчиком DHT22


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

Сообщений 1 страница 4 из 4

1

Решил поделиться опытом работы с цифровым датчиком температуры и влажности DHT22. Для передачи данных датчик использует всего одну ногу с выходом открытый коллектор, ее нужно подтянуть к плюсу через резистор 4.7к. Для начала передачи данных от датчика, МК должен "прижать" линию к минусу как минимум на 1 мс. После этого датчик пошлет импульс присутствия, после чего выдаст в шину 40 бит данных (2 байта - значение влажности, 2 байта - значение температуры, 1 байт - контрольная сумма (сумма 4 байт данных)). Данные передаються старшим вперед.
  Передача бита начинаеться с прижимания линии к минусу на время 50мкс, после чего датчик отпускает линию на время зависимое от того что он передает, если "0" - 26 мкс, если "1" - 70 мкс.
  http://s5.uploads.ru/t/vkI4m.jpg
  http://sf.uploads.ru/t/rpmYM.jpg

  Судя по ДШ максимальная периодичность опроса 2 раза в секунду.
  Используя таймер с двумя каналами захвата/сравнения можно реализовать опрос датчика практически 100% на аппаратном уровне. В МК для формирования сигнала "старт" и приема данных используеться выход канала таймера, который настроен как выход с открытым стоком. Таймер настроен на периодичность срабатывания 10 мкс, и переполнением 0.5 с. Для формирования сигнала "старт" используеться канал сравнения в режиме ШИМ + канал ПДП. По прерыванию канала сравнения (начало формирования сигнала "старт"), включаеться в работу 2 канал таймера в режиме захвата + ПДП для складирования данных в буфер. По прерыванию канала ПДП, после приема 43 захваченных бит производиться разбор буфера, расчет контрольной суммы и сохранение данных температуры и влажности.

  Так выглядит структурная схема таймера:
http://sd.uploads.ru/t/B8Z15.jpg

  Инициализация таймера и ПДП:

Код:
void TIM2_Init(void)
{
  // настраиваем на работу с DHT22
  GPIO_SetMode((gpOutput_AlternateOpenDrain | gp50MHz), PA0);

  DMA1_Ch2_Init();
  DMA1_Ch7_Init();

  TIM2->PSC = 719;  // настраиваем на период 10 мкс и переполнение на 100мс
  TIM2->ARR = 49999;
  TIM2->SR = 0;
  TIM2->DIER = TIM_DIER_UDE | TIM_DIER_CC1IE | TIM_DIER_CC2DE;
  TIM2->CCMR1 = TIM_CCMR1_OC1M | TIM_CCMR1_CC2S_1;
  TIM2->CR1 = TIM_CR1_ARPE;
  TIM2->EGR = TIM_EGR_UG;
  TIM2->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC2P;
  TIM2->CR1 |= TIM_CR1_CEN;
}

void DMA1_Ch2_Init(void)
{
  DMA1_Channel2->CCR = 0;
  DMA1_Channel2->CMAR = (uint32_t) &DHT22_TimDelayBuff[0];
  DMA1_Channel2->CPAR = (uint32_t) &TIM2->CCR1;
  DMA1_Channel2->CNDTR = sizeof(DHT22_TimDelayBuff)/sizeof(*DHT22_TimDelayBuff);
  DMA1_Channel2->CCR = DMA_CCR2_PL | DMA_CCR2_MSIZE_0 | DMA_CCR2_PSIZE_1 | DMA_CCR2_MINC | DMA_CCR2_CIRC | DMA_CCR2_DIR;
  DMA1->IFCR = DMA_IFCR_CGIF2 | DMA_IFCR_CHTIF2 | DMA_IFCR_CTCIF2 | DMA_IFCR_CTEIF2;
  DMA1_Channel2->CCR |= DMA_CCR5_EN;
}

void DMA1_Ch7_Init(void)
{
  DMA1_Channel7->CCR = 0;
  DMA1_Channel7->CMAR = (uint32_t) &DHT22_DataBuff[0];
  DMA1_Channel7->CPAR = (uint32_t) &TIM2->CCR2;
  DMA1_Channel7->CNDTR = sizeof(DHT22_DataBuff)/sizeof(*DHT22_DataBuff);
  DMA1_Channel7->CCR = DMA_CCR7_PL | DMA_CCR7_MSIZE_0 | DMA_CCR7_PSIZE_1 | DMA_CCR7_MINC | DMA_CCR7_TCIE;
  DMA1->IFCR = DMA_IFCR_CGIF7 | DMA_IFCR_CHTIF7 | DMA_IFCR_CTCIF7 | DMA_IFCR_CTEIF7;
}

   

  Обработчик прерывания таймера:

Код:
void TIM2_IRQHandler(void)
{
  if(TIM2->SR & TIM_SR_CC1IF)
  {
   DMA1_Channel7->CCR &= ~DMA_CCR7_EN;
   DMA1_Channel7->CMAR = (uint32_t) &DHT22_DataBuff[0];
   DMA1_Channel7->CNDTR = sizeof(DHT22_DataBuff)/sizeof(*DHT22_DataBuff);
   DMA1_Channel7->CCR |= DMA_CCR7_EN;
   TIM2->CCER |= TIM_CCER_CC2E;

   TIM2->SR &= ~TIM_SR_CC1IF;
  }
}

  Обработчик прерывания канала ПДП:

Код:
void DMA1_Channel7_IRQHandler(void)
{
uint64_t tData = 0;
uint8_t *tDataBuff = (uint8_t*)&tData;

uint16_t a;
uint32_t *b;
uint8_t tCRC;


  if(DMA1->ISR & DMA_ISR_TCIF7)
  {// приняли данные от DHT22
   TIM2->CCER &= ~TIM_CCER_CC2E;

   b = BITBAND_RAMADR((uint32_t)&tData, 0);

   for(a = 0; a < 40; a++) if((DHT22_DataBuff[a + 2] - DHT22_DataBuff[a + 1]) > 10) b[39 - a] = 1; else b[39 - a] = 0;

   // подсчет CRC
   tCRC = 0;
   for(a = 4; a > 0; a--) tCRC = tCRC + tDataBuff[a];

   //
   if(tCRC == tDataBuff[0])
   {
    a = (uint16_t)(tData >> 24);
    H = (float)a / 10;

    a = (uint16_t)(tData >> 8);
    T = (float)a / 10;
   }
   else
   {

   }

   DMA1->IFCR = DMA_IFCR_CTCIF7;
  }
}

2

Ссылка на проект: https://drive.google.com/open?id=1VLHJL … qx54mdtXws
Я немного запутался в том как данные храняться в памяти, я думаю что способ преобразования получился не самый лучший.

P.S. Данный способ отлично подойдет для работы по шине 1-Wire (ds18b20)

Отредактировано MasterElectric (2018-01-25 18:17:26)

3

Витиевато как-то получилось... да ещё и с прерываниями... Но если работает... то тоже вариант...
Хардварно... "практически 100% на аппаратном уровне"... это если вообще без прерываний... Прерывание по кончанию приёма не в счёт... оно может быть... а может и не быть... по задаче...

4

Я решил переписать свой код на Ваш способ. Более менее все понятно, но вот мне нужно использовать ногу PB6 например, которая висит на таймере 4 канале 1.

Я начал писать и вот смотрю на строки

Код:
DMA1_Channel2->CPAR = (uint32_t) &TIM2->CCR1;
Код:
DMA1_Channel7->CPAR = (uint32_t) &TIM2->CCR2;

Я так понимаю это два разных канала одного таймера.
Но каналы на разных ногах мк. Мне нужно две ноги мк подключать к даталайн DHT? Или я что то упускаю и оба канала с одной ногой работают?


Вы здесь » Микроконтроллеры » Архив » Работа с датчиком DHT22