В микроконтроллер RP2040 на плате Raspberry Pi Pico встроен аналоговый датчик температуры. Датчик температуры внутри микроконтроллера подключён к ADC4 (четвёртый канал аналогово-цифрового преобразователя АЦП) микроконтроллера.
4.9.5. Датчик температуры
Датчик температуры измеряет напряжение Vbe смещённого биполярного диода, подключённого к пятому каналу АЦП (AINSEL=4).
Как правило, Vbe = 0,706 В при 27 градусах Цельсия, с температурным градиентом -1,721 мВ на градус. Следовательно, температуру можно аппроксимировать следующим образом:T = 27 - (ADC_voltage - 0,706) / 0,001721
Поскольку значения Vbe и его градиента могут варьироваться в рабочем температурном диапазоне и от экземпляра к экземпляру устройства, для получения точных измерений может потребоваться дополнительная калибровка пользователем.
Перед использованием источник смещения датчика температуры должен быть включён через бит CS.TS_EN. Это увеличивает потребление тока от источника ADC_AVDD примерно на 40 мкА.
"Datasheet RP2040". Перевод с английского стр. 584.
Чтобы измерить температуру кристалла микроконтроллера RP2040 с помощью встроенного в микроконтроллер аналогового датчика температуры необходимо воспользоваться встроенным в микроконтроллер аналогово-цифровым преобразователем АЦП (ADC). Вывод данных из программы будет происходить в монитор последовательного порта компьютера через USB интерфейс. С учётом изложенного файл CMakeLists.txt будет иметь вид представленный в листинге 1.
cmake_minimum_required(VERSION 3.13) # Минимальная версия CMake
include(pico_sdk_import.cmake) # Импорт Pico SDK
project(CPUtemperature) # Имя проекта
pico_sdk_init() # Инициализация SDK
add_executable(CPUtemperature main.c) # Создание исполняемого файла из указанного исходника
target_link_libraries(CPUtemperature # Подключение обязательных библиотек
pico_stdlib # Базовая функциональность
hardware_adc # Работа с АЦП
)
pico_enable_stdio_uart(CPUtemperature 0) # Настройка вывода: отключить UART
pico_enable_stdio_usb(CPUtemperature 1) # Настройка вывода: включить USB
pico_add_extra_outputs(CPUtemperature) # Генерация UF2/BIN/HEX файлов
Лист. 1. Файл CMakeLists.txt
В программе лист. 2 настроим микроконтроллер на вывод значений измерений напряжения выполняемых АЦП по четвёртому каналу ADC4.
#include <stdio.h> // Стандартный ввод/вывод
#include "pico/stdlib.h" // Базовые функции Pico SDK
#include "hardware/adc.h" // Работа с АЦП (аналогово-цифровым преобразователем)
int main() {
stdio_init_all(); // Инициализация USB/UART для printf
adc_init(); // Включение блока АЦП
adc_select_input(4); // Выбор 4-го канала АЦП (встроенный датчик температуры)
while (true) { // Бесконечный цикл
sleep_ms(1000); // Пауза 1 секунда между измерениями
int adc = adc_read(); // Чтение сырого значения АЦП (0-4095)
// Вывод результата преобразования:
printf("Значение, полученное в результате АЦП преобразования: %d\n", adc);
}
}
Лист. 2. Файл main.c
Результат работы программы лист. 2 показан на рис. 1.
Рис. 1. Serial Monitor.
Аналогово-цифровой преобразователь
- Характеристики АЦП RP2040:
- Разрешение 12-битное (диапазон 0-4095)
- Скорость: до 500 тыс. выборок/сек (500 kSPS)
- 5 аналоговых каналов:
- GPIO26-28: внешние каналы 0-2
- GPIO29: измерение напряжения питания (ADC_VREF)
- Канал 4: встроенный датчик температуры
- Фиксированное опорное напряжение 3.3V (изменяется только через внешний делитель)
Практический совет: При работе с датчиком температуры включайте источник смещения (adc_set_temp_sensor_enabled(true))
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
int main() {
stdio_init_all();
adc_init();
adc_select_input(4);
adc_set_temp_sensor_enabled(true); // Включение встроенного датчика температуры
while (true) {
sleep_ms(1000);
int adc = adc_read();
printf("Значение, полученное в результате АЦП преобразования: %d\n", adc);
}
}
Лист. 3. Файл main.c
В программе лит. 2 включён источник смещения датчика температуры. Это увеличивает потребление тока от источника ADC_AVDD примерно на 40 мкА.
Результат работы программы лист. 3 показан на рис. 2.
Рис. 2. Serial Monitor.
Микроконтроллер RP2040, работающий под управлением программы лист. 3 измеряет напряжение на входе АЦП ADC4 и выдаёт цифровые значения, например 882. Напомним, к ADC4 подключён смещённый биполярный диод напряжение на котором имеет некоторый температурный дрейф. Разберёмся, как преобразовать значение, возвращаемое АЦП в значение измеренного напряжения.
АЦП измеряет напряжения в диапазоне от 0 Вольт до напряжения на выводе 34 микроконтроллера обозначаемого на схемах как ADC_VREF/AVDD. На плате Raspberrry Pi Pico напряжение на выводе ADC_VREF/AVDD равно 3.3 Вольта. И так, мы имеем преобразователь значений напряжения от 0 до 3.3 Вольт в 12 битное число в диапазоне от 0 до 4095 (4096 значений).
Коэффициент преобразования АЦП, его масштаб, можно посчитать по формуле:
k = 3.3 Вольта / 4096 = 0,000805664 Вольта
Если умножить на этот коэффициент значение полученное АЦП, мы получим значение измеряемого напряжения в Вольтах.
Изменим программу лист. 3 таким образом, чтобы она выводила на монитор последовательного порта напряжение измеренное на входе ADC4 в Вольтах:
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
int main() {
stdio_init_all();
adc_init();
adc_select_input(4);
adc_set_temp_sensor_enabled(true);
while (true) {
sleep_ms(1000);
float voltage = adc_read() * 3.3f / 4096; // Единица измерения Вольт
printf("Напряжение, измеренное АЦП на входе ADC4: %.4f Вольт\n", voltage);
}
}
Лист. 4. Файл main.c
Рис. 3. Serial Monitor.
Осталось перевести напряжение, измеренное АЦП на датчике температуры в градусы Цельсия. Вставим в программу листинг 4 формулу из datasheet микроконтроллера RP2040. Смотрите формулу в начале этой статьи.
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
int main() {
stdio_init_all();
adc_init();
adc_select_input(4);
adc_set_temp_sensor_enabled(true);
while (true) {
sleep_ms(1000);
float voltage = adc_read() * 3.3f / 4096; // Единица измерения Вольт
float temp = 27.0f - (voltage - 0.706f) / 0.001721f; // Единица измерения C
printf("Температура кристалла мк, измеренная АЦП: %.1f °C\n", temp);
}
}
Лист. 5. Файл main.c
Рис. 4. Serial Monitor.
Задание. Переведите температуру микроконтроллера из градусов Цельсия в градусы по Фаренгейту. Формула:
F = C × 9/5 + 32
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
int main() {
stdio_init_all();
adc_init();
adc_select_input(4);
adc_set_temp_sensor_enabled(true);
while (true) {
sleep_ms(1000);
float voltage = adc_read() * 3.3f / 4096; // Единица измерения Вольт
float temp = 27.0f - (voltage - 0.706f) / 0.001721f; // Единица измерения C
float temp_f = temp * 9.0f / 5 + 32; // Единица измерения Фаренгейты F
printf("Температура кристалла мк: %.1f °C (%.1f °F)\n", temp, temp_f);
}
}
Лист. 6. Файл main.c
Рис. 5. Serial Monitor.
Задание. Перепишите программу листинг 6 дополнив её подробными комментариями.
#include <stdio.h> // Стандартная библиотека ввода/вывода
#include "pico/stdlib.h" // Библиотека специфичных для Pico функций
#include "hardware/adc.h" // Библиотека работы с АЦП
int main() {
// Инициализация средств вывода (USB/UART для printf)
stdio_init_all();
// Инициализация АЦП (включает блок аналого-цифрового преобразователя)
adc_init();
// Выбор 4-го канала АЦП (встроенный датчик температуры)
adc_select_input(4);
// Включение источника смещения для датчика температуры
// (необходимо для корректной работы, потребляет ~40 мкА)
adc_set_temp_sensor_enabled(true);
// Бесконечный цикл измерений
while (true) {
// Пауза 1 секунда между измерениями
sleep_ms(1000);
/*
[ШАГ 1] Чтение и преобразование сырого значения АЦП
- adc_read() возвращает 12-битное значение (0-4095)
- 3.3f: опорное напряжение АЦП (3.3 Вольта)
- 4096: количество шагов АЦП (2^12 = 4096)
Формула: напряжение = (значение_АЦП * Vref) / 4096
*/
float voltage = adc_read() * 3.3f / 4096; // Результат в Вольтах
/*
[ШАГ 2] Расчет температуры в Цельсиях
Стандартная формула для встроенного датчика RP2040:
T = 27.0 - (Vbe - 0.706) / 0.001721
Где:
- 27.0: калибровочная температура (в °C)
- 0.706: напряжение Vbe при 27°C (в Вольтах)
- 0.001721: температурный коэффициент (1.721 мВ/°C)
*/
float temp = 27.0f - (voltage - 0.706f) / 0.001721f;
// [ШАГ 3] Конвертация в Фаренгейты: F = C × 9/5 + 32
float temp_f = temp * 9.0f / 5 + 32;
// Вывод результатов с одним знаком после запятой
printf("Температура кристалла мк: %.1f °C (%.1f °F)\n", temp, temp_f);
}
}
Лист. 7. Файл main.c