HAL_UART_Receive_DMA(&HUARTx, ow_buf, num_bits);
HAL_UART_Transmit_DMA(&HUARTx, ow_buf, num_bits);
Передмова
Макет |
Створюємо проект в CubeMX або CubeIDE
Запускаємо CubeIDE, обираємо свій мікроконтролер, або дошку. Даємо назву проекту, та налаштовуємо проект:Налаштування проекту |
- RCC - тактуємось від зовнішнього кварцу "Crystal/Ceramic resonator";
- SYS - відладка по "Serial Wire";
- USART1 або USART3 - обираємо режим "Single Wire (Half-Duplex)" та додаємо канали DMA як для прийому так і для передачі, а також вмикаємо глобальні переривання "USART global interrupt";
- USART2 - за замовчуванням, для передачі даних температури на послідовний порт комп'ютера.
В файлі DallasTemperature.h за замовчуванням, на лінії 1-Wire йде пошук, максимум 5 сенсорів. Змінити можна в рядку:
#define ONEWIRE_MAX_DEVICES 5
Схема підключення
Схема підключення |
Демо-код
/* USER CODE BEGIN Includes */ #include "OneWire.h" #include "DallasTemperature.h" /* USER CODE END Includes */
/* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ int _write(int file, char *ptr, int len) { HAL_UART_Transmit(&huart2, (uint8_t *) ptr, len, HAL_MAX_DELAY); return len; } // function to print a device address void printAddress(CurrentDeviceAddress deviceAddress) { for (uint8_t i = 0; i < 8; i++) { printf("0x%02X ", deviceAddress[i]); } } /* USER CODE END 0 */
/* USER CODE BEGIN PV */ OneWire_HandleTypeDef ow; DallasTemperature_HandleTypeDef dt; /* USER CODE END PV */
В секцію 2 додаємо перевірку чи на лінії є якісь сенсори 1-Wire, взнаємо кількість підключених до лінії сенсорів, задаємо роздільну здатність сенсорів, та прочитаємо їхню адресу і поточну роздільну здатність:
/* USER CODE BEGIN 2 */ printf("[%8lu] Debug UART2 is OK!\r\n", HAL_GetTick()); OW_Begin(&ow, &huart3); if(OW_Reset(&ow) == OW_OK) { printf("[%8lu] OneWire devices are present :)\r\n", HAL_GetTick()); } else { printf("[%8lu] OneWire no devices :(\r\n", HAL_GetTick()); } DT_SetOneWire(&dt, &ow); // arrays to hold device address CurrentDeviceAddress insideThermometer; // locate devices on the bus printf("[%8lu] Locating devices...", HAL_GetTick()); DT_Begin(&dt); printf("[%8lu] Found %d devices.\r\n", HAL_GetTick(), DT_GetDeviceCount(&dt)); if (!DT_GetAddress(&dt, insideThermometer, 0)) printf("[%8lu] Unable to find address for Device 0\r\n", HAL_GetTick()); printf("[%8lu] Device 0 Address: ", HAL_GetTick()); printAddress(insideThermometer); printf("\r\n"); // set the resolution to 12 bit (Each Dallas/Maxim device is capable of several different resolutions) DT_SetResolution(&dt, insideThermometer, 12, true); printf("[%8lu] Device 0 Resolution: %d\r\n", HAL_GetTick(), DT_GetResolution(&dt, insideThermometer)); if (!DT_GetAddress(&dt, insideThermometer, 1)) printf("[%8lu] Unable to find address for Device 1\r\n", HAL_GetTick()); printf("[%8lu] Device 1 Address: ", HAL_GetTick()); printAddress(insideThermometer); printf("\r\n"); // set the resolution to 12 bit (Each Dallas/Maxim device is capable of several different resolutions) DT_SetResolution(&dt, insideThermometer, 12, true); printf("[%8lu] Device 1 Resolution: %d\r\n", HAL_GetTick(), DT_GetResolution(&dt, insideThermometer)); /* USER CODE END 2 */
Приклад розрахований для двох DS18B20 на одній лінії. Як у вас один сенсор, видаліть код для другого сенсора з індексом 1.
А в безкінечному циклі раз на 2 секунди будемо опитувати сенсори і виводити в послідовний порт отриману температуру:
/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { // call DT_RequestTemperatures(&dt) to issue a global temperature // request to all devices on the bus printf("[%8lu] Requesting temperatures...", HAL_GetTick()); DT_RequestTemperatures(&dt); // Send the command to get temperatures printf("\r\n[%8lu] DONE\r\n", HAL_GetTick()); // After we got the temperatures, we can print them here. // We use the function ByIndex, and as an example get the temperature from the first sensor only. printf("[%8lu] Temperature for the device 1 (index 0) is: %.2f\r\n", HAL_GetTick(), DT_GetTempCByIndex(&dt, 0)); printf("[%8lu] Temperature for the device 2 (index 1) is: %.2f\r\n", HAL_GetTick(), DT_GetTempCByIndex(&dt, 1)); HAL_Delay(2000); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
Щоб функція "printf" могла виводити значення типу "float" потрібно відповідно налаштувати проект в CubeIDE, а саме додати ключ "-u _printf_float":
Налаштування друку float |
І для Atolic TrueStudio обрати "NewLib standart":
Налаштування для друку float |
Компілюємо, заливаємо. Запускаємо будь-яку термінальну програму і спостерігаємо:
Приклад роботи двох датчиків на лінії |
Відео-посібник
Текст коду з відео:
/* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "stdio.h" #include "OneWire.h" #include "DallasTemperature.h" /* USER CODE END Includes */ /* USER CODE BEGIN PV */ OneWire_HandleTypeDef ow1; DallasTemperature_HandleTypeDef dt1; OneWire_HandleTypeDef ow2; DallasTemperature_HandleTypeDef dt2; /* USER CODE END PV */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ int _write(int file, char *ptr, int len) { HAL_UART_Transmit(&huart2, (uint8_t *) ptr, len, HAL_MAX_DELAY); return len; } // function to print a device address void printAddress(CurrentDeviceAddress deviceAddress) { for (uint8_t i = 0; i < 8; i++) { printf("0x%02X ", deviceAddress[i]); } } /* USER CODE END 0 */ /* USER CODE BEGIN 2 */ printf("[%8lu] Debug UART2 is OK!\r\n", HAL_GetTick()); OW_Begin(&ow1, &huart1); OW_Begin(&ow2, &huart3); if(OW_Reset(&ow1) == OW_OK) { printf("[%8lu] OneWire 1 line devices are present :)\r\n", HAL_GetTick()); } else { printf("[%8lu] OneWire 1 line no devices :(\r\n", HAL_GetTick()); } if(OW_Reset(&ow2) == OW_OK) { printf("[%8lu] OneWire 2 line devices are present :)\r\n", HAL_GetTick()); } else { printf("[%8lu] OneWire 2 line no devices :(\r\n", HAL_GetTick()); } DT_SetOneWire(&dt1, &ow1); DT_SetOneWire(&dt2, &ow2); // arrays to hold device address CurrentDeviceAddress insideThermometer; // locate devices on the bus printf("[%8lu] 1-line Locating devices...\r\n", HAL_GetTick()); DT_Begin(&dt1); uint8_t numDevOneLine = DT_GetDeviceCount(&dt1); printf("[%8lu] 1-line Found %d devices.\r\n", HAL_GetTick(), numDevOneLine); printf("[%8lu] 2-line Locating devices...\r\n", HAL_GetTick()); DT_Begin(&dt2); uint8_t numDevTwoLine = DT_GetDeviceCount(&dt2); printf("[%8lu] 2-line Found %d devices.\r\n", HAL_GetTick(), numDevTwoLine); for (int i = 0; i < numDevOneLine; ++i) { if (!DT_GetAddress(&dt1, insideThermometer, i)) printf("[%8lu] 1-line: Unable to find address for Device %d\r\n", HAL_GetTick(), i); printf("[%8lu] 1-line: Device %d Address: ", HAL_GetTick(), i); printAddress(insideThermometer); printf("\r\n"); // set the resolution to 12 bit (Each Dallas/Maxim device is capable of several different resolutions) DT_SetResolution(&dt1, insideThermometer, 12, true); printf("[%8lu] 1-line: Device %d Resolution: %d\r\n", HAL_GetTick(), i, DT_GetResolution(&dt1, insideThermometer)); } for (int i = 0; i < numDevTwoLine; ++i) { if (!DT_GetAddress(&dt2, insideThermometer, i)) printf("[%8lu] 2-line: Unable to find address for Device %d\r\n", HAL_GetTick(), i); printf("[%8lu] 2-line: Device %d Address: ", HAL_GetTick(), i); printAddress(insideThermometer); printf("\r\n"); // set the resolution to 12 bit (Each Dallas/Maxim device is capable of several different resolutions) DT_SetResolution(&dt2, insideThermometer, 12, true); printf("[%8lu] 2-line: Device %d Resolution: %d\r\n", HAL_GetTick(), i, DT_GetResolution(&dt2, insideThermometer)); } /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { // call sensors.requestTemperatures() to issue a global temperature // request to all devices on the bus printf("[%8lu] 1-line: Requesting temperatures...", HAL_GetTick()); DT_RequestTemperatures(&dt1); // Send the command to get temperatures printf("\r\n[%8lu] 1-line: DONE\r\n", HAL_GetTick()); printf("[%8lu] 2-line: Requesting temperatures...", HAL_GetTick()); DT_RequestTemperatures(&dt2); // Send the command to get temperatures printf("\r\n[%8lu] 2-line: DONE\r\n", HAL_GetTick()); for (int i = 0; i < numDevOneLine; ++i) { // After we got the temperatures, we can print them here. // We use the function ByIndex, and as an example get the temperature from the first sensor only. printf("[%8lu] 1-line: Temperature for the device %d (index %d) is: %.2f\r\n", HAL_GetTick(), i, i, DT_GetTempCByIndex(&dt1, i)); } for (int i = 0; i < numDevTwoLine; ++i) { // After we got the temperatures, we can print them here. // We use the function ByIndex, and as an example get the temperature from the first sensor only. printf("[%8lu] 2-line: Temperature for the device %d (index %d) is: %.2f\r\n", HAL_GetTick(), i, i, DT_GetTempCByIndex(&dt2, i)); } HAL_Delay(DT_MillisToWaitForConversion(DT_GetAllResolution(&dt1))); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
Щиро дякую за Вашу роботу.
ВідповістиВидалитиБудь ласочка.
ВидалитиБібліотека на FreeRTOS буде працювати?
ВідповістиВидалитиНе бачу перешкод для цього. В якійсь задачі іноді опитуйте датчик, та й все.
ВидалитиАвтор видалив цей коментар.
ВідповістиВидалитиДобрый день.
ВідповістиВидалитиЗапустил на stm32l476rg, но отрабатывает только reset (по анализатору видно, что presence condition приходит), но после этого зависает на DT_Begin и все. Подключил только один датчик...
Зависает на функции OW_Send...Состояние HAL_UART_STATE_READY никогда не появляется. Надо будет найти еще один датчик, может этот бракованный.
ВидалитиШановний, Валерій.
ВидалитиЗараз немає можливості перепровірити для stm32f4xx. Але здається я перевіряв роботу на discovery 407 . Одначе колись в мене була схожа ситуація, як у вас. Розбиратись не було часу тоді і створив новий проект з нуля, а код зкопіпастив і все запрацювало. Я не знаю в чому була справа і більш такого не виникало. Декілька людей відписувало, що все працює нормально.
Добрый день.
ВидалитиПодключил вашу библиотеку к проекту для discovery 407, вместо huart2 вывожу данные на TFT с EmWin. Зависает на OW_Reset (). Можно как нибудь посмотреть ваш проект для stm32f407? Большое спасибо за вашу работу.
Добрый день. Спасибо. Попробую так сделать, т.к. думаю что проблемы где-то в настройках дма...
ВідповістиВидалитиАндрей, здравствуйте
ВідповістиВидалитиНедавно перешел на STM32 и язык С, пытаюсь раскочегарить DS18B20 с помощью вашей библиотеки, поскольку использую те же самые инструменты CubeMX -> Atollic-> STM32F103C8T6
Начал с простого:
int b = OW_Reset();
number = b; //выводится на 8-сегментный индикатор
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // проверка на зависание главного цикла
HAL_Delay(1000);
До этого момента всё прекрасно.
Отправляю команду
OW_Send(OW_SEND_RESET, (uint8_t *) "\xcc\x44", 2, (uint8_t *) NULL, 0, OW_NO_READ);
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(1000);
Уже на этом этапе зависает.
На осциллографе вижу, что он что-то пытается посылать, но передача обрывается на первом байте, и дальше ничего не происходит. Подскажите, в какую сторону копать. Спасибо.
Вітання, бібліотека сира. Хоч в мене і працює, але є випадки що в інших не працює. Як вам не принципово по uart dma, то можете використовувати цю бібліотеку з ногодригом https://github.com/taburyak/ds18b20 - працює як слід.
ВидалитиЯ ещё пока сам не знаю, критично мне или нет :)
ВидалитиКогда на атмеге дрыгал ногодрыгом, работоспособность протокола зависела от количества и нагруженности прерываний. В аналогичной задаче их количество пришлось уменьшать. Поскольку STM32F103 раз в 10 быстрее, прерывания выполняются за меньшее время, они должны гораздо меньше влиять на тайминги протокола. Так что да, по крайней мере в этой задаче всё должно работать. Спасибо.
А можна контакти для детальнішого питання?
ВідповістиВидалитиШановний Андрію! Як налаштовується STM32F103C8Tx і які при цьому параметри FreeTos у випадку "ногодрига"?
ВідповістиВидалитиДякую заздалегить.
В бібліотеці https://github.com/taburyak/ds18b20 є конфігураційний файл де можна зазначити що буде використовуватись FRTOS а також порт і пін де шина 1-wire
ВидалитиДякую, я це бачив. Який режим треба вибрати для цього піну, бо він жеш один що на прийом, що на передачу. Це може бути тільки на пінах USART, налаштованих в режимі OW. Чи я помиляюсь?
ВідповістиВидалитиВказуєш в бібліотеці який пін 1-wire. Все інше робить бібліотека своїми функціями.
ВидалитиЗрозуміло, дякую.
ВідповістиВидалитиУ bool DT_ReadScratchPad()
ВідповістиВидалитивиправіть рядок
b = OW_Send(OW_SEND_RESET, query, 19, scratchPad, 9, 10);//була помилка 18-8.
Тоді функція DT_IsConnected_ScratchPad()
з
return b && (OW_crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]);
запрацює.
Можна ще додати перевірку на нулі
// Returns true if all bytes of scratchPad are '\0'
bool isAllZeros(const uint8_t * const scratchPad, const size_t length) {
for (size_t i = 0; i < length; i++) {
if (scratchPad[i] != 0) {
return false;
}
}
return true;
}
А строку з перевіркою на
return b && !isAllZeros(scratchPad, 8) && (OW_crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]);
Працює на f070 та f103 без корректіровок.
Дякую автору за публікацію.
###########
P.S.На космодроме купил датчики в ТО-92 и на метровом проводе. На метровом проводе работает ок на +127-50'С.
Для ТО-92 уменьшил скорость baudRate = (baudRate*88)/100;
, иначе не работает в полном диапазоне температур +127-50'C.
Щира дяка за ваш коментар. Я найближчим часом перевірю. І як, все добре, обов'язково виправлю і внесу корекції до статті.
ВидалитиЗ вашими виправляннями return b && (OW_crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]); запрацювало, але для сенсора по індексу 0. На жаль інші сенсори вже не бачаться. Тому поки питання залишається відкритим.
Видалити1. В описі слід наголосити, що в кубі треба включати глобальні переривання для того usart на якому висить датчик температури. Бо цей момент не є очевидним для всіх. Без перериваннь функція HAL_UART_Transmit_DMA працює некоректно. Зарившись в нутрощі цієї функції можна побачити, що статус "HAL_UART_STATE_READY" передавачу повертається саме після обробки переривання transmitcomplete. Саме тому у більшості коментаторів програма зависає в циклі
ВідповістиВидалитиwhile (HAL_UART_GetState(&HUARTx) != HAL_UART_STATE_READY)
{
__NOP();
}
2. Слід переставити місцями функції HAL_UART_Transmit_DMA та HAL_UART_Receive_DMA - першим включаємо приймач, а вже за ним передавач. Теоретично, на низькій частоті системної шини приймач може пропустити корисну інформацію від передавача в момент свого запуска.
Щира дяка за такий конструктивний коментар. Найближчим часом перевірю і виправлю. Дякую.
ВидалитиКорективи до статті додав. Зазначив що потрібно увімкнути глобальні переривання для USART.
ВидалитиФункції поміняв місцями.
Щира дяка.
Елки! Полтора года спустя! Хехе, спасибо, даже сейчас тема не утратила актуальности!
Видалити