Как стать автором
Обновить

Измерение положения ротора СКВТ с помощью микроконтроллера K1986BE92QI

Время на прочтение21 мин
Количество просмотров13K

Здравствуйте, уважаемые читатели! Сегодня я расскажу вам об интересном эксперименте - измерении угла положения синус-косинусного вращающегося трансформатора с помощью микроконтроллера K1986BE92QI фирмы Миландр без применения каких-либо специализированных микросхем-контроллеров СКВТ!

Недавно мне на глаза попалось техническое описание советского комплектного электропривода "Размер-2М". Конструктивно это был самый настоящий сервопривод! В качестве датчиков обратной связи на двигателях шпинделя и подач были установлены синус-косинусные вращающиеся трансформаторы (СКВТ), или по-другому, резольверы. С помощью СКВТ помимо фактической скорости вращения определялся фактический угол поворота ротора и эмулировались сигналы инкрементальных энкодеров - двухфазные импульсы для передачи информации о перемещения в УЧПУ станка. Разрешающая способность была равна 10000 дискрет на один оборот ротора. При шаге винта в 10мм это означало что одна дискрета равна одному микрону - и всё это уже было в начале 1980-х! А у меня как нельзя кстати завалялся трофейный советский СКВТ ФВ67-12-008 от "Размера", доставшийся мне на опыты. И мне стало интересно, а как же в "Размере" определялось положение ротора СКВТ? Оказывается, конструкторы "Размера" применили довольно простой фазовый метод. Недолго думая, я решил воспроизвести "Размеровский" измеритель положения СКВТ в лабораторных условиях. Изначально вся затея с СКВТ была чистым экспериментом, который неожиданно дал хорошие результаты и вылился в небольшое исследование по повышению производительности программного кода для микроконтроллеров с ядром ARM Cortex-M3.

Конструктивно СКВТ является дальнейшим развитием конструкции сельсинов - специализированных микромашин переменного тока. СКВТ, как и сельсин, состоит из статора с двумя неподвижными фазными обмотоками, расположенных под 90 градусов и ротора с одной подвижной обмоткой. Чтобы уйти от потенциально ненадёжного контактно-щёточного узла, в СКВТ передача сигнала с роторной обмотки происходит с помощью дополнительного вращающегося трансформатора. Рассмотрим СКВТ ФВ67-12-008 подробнее. Статор, кроме двух фазных обмоток, сдвинутых на 90 градусов содержит ещё вторичную обмотку вращающегося трансформатора:

Ротор, помимо подвижной обмотки несёт первичную обмотку вращающегося трансформатора для бесконтактной передачи сигнала на статор:

По сути, СКВТ является конструктивным объединением двухфазного сельсина и однофазного вращающегося трансформатора. Такая конструкция позволяет изготовить СКВТ полностью разборным, его статор и ротор являются электрически и механически не связанными друг с другом! В итоге, СКВТ весьма неприхотлив к условиям эксплуатации и очень надёжен - случаи выхода СКВТ из строя на производстве крайне редки. Как и сельсины, СКВТ используются как датчики углового положения.

Наиболее известны три способа опредения положения ротора СКВТ.

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

Второй способ - фазовый, как раз применённый в электроприводе "Размер-2М". Напряжение возбуждения - два синусоидальных напряжения возбуждения с фазовым сдвигом в 90 градусов - подаётся на фазные обмотки, также сдвинутые на 90 градусов. В статоре СКВТ образуется вращающееся магнитное поле, а на подвижной обмотке наводится синусоидальная ЭДС. Фазовый сдвиг относительно фазных напряжений возбуждения напрямую зависит от угла положения ротора. То есть, измерив фазовый сдвиг выходного напряжения относительно фаз возбуждения, получим фактический угол поворота ротора. Достоинство - относительная простота расчётов и малая чувствительность к помехам, недостаток - разрешающая способность ограничена дискретностью измерения времени и фазовой/амплитудной точностью системы напряжений возбуждения.

Третий способ - следящий, СКВТ включается в цепь замкнутой обратной связи системы измерения. На сегодняшний момент этот способ лучший из всех трёх перечисленных, хотя и наиболее сложный. Применяется в специализированных микросхемах, например 1310НМ025 от Миландра и AD2S1210 от Analog Devices.

Фазовый способ определения угла СКВТ сам по себе очень прост и обладает хорошей помехоустойчивостью - его и будем осуществлять в лабораторных условиях. Основа измерителя - микроконтроллер К1986ВЕ92QI в составе когда-то самой дешёвой отладочной платы "русская синяя таблетка" LDM-BB-K1986BE92QI. В качестве датчика угла будет применён валявшийся без дела СКВТ ФВ67-12-008.

Первая задача - формирование двухфазного синусоидального напряжения возбуждения. В микросхеме К1986ВЕ92QI на контакты выведен выход только одного ЦАП - для формирования двух аналоговых сигналов придётся использовать ШИМ. Для упрощения расчётов будем пользоваться заранее рассчитанной синусной таблицей. Перебор табличных значений будем осуществлять по прерыванию таймера 1. Для улучшения формы сигналов и последующей фильтрации несущей ШИМ повысим частоту дискретизации, насколько позволят вычислительные возможности К1986ВЕ92QI. Вторая задача - это фиксация текущего фазового сдвига выходного сигнала СКВТ. Сперва будем выделять переход сигнала через ноль аналоговым компаратором, а уже далее, результирующий фазовый сдвиг будем фиксировать с помощью функции захвата таймера. Наконец, будем выводить результаты измерения на двухстрочный символьный ЖКИ MT16S2D.

Для наибольшей скорости работы микроконтроллера К1986ВЕ92QI тактовую частоту ядра выберем равной максимальной паспортной - 80МГц. Для формирования ШИМ будем использовать каналы 1 и 2 таймера 1, выведенных на контакты РА1 - РА5 порта РА. В эксперименте не будем использовать инверсные выходы и ограничимся только прямыми сигналами ШИМ с контактов РА1 и РА3. Для захвата перепадов входящих импульсов будем использовать каналы 1 и 3 таймера 2, выведенных на контакты РЕ0 и РЕ2 порта РЕ. Третий таймер использовать НЕ будем! Для вывода информации на символьный ЖКИ используем контакты PF0 - PF5 порта РF, а выводить контрольный сигнал будем через контакт PF6. По контрольному сигналу с помощью осциллографа можно будет оценивать время выполнения контролируемых участков кода.

Поскольку метод измерения угла положения СКВТ фазовый, то нужно максимально снизить фазовые искажения, как при формировании фазных напряжений возбуждения СКВТ, так и в тракте измерения фазового сдвига выходного сигнала. Поэтому формировать лучше центрированную ШИМ, чтобы выровнять времянки между фронтами и спадами выдаваемых микроконтроллером импульсов ШИМ. Центрированную ШИМ можно получить, задав автореверс направления счёта - сперва таймер считает прямо, потом дойдя до основания счёта, считает обратно, а дойдя до ноля снова начинает считать прямо. Заполнение импулься задаётся точно также, как и с обычной ШИМ, указанием в регистре CCR, но при этом период ШИМ удваивается. В нашем эксперименте сформируем ШИМ несколько по-другому. Счёт будет только прямой, а для заполнения выходных импульсов будем использовать два регистра - CCR и CCR1. CCR будет задавать начало импульса, а CCR1 - конец импульса. Получается, это уже не центрированная, а оконная ШИМ, но период выходных ипульсов останется прежним. Если задать опорный уровень, равный половине основания счёта, CCR задавать как опорный уровень за вычетом задания, а CCR1 как сумма опорного уровня и задания, то оконная ШИМ сведётся к центрированной. Период сохранится как и на обычной ШИМ, но разрешение по времени сократится вдвое. Кроме того, важно задать обновление регистров CCR и CCR1 только при переходе через ноль основного счётчика таймера, чтобы перезапись этих регистров в цикле прерывания таймера не влияла на ШИМ, это важно!

Частоту ШИМ нужно выбрать максимально высокой - не только для упрощения задачи последующей фильтрации несущей, но и для ускорения обновления угловой координаты СКВТ. По результатам экспериментов, оказалось что частоту ШИМ можно поднять аж до 320кГц - период таймера на частоте ядра 80МГц составляет всего 250 тактов. И в эти 250 тактов надо обязательно всеми правдами и неправдами уместиться - процессорное время будем решительно экономить. Для формирования синусного сигнала с номинальной для СКВТ ФВ67-12-008 частотой возбуждения в 2кГц достаточно массива на 160 отсчётов. Но для формирования двух фаз проще будет сделать увеличенную синусную таблицу на 360 + 90 градусов - в 200 отсчётов с выборкой фазных коэффициентов со смещением на 40 отсчётов. Как дополнительные вычисления при массиве в 160 отсчётов, так и задание двух массивов по 160 отсчётов, только увеличивают затраты процессорного времени, которого у нас и без того немного. Код настройки таймера 1 представлен ниже:

	//настройка таймера1 - генерация ШИМ
	MDR_TIMER1 ->CNT = 0x0000; //сброс основного счётчика
	MDR_TIMER1 ->PSG = 0x0000; //предделитель выключен
	MDR_TIMER1 ->ARR = 249;	 //основание делителя равно 250, частота 320 кГц
	MDR_TIMER1 ->CNTRL = 0x0002; //режим счёта - прямой, таймер вырублен!
	MDR_TIMER1 ->CCR1 = 125; //ШИМ
	MDR_TIMER1 ->CCR11 = 125; //ШИМ
	MDR_TIMER1 ->CH1_CNTRL = 0x0E00; //оконная ШИМ, перезапись ARR после окончания счёта
	MDR_TIMER1 ->CH1_CNTRL1 = 0x0D0D; //на выходы идёт сигнал с защитной паузой
	MDR_TIMER1 ->CH1_CNTRL2 = 0x000C; //обновление CCR только при переходе через ноль, CCR1 используется!
	MDR_TIMER1 ->CH1_DTG = 0x0000; //защитная пауза 0 тактов входного сигнала
	MDR_TIMER1 ->CCR2 = 125; //ШИМ
	MDR_TIMER1 ->CCR21 = 125; //ШИМ
	MDR_TIMER1 ->CH2_CNTRL = 0x0E00; //оконная ШИМ, перезапись ARR после окончания счёта
	MDR_TIMER1 ->CH2_CNTRL1 = 0x0D0D; //на выходы идёт сигнал с защитной паузой
	MDR_TIMER1 ->CH2_CNTRL2 = 0x000C; //обновление CCR только при переходе через ноль, CCR1 используется!
	MDR_TIMER1 ->CH2_DTG = 0x0000; //защитная пауза 0 тактов входного сигнала
	MDR_TIMER1 ->BRKETR_CNTRL = 0x0000;//BRK ETR не используются
	MDR_TIMER1 ->IE = 0x00000002; //запрос прерывания при окончании счёта!
	MDR_TIMER1 ->DMA_RE = 0x0000; //таймер не запрашивает ПДП
	NVIC_EnableIRQ(Timer1_IRQn); //разрешаем прерывания от таймера 1

Захват входящих импульсов будем производить только по положительному фронту в регистры CCR каналов 1 и 3! Мои опыты по захвату отрицательных фронтов входящих импульсов в регистр CCR1 показали явную нецелесообразность этого - неидеальность компаратора не даёт одинаковых значений измеренных фазовых сдвигов положительного и отрицательного фронтов. При тактовой частоте 80МГц и частоте возбуждения СКВТ 2кГц наибольшее теоретическое разрешение равно 40000 дискрет. Но для эксперимента зададимся дискретностью положения ротора СКВТ как в советском электроприводе "Размер-2М" - 10000 дискрет на оборот или 5000 дискрет на пару полюсов четырёхполюсного СКВТ ФВ67-12-008. Значит, при настройке таймера 2 зададим значение предделителя равным (40000/10000)-1=3 и основанием счёта равным количеству дискрет на пару полюсов за вычетом единицы 5000-1=4999. Полезно будет дополнительно задать фильтрацию входных импульсов, чтобы не происходило захвата очень коротких импульсов-иголок. Фильтрация будет осуществляться фиксацией в 8 триггерах на частоте ядра микроконтроллера. Вот код настройки таймера 2:

	//настройка таймера2 - измерение фаз входных сигналов
	MDR_TIMER2 ->CNT = 0x0000; //сброс основного счётчика
	MDR_TIMER2 ->PSG = 0x0003; //предделитель равен 4
	MDR_TIMER2 ->ARR = 4999; //основание делителя равно 5000, частота 2 кГц.
	MDR_TIMER2 ->CNTRL = 0x0002; //режим счёта - прямой, обновление при окончании счёта, таймер вырублен!
	MDR_TIMER2 ->CCR1 = 0; //
	MDR_TIMER2 ->CCR11 = 0; //
	MDR_TIMER2 ->CH1_CNTRL = 0x8003; //канал работает в режиме захвата положительного фронта
	MDR_TIMER2 ->CH1_CNTRL1 = 0x0000; //все выходы отключены
	MDR_TIMER2 ->CH1_CNTRL2 = 0x0000; //обновление CCR в любой момент времени
	MDR_TIMER2 ->CH1_DTG = 0x0000; //защитная пауза не нужна
	MDR_TIMER2 ->CCR3 = 0; //
	MDR_TIMER2 ->CCR31 = 0; //
	MDR_TIMER2 ->CH3_CNTRL = 0x8003; //канал работает в режиме захвата положительного фронта
	MDR_TIMER2 ->CH3_CNTRL1 = 0x0000; //все выходы отключены
	MDR_TIMER2 ->CH3_CNTRL2 = 0x0000; //обновление CCR в любой момент времени
	MDR_TIMER2 ->CH3_DTG = 0x0000; //защитная пауза не нужна
	MDR_TIMER2 ->BRKETR_CNTRL = 0x0000; //BRK ETR не используются
	MDR_TIMER2 ->IE = 0x00000000; //таймер не запрашивает прерывания
	MDR_TIMER2 ->DMA_RE = 0x0000; //таймер не запрашивает ПДП
	//NVIC_EnableIRQ(Timer2_IRQn); //не разрешаем прерывания от таймера 2

Кстати, если для настройки тактового генератора писать отдельную функцию, например, с помощью программы сообщества MilandrPLL, то есть смысл закомментировать вызов встроенной функции SystemInit() в файле startup_Cortex_M3.c, входящем в набор функций CMSIS. Отдельная функция настройки тактового генератора по сути дублирует стандартную функцию SystemInit() которую в этом случае можно без сожаления исключить. Подробно разбирать настройку портов и вывод информации на символьный ЖКИ не вижу смысла - эти вопросы неоднократно и подробно рассмотрены в различных руководствах по программированию К1986ВЕ92QI. Основные вопросы настройки периферии К1986ВЕ92QI, в особенности таймеров для выдачи ШИМ и захвату сигналов, расписаны, теперь пора рассмотреть вопросы построения аналогового тракта.

В первую очередь, начнём с усилителя сигнала возбуждения. Фазных обмоток на СКВТ две, значит и усилитель сигнала для их возбуждения будет (нет, не стерео) двухканальным. Я не стал строить усилитель на операционных усилителях общего назначения с дополнительными каскадами усиления тока, а решил применить мощные советские операционники К157УД1, которые как нельзя кстати оказались в моих запасах. Цепи коррекции оставлены с небольшим отличием от стандартных. Практическое отсутствие мощных операционных усилителей в составе современной элементной базы, если честно, меня очень удивило! Никак не ожидал, что у давно снятых с производства К157УД1 в прайсе известного радиомагазина не окажется современной альтернативы...

Для фильтрации сигнала с выхода формирователя ШИМ нужно максимально очистить его от несущей 320кГц, не внося при этом фазовых искажений. Первым звеном стал полосовой фильтр Вина, настроенный на частоту модуляции в 2кГц. Вторым звеном стал неинвертирующий усилитель на операционном усилителе. Постоянные времени цепей отрицательной обратной связи также были рассчитаны на частоты среза по высоким и по низким частотам в 2кГц. Коэффициент усиления подобран таким образом, чтобы получить наибольший размах неискажённого выходного напряжения при питании от источника постоянного тока напряжением в 9В. Да, величина амплитуды напряжения возбуждения у меня вчетверо меньше (3В) против паспортного значения (12В) для СКВТ ФВ67-12-008, но для нашего эксперимента этого вполне достаточно.

Во-вторых, нужно отфильтровать выходное напряжение СКВТ от помех, при этом величина сопротивления нагрузки выходной обмотки не должна сильно отличаться от паспортных 15кОм для ФВ67-12-008.

Для снижения фазовых искажений фильтр выходного напряжения также будет полосовым фильтром Вина, настроенным на 2кГц. Его задача - уменьшить влияние как наводок промышленной электросети (50Гц), так и высокочастотных помех-иголок. Компаратором будет дешёвая и распространённая микросхема LM358 (российский аналог К1464СА1), с выходов которой подадим сигнал на входы захвата К1986ВЕ92QI. Кроме уже упомянутой отладочной платы LDM-BB-K1986BE92QI, нам понадобится двухстрочный символьный ЖК индикатор MT16S2D и стабилизированный источник питания на напряжение =9В постоянного тока. Схема проведения эксперимента представлена на рисунке:

Изначально схема рассчитана на два СКВТ, но участвовать в эксперименте будет всего один - соответствующие входы будут соединены параллельно и согласно. Итак, периферия подготовлена и настроена, теперь можно писать функцию обработки прерывания таймера 1, сокращая при этом насколько возможно время выполнения программного кода.

Во-первых, нужно выбрать флаг оптимизации с лучшим результатом. Практический интерес представляют флаги -O2 (средняя оптимизация) -O3 (агрессивная оптимизация) и -Os (оптимизация по объёму). Как оказалось, наименьшее время выполнения функции давала оптимизация по объёму -Os, далее шла средняя оптимизация -О2. Как ни странно, на последнем месте оказалась агрессивная оптимизация -О3. Благодаря предвыборке команд при обнаружении команд ветвления, ядро ARM Cortex-M3 несколько снижает простои конвейера. С другой стороны, дают о себе знать задержки при обращении к флешпамяти при нарушении линейного порядка считывания команд/данных.

Во-вторых, из-за невысокой скорости флэш-памяти константы лучше хранить в оперативной памяти, объявив массив табличных значений как переменные unsigned short {}, а не как константы const unsigned short {}. Таким образом я выиграл порядка 125нс или 10 тактов!

В-третьих, различные типы переменных - байт, 16-битное полуслово и 32-битное слово требуют неодинакового времени при обработке. Хоть ядро 32-х битное, но система команд Thumb и её расширение Thumb-2 при загрузке и сохранении оперируют преимущественно 16-битными полусловами! Байты и целые слова при обращении к памяти требуют дополнительных процессорных затрат! Соответственно, для наибольшего быстродействия целесообразно использовать 16-битные переменные, если это не идёт вразрез с целевой задачей, например, если диапазон чисел укладывается в рамки 0...65535 или -32768...+32767. Люди, двадцать первый век на дворе! Ну не стоит уже буквально каждый байт оперативной памяти экономить! Кроме шуток - объявив массив unsigned short {} вместо unsigned char {} я выиграл около 200 нс или 16 тактов!

Наконец, нужно учитывать время реакции на прерывания, которое для ARM Cortex-M3 составляет 12 тактов. Ядру нужно запомнить адрес возврата и сохранить часть регистров R0-R3 и R12 в стеке. Значит и при возврате из прерывания тоже потребуется время для возврата ядра в исходное состояние в момент прерывания. Плюс задержки флеш-памяти при ветвлении. Итого - затраты только на само прерывание без учёта полезного кода функции могут оказаться заметными.

Для оценки затрат процессорного времени выполнения функции обработки прерывания таймера 1 я добавил в функцию вывод контрольного сигнала на контакт PF6. В начале функции выводим единицу в порт, а в конце функции выводим ноль. Импульсы с контрольного выхода можно наблюдать с помощью осциллографа, а по ширине импульса можно определить время выполнения. В первую очередь, важно измерить время вывода в порт. Для этого оставляем в главном цикле только четыре команды вывода единиц и нулей на контакты портов PC2 и PF6:

	while (1) // главный цикл
	{
	MDR_PORTF ->RXTX |= 0x0040;
	MDR_PORTC ->RXTX |= 0x0004;
	MDR_PORTF ->RXTX &= ~ 0x0040;
	MDR_PORTC ->RXTX &= ~ 0x0004;
	}

Осциллограмма контрольных сигналов имеет такой вид:

Тактовая частота равна 80МГц, соответственно, период следования тактовых импульсов составляет 12,5нс. Период следования двух фаз импульсов составляет 550нс или 44 такта, а время вывода трёх бит составляет 375нс или 30 тактов. Значит, время вывода бита в порт составляет 125нс или 10 тактов. Разница между периодом и временем вывода четырёх бит равно затратам времени на ветвление, которое в нашем случае равно четырём тактам!

Функция обработки прерывания от таймера 1, кроме перебора значений из таблицы для формирования двухфазной синусной ШИМ будет попутно проверять состояние флагов захвата таймера 2 и фиксировать события захвата. Выделение отдельного прерывания для обработки событий захвата явно нецелесообразно из-за заметных накладных расходов процессорного времени. В начале функции находится вывод контрольного сигнала:

void Timer1_IRQHandler () //обработка прерывания таймера 1 - ШИМ
{
	MDR_PORTF ->RXTX |= 0x0040;//контрольный сигнал

Далее, идёт расчёт значений синусной ШИМ по заранее рассчитанной таблице в массиве sinus [200], причём первая фаза идёт с опережением в четверть периода и соответственно она идёт со смещением:

	if ( ( MDR_TIMER1 ->STATUS & 0x0002 ) == 0x0002 ){//циклический перебор синусной таблицы
		MDR_TIMER1 ->CCR1 = 125 - sinus [ ( step + 40 ) ]; //фаза А возбуждения
		MDR_TIMER1 ->CCR11 = 125 + sinus [ ( step + 40 ) ]; //фаза А возбуждения
		MDR_TIMER1 ->CCR2 = 125 - sinus [ step ]; //фаза В возбуждения
		MDR_TIMER1 ->CCR21 = 125 + sinus [ step ]; //фаза В возбуждения
		MDR_TIMER1 ->STATUS &= ~ 0x0002; //сброс флага прерывания счётчика
	}

Потом проверяются флаги захвата. Если произошло событие захвата, то рассчитывается текущие координаты угла по соответствующему каналу:

	if ( ( MDR_TIMER2 ->STATUS & 0x0020 ) == 0x0020 ) {
		phase12 = phase11;// запоминаем старую координату
		phase11 = MDR_TIMER2 ->CCR1;// положительный перепад X
		if ( phase11 > phase12 ) {
			if ( ( phase11 - phase12 ) < 2500 ) {
				phase1 = phase11 - phase12;
			}
			else {
				phase1 = phase12 - phase11;
			}
		}
		else {
			if ( ( phase12 - phase11 ) < 2500 ) {
				phase1 = phase12 - phase11;
			}
			else {
				phase1 = phase11 - phase12;
			}
		}
		MDR_TIMER2 ->STATUS &= ~ 0x0020;//сброс флага захвата CCR1
	}
	if ( ( MDR_TIMER2 ->STATUS & 0x0080 ) == 0x0080 ) {
		phase22 = phase21;// запоминаем старую координату
		phase21 = MDR_TIMER2 ->CCR3;// положительный перепад Z
		if ( phase21 > phase22 ) {
			if ( ( phase21 - phase22 ) < 2500 ) {
				phase2 = phase21 - phase22;
			}
			else {
				phase2 = phase22 - phase21;
			}
		}
		else {
			if ( ( phase22 - phase21 ) < 2500 ) {
				phase2 = phase22 - phase21;
			}
			else {
				phase2 = phase21 - phase22;
			}
		}
		MDR_TIMER2 ->STATUS &= ~ 0x0080;//сброс флага захвата CCR3
	}

В конце функции идёт обновление значения указателя синусной таблицы, декремент указателя времени для программных задержек и сброс контрольного сигнала:

	if ( step < 159 ) step ++;
	else step = 0;
	if ( counter > 0 ) counter --;// таймер отсчёта задержек;
	else counter = 0;
	MDR_PORTF ->RXTX &= ~ 0x0040;
}

Напомню, что команда сброса флага прерывания НЕ должна быть последней в функции обработки прерывания! Из-за особенностей работы конвейера ARM Cortex-M3 при возврате из прерывания эта команда не успервает дойти до исполнения и несброшенный флаг снова вызовет прерывание! Обязательно нужно оставлять минимум одну операцию после сброса флага прерывания в конце функции.

В главном цикле текущие значения отсчётов угла СКВТ преобразуются из двоичного в двоично-десятичный формат и выводятся на символьный ЖКИ с периодичностью около 25мс. Подробно расписывать главный цикл не вижу смысла, преобразование форматов и работа с ЖКИ - задачи типовые.

Итак, микроконтроллер K1986BE92QI прошит, пора переходить к измерениям и испытаниям! Схема для проведения экспериментов с СКВТ была собрана навесным монтажом на двух беспаечных макетных платах. На одной собран макет усилителя возбуждения, на второй установлены стабилизаторы, отладочная плата с K1986BE92QI и смонтирован компаратор входных сигналов. СКВТ просто лежит на столе, ротор установлен в статор, зазор между ними задан полоской бумаги:

Питание подано - если схема собрана без ошибок, то на ЖКИ появятся значения текущей угловой координаты, которые будут меняться при повороте ротора СКВТ. С выходов K1986BE92QI импульсы ШИМ подаются на входы макета усилителя. После фильтрации импульсов ШИМ и последующего усиления, сигналы с выхода усилителей становятся практически синусоидальными и их спокойно можно подавать на фазные обмотки СКВТ:

Фаза А (жёлтый луч) опережает фазу В (синий луч) на четверть периода или аккурат на 90 градусов! Включив режим отображения XY на осциллографе, можно полюбоваться на аккуратную окружность, как простейшую фигуру Лиссажу:

Эта окружность наглядно демонстрирует последующее формирование вращающегося магнитного поля в статоре СКВТ. Оставим первый канал (жёлтый луч) на фазе А как опорном сигнале, а второй канал (синий луч) переключим на выходную обмотку СКВТ. Провернём ротор для визуального совмещения фазы входного сигнала:

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

Помехи эти преимущественно синфазные и хорошо подавляются самим компаратором. А вот без фильтрации у меня была существенная нестабильность показаний ЖК индикатора! Наконец, сигнал с выхода компаратора представляет собой прямоугольные импульсы, фазовый сдвиг которых относительно фазы напряжения возбуждения СКВТ напрямую зависит от угла поворота ротора:

Несмотря на навесной монтаж, импульсный блок питания и отсутствие заземления, дрожание показаний на ЖКИ составило около одной дискреты - 1/10000 оборота или чуть больше двух угловых минут! Впечатляющий результат! Разность показаний между каналами X и Z в 7 дискрет (это около 15 угловых минут) объясняется неодинаковостью характеристик компараторов на одном кристалле в составе микросхемы LM393. Это довольно медленный компаратор и для практического измерителя угла положения СКВТ следует применить более быстродействующий компаратор. Если же подать на оба входа захвата сигнал с одного выхода компаратора, то значения X и Z на ЖК индикаторе будут полностью совпадать.

Теперь оценим затраты процессорного времени. Опорным сигналом будет выход первого канала компаратора, а измеряемым сигналом будет состояние контрольного выхода PF6. Для начала закомментируем часть функции, обрабатывающую события захвата, соберём и загрузим в микроконтроллер прошивку.

Ширина импульса - 1412,5 нс или 113 тактов. За вычетом 10 тактов на операцию вывода на контакт порта получаем 103 такта! Почти половину периода таймера требует формирование двухфазной синусной ШИМ! Восстановим исходную прошивку:

Теперь ширина импульса - 1875нс или 150 тактов. За вычетом предыдущих 113 тактов, время затрачиваемое на проверку событий захвата двух каналов занимает 37 тактов! А если произойдёт захват, то будут дополнительные затраты времени на его обработку. Наибольшие затраты будут при одновременном захвате на двух каналах - как раз в нашей схеме один СКВТ работает сразу на два канала:

Ширина импульса становится максимальной - 3125нс или 250 тактов! Выходит, что затраты на обработку событий захвата двух каналов составляет 100 тактов, по 50 тактов на каждое. Кстати, процессор-то явно не успевает за цикл обработать прерывание - к моменту возврата из прерывания уже ждёт очереди новое прерывание от таймера! После выхода из прерывания микроконтроллер сразу же приступает к обработке нового прерывания, даже не приступая к прерванной программе!

Итак, длительность между спадом импульса обработки прерывания с захватом и фронтом следующего импульса обработки без захвата равно 550нс или 44 такта. За вычетом 10 тактов затрат на вывод контрольного сигнала в порт, получаем суммарные затраты на прерывание - реакцию с возвратом - в 34 такта процессорного времени!

Насколько критична нехватка времени цикла на обработку прерывания с захватом импульсов? Давайте посчитаем. В функции обработки прерывания таймера сначала идёт загрузка регистров CCR и CCR1, но их обновление происходит при переходе через ноль - в момент следующего прерывания. Итак, будем считать с "запасом". 34 такта на само прерывание, 103 такта на обновление регистров ШИМ, а также 10 тактов на первоначальную операцию вывода контрольного сигнала - итого 147 тактов, что меньше периода в 250 тактов. Но чтобы уложиться в период таймера, время обработки функции должно быть 250 - 34 = 226 тактов! То есть, задержка в обработке второго прерывания составляет 250 - 226 = 34 такта, значит к затратам нужно прибавить эту задержку. Итого - 34 + 103 + 20 + 37 = 191 такт времени, что меньше максимальных 226 тактов! И ещё остаётся резерв в 35 тактов. Благодаря обдуманной настройке таймеров можно выиграть при определённых условиях немного процессорного времени!

Подсчитаем средние затраты процессорного времени, относительно цикла счёта таймера в 250 тактов. Поскольку событие захвата происходит раз в 500мкс, то его усреднённые затраты будут в 160 раз меньше.

  • Само прерывание - 34/250 = 13,6%

  • Двухфазная ШИМ - 103/250 = 41,2%

  • Проверка событий захвата - 37/250 = 14,8%

  • Обработка событий захвата - 100/(160*250) = 0,25%

Итого, почти 70% (69,85%) процеccорного времени тратится на функцию обработки прерывания и только 30% остаются свободны для прочих задач - перевод чисел в двоично-десятичую форму и выдачу на символьный ЖКИ. Это много, и лучше понизить частоту ШИМ, а соответственно и прерываний от таймера, хотя бы до 250кГц.

Пора подвести итоги нашему эксперименту. Результаты получились довольно неоднозначные. Неожиданно заметными оказались затраты на само прерывание - целых 34 такта. Удивили затраты времени на обращение к периферии - ядро ARM Cortex-M3 и контроллер ПДП работает с ОЗУ и флеш к шине AMBA через арбитр AHB ("северный мост"), а периферия доступна через промежуточный мост APB ("южный мост"), подключённый к основному арбитру AHB. Обращение к периферии из-за промежуточного моста APB происходит с дополнительными двумя тактами ожидания. Казалось бы, странное повышение быстродействия при большем расходе памяти при переходе от байтового формата переменных к 16-битным полусловам.

На основе экспериментальных результатов можно составить несколько рекомендаций по повышению быстродействия критичных участков программного кода для ARM Cortex-M3. Если нужно выжать максимальную скорость из К1986ВЕ92QI, то настройки тактового генератора на максимальную частоту в 80МГц недостаточно - нужно ещё предпринять ряд дополнительных мер. Во-первых, очередь нужно выбрать оптимизацию - лучшие результаты показала оптимизация объёму -Os. Во-вторых, переменные по возможности должны быть 16-битными. В-третьих, лучше снизить количество обращений к периферии. В четвёртых, критичные константы стоит хранить в оперативной памяти. В пятых, по возможности надо сократить количество прерываний. Наконец, снизить количество избыточных ветвлений в коде.

Как ни покажется странным читателю, но максимальную частоту К1986ВЕ92QI лучше ограничить на уровне 75МГц. Это позволит уменьшить количество циклов ожидания флеш-памяти с трёх до двух. Не смотря на снижение тактовой частоты на 7%, общая производительность микроконтроллера за счёт снижения задержек флеш-памяти только возрастёт! А вот размещение кода в оперативной памяти не даёт существенных преимуществ - программист только теряет возможность одновременной выборки команд из флеш с обращением к оперативной памяти.

У читателя после прочтения статьи может возникнуть вполне резонный вопрос - а почему автор не стал использовать специализированную микросхему для СКВТ? Есть же как отечественная 1310НМ025, так и зарубежная AD2S1210? Я могу сказать, что количество дискрет отсчёта у спецмикросхем, например, у той же AD2S1210 как правило кратно двойке с целой степенью. 1024, 4096, 16384 дискрет - но это может оказаться по каким-либо причинам неудобным. Например, мне нужно не 1024, а 1000 дискрет, не 4096, а 5000.

Опыт конечно интересный, но где практическая целесообразность проведённого эксперимента? Да, микроконтроллеру вполне по силам определить положение угла СКВТ и без специализированных микросхем. Но для каких задач это применимо? На мой взгляд, при построении промышленного контроллера возможность подключения датчиков положения угла вполне оправдана. Ряд промконтроллеров изначально имеет специальные быстрые входы для подключения энкодеров. Но если не требуется высокая точность (хватает 10 угловых минут), большая дискретность (хватает ~2000 дискрет на оборот) то энкодеры теряют свои преимущества перед СКВТ по точности. Зато в полный рост вылазят их недостатки - во-первых, банальная хрупкость, во-вторых, загрязняемость (на производстве бывало приходилось продувать сжатым воздухом (!) энкодеры от пыли) и в третьих - относительная сложность стыковки с контролируемым механизмом. СКВТ, по сравнению с энкодером, почти неубиваем, малочувствителен к загрязнению, и главное - статор и ротор электрически и механически не связаны друг с другом и вопросов при стыковке с механизмами гораздо меньше. В эксперименте оставалось больше половины свободных контактов К1986ВЕ92QI, которые помимо двухканального измерителя положения ротора СКВТ можно использовать для организации дискретных и аналоговых входов-выходов, а также различных интерфейсов. Так что я могу сказать, что вопрос применения микроконтроллера K1986BE92QI фирмы Миландр определяется его возможностями, документацией, доступностью и поставленной задачей.

Напоследок, расскажу о реальном применении К1986ВЕ92QI на производстве. Столкнувшись как с невысоким качеством, так и неремонтопригодностью китайских мощных микрошаговых драйверов, я задумался о создании альтернативы. Год назад, когда на производстве была поставлена задача модернизировать советский фрезерный станок под ЧПУ, я стал экспериментировать с различными вариантами блока управления для мощного микрошагового драйвера, рассчитанного на питание от однофазной сети переменного тока ~220В 50Гц. С силовой платой не возникло проблем, а вот создать блок управления оказалось далеко не так просто. С блоком управления на ПЛИС устройство работало чисто условно - явно не хватало диапазона регулирования ШИМ. После неудачных экспериментов с ПЛИС я решил строить систему управления на микроконтроллере с ядром ARM Cortex-M3. Выбор между STM32F10x и К1986ВЕ92QI однозначно определил опыт Серёги (Декстроплат) Тарасова - миландровкий микроконтроллер показал лучшую надёжность работы тактового генератора. Кроме того, К1986ВЕ92QI показал хорошую помехоустойчивость и в моих экспериментах. При диком монтаже моего экспериментального макета частотного преобразователя, от уровня помех которого через пятнадцать минут зависал даже дубовый мэлтовский ЖКИ, микроконтроллер работал как ни в чём ни бывало. Асинхронный двигатель спокойно продолжал работать и реагировать на команды с пульта управления! Первоначально блоком управления моего микрошагового драйвера была та же самая отладочная плата "русская синяя таблетка" LDM-BB-K1986BE92QI, установленная в беспаечную макетку, благо "восьмикрутовская" триггерная защита на силовой плате безнаказанно позволяла и не такое:

После отладки первоначальной прошивки, были разработаны блоки управления. В Резоните были заказаны платы и смонтированные блоки управления были впаяны в уже готовые силовые платы:

Из-за некоторой спешки в процессе разработки, платы управления потребовали вмешательства скальпеля и паяльника, но устройство в целом было налажено. Прошивка в дальнейшем была переработана, а отлаженные экспериментальные микрошаговые драйверы были установлены в электрошкаф модернизированного под ЧПУ фрезерного станка:

И вот эти экспериментальные микрошаговые драйверы моей конструкции на данный момент уже три месяца крутят вот такими мощными (20кг!) шаговыми двигателями приводов осей в составе теперь ЧПУ фрезерного станка:

Если сравнивать STM32F10x и К1986ВЕ92QI, то миландровкий микроконтроллер имеет два основных преимущества - русскоязычную документацию и выявившуюся повышенную устойчивость тактового генератора. В остальном - самый обыкновенный микроконтроллер с ядром ARM Cortex-M3.

Теги:
Хабы:
+36
Комментарии11

Публикации

Изменить настройки темы

Истории

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн