Перейти к содержанию
    

Сегодня провел такой эксперимент: подавал 3,3В поочередно на каждый вход АЦП (РА3...РА5), а на остальные не подавал ничего. На референсный вход РА6 подал 12В. Т.е. обеспечил условия, при которых ZeroCross не происходит. Сделал присвоение x=V_BEMF; после получения в V_BEMF результата конверсии. Выводил в терминал строчки: № шага, № канала АЦП, значение х. В х после окончания шага должно было оставаться последнее значение V_BEMF. Неожиданно для меня получилось вывести результат. На каждом канале АЦП на номере соответствующем тому, куда в этот момент подавалось 3,3В выводились значения равные напряжению после делителей.

Подключил резисторную звезду и надеялся увидеть на всех каналах АЦП значения равные опорному напряжению. Но почему то выводится только на одном канале РА4 значение равное удвоенному опорному напряжению. Т.е. похоже измерение происходит не в момент, когда фаза свободна, а в момент, когда она ШИМится.

Пока взял паузу потому что уже "глаз замылился".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

После небольшого перерыва вернулся к схеме и кое-что подправил. Прежде всего подрихтовал код. Вот так теперь выглядит процедура оббработки прерывания по обновлению счётчика ШИМ:


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(); были в начале процедуры и это сбивало последовательность работы мотора и переключение каналов АЦП. Сечас вроде всё на месте и картинка на осциллографе выглядит вот так:

 

PHASE_ZeroCrossing.JPG

Жёлтый луч  - это как раз сигнал 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;

мотор начинает стопориться. Вот причину этого я пока не понимаю:umnik2:

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мне с самого начала не понравилась форма сигнала противо-эдс на шагах паузы. У вас трапеции направлены в другую сторону. Как-то неправильно.
Погуглил по картинкам, вот похожие картинки, человеку тоже не нравились: BLDC BEMF not right
Пишет, что починил это, что мотор крутится при таких картинках чуть ли не в противофазе к норме.
Посмотрите, может поможет...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 6/20/2020 at 12:02 AM, Baser said:

Посмотрите, может поможет...

Посмотрел, почитал. Как я понял из всего прочитанного, нужно очень точно попасть в "ворота" (doors, как их называет один из участников обсуждения) коммутации.

Решил последовать его совету. Запустил программу начиная с периода коммутации в 10мСек и с шагом в 20мкСек укорачивал этот интервал, делая по 12 шагов на каждом значении периода коммутации. Процедура занимала довольно много времени и я сидел пялясь в осциллограф и рассчитывая увидеть хоть что то похожее на картинки из апноутов. 

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

Позапускав эдак несколько раз, убедился, что картина не меняется и перестал насиловать несчастный моторчик. Так что снова вышел облом.:swoon:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

После перерыва вернулся к своей схеме. Подкорректировал код и добился устойчивой работы мотора в диапазоне порядка 70-75% от максимальной скважности. причём регулировка скорости в этом диапазоне происходит без срывов и даже быстрое изменение скважности потенциометром не приводит к потере контроля. При всём при том форма сигнала на фазах осталась такой, как и была - "неконфессиональной", я бы сказал)))

При превышении определённого уровня скважности ШИМ мотор резко меняет режим вращения и на сигналах с фаз видно сильное зашумление. Контроль оборотов потенциометром, тем не менее, сохраняется, но и при уменьшении скважности до минимальной (10%) сигнал всё равно остаётся очень "грязным".

Проанализировав вышеописанную ситуацию, я предположил, что при увеличении скважности не хватает времени на зарядку конденсаторов подкачки в драйверах верхних ключей, т.к. они заряжается через нагрузку - обмотки. Возможно сопротивление обмоток таково, что оно на частоте ШИМ (10кГц) ощутимо увеличивает время зарядки конденсатора подкачки.

Исходя из этих соображений решил попробовать установить зарядовый насос для подкачки заряда в конденсатор, питающий драйвер верхнего ключа в период, когда верхний ключ открыт. Схема зарядового насоса (charge pump) была позаимствована мной из апнота фирмы IR. Прежде, чем реализовывать это схемное решение, хочу узнать мнения участников о схеме и о самом принципе. Вот схема:

 

POWER_STAGE.JPG

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...