MPetrovich 3 14 июня, 2020 Опубликовано 14 июня, 2020 · Жалоба Сегодня провел такой эксперимент: подавал 3,3В поочередно на каждый вход АЦП (РА3...РА5), а на остальные не подавал ничего. На референсный вход РА6 подал 12В. Т.е. обеспечил условия, при которых ZeroCross не происходит. Сделал присвоение x=V_BEMF; после получения в V_BEMF результата конверсии. Выводил в терминал строчки: № шага, № канала АЦП, значение х. В х после окончания шага должно было оставаться последнее значение V_BEMF. Неожиданно для меня получилось вывести результат. На каждом канале АЦП на номере соответствующем тому, куда в этот момент подавалось 3,3В выводились значения равные напряжению после делителей. Подключил резисторную звезду и надеялся увидеть на всех каналах АЦП значения равные опорному напряжению. Но почему то выводится только на одном канале РА4 значение равное удвоенному опорному напряжению. Т.е. похоже измерение происходит не в момент, когда фаза свободна, а в момент, когда она ШИМится. Пока взял паузу потому что уже "глаз замылился". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MPetrovich 3 19 июня, 2020 Опубликовано 19 июня, 2020 · Жалоба После небольшого перерыва вернулся к схеме и кое-что подправил. Прежде всего подрихтовал код. Вот так теперь выглядит процедура оббработки прерывания по обновлению счётчика ШИМ: void BEMF_Sampling(void) { //wait, while there are interconnection glitch volatile uint8_t i=10; while(i>0)i--; //29*0,167~5uSec B12_ON ADC_SoftwareStartConvCmd(ADC1, ENABLE); //Start ADC conversion manually while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)==RESET); //Wait while ADC sample complete. //After read conersion result from ADC_DR, flag EOC is cleared. uint16_t V_BEMF = ADC_GetConversionValue(ADC1);//read ADC Conversion Value in V_BEMF; //************************************************************************* //Первый результат измерения всегда отбрасывается, т.к. в Commutate() Prev_V_BEMF=0 if(/*(V_BEMF>(V_ref-300))&&(V_BEMF<(V_ref+300))&&*/(Prev_V_BEMF!=0)) { if(((V_BEMF>V_ref)&&(Prev_V_BEMF<=V_ref))||((V_BEMF<V_ref)&&(Prev_V_BEMF>=V_ref))) { TIM4->DIER = 0;//Disable TIM4 interrupts, stop V_BEMF measuring ZeroCross = TRUE; LED_ON if(GPIOB->ODR & GPIO_Pin_13)GPIOB->BRR = GPIO_Pin_13;//if bit 13 SET, RESET bit else GPIOB->BSRR = GPIO_Pin_13;//if bit 13 RESET, SET bit //***************************************************************** //Save time from last commutation to ZeroCross event. It's the FIRST half of intercommutation time. uint16_t Temp = TIM_GetCounter(TIM3); //TimeSinceCommutation = TIM_GetCounter(TIM3); // Filter the ZC detection with earlier measurements through IIR(recoursive) filter. //TimeSinceCommutation = (1*Temp+3*TimeSinceCommutation)/4; //Write this value in TIM3_CCR1 register. It's the SECOND half of intercommutation period //When counter will reach this value, next Commutate() will happen //TIM3 -> CNT = 0; //TIM3 -> CCR1 = 2*TimeSinceCommutation; } } //*****************************************************************/ Prev_V_BEMF = V_BEMF;//Save V_BEMF in Prev_V_BEMF if(ZeroCross != TRUE) B12_OFF } И самое главное - нашел ошибку в последовательности операций в функции, работающей в основном цикле и определяющей последовательность работы всей программы: static void PWMControl(void) { /* Calculate duty cycle from speed reference value. * SPEED_Ref=ADC channel_7 conversion result: 0<SPEED_Ref<4096 * Duty_Cycle =((100*SPEED_Ref)/ADC_RESOLUTION); */ Set_PWM_Duty_Cycle(SPEED_Ref/41); //Wait when counter will reach TIM3_CCR1 value = TimeSinceCommutation. //Then Commutate() will happen. while(TIM_GetFlagStatus(TIM3, TIM_IT_CC1)==RESET); //Commutate(); TIM3->SR = 0; B12_OFF ZeroCross = FALSE; LED_OFF Prev_V_BEMF=0; TIM4->DIER = 0;//Запрещаем прерывания от PWM, т.к. идут пререходные процессы. PWM_Distribution(nextCommutationStep);//Переключаем фазы мотора на следующий шаг комутации. TIM3 -> CCR1 = 300;//TimeSinceCommutation-300;//2250-300;// TIM3 -> CNT = 0; Read_Vref(); Read_SPEED_Ref(); ADC_Multiplexor(ADMUXTable[nextCommutationStep]); nextCommutationStep++;//Commutation step counter. Define the next commutation step number if (nextCommutationStep > 5) {nextCommutationStep = 0;} //************************************************************************************* while(TIM_GetFlagStatus(TIM3, TIM_IT_CC1)==RESET); TIM3->SR = 0;//Clear allTIM3 flags TIM4->SR = 0; TIM4->DIER |= 0x0001;//Enable TIM4 Update interrupt. TIM3->CCR1 = 2*TimeSinceCommutation;//4500;// } Раньше операции Read_Vref(); Read_SPEED_Ref(); были в начале процедуры и это сбивало последовательность работы мотора и переключение каналов АЦП. Сечас вроде всё на месте и картинка на осциллографе выглядит вот так: Жёлтый луч - это как раз сигнал ZeroCross. Он получается на ноге В13 как результат вот этих действий : if(GPIOB->ODR & GPIO_Pin_13)GPIOB->BRR = GPIO_Pin_13;//if bit 13 SET, RESET bit else GPIOB->BSRR = GPIO_Pin_13;//if bit 13 RESET, SET bit Пунктирная линия - уровень порогового напряжения ZeroCross. Получается теперь вроде бы всё работает, однако, если раскомментировать вот эти строчки: //TimeSinceCommutation = (1*Temp+3*TimeSinceCommutation)/4; //Write this value in TIM3_CCR1 register. It's the SECOND half of intercommutation period //When counter will reach this value, next Commutate() will happen //TIM3 -> CNT = 0; //TIM3 -> CCR1 = 2*TimeSinceCommutation; мотор начинает стопориться. Вот причину этого я пока не понимаю Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Baser 5 19 июня, 2020 Опубликовано 19 июня, 2020 · Жалоба Мне с самого начала не понравилась форма сигнала противо-эдс на шагах паузы. У вас трапеции направлены в другую сторону. Как-то неправильно. Погуглил по картинкам, вот похожие картинки, человеку тоже не нравились: BLDC BEMF not right Пишет, что починил это, что мотор крутится при таких картинках чуть ли не в противофазе к норме. Посмотрите, может поможет... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MPetrovich 3 21 июня, 2020 Опубликовано 21 июня, 2020 · Жалоба On 6/20/2020 at 12:02 AM, Baser said: Посмотрите, может поможет... Посмотрел, почитал. Как я понял из всего прочитанного, нужно очень точно попасть в "ворота" (doors, как их называет один из участников обсуждения) коммутации. Решил последовать его совету. Запустил программу начиная с периода коммутации в 10мСек и с шагом в 20мкСек укорачивал этот интервал, делая по 12 шагов на каждом значении периода коммутации. Процедура занимала довольно много времени и я сидел пялясь в осциллограф и рассчитывая увидеть хоть что то похожее на картинки из апноутов. Однако увы, ничего похожего я так и не дождался, хотя раскрутил мотор основательно. Не знаю сколько оборотов он выдал, но уже перешёл с гула на вой, а потом на визг Позапускав эдак несколько раз, убедился, что картина не меняется и перестал насиловать несчастный моторчик. Так что снова вышел облом. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MPetrovich 3 4 июля, 2020 Опубликовано 4 июля, 2020 · Жалоба После перерыва вернулся к своей схеме. Подкорректировал код и добился устойчивой работы мотора в диапазоне порядка 70-75% от максимальной скважности. причём регулировка скорости в этом диапазоне происходит без срывов и даже быстрое изменение скважности потенциометром не приводит к потере контроля. При всём при том форма сигнала на фазах осталась такой, как и была - "неконфессиональной", я бы сказал))) При превышении определённого уровня скважности ШИМ мотор резко меняет режим вращения и на сигналах с фаз видно сильное зашумление. Контроль оборотов потенциометром, тем не менее, сохраняется, но и при уменьшении скважности до минимальной (10%) сигнал всё равно остаётся очень "грязным". Проанализировав вышеописанную ситуацию, я предположил, что при увеличении скважности не хватает времени на зарядку конденсаторов подкачки в драйверах верхних ключей, т.к. они заряжается через нагрузку - обмотки. Возможно сопротивление обмоток таково, что оно на частоте ШИМ (10кГц) ощутимо увеличивает время зарядки конденсатора подкачки. Исходя из этих соображений решил попробовать установить зарядовый насос для подкачки заряда в конденсатор, питающий драйвер верхнего ключа в период, когда верхний ключ открыт. Схема зарядового насоса (charge pump) была позаимствована мной из апнота фирмы IR. Прежде, чем реализовывать это схемное решение, хочу узнать мнения участников о схеме и о самом принципе. Вот схема: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться