|
Странное поведение DS18b20 |
|
|
|
Jan 27 2016, 17:45
|
Местный
  
Группа: Участник
Сообщений: 322
Регистрация: 28-05-05
Пользователь №: 5 512

|
Всем доброго времени суток! Есть проблема с датчиками DS18b20 Заказал пару штук этих датчиков во влагозащищенном исполнении. Подключил один из них по 2-проводной схеме - т.е. красный и черный провод объединил и посадил на "землю". Желтый провод сделал PullUP (к 3,3В через 3,3кОм) посадил на передатчик USART4. МК - STM32F103RE (отладочная плата - Махаон). Для упрощения жизни запустил CubeMX последней версии, настроил USART4 на HalfDuplex. И ситуация следующая: на F0 датчик отвечает E0, а вот на остальные команды не отвечает вообще никак. Ни на 0хсс 0хBE (чтение памяти 9 байт) ни на 0x33. Собственно, результаты смотрел в отладчике Keil и осциллографом. Скорость UART меняется адекватно, оценивал длительность импульсов согласно скорости. Код ниже: Код uint8_t TxCmdReset=0xF0; uint8_t RxAnswReset1; uint8_t RxData[100]; uint8_t ow_buf[8];
HAL_HalfDuplex_EnableReceiver(&huart4); MX_UART4_Init_wBoudRate(9600); //Reset HAL_UART_Receive_IT(&huart4,&RxAnswReset1,1); HAL_UART_Transmit(&huart4, &TxCmdReset, sizeof(TxCmdReset), 2); for(i=0;i<1000;i++) {__NOP();} MX_UART4_Init_wBoudRate(115200); HAL_UART_Receive_IT(&huart4, RxData, sizeof(RxData)); OW_toBits(0xCC, ow_buf); HAL_UART_Transmit(&huart4, (uint8_t *)ow_buf, 8, 3); OW_toBits(0xB4, ow_buf); HAL_UART_Transmit(&huart4, (uint8_t *)ow_buf, 8, 3); HAL_Delay(2); while(1); Код void MX_UART4_Init_wBoudRate(uint32_t BoudRate) { huart4.Instance = UART4; huart4.Init.BaudRate = BoudRate; huart4.Init.WordLength = UART_WORDLENGTH_8B; huart4.Init.StopBits = UART_STOPBITS_1; huart4.Init.Parity = UART_PARITY_NONE; huart4.Init.Mode = UART_MODE_TX_RX; huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart4.Init.OverSampling = UART_OVERSAMPLING_16; HAL_HalfDuplex_Init(&huart4); } Функция преобразования байта в 8 байт для отправки заимствован. Тем не менее его в отладчике проверял - замечаний нет. Код void OW_toBits(uint8_t ow_byte, uint8_t *ow_bits) { uint8_t i; for (i = 0; i < 8; i++) { if (ow_byte & 0x01) { *ow_bits = OW_1; } else { *ow_bits = OW_0; } ow_bits++; ow_byte = ow_byte >> 1; } } Пробовал оба датчика - ведут себя одинаково. Значит есть надежда что ошибка в коде. Может кто прояснит в чем я не прав?
Сообщение отредактировал Halfback - Jan 27 2016, 17:57
|
|
|
|
|
 |
Ответов
|
Jan 29 2016, 13:52
|
Местный
  
Группа: Участник
Сообщений: 322
Регистрация: 28-05-05
Пользователь №: 5 512

|
Частично разобрался. Решил пока забить на UART и сделал долбатню пином. Все временные выдерки взял согласно даташиту на датчик. Всё четко как в аптеке. Свою задержку 1us замерял осциллом. Собственно основной цикл: Код #define ONEWIRE_LOW() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET) #define ONEWIRE_HIGH() HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET) #define ONEWIRE_INPUT() MX_GPIO_P10_Init(2) // IN NoPull #define ONEWIRE_OUTPUT_PP() MX_GPIO_P10_Init(1) // OUT PP #define ONEWIRE_OUTPUT_OD() MX_GPIO_P10_Init(0) // OUT OD #define ONEWIRE_READPIN() HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_10) #define DELAY_1us() {__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\ __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\ __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\ __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\ __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();\ __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();} #define ONEWIRE_DELAY(delay_us) {for(volatile uint16_t i=0;i<delay_us-1;i++) DELAY_1us();} ...... volatile uint8_t ResetAnsw=0x55; uint8_t RxByte[9]={0,0,0,0,0,0,0,0,0}; volatile uint8_t Temperature=0; .... ResetAnsw=TM_OneWire_Reset(); TM_OneWire_WriteByte(0xcc); // skip ROM command TM_OneWire_WriteByte(0x44); // convert T command ONEWIRE_OUTPUT_PP(); ONEWIRE_HIGH(); HAL_Delay(800); // at least 750 ms for the default 12-bit resolution ResetAnsw=TM_OneWire_Reset(); TM_OneWire_WriteByte(0xcc); // skip ROM command TM_OneWire_WriteByte(0xbe); // read scratchpad command for(uint8_t t=0;t<10;t++) RxByte[t]=TM_OneWire_ReadByte(); Temperature = ((RxByte[1]&7)<<4)|(RxByte[0]>>4); Но на самом деле дъявол кроется в этих функциях: CODE void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); }
void MX_GPIO_P10_Init(uint8_t PC10_Mode) // 0- Out OD, 1- Out PP, 2- In {
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */ __GPIOD_CLK_ENABLE(); __GPIOC_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET); /*Configure GPIO pin : PC10 */ if(PC10_Mode==0) {GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; } else if(PC10_Mode==1) {GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;} else if(PC10_Mode==2) {GPIO_InitStruct.Mode = GPIO_MODE_INPUT;} GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); }
uint8_t TM_OneWire_Reset(void) { uint8_t i;
ONEWIRE_OUTPUT_OD(); ONEWIRE_LOW(); ONEWIRE_DELAY(480); ONEWIRE_HIGH(); ONEWIRE_INPUT(); ONEWIRE_DELAY(70); i = ONEWIRE_READPIN(); ONEWIRE_DELAY(410); ONEWIRE_OUTPUT_OD(); return i; }
void TM_OneWire_WriteByte(uint8_t byte) { uint8_t i = 8;
ONEWIRE_OUTPUT_OD(); for(i=0;i<8;i++) { if((byte&0x01)==0x01) { ONEWIRE_LOW(); // Drive bus low ONEWIRE_DELAY(2); ONEWIRE_HIGH(); ONEWIRE_DELAY(55); //sample time slot for the slave //ONEWIRE_DELAY(2); //recovery time slot } else { ONEWIRE_LOW(); // Drive bus low ONEWIRE_DELAY(90); ONEWIRE_HIGH(); ONEWIRE_DELAY(2); //recovery time slot } byte=byte>>1; ONEWIRE_HIGH(); } }
uint8_t TM_OneWire_ReadByte(void) { uint8_t i = 8, byte = 0;
while (i--) { ONEWIRE_OUTPUT_OD(); ONEWIRE_LOW(); ONEWIRE_DELAY(2); ONEWIRE_INPUT(); ONEWIRE_DELAY(6); byte >>= 1; byte |= (ONEWIRE_READPIN() << 7); ONEWIRE_DELAY(50); } return byte; } Буду ли ковыряться с UART - не знаю. Слишком много времени убил на этот датчик.
Сообщение отредактировал Herz - Jan 31 2016, 17:43
|
|
|
|
|
Jan 31 2016, 14:56
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(Halfback @ Jan 29 2016, 17:52)  Частично разобрался. Решил пока забить на UART и сделал долбатню пином. Все временные выдерки взял согласно даташиту на датчик. Всё четко как в аптеке. Свою задержку 1us замерял осциллом. . . . . Буду ли ковыряться с UART - не знаю. Слишком много времени убил на этот датчик. Работа с датчиком в таком режиме предполагает отсутствие всех прерываний. Возможно, чтобы не ограничиваться в этом, и "замутили" работу через UART. Запретить прерывания можно только на время цикла обмена с DS18B20. цена вопроса пара миллисекунд (кажется) И все будет феншуй.
|
|
|
|
|
Feb 5 2016, 06:09
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Леонид Иванович @ Feb 5 2016, 04:09)  Прерывания надо запрещать только в промежутке от окончания импульса сброса до момента поллинга "presence pulse" (это 75 мкс), а также от начала тайм-слота до считывания бита (это примерно 60 мкс). Остальное время прерывания могут как угодно растягивать процесс обмена - ни на что это не повлияет. За 75 или 60 мкс у Вас успеет потеряться к примеру один байт в UART-е работающем без FIFO на скорости 230400. Прерывания вообще запрещать не нужно. Вся работа идёт в ISR. Процесс приёма бита: 1.Мастер включает pull down шины; программирует таймер на выдержку 15 мкс; выходит из ISR. 2.Получив прерывание таймера: выключает pull down шины; программирует таймер в режим capture с прерыванием/защёлкиванием значения таймера от фронта сигнала на шине; также программируется таймер на отслеживание таймаута (на случай если удалённая сторона померла или линия залипла в "pull down"); выходит из ISR. 3.Получив прерывание таймера (таймаут): детектирует состояние ошибки обмена с датчиком - завершает процедуру обмена; выходит из ISR. 4.Получив прерывание таймера (обнаружен фронт на шине): считывает защёлкнутое значение таймера, вычисляет прошедшее время - определяет значение бита, сохраняет его; декрементирует счётчик оставшихся бит, если не 0 - программирует таймер на выдержку интервала времени до начала след. бита согласно требуемой и допустимой скорости обмена по шине; выходит из ISR. 5.Переход к п.1. Всё! Ни одного запрета прерывания! Тем более на огромные интервалы порядка десятков мкс. Можно немного упростить алгоритм, если не использовать режим capture таймера, а работать на обычных выдержках с принятием решений по границам состояний бит '0' и '1'. Но правильнее будет с capture. Алгоритм передачи ещё проще, даже описывать смысла нет.
|
|
|
|
|
Feb 5 2016, 16:22
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Леонид Иванович @ Feb 5 2016, 16:55)  Есть множество проектов, где запрещение прерываний на десятки мкс не является критичным. Тогда можно делать чисто программную реализуцию 1-Wire, которая намного проще для понимания, чем вариант с таймером. Здесь раздел для начинающих. Т.е. - для тех кто должен учиться. Учиться делать правильно. Чтобы это потом можно было использовать в других проектах, наращивать функциональность проектов добавляя новые интерфейсы например и функции. Да и опыта надо набираться начинающим. Как раз вот на таких примитивных интерфейсах это и можно делать. Я считаю - если сейчас он делает тяп-ляп, лишь бы кое-как, то и потом с него толка не будет.
|
|
|
|
|
Feb 5 2016, 16:39
|

Местный
  
Группа: Участник
Сообщений: 329
Регистрация: 23-04-14
Пользователь №: 81 502

|
Цитата(jcxz @ Feb 5 2016, 16:22)  Здесь раздел для начинающих. Т.е. - для тех кто должен учиться. Учиться делать правильно. Чтобы это потом можно было использовать в других проектах, наращивать функциональность проектов добавляя новые интерфейсы например и функции. Да и опыта надо набираться начинающим. Как раз вот на таких примитивных интерфейсах это и можно делать. Я считаю - если сейчас он делает тяп-ляп, лишь бы кое-как, то и потом с него толка не будет. Можно получить четкое определение "правильно" ? Вот у меня, например, похожий термометр был прикручен к pic12 и все микросекундные тайминги для обмена сделаны на задержках... Просто потому что не имело смысла возюкаться с таймерами и прерываниями.. Это правильно или неправильно ?
|
|
|
|
Сообщений в этой теме
Halfback Странное поведение DS18b20 Jan 27 2016, 17:45 k155la3 Насколько мне не изменяет (?) память, DS18B20 рабо... Jan 28 2016, 07:13 adnega Цитата(Halfback @ Jan 27 2016, 20:45) Про... Jan 28 2016, 07:28 Halfback Спасибо что откликнулись.
Тайминги на соответствие... Jan 28 2016, 08:33 adnega Цитата(Halfback @ Jan 28 2016, 11:33) Что... Jan 28 2016, 08:48 AHTOXA Цитата(Halfback @ Jan 27 2016, 22:45) Для... Jan 28 2016, 10:13 k155la3 Вот подвернулось тут. Работа с DS18B20
По ссылке, ... Jan 29 2016, 06:27 adnega Цитата(Halfback @ Jan 29 2016, 16:52) Час... Jan 29 2016, 14:04  jcxz Цитата(Halfback @ Jan 29 2016, 19:52) Реш... Feb 1 2016, 05:16   rx3apf Цитата(jcxz @ Feb 1 2016, 08:16) И причём... Feb 1 2016, 10:39  adnega Цитата(k155la3 @ Jan 31 2016, 17:56) Запр... Jan 31 2016, 17:30   k155la3 Цитата(adnega @ Jan 31 2016, 20:30) )))
О... Feb 3 2016, 10:54    Сергей Борщ Цитата(jcxz @ Feb 5 2016, 08:09) Алгоритм... Feb 5 2016, 07:50       adnega Цитата(CrimsonPig @ Feb 5 2016, 19:39) Мо... Feb 5 2016, 18:55       jcxz Цитата(CrimsonPig @ Feb 5 2016, 22:39) Во... Feb 6 2016, 09:15 ILYAUL Самый простой способ работать с 1-wire через UART ... Feb 9 2016, 16:49
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|