2017-01-21 2 views
0

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

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); 
    } 
} 
} 
+0

Вы не уверены, что это правильно? Ты это пробовал? Обработчик прерываний с бесконечным циклом вряд ли будет работать вообще! Если счетчик был 'uint8_t', вам также не нужен'% 256'. – Clifford

ответ

3

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

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

Используя PWM, вы можете управлять с гораздо более низким процессором производительности, если управление светодиодами - это все, что он сделает.

Если вы должны использовать прерывание/GPIO (например, ваш таймер не поддерживает генерацию PWM или светодиод не подключен к штырю с поддержкой PWM), тогда было бы более эффективно устанавливать таймер пошагово. Например, для отметки: пространство 150: 105, вы должны установить таймер для 150 * 5us (9,6 мс), при прерывании переключить GPIO, а затем установить таймер на 105 * 5us (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) ; 
} 
+0

Простая альтернатива, если аппаратное обеспечение не имеет подходящих каналов PWM, заключается в использовании дельта-сигма-модуляции и уменьшении частоты при сохранении разрешения. Это сводится к добавлению яркости к модульному аккумулятору и освещению светодиода на циклах прерываний, при которых происходит переполнение. Недостаток заключается в том, что почти нулевые/полные значения яркости, возможно, потребуется зажать, чтобы избежать низкочастотного переключения. – doynax

+1

@doynax: Это должно быть опубликовано как ответ на комментарий к вопросу; Я не уверен, что это актуально как комментарий к этому ответу. – Clifford

+0

Shrug .. Это альтернативная стратегия для проблемы, отмеченная в ответе, в случае, если аппаратное обеспечение несовместимо. Вероятно, есть дополнительные проблемы, поскольку исходное решение должно по-прежнему выполнять затемнение, если на пониженной частоте и при запуске процессора. Кроме того, публикация полных ответов - больше работы;) – doynax

0

На позывах Клиффорд я разрабатывающие на альтернативной стратегии для снижения нагрузки программного обеспечения затемнения так как прерывание обслуживания каждые 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.

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

Смежные вопросы