управление яркостью светодиода микроконтроллера rtos / bios

Я пытаюсь управлять своим светодиодом с 256 (0-255) различными уровнями яркости. мой контроллер настроен на 80 МГц и работает на RTOS. Я устанавливаю модуль часов на прерывание каждые 5 микросекунд и яркость, например. до 150. светодиод тускнеет, но я не уверен, правильно ли все сделано, чтобы действительно иметь 256 различных уровней

int counter = 1;
int brightness = 0;


void SetUp(void)
{

SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
GPIOPinTypeGPIOOutput(PORT_4, PIN_1);

Clock_Params clockParams;
Clock_Handle myClock;
Error_Block eb;
Error_init(&eb);
Clock_Params_init(&clockParams);
clockParams.period = 400; // every 5 microseconds
clockParams.startFlag = TRUE;
myClock = Clock_create(myHandler1, 400, &clockParams, &eb);
if (myClock == NULL) {
    System_abort("Clock create failed");
}

}


void myHandler1 (){

brightness = 150;


while(1){
    counter = (++counter) % 256;
    if (counter < brightness){
        GPIOPinWrite(PORT_4, PIN_1, PIN_1);
    }else{
        GPIOPinWrite(PORT_4, PIN_1, 0);
    }
}
}

person Liam    schedule 21.01.2017    source источник
comment
Вы не уверены, что это правильно? Ты пробовал это? Обработчик прерывания с бесконечным циклом вряд ли вообще сработает! Если бы счетчик был uint8_t, вам тоже не нужен % 256.   -  person Clifford    schedule 21.01.2017


Ответы (2)


Прерывание в 5 микросекунд - это непростая задача для процессора с частотой 80 МГц, и у него останется мало времени для другой работы, а если вы не выполняете другую работу, вам вообще не нужно использовать прерывания - вы можете просто опросить счетчик часов; тогда для решения довольно тривиальной задачи все равно потребуется много процессора - да и ОСРВ тоже излишняя.

Лучший способ выполнить вашу задачу - использовать функцию таймера ШИМ (широтно-импульсная модуляция). После этого вы сможете точно регулировать яркость без дополнительных затрат на программное обеспечение; оставляя процессор заниматься более интересными делами.

Используя ШИМ, вы могли бы справиться с процессором с гораздо меньшей производительностью, если бы это было только светодиодное управление.

Если вы должны использовать прерывание / GPIO (например, ваш таймер не поддерживает генерацию ШИМ или светодиод не подключен к выводу, поддерживающему ШИМ), тогда было бы более эффективно установить таймер постепенно. Так, например, для mark: space 150: 105 вы должны установить таймер на 150 * 5 мкс (9,6 мс), при прерывании переключить GPIO, а затем установить таймер на 105 * 5 мкс (6,72 мс).

Основная проблема с вашим решением заключается в том, что обработчик прерывания не возвращает - прерывания должны выполняться до завершения и быть как можно более короткими и предпочтительно детерминированными по времени выполнения.

Без использования аппаратного ШИМ следующий фрагмент кода, вероятно, будет ближе к тому, что вам нужно:

#define PWM_QUANTA = 400 ; // 5us
static volatile uint8_t brightness = 150 ;
static Clock_Handle myClock ;


void setBrightness( uint8_t br )
{
  brightness = br ;
}

void SetUp(void)
{
  SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
  GPIOPinTypeGPIOOutput(PORT_4, PIN_1);

  Clock_Params clockParams;
  Error_Block eb;
  Error_init(&eb);
  Clock_Params_init(&clockParams);

  clockParams.period = brightness * PWM_QUANTA ;

  clockParams.startFlag = TRUE;
  myClock = Clock_create(myHandler1, 400, &clockParams, &eb);
  if (myClock == NULL)
  {
    System_abort("Clock create failed");
  }
}

void myHandler1(void)
{
  static int pin_state = 1 ;

  // Toggle pin state and timer period
  if( pin_state == 0 )
  {
    pin_sate = 1 ;
    Clock_setPeriod( myClock, brightness * PWM_QUANTA ) ;
  }
  else
  {
    pin_sate = 0 ;
    Clock_setPeriod( myClock, (255 - brightness) * PWM_QUANTA ) ;
  }

  // Set pin state
  GPIOPinWrite(PORT_4, PIN_1, pin_state) ;
}
person Clifford    schedule 21.01.2017
comment
Простая альтернатива, если в оборудовании не хватает подходящих каналов ШИМ, состоит в том, чтобы вместо этого использовать дельта-сигма модуляцию и уменьшить частоту при сохранении разрешения. Это сводится к добавлению яркости модульному аккумулятору и включению светодиода в циклах прерывания, при которых произошло переполнение. Недостатком является то, что результирующие значения почти нулевой / полной яркости, возможно, придется ограничить, чтобы избежать низкочастотного переключения. - person doynax; 21.01.2017
comment
@doynax: Это должно быть опубликовано как ответ или комментарий к вопросу; Я не уверен, что это уместно в качестве комментария к этому ответу. - person Clifford; 21.01.2017
comment
Пожать плечами .. Это альтернативная стратегия решения проблемы, указанной в ответе, на случай, если разработанное оборудование окажется несовместимым. Вероятно, возникнут дополнительные проблемы, поскольку исходное решение должно в противном случае по-прежнему выполнять затемнение, если оно выполняется на пониженной частоте и при загрузке ЦП. Кроме того, публикация полных ответов - это больше работы;) - person doynax; 21.01.2017
comment
@doynax: Я ценю это, но если у вас есть альтернативное решение, у вас есть альтернативный ответ. Я хочу сказать, что ваш комментарий не имеет прямого отношения к моему ответу. Более того, я не уверен, что понимаю ваше решение; публикация ответа позволит вам уточнить, что поможет OP и сообществу. - person Clifford; 21.01.2017
comment
Спасибо вам, ребята! действительно помог мне лучше разобраться в этой теме! Я новичок в программировании микроконтроллеров - person Liam; 22.01.2017

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

Один из вариантов - установить прерывания только на флангах ШИМ. К сожалению, эта стратегия имеет тенденцию вводить гонки и дрейф по мере того, как проходит время, когда происходят корректировки, и плохо масштабируется для нескольких каналов.

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

Ниже приведен пример реализации:

// Brightness to display. More than 8-bits are required to handle full 257-step range.
// The resolution also course be increased if desired.
volatile unsigned int brightness = 150;

void Interrupt(void) {
 // Increment the accumulator with the desired brightness
 static uint8_t accum;
 unsigned int addend = brightness;
 accum += addend;
 // Light the LED pin on overflow, relying on native integer wraparound.
 // Consequently higher brightness values translate to keeping the LED lit more often
 GPIOPinWrite(PORT_4, PIN_1, accum < addend);
}

Ограничением является то, что частота переключения уменьшается с расстоянием от 50% яркости. Таким образом, последние N шагов, возможно, придется ограничить до 0 или 256, чтобы предотвратить видимое мерцание.

Да, и будьте осторожны, если потери при переключении вызывают беспокойство в вашем приложении.

person doynax    schedule 21.01.2017