В предыдущей части урока мы написали полностью функцию поиска идентификаторов датчиков и считали уникальные коды со всех датчиков температуры.
Перейдём в функцию main() файла main.c и добавим локальную переменную для счётчика
char c;
uint8_t i;
Затем после вызова функции инициализации покажем наши результаты в терминальной программе
HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
sprintf(str1,"Dev count: %d\r\n", Dev_Cnt);
HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
for(i=1;i<=Dev_Cnt;i++)
{
sprintf(str1,"Device %d\r\n", i);
HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
sprintf(str1,"ROM RAW: %02X %02X %02X %02X %02X %02X %02X %02X\r\n",
Dev_ID[i-1][0], Dev_ID[i-1][1], Dev_ID[i-1][2], Dev_ID[i-1][3],
Dev_ID[i-1][4], Dev_ID[i-1][5], Dev_ID[i-1][6], Dev_ID[i-1][7]);
HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
sprintf(str1,"Family CODE: 0x%02X\r\n", Dev_ID[i-1][0]);
HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
sprintf(str1,"ROM CODE: 0x%02X%02X%02X%02X%02X%02X\r\n", Dev_ID[i-1][6], Dev_ID[i-1][5],
Dev_ID[i-1][4], Dev_ID[i-1][3], Dev_ID[i-1][2], Dev_ID[i-1][1]);
HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
sprintf(str1,"CRC: 0x%02X\r\n", Dev_ID[i-1][7]);
HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
}
/* USER CODE END 2 */
Соберём код, прошьём контроллер и посмотрим результат в терминальной программе
Осталось нам только научиться раздельно передавать команды каждому устройству, чтобы с них считывать текущие показания температуры.
Перейдём в функцию ds18b20_MeasureTemperCmd файла ds18b20.c и добавим для начала в неё локальную переменную
void ds18b20_MeasureTemperCmd(uint8_t mode, uint8_t DevNum)
{
int i = 0;
ds18b20_Reset();
В данной функции у нас есть условие для случая, когда мы пропускаем чтение кода ROM. Добавим противный случай также сразу с телом
ds18b20_WriteByte(0xCC);
}
else
{
//Match Rom
ds18b20_WriteByte(0x55);
for(i=0;i<=7;i++)
{
ds18b20_WriteByte(Dev_ID[DevNum-1][i]);
}
}
//CONVERT T
Здесь мы используем команду Match Rom с кодом 0x55, после передачи которой мы передаём полностью ROM-код устройства вместе с вендором и контрольной суммой. Поэтому нам нет необходимости её генерировать заново. И после этого все команды и всё чтение до сброса устройств будут принадлежать тому устройсву, чей код в шину мы и передадим.
Мы поступим следующим образом. Мы передадим команду на чтение температуры всем устройствам, потом подождём нужное время и лишь потом будем считывать с них со всех температуру. Это делается для того, чтобы не терять время. То есть конвертация считанной температуры будет происходить одновременно во всех датчиках.
Вернёмся в файл main.c и в бесконечном цикле функции main() дадим всем нашим датчикам команду начинать конвертировать значение температуры
/* USER CODE BEGIN 3 */
for(i=1;i<=Dev_Cnt;i++)
{
ds18b20_MeasureTemperCmd(NO_SKIP_ROM, i);
}
HAL_Delay(800);
Соберём код, прошьём контроллер, и посмотрим как происходит обращение к разным устройствам в программе логического анализа
Вернёмся в файл ds18b20.c в функцию ds18b20_ReadStratcpad и уже известный нам по предыдущей функции код в неё. Переменная для счётчика у нас уже есть
ds18b20_WriteByte(0xCC);
}
else
{
//Match Rom
ds18b20_WriteByte(0x55);
for(i=0;i<=7;i++)
{
ds18b20_WriteByte(Dev_ID[DevNum-1][i]);
}
}
//READ SCRATCHPAD
Также мы кое-что не закончили в функции инициализации. Мы там не проинициализировали некоторые конфигурационные регистры в датчике, так как мы ещё не знали как к ним обращаться и с каким кодом.
Выйдем в данной функции из цикла считывания кодов ROM из датчиков и напишем ещё один цикл, который и запишет необходимые значения в регистры всех наших датчиков
else break;
}
for(i=1;i<=Dev_Cnt;i++)
{
if(ds18b20_Reset()) return 1;
//Match Rom
ds18b20_WriteByte(0x55);
for(j=0;j<=7;j++)
{
ds18b20_WriteByte(Dev_ID[i-1][j]);
}
//WRITE SCRATCHPAD
ds18b20_WriteByte(0x4E);
//TH REGISTER 100 градусов
ds18b20_WriteByte(0x64);
//TL REGISTER - 30 градусов
ds18b20_WriteByte(0x9E);
//Resolution 12 bit
ds18b20_WriteByte(RESOLUTION_12BIT);
}
}
return 0;
Вернёмся в бесконечный цикл функции main() файла main.c и добавим туда следующий код для считывания и обработки показаний
HAL_Delay(800);
for(i=1;i<=Dev_Cnt;i++)
{
ds18b20_ReadStratcpad(NO_SKIP_ROM, dt, i);
sprintf(str1,"STRATHPAD %d: %02X %02X %02X %02X %02X %02X %02X %02X; ",
i, dt[0], dt[1], dt[2], dt[3], dt[4], dt[5], dt[6], dt[7]);
HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
raw_temper = ((uint16_t)dt[1]<<8)|dt[0];
if(ds18b20_GetSign(raw_temper)) c='-';
else c='+';
temper = ds18b20_Convert(raw_temper);
sprintf(str1,"Raw t: 0x%04X; t: %c%.2f\r\n", raw_temper, c, temper);
HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
}
HAL_Delay(150);
}
/* USER CODE END 3 */
Соберём код, прошьём контроллер и посмотрим результат в терминальной программе
Мы видим, как попеременно читается температура из обоих датчиков.
Давайте поместим один из датчиков в стакан с кипятком и посомтрим реакцию программы
Мы видим, что показания температуры первого датчика неуклонно увеличиваются, а показания второго — не меняются.
Это с уверенностью позволяет нам убедиться в том. что мы написали всё правильно и тем самым также убедиться в том, что мы научились работать с несколькими устройствами на шине 1-WIRE, отдавая раздельно им команды, считывать с них уникальные коды независимо от количества таких устройства, а также обращаться раздельно к любому из них.
Спасибо всем за внимание!
Предыдущая часть Программирование МК STM32 Следующий урок
Отладочную плату можно приобрести здесь STM32F103C8T6
Логический анализатор можно приобрести здесь Логический анализатор на 8 каналов
Датчик температуры в экране с проводом можно приобрести здесь DS18B20 в экране с проводом
Переходник USB to TTL можно приобрести здесь ftdi ft232rl
Смотреть ВИДЕОУРОК (нажмите на картинку)