Подключение фоторезистора к STM32 (измерение освещенности)
Обычно фоторезистор используется просто для определения наличия света, но в данном случае мы попробуем с помощью него измерять значение освещенности, используя его как первичный преобразователь.
Купить на Aliexpress
20 pcs 5539 Photresistor
Цена: 0.62$ + 0.25$ = 0.87$
20 pcs 5516 5537 5528 5549 5539 Photresistor
Цена: 0.61$ + 0.25$ = 0.86$
Проверка
Просто подключите любое фотосопротивление к омметру и посмотрите как изменяется его сопротивление при изменении освещенности.
Освещенность | R, Ом |
Пасмурная погода | 1.5 кОм |
Темнота (прикрыто рукой) | 500 кОм |
Яркий свет (фонарик) | 100 Ом |
Выбор фоторезистора
Первое что нужно это знать это название используемого фоторезистора, чтобы выяснить его электрические параметры, например у меня GL5539 100 кОм, вот данные на него:
Нам нужны две величины: сопротивление при освещенности 10 лк и коэффициент гамма γ (логарифм соотношения значения сопротивления при 10 люкс 100 люкс).
γ = 0.8
Ну и взглянем на на его световую характеристику, вот такую вот широкую. Точных показаний не добиться, но это было понятно с самого начала
.
Вывод освещенности из формулы
Остается вывести отсюда одну, нужную нам неизвестную - освещенность.
Также построим идеальную характеристику, по ней видно что при низкой освещенности сопротивление больше, а при высокой - маленькое.
Схема подключения
Также очень советую параллельно фоторезистору поставить конденсатор 100 нФ.
Создание проекта в STM32CubeMX
Файл, новый проект: File -> New Project
Выбираем нужный МК: STM32F103C8
Включаем отладчик: System Core -> SYS -> Debug: Serial Wire
Включаем АЦП, Канал 0:
ADC1 -> IN0
Настраиваем работу ПДП:
ADC1 -> DMA Settings -> Add -> ADC1 (DMA Request) -> Mode: Circular
Включаем тактирование Таймера 4:
TIM4 -> Internal Clock
Включаем прерывание:
NVIC Settings -> TIM4 global interrupt
И для периода вызова этого прерывания 100 мс:
Предделитель (Prescaler):
800-1
Регистр автоперезагрузки (Auto-reload register):
1000-1
Нужен период T = 100 мс (f = 10 Гц).
Частота шины, от которой тактируется таймер (смотреть в Clock Configuration) делится на необходимую.
PSC*ARR = fAHB/f = 8000000/10 = 800000
Распределяем полученное число (800000) между предделителем и регистром автоперезагрузки:
PSC = 800-1; ARR = 1000-1;
Отлично, 800*1000=800000. Почему минус один? Счет идет с нуля, когда в предделитель записано ноль, то частота делится конечно же не на ноль, а на единицу (не изменяется), когда 1, то на два. Получается нужная частота (формула из RF):
fTIM4 = fAHB/(PSC+1)*(ARR+1) = 8000000/(800-1+1)*(1000-1+1) = 10 Гц
Таким образом в регистры PSC, ARR, CCRx записывайте за вычетом единицы.
Во вкладке настройки тактирования ничего не меняем HCLK = 8 MHz:
Любое название и для
Keil:
Project Name: photocell
Toolchain/IDE: MDK-ARM, Min Version: V5.27
Генерируем код и открываем проект: GENERATE CODE -> Open Project
Определение сопротивления фоторезистора
Здесь нужно просто узнать сопротивление фоторезистора, при известном сопротивлении верхнего плеча R1, напряжении питания Vdd и падении напряжения собственно на датчике ADCR2 (данные с АЦП).
*Vdd берется равным 4096, чтобы не получить ноль в знаменатели.
Если сопротивление очень мало, то падение напряжение также маленькое и может случится так, что АЦП выдаст ноль, что недопустимо, как и максимум 4095 при большом сопротивлении, поэтому от этого нужно застраховаться.
Программирование
Ввиду того, что данные в моем случае будут переданы на телефон, то тяжелые математические вычисления конечно же будет выполнять он, а передаваться будут сырые данные с АЦП.
Но конечно же делать это можно и на МК, но сожрется куча памяти (годится в целях обучения).
Создаем глобальные переменные:
/* Photocell vars */
uint32_t Pht_R;
float Pht_Div;
float Pht_Temp;
uint32_t Pht_Lux;
#define PHT_UP_R 10000.0F
#define PHT_10LX_R 50000.0F
#define PHT_GAMMA 0.8F
/* ADC vars */
uint16_t ADC_Raw[1];
/* Sheduler vars */
uint8_t Sch_100ms = 255;
Запускаем прерывание от таймера и преобразования от АЦП:
/* USER CODE BEGIN 2 */
/* adc calibration */
HAL_ADCEx_Calibration_Start(&hadc1);
/* adc start */
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_Raw, 1);
HAL_ADC_Start_IT(&hadc1);
/* timer 4 start it (100ms) */
HAL_TIM_Base_Start_IT(&htim4);
/* USER CODE END 2 */
В прерывании от таймера присваиваем переменной-флагу 255.
/* USER CODE BEGIN 0 */
/************** timer 4 irqhandler *************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM4)
{
/* set every 100ms */
Sch_100ms = 255;
}
}
/* USER CODE END 0 */
В главном цикле проверяем выставлен ли флаг T_100ms, если да, то вычисляем текущее сопротивление фоторезистора (по значению АЦП), ну а далее уже находим значение освещенности.
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(Sch_100ms)
{
/* get adc value */
HAL_ADC_Start_IT(&hadc1);
/* calc photoresistor resistance */
Pht_R = ((PHT_UP_R)/((4095.0)/(ADC_Raw[0])-1));
/* internim calcs */
Pht_Div = PHT_10LX_R/Pht_R;
Pht_Temp = ((0.42*log(Pht_Div))/(PHT_GAMMA)) + 1;
/* illuminance calc */
Pht_Lux = pow(10, Pht_Temp);
/* nulify */
Sch_100ms = 0;
}
/* USER CODE END WHILE */
Получение показаний в отладчике
Как всегда добавляем все в окошко для просмотра (ПКМ на переменной -> Add to Watch 1), убираем представление в HEX и запускаем работу:
Но гораздо лучше (оперативней и наглядней) выводить значение так:
Посмотрев на график я сразу понял почему показания меняются, тем более с такой интересной периодичностью - китайская говнолампа.
Также пока игрался облака пару раз закрыли солнце, вот так это выглядело:
Сравнение точности
Если проводить измерения при небольших значениях, то совпадение очень неплохое, а вот на ярком Солнце, где должно зашкаливать больших значений получить не получается. Это связано с тем, что коэффициент γ был взят в диапазоне 10-100 люкс, таким образом для повышения точности на всем диапазоне возможно введение нескольких значений для разных участков.
Также при сравнении еще стоит учитывать направление света, т.к. фоторезистор чувствителен практически на 180 градусов, а вот у сенсора в телефоне очень направленная чувствительность (как раз хорошо для определения препятствия).
Доказательство закона Вебера-Фехнера
Измерив величины освещенности в солнечную погоду и в комнате видим огромную разницу в цифрах, но глаз легко перестраивается, вот доказательство того, что ощущение логарифмическое.
Получение и отображение освещенности на телефоне
Используя bluetooth модуль JDY-23 и конструктор приложений App Invertor 2 несложно создать приложение, которое получает переданные данные с АЦП и делает нужные нам расчеты с удобным заданием постоянных величин:
Калибровка
В современных телефонах есть встроенный датчик света, с которого с можно легко получить показания используя различные приложения ( Lux Meter). Таким образом можно откалибровать нашу систему.
*диапазон измерения у моего датчика 0-32767 (15-бит)
А при использовании самодельного приложения это вообще можно встроить как функцию, что-то вроде: положите телефон и нажмите кнопку. Нужный множитель сам подберется!
Моделька
3D модель фоторезистора также думаю не помешает при визуализации ПП.
D = 4.1 мм, H = 2.1 мм, Lвыводов = 10 мм, dмежду выводами = 3 мм.
Скачать
|
photocell.step |
Модель фоторезистора. |
|
https://github.com/Egoruch/LDR-STM32-HAL (ссылка на GitHub) LDR-STM32-HAL-master.zip (прямая ссылка) |
Рабочий проект STM32CubeMX + Keil. |
Видос
Итого
Понятное дело, что с фоторезистором измерительного прибора у нас не получится сотворить, но все же применить этот показометр для некоторых целей можно. Например, для отслеживания зависимости освещения от времени суток, где важно не конкретное значение, а именно изменение, к тому же низкая скорость изменения сопротивления никак не помешает.
Вывод освещенности из формулы:
Освещенность 100 Лк и 10 Лк.
Вывод освещенности из формулы:
E10 = 10 Лк
E100 = 100 Лк
Одну как постоянную величину, а другая послужила для вывода выражения для вычисления освещённости.
С языке Си log — это натуральный логарифм (логарифм по основанию e), нам же нужен десятичный логарифм, умножение на 0,42 дает приближенное значение десятичного логарифма.
Нужно просто в части определений поставить нужный коэффициент:
#define PHT_GAMMA 0.8F
1. «Ну и взглянем на на его световую характеристику, вот такую вот широкую»
Смотрел даташит GL5539, у первого фоторезистора световая характеристика самая узкая.
Если я правильно понял, чем уже световая характеристика, тем точнее измерения?
т.е. нужно выбирать фоторезистор с меньшим сопротивлением (первый в таблице 5-10 кОм, гамма 0,5) ?
2. Как выбрать сопротивление верхнего плеча R1? Почему у Вас 10 кОм?
(#define PHT_UP_R 10000.0F)
1) Да, тем лучше, хотя измерения все равно очень грубые.
2) Здесь не подбирал, но нужно брать такой, чтобы как можно больше разрядов АЦП использовалось, в зависимости от диапазона измерения сопротивления.
http://othermedia.info/?p=20192
Для более точного измерения сопротивления лучше использовать другой метод: разряд емкости на сопротивление. Подключаем к выводам контроллера эталонный резистор. Один из выводов — вход для измерения, лучше, если это будет компаратор.
Второй вывод контроллера подключаем к измеряемому сопротивлению (фоторезистору). Второй вывод измеряемого резистора подключаем ко входу контроллера. Также между входом и землей подключаем конденсатор.
Алгоритм измерения следующий: выполняем заряд конденсатора, установив на выводе эталонного резистора лог.1, остальные выводы — на вход. Время заряда не менее 2RC. После чего на выводе эталонного резистора выставляем лог. 0 и измеряем время разряда конденсатора. Аналогичным образом разряжаем конденсатор через измеряемый резистор. Отношение полученных цифр и будет искомым сопротивлением. Плюс — постоянная калибровка. Таким методом пользуются для измерения сопротивления датчиков влажности, где диапазон изменения сопротивления составляет от 10 кОм до 10-20 МОм.
спасибо за совет
Скажите, пожалуйста, каким уравнением Вы описали идеальную характеристику ?
Как-то так:
Точно должно быть в файлах MathCad, открыть сейчас не могу, но вот вам исходники, там и график этот присутствует: photocell_equations.zip
Скажите пароль от архива, пожалуйста
Пароль: cxemka.com
Я занимаюсь исследованиями динамики механических систем, результатом которой является изменение сопротивления фоторезистора в зависимости от освещения его поверхности. Получаемую динамику мне необходимо записывать круглосуточно как минимум в течение года. Потом эти записи будут представлены для обозрения широкой аудитории, чтобы умники и умницы ломали головы, а что собственно регистрировалось механической системой и не участвовали в ней планеты солнечной системы, включая и далекий Плутон.
При этом, измерение сопротивления фоторезистора цифровым омметром дает пеструю картину и вот эту картину нужно записывать. Очевидно лучше сначала записывать на комп, а потом нужные интересные участки распечатывать на принтере с компа. Схемка включения ф/резистора на линейный вход аудиокарты компа проста, но программ великое множество, но все они какие-то простецкие и не дают возможности исследовать подробности. Может кто-то уже осваивал подобную тематику или знает как решить эту задачу для меня как не айтишника.
Буду признателен за помощ и заранее благодарю каждого кто откликнется!