控制微控制器的 LED 亮度 rtos/bios

control led brightness of microcontroller rtos/bios

我正在尝试以 256 (0-255) 种不同的亮度级别控制我的 LED。我的控制器在 rtos 上设置为 80mhz 和 运行。我将时钟模块设置为每 5 微秒中断一次,亮度例如到 150。led 变暗了,但我不确定是否真的有 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);
    }
}
}

5 微秒的中断对于 80 MHz 的处理器来说是一个很高的要求,并且会留给其他工作的时间很少,如果您不做其他工作,则根本不需要使用中断 - 您可以简单地轮询时钟计数器;那么它仍然需要大量的处理器来完成一项相当微不足道的任务——而且 RTOS 也太过分了。

执行任务的更好方法是使用定时器的 PWM(脉冲宽度调制)功能。然后,您将能够以零软件开销准确控制亮度;让您的处理器去做更多有趣的事情。

如果只需要 LED 控制,您可以使用性能低得多的处理器来管理 PWM。

如果您必须使用 interrupt/GPIO(例如,您的定时器不支持 PWM 生成或 LED 未连接到支持 PWM 的引脚),那么递增设置定时器会更有效。因此,例如对于 150:105 的 mark:space,您可以将定时器设置为 150*5us(9.6ms),在中断上切换 GPIO,然后将定时器设置为 105*5us(6.72ms) .

您的解决方案的一个主要问题是中断处理程序没有 return - 中断必须 运行 完成并且尽可能短,并且最好在执行时间上具有确定性。

在不使用硬件 PWM 的情况下,根据您的代码片段,以下内容可能更接近您的需要:

#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) ;
}

在 Clifford 的敦促下,我正在详细阐述一种替代策略,以减少软件调光的负载,因为每 400 个时钟周期服务中断可能会很困难。首选解决方案当然应该是在可用时使用硬件 pulse-width 调制。

一种选择是仅在 PWM 侧翼设置中断。不幸的是,随着时间的流逝,这种策略往往会引入竞争和漂移,同时进行调整并且无法很好地扩展到多个通道。

或者我们可以从 pulse-width 切换到 delta-sigma 调制。这个概念背后有一些理论,但在这种情况下,它可以归结为尽快打开和关闭引脚,同时保持与调光水平成比例的平均值 on-time。因此,中断频率可能会降低,而不会将整体开关频率降低到可见水平。

下面是一个示例实现:

// 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 以防止可见闪烁。

哦,如果开关损耗是您应用中的一个问题,请注意。