控制微控制器的 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 以防止可见闪烁。
哦,如果开关损耗是您应用中的一个问题,请注意。
我正在尝试以 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 以防止可见闪烁。
哦,如果开关损耗是您应用中的一个问题,请注意。