Меню

Stm32 не работает ацп

Stm32 не работает ацп

Приветствую всех.
Решил реализовать задачу из разряда «Hello World» — термометр. Реализация с прерывание отлично работает, но (скорее из академического интереса) решил избавится от прерывания и вот тут случилась засада, программа работает совсем не так, как должна. Чувствую что решение где то близко, но видимо знания для решения не хватает.

Ход моих мыслей следующий — таймер TIM3 отсчитывает 5сек, после чего срабатывает триггер, который запускает обработку сигнала от датчика температуры АЦП. В main производится проверка если АЦП закончил преобразование, данные оправляются в функцию, которая вычисляет значение температуры и выводит данные (тут я расписывать ее не стал), после чего последовательность действий должна повториться.

Прошу подскажите где я ошибаюсь?

void Timer_ini()<
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
TIM3->ARR = 48000-1;
TIM3->PSC = 5000;
TIM3->CR2 |= TIM_CR2_MMS_1; // MMS Update mode
TIM3->DIER |= TIM3_DIER_TIE;
TIM3->CR1 |= TIM_CR1_ARPE;
TIM3->CR1 |= TIM_CR1_CEN;
>

void ADC_ini()<
RCC->CR2 |= RCC_CR2_HSI14ON;
while (!(RCC->CR2 & RCC_CR2_HSI14RDY));
RCC->APB2ENR = RCC_APB2ENR_ADCEN;
ADC1->CHSELR = ADC_CHSELR_CHSEL16; //Канал датчика температуры
ADC1->CR |= ADC_CR_ADCAL; // Калибровка датчика температуры
while ((ADC1->CR & ADC_CR_ADCAL) != 0);
ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2;
ADC1->CFGR1 |= ADC_CFGR1_EXTEN_0;
ADC1->CFGR1 |= ADC_CFGR1_EXTSEL_0 | ADC_CFGR1_EXTSEL_1; //Выбор триггера TIM3
ADC->CCR |= ADC_CCR_TSEN;
ADC1->CR |= ADC_CR_ADEN;
while ((ADC1->ISR & ADC_ISR_ADRDY) == 0);
ADC1->CR |= ADC_CR_ADSTART;
>

void main() <
ADC_ini();
Timer_ini();

//Судя по Reference manual бит EOC должен сбрасываться по прочтению данных из ADC->DR,
//но этого не происходит, по этой причине добавлен «насильный» сброс
ADC1->ISR |= ADC_ISR_EOC;
>
>
>

Источник

Проблемы с АЦП

Возможно кто-то сталкивался с подобной проблемой и сможет подсказать: на STM32F207 после коммутации питания показания АЦП получаются разными в пределах 3,5%.

Речь идёт об усреднённых и фильтрованных результатах, при условии стабильного входного сигнала. При этом, установившийся уровень стабилен и сохраняется протяжении всего времени наличия питания. После перекоммутации — рулетка — может оказаться в районе 10 единиц из 270 (отсюда и 3,5%).

Код приведу ниже. В кратце: режим SCAN, 4 канала, запуск преобразования по таймеру, раз в 1мс. (или 2мс), результаты забираю через DMA.

Соображения и тесты были следующие:

1. Нестабильность внешнего источника питания (служащего опорой АЦП) была отброшена исходя из того, что ситуация повторяется при программном RESIT МК. (через ST-LINK отладчик).

2. Ошибки программирования были отброшены, т.к. я вывел измерительные входы на инжектированные каналы АЦП (у них у каждого свой регистр результата, а не один общий) — результат измерения конечно же болтается, но визуально видно, что уровень меняется (после RESIT).

3. Так же на инжектированный канал я вывел измерение напряжения опоры VREFIN (Это отдельный канал АЦП МК, который внутри МК заведён на АЦП) — эффект тот же.

4. При нулевых входных сигналах — на выходе АЦП так же 0, т.е. смещение не появляется. Отсюда вывод, что плавает усиление (опора и т.п.).

5. Изменение VREFIN НЕ полностью пропорционально изменению сигнала другого канала. Картина примерно такая (пишу по память, за большое количество измерений, но тенденция именно такая):

VREFIN — CH
0x17C —- 0x112
0x17A —- 0x111
0x174 —- 0x10A
0x175 —- 0x10B
0x172 —- 0x109
0x170 —- 0x108

(Т.е. сколько я ни делал рестарт — показания VREFIN были в этих пределах — 0x170-0x175, 0x17A-0x17C, серединки диапазона не было)

6. Я попробовал измерять уровень опоры (VREFIN), естественно, фильтровать его, получая надёжный результат и делать корректировку. Как можно было бы догадаться из предыдущего пункта — получилось лучше — в районе 2-4 единиц из 270, но всё равно не понятно что за ерунда.

Пробовал пока только на одном изделии, срок эксплуатации полтора года, условия -30. +30С. Было ли это сразу или эффект появился только сейчас сказать не могу, т.к. выявил только когда сигнал стал стабильным и вызвало вопросы почему показания разные.

Источник

Управляем генератором или борьба с АЦП в STM32F030

У меня как-то исторически не сложилось с семейством STM32F030, лет 5 назад попробовал поработать с ними и долго удивлялся корявости работы большей части периферии, а потом забил на них. И вот на днях мне все таки пришлось вернуться к данной серии, нужно было измерять за минимальные деньги постоянное напряжение на свинцовом АКБ (или сборке до 4 штук последовательно) от 8 до 60В с точностью не хуже ±0.1В с небольшой частотой опроса.

Читайте также:  Триколор при помощи чего настроить самому

Решение задачи «в лоб» позволило достаточно точно измерять напряжение только когда на входе АЦП значение больше 1,5. 1,6В, то есть только во второй половине диапазона, что для меня означало 30. 60В вместо требуемых 8. 60В. Основная проблема была в интервале 0. 1.6В, выглядело это все как будто у меня делитель напряжения «плавал» или опорное напряжение для АЦП (Vref) было крайне нестабильным.

Нужно было быстро решать задачу, пускай и не самым элегантным способом, но хотя бы без явных костылей. Для этого предстояло сначала изучить проблему и понять откуда «ноги растут», а затем устранить эту проблему. Если устранить не получится, то хотя бы как-то обойти ее, чтобы в итоге получить работающее устройство и отправить его заказчику.

Суть задачи

Вообще я за такую мелочь давно старюсь не браться, но тут ко мне обратился родственник, а по совместительству хороший человек, который еще и работает в близкой мне тематике — собирает где-то в в Подмосковье небольшие СЭС. Отказывать не хотелось, да и в тот момент эта задача мне казалась «пара часов железо + пара часов код». Проект в Altium Designer и правда занял у меня пару часов, а вот борьба с АЦП съела весь вечер, поэтому решил поделиться информацией, чтобы другие не тратили время.

Само устройство крайне простое, алгоритм работы следующий:

  • измеряем напряжение на сборке из 1. 4 последовательно включенных свинцовых АКБ;
  • если напряжение меньше «нижнего порога», то замыкаем реле и оно включает генератор, который заряжает наши АКБ;
  • если напряжение поднялось выше «нижнего порога + гистерезис», то есть АКБ зарядились до установленного порога, тогда выключаем генератор;
  • если напряжение выше «верхнего порога», то запрещаем на всякий случай включать генератор.

Все! Пример: есть один АКБ на 12В и от него питается инвертор. Если напряжение упало ниже «нижнего порога», по умолчанию 10.2В, то включаем генератор. Если напряжение на АКБ выросло до «нижнего порога + гистерезиса», то выключаем. По умолчанию гистерезис установлен 2В и нужен для того, чтобы бензиновый генератор не вырубался сразу как только чуть зарядил АКБ до 10.3В. От постоянного вкл/выкл генератор просто умрет. Ну и на всякий случай защита: если напряжение на АКБ выше 14.4В, то генератор точно не включать.

Алгоритм простой и понятный, дополнительно нужно было сделать небольшое меню, чтобы можно было изменять три переменные: «нижний порог», «гистерезис», «верхний порог». Ничего сложного, но дьявол в мелочах.

Изначально в компании, где работает родственник, использовали китайское устройство со схожим функционалом. Из мелких минусов — нельзя было изменять гистерезис, для питания нужен был дополнительный источник на 5В и измерение всего до 30В, то есть для 1 или 2 АКБ. Из больших минусов — китайское устройство иногда зависало и перезагружалось в момент запуска бензинового генератора, которым управляло. Последняя «особенность» как раз и стала причиной попытки отказаться от китайского решения.

От меня хотели устранения всех этих минусов и чтобы цена устройства была как у китайского, то есть 10$. «Дьявольской мелочью» в данном случае было то, что они хотели покупать у меня готовое устройство за 10$ партиями всего по 20-30 штук, правда стабильно и достаточно часто. То есть мне надо было в мелкой серии сделать устройство сильно лучше и очень сильно дешевле китайцев, заработать то тоже надо в перспективе. Ага, мне тоже было смешно в первые 10 минут, но к моменту осознания сей ситуации я уже сказал «ДА», то есть за Волгой для меня земли уже не было…

Решение железных проблем

Как я выше писал, основной проблемой является нестабильная работа устройства во время запуска генератора. В итоге было куплено китайское устройство с алиэкспресс для тестирования и исследования. Основная причина «сноса башки» оказалась не в генераторе, а в реле :)) В момент переключения по питанию в шине 3.3В проходил импульс с амплитудой около 25В, что как бы намекало… Так же помехи шли и на сигнальные цепи. В китайской схеме для борьбы с такой проблемой стояли диоды LL4148, которые типа преграждали путь помехам. Этого достаточно оказалось, чтобы устройство работало нормально на столе, но не в условиях кучи внешних дополнительных помех типа генератора и прочего оборудования. Чтобы навсегда избавиться от выше описанного я решил применить гальваническую развязку через связку «оптрон + dc/dc», что позволило полностью исключить электрический контакт и путь прохождения помех между управляющей обмоткой реле и остальной схемой.

Читайте также:  Не работает кнопка настройки виндовс 10

Альтернативой такому решению было применение защитных TVS диодов вместе с синфазным дросселем, а так же усложнение фильтра по питанию. Но зачем такой колхоз? Поставить dc/dc проще, а на практике оказалось даже дешевле — китайский модуль Mornsun B0505S-1WR2 обошелся мне в 0,4$ при стоимость одного синфазного дросселя на мелкой партии около 0,32$.

В итоге после такого решения и тестирования прототипов устройство начало работать как автомат Калашникова и проблемы с перезагрузкой ушли. Вообще я немного удивлен, что реле + чутка генератор все таки заставляли перезагружаться stm-ку, китайские разработчики в принципе сделали все неплохо: 10 кОм + 0.1 мкФ на reset, блокирующие конденсаторы по питанию, ферритовые бусинки, все было, но этого все равно оказалось мало.

Второй минус «китайцев» был в необходимости дополнительного питания, сэкономили видимо на dc/dc. Я решил проблему в лоб — взял питание с входного сигнала, прямо с одного разъема. Для этого надо было просто поставить dc/dc, который переварит минимум 4 * 14.4В, то есть 57,6В. Мой выбор пал на LMR16010PDDAR. Во-первых, это Texas и этим все сказано. Во-вторых, мне данную микросхему азиатские товарищи предложили таскать очень дешево.

Предыдущий пункт комплексно решил третий минус — возможность подключать до 4-х АКБ последовательно. DC/DC легко переваривает 60В, начинает пытаться сгореть только при 72. 73В, так что максимальные 57.6В ему точно не страшны. Делителю напряжения вообще все равно сколько на входе, поэтому все решилось с минимальными усилиями.

Посмотреть как все это реализовано на схеме вы можете тут — PDF. Схема достаточно большая, поэтому картинкой не стал заливать. Кстати, в pdf-ке вы можете увидеть еще и габариты с печатной платой, но там ничего сверхестественного.

В итоге для первой пробно-тестовой партии было заказано компонентов на 10 устройств, а после сборки получилось вот так:

Без происшествий не обошлось — когда создавал компонент для dc/dc модуля перепутал 1 и 2 ногу местами, пришлось немного наколхозить. Хотя на последующих платах сделал аккуратнее, чтобы никто не заметил, а плата на фото осталась у меня в качество отладки на всякий случай или для доработок по софту, если заказчик чего придумает во время тестирования.

Борьба с точностью АЦП

Теперь перейдем к основной части статьи. Как писал в начале статьи — АЦП у F030 оказался неточным, то есть до напряжения 30. 32В на входе устройства показания плавали с отклонением до 15. 20%, а затем ошибка плавно сходила на нет. Одно меня радовало — на первый взгляд отклонения имели какую-то закономерность, а значит это не рандомная ошибка и ее можно отследить и попытаться скорректировать.

Давайте чуть подробнее об ошибке… АЦП после завершения преобразования отдает сырые данные в регистр DR, который содержит значение от 0 до 4095 (2 12 ). Чтобы пересчитать данное значение в напряжение нужно умножить его на шаг квантования. В моем случае напряжение на выводе VDDA, с которого АЦП берет опору, составляло 3,3072В и соответственно шаг равен 3,3072В / 4096 = 0,000807В, я его округлил до 0,0008. Чтобы получить напряжение на входе устройства, полученное напряжение нужно умножить на коэффициент делителя напряжения, в моем случае резистор в верхнем плече 100 кОм, а в нижнем 4,7 кОм, что дает делитель 22,2765. Исходя из этого напряжение на входе устройства, то есть напряжение АКБ, находится с помощью формулы:

Получается, что после считывания данных ADC1->DR, они приводится к типу float и просто умножаются на коэффициенты, которые константы, и получаем результат в привычных вольтах. На практике оказалось, что все сильно плохо с точностью.

Вспомнив о бритве Хэнлона, я начал искать место где совершил ошибку. Сначала проверил напряжение на ноге VDDA, думал что оно как-то плавает и зависит от входного напряжения, например, LDO неисправный. Вооружившись настольным мультиметром следил за напряжением на VDDA и изменял напряжение на входе от 8 до 60В, при этом напряжение на ноге VDDA мертво держалось на отметке 3,3072В плавали только следующие 2 знака, что очень хорошо для линейника за 10 центов.

Читайте также:  Как настроить алкатель one touch

Следующим местом потенциальной ошибки был делитель напряжения. Хотя мне показалось странно, что резисторы от Bourns на ±0.1% плавают так, что данные имеют ошибку до 20% и эта ошибка имеет нелинейный характер. Провел такой же эксперимент: мультиметром измерял напряжение после делителя, а входное напряжение изменял с шагом 0.5В и в итоге коэффициент делителя был так же намертво зафиксирован на уровне 22,2768.

В этот момент начало становиться интересно. Оставался один компонент в котором я мог сомневаться — это операционный усилитель LMV611MFX. Включен данный ОУ как повторитель напряжения. Напряжение ДО и ПОСЛЕ него было одинаковым до 4-х знаков после запятой. Странно… По даташиту он неплох и это все тот же TI, сомневался, но решил проверить, т.к. именно этот ОУ никогда не использовал. На всякий случай впаял на его место мой любимый и проверенный в куче проектов OPA320, который у меня лежит в катушках и он показал такой же результат.

Оставался последний компонент — МК, а именно его АЦП. За годы применения STM я привык доверять их продукции, тем более беру только оригиналы, поэтому на МК подумал в последнюю очередь. Первым делом подумал, что забыл сделать калибровку или сделал неправильно. Полез в reference manual, там требовали не только вырубить АЦП записью нуля в бит ADEN, но и выставить 1 в бит ADDIS и 0 в бит DMAEN. Последние 2 шага не были сделаны, обычно я вырубаю АЦП и все работает хорошо, в итоге поправил кусок кода с калибровкой:

К сожалению не помогло и решил провести следующий опыт… Коэффициенты уже проверил и они 100% правильные, значит буду подавать на вход напряжение с лабораторного блока питания, изменять его и выводить сырые результаты измерения АЦП на семисегментный индикатор, а затем сравню с тем, что должно там быть с тем, что реально измерил. В итоге получил следующие результаты:

Как видите теоретический график имеет отличную линейность, т.к. не привязан к железу. График, построенный по реальным данным, тоже практически линейный с минимальными отклонениями. По сути график с реальными данными может быть совмещен с теоретическим графиком путем параллельного переноса на некоторую константу. Если говорить языком электроники — у АЦП имеется смещение!

По данным, на основе которых строились графики, я выяснил, что АЦП имеет смещение в разных точках 71. 73 шага. В этом и была проблема, а «нелинейность» мне почудилась потому, что смещение в 71 шаг при 10В это около 14%, а при 30В уже 4%. То есть если построить график отклонений в %, то зависимость будет иметь экспоненциальный вид, но такой график не интересен.

Было решено, что для уточнения результатов, попробовать ввести в формулу еще одну переменную, которая будет смещать мои значения вверх и иметь следующий вид:

После этих несложных манипуляций мое устройство начало точно измерять напряжение и данные перестали плавать. До этого же момента оно врало на 72 * 0,0008В * 22,2768 = 1,28В, что в случае контроля одного АКБ очень критично. Свинцовый АКБ конечно не взрывается как Li-ion, но все равно быстро выходит из строя, особенно если его разряжать постоянно не до 10.2В, а до 8,92В.

Вот такая небольшая история о небольшой железке. Надеюсь кому-то данный материал станет полезным или хотя бы будет просто интересным для чтения. Будьте внимательны со всякими этими АЦП и прочими гадостями :))

UPD. olartamonov очень усердно просит не дурить народ и использовать код калибровки из reference manual — внес изменение с удовольствием. К сожалению, в моем случае это не изменило ситуацию и смещение никуда не делось. Вероятно, проблема в самом чипе. по указанию из госдепа подкинули контрафактную продукцию

Источник

Adblock
detector