微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Tiva C 系列 TM4C123G 中的呼吸引导

如何解决Tiva C 系列 TM4C123G 中的呼吸引导

我必须写一个 C 代码,以便板上的 RGB LED 呼吸。我的代码闪烁而不是呼吸。我的老师说不同的亮度是通过改变占空比来实现的,所以在这种情况下我不能使用 pwm。请帮助我理解这段代码

#include <stdint.h>
#include <stdlib.h>

#define SYSCTL_RCGC2_R          (*((volatile unsigned long *)0x400FE108))
#define SYSCTL_RCGC2_GPIOF       0x00000020  //port F clock gating control
#define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R        (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_DEN_R        (*((volatile unsigned long *)0x4002551C))
   

void delay (double sec);
int cond;
int main(void){
   SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOF;
   
   GPIO_PORTF_DIR_R=0x0E;
   GPIO_PORTF_DEN_R=0x0E;
   cond=0;
   while(1){
       
       GPIO_PORTF_DATA_R = 0x02;
       delay(12.5);
           GPIO_PORTF_DATA_R = 0x00;
           delay(0);
           GPIO_PORTF_DATA_R = 0x02;
       delay(2.5);
           GPIO_PORTF_DATA_R = 0x00;
           delay(10);
   
           GPIO_PORTF_DATA_R = 0x02;
           delay(5);
           GPIO_PORTF_DATA_R = 0x00;
           delay(7.5);
           GPIO_PORTF_DATA_R = 0x02;
           delay(7.5);
           GPIO_PORTF_DATA_R = 0x00;
           delay(5);
           GPIO_PORTF_DATA_R = 0x02;
           delay(12.5);
           GPIO_PORTF_DATA_R = 0x00;
           delay(0);
           GPIO_PORTF_DATA_R = 0x02;
           delay(7.5);
           GPIO_PORTF_DATA_R = 0x00;
           delay(5);
           GPIO_PORTF_DATA_R = 0x02;
           delay(5);
           GPIO_PORTF_DATA_R = 0x00;
           delay(7.5);
       
       
   }
   return 0;
   
}
void delay(double sec){
   int c=1,d=1;
   for(c=1;c<=sec;c++)
       for(d=1;d<= 4000000;d++){}
           }

解决方法

有两种方法可以驱动 LED:通过某些通用 I/O 使用恒定电流,或者使用 PWM 的重复占空比。 PWM 意思是脉宽调制,它会发生在人眼无法察觉的脉冲中,可能在 100Hz 到 10kHz 左右。

PWM 的主要优点是您可以轻松控制电流。 RGB 的情况是指 3 个独立 LED 的颜色强度。大多数较小的 LED 的额定电流为 20mA,因此这通常是您要达到的最大电流,对应于 100% 的占空比。 实现这一点的正确方法是使用 PWM。

但是您当前的代码所做的是通过拉动 GPIO 引脚来“按部就班”模拟 PWM。这是非常粗糙和低效的。通常微控制器有一个内置的定时器和/或 PWM 硬件外设,您只需提供一个占空比,硬件就可以从那里处理一切。在这种情况下,您将设置 3 个 PWM 硬件通道,理想情况下应该同时计时。

LED 是具有不同正向电压的二极管,具体取决于化学性质。因此,您很可能对 3 种颜色中的每一种都有不同的正向电压。您必须检查 RGB 的数据表并寻找以坎德拉表示的发光强度。在这种情况下很可能millicandela,mcd。假设您的绿色 LED 具有 300mcd,但红色和蓝色 LED 具有 100mcd。它们有点线性,或者你可以假设它们是线性的。因此,在这种情况下,一个粗略的公式是为绿色 LED 提供比其他 LED 少 3 倍的电流,以获得均匀的颜色混合。一旦你补偿了它,你就可以给你的 3 个 PWM 通道一个 RGB 代码,并希望得到相应的颜色。


顺便提一下,您代码中的延迟功能在很多方面都被完全破坏了。这种忙延迟的循环迭代器必须是易失性的,否则在启用优化时,任何半体面的编译器都会简单地消除延迟。也没有理由使用浮点数。

,

如果您使用延迟功能进行操作并且您的延迟分辨率按照代码中的建议以秒为单位,那么它当然会“闪烁”-频率需要比人类视觉感知更快-例如大约 50Hz,然后要获得平滑的变化,您可以将其分成 20 个级别,这需要 毫秒 延迟。

在任何情况下,您的 Image.getSize(uri,success,failure) 函数都会通过采用浮点秒数但将其与 整数 循环计数器进行比较来击败自己 - 它只会在 整秒内工作.

所以给定一个函数 Image.getSize( 'https://link-to-image',(width,height) => { setWidth(width); setHeight(height); } ); (我稍后讨论)然后:

delay()

delayms( unsigned millisec ) 更改为更快呼吸,将 #define BREATHE_UPDATE_MS 100 #define BREATHE_MINIMUM 0 #define PWM_PERIOD_MS 20 unsigned tick = 0 ; unsigned duty_cycle = 0 ; unsigned cycle_start_tick= 0 ; unsigned breath_update_tick = 0 ; int breathe_dir = 1 ; for(;;) { // If in PWM "mark"... if( tick - cycle_start_tick < duty_cycle ) { // LED on GPIO_PORTF_DATA_R |= 0x02 ; } // else PWM "space" else { // LED off GPIO_PORTF_DATA_R &= ~0x02 ; } // Update tick counter tick++ ; // If PWM cycle complete,restart if( tick - cycle_start_tick >= PWM_PERIOD_MS ) { cycle_start_tick = tick ; } // If time to update duty-cycle... if( tick - breath_update_tick > BREATHE_UPDATE_MS ) { breath_update_tick = tick ; duty_cycle += breathe_dir ; if( duty_cycle >= PWM_PERIOD_MS ) { // Breathe in breathe_dir = -1 ; } else if( duty_cycle == BREATHE_MINIMUM ) { // Breathe out breathe_dir = 1 ; } } delayms( 1 ) ; } 更改为“浅呼吸” - 即不暗淡关闭。

如果您的延迟函数确实导致以秒为单位的延迟分辨率,那么大约并且相当粗略:

BREATHE_UPDATE_MS

然而,这对我来说意味着一个相当低的核心时钟频率,所以你可能需要调整它。请注意使用 BREATHE_MINIMUM 来防止优化器删除空循环。这种延迟的问题在于,您需要将其校准为目标的时钟速度,并且在任何情况下,其时序都可能会有所不同,具体取决于您使用的编译器和使用的编译器选项。这通常是一个糟糕的解决方案。

实际上,为此使用“忙循环”延迟是不明智和粗暴的,最好使用 Cortex-M SYSTICK:

void delayms( unsigned millisec )
{
   for( int c = 0; c < millisec; c++ )
   {
       for( volatile int d = 0; d < 4000; d++ ) {}
   }
}

... 从原始中删除 volatilevolatile uint32_t tick = 0 ; void SysTick_Handler(void) { tick++ ; } ;代码。然后你不需要在上面的循环中延迟,因为所有的时间都与 tick 的值挂钩。但是,如果您出于其他原因想要延迟,那么:

tick++

然后您将在启动时初始化 SYSTICK,因此:

tick

这假设您正在使用 CMSIS,但您的代码表明您没有这样做(甚至使用供应商提供的寄存器标头)。在这种情况下,如果您(或您的导师)坚持这样做,您将需要使用 SYSTICK 和 NVIC 寄存器。 delayms( uint32_t millisec ) { uint32_t start = tick ; while( tick - start < millisec ) ; } 的来源如下:

int main (void)  
{
    SysTick_Config(SystemCoreClock / 1000) ;
 
    ...
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。