Tiva C系列TM4C123G中的呼吸led
我必须写一个C代码,这样板上的RGB发光二极管才能呼吸。我的密码在闪烁,没有呼吸。我的老师说改变亮度是通过改变占空比来实现的,所以在这种情况下我不能使用pwm。请帮我理解这个代码Tiva C系列TM4C123G中的呼吸led,c,arm,embedded,cortex-m,keil,C,Arm,Embedded,Cortex M,Keil,我必须写一个C代码,这样板上的RGB发光二极管才能呼吸。我的密码在闪烁,没有呼吸。我的老师说改变亮度是通过改变占空比来实现的,所以在这种情况下我不能使用pwm。请帮我理解这个代码 #include <stdint.h> #include <stdlib.h> #define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108)) #define SYSCTL_RCGC2_GPIOF
#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++){}
}
#包括
#包括
#定义SYSCTL_RCGC2_R(*(易失性无符号长*)0x400FE108))
#定义SYSCTL\U RCGC2\U GPIOF 0x00000020//端口F时钟选通控制
#定义GPIO端口数据(*(易失性无符号长*)0x400253FC))
#定义GPIO_端口f_DIR_R(*(易失性无符号长*)0x40025400))
#定义GPIO端口号(*(易失性无符号长*)0x4002551C))
无效延迟(双秒);
int-cond;
内部主(空){
SYSCTL\u RCGC2\u R=SYSCTL\u RCGC2\u GPIOF;
GPIO_PORTF_DIR_R=0x0E;
GPIO_PORTF_DEN_R=0x0E;
cond=0;
而(1){
GPIO_端口数据_R=0x02;
延误(12.5);
GPIO端口数据=0x00;
延迟(0);
GPIO_端口数据_R=0x02;
延误(2.5);
GPIO端口数据=0x00;
延迟(10);
GPIO_端口数据_R=0x02;
延误(5);
GPIO端口数据=0x00;
延误(7.5);
GPIO_端口数据_R=0x02;
延误(7.5);
GPIO端口数据=0x00;
延误(5);
GPIO_端口数据_R=0x02;
延误(12.5);
GPIO端口数据=0x00;
延迟(0);
GPIO_端口数据_R=0x02;
延误(7.5);
GPIO端口数据=0x00;
延误(5);
GPIO_端口数据_R=0x02;
延误(5);
GPIO端口数据=0x00;
延误(7.5);
}
返回0;
}
无效延迟(双秒){
int c=1,d=1;
对于(c=1;c有两种方法可以驱动LED:通过一些通用I/O的恒定电流,或通过PWM的重复占空比。PWM意味着脉冲宽度调制,它将发生在人眼无法注意到的太快的脉冲上,可能在约100Hz到10kHz之间
PWM的主要优点是,您可以轻松控制电流。RGB的情况意味着3个单独LED的颜色强度。大多数较小的LED的额定电流为20mA,因此这通常是您目标的最大电流,对应于100%的占空比。
实现这一点的正确方法是使用PWM
但您当前的代码所做的是“bitbang”通过拉动GPIO引脚来模拟PWM。这非常粗糙和低效。通常微控制器内置计时器和/或PWM硬件外围设备,您只需提供一个占空比,硬件就可以从那里处理所有事情。在这种情况下,您将设置3个PWM硬件通道,理想情况下应同时计时
led是具有不同正向电压的二极管,具体取决于化学成分。因此,3种颜色中的每种颜色很可能具有不同的正向电压。您必须检查RGB的数据表,并查找以坎德拉表示的发光强度。在这种情况下,很可能是毫坎德拉,mcd。假设您的绿色led具有300mcd,但红色led具有300mcd钕蓝有100mcd。它们有些线性,或者你可以假设它们是线性的。因此,在这种情况下,一个粗略的公式是,为绿色LED提供比其他LED少3倍的电流,以获得均匀的颜色混合。一旦你补偿了这一点,你可以给你的3个PWM通道一个RGB代码,并希望得到相应的颜色g颜色
顺便说一句,代码中的延迟函数在很多方面都是完全失效的。用于这种繁忙延迟的循环迭代器必须是易失的,否则任何半体面的编译器在启用优化时都会简单地删除延迟。而且也没有理由使用浮点。如果您使用延迟函数和延迟函数执行此操作分辨率是以秒为单位的,正如代码中所建议的那样,它当然会“闪烁”——频率需要比人类的视觉感知速度快——比如说大约50Hz,然后为了获得平稳的变化,你可以将其划分为20个级别,需要毫秒的延迟
在任何情况下,delay()
函数都会以秒为浮点数,但将其与整数循环计数器进行比较,从而使自身失效-它只会在整秒内工作
因此,给定一个函数delayms(无符号毫秒)
(我将在后面讨论),然后:
然而,这对我来说意味着一个相当低的核心时钟频率,因此您可能需要调整它。请注意使用volatile
,以防止优化程序删除空环路。此延迟的问题是,您需要将其校准到目标的时钟速度,并且其计时在任何情况下都可能因时间而异关于你使用什么编译器和你使用什么编译器选项。这通常是一个糟糕的解决方案
实际上,使用“忙循环”延迟进行此操作是不明智和粗糙的,最好使用Cortex-M系统:
volatile uint32_t tick = 0 ;
void SysTick_Handler(void)
{
tick++ ;
}
…从原始代码中删除勾号
和勾号+
。这样,您就不需要在上面的循环中进行延迟,因为所有计时都与勾号
的值挂钩。但是,如果您出于其他原因需要延迟,那么:
delayms( uint32_t millisec )
{
uint32_t start = tick ;
while( tick - start < millisec ) ;
}
这假设您正在使用CMSIS,但您的代码表明您没有这样做(甚至没有使用供应商提供的注册表头)。在这种情况下,如果您(或您的导师)坚持这样做,您将需要使用SYSTICK和NVIC注册表。SYSTICK\U Config()的源代码如下所示:
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0UL); /* Function successful */
}
\uuuuuuuuuu静态uuuu内联uint32\uu系统单击配置(uint32\ut勾号)
{
如果((滴答声-1UL)>系统滴答声\u加载\u重新加载\u Msk)
{
返回(1UL);/*不可能重新加载值*/
}
SysTick->LOAD=(uint32_t)(滴答声-1UL);/*设置重新加载寄存器*/
NVIC_设置优先级(SysTick_IRQn,(1UL)
delayms( uint32_t millisec )
{
uint32_t start = tick ;
while( tick - start < millisec ) ;
}
int main (void)
{
SysTick_Config(SystemCoreClock / 1000) ;
...
}
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0UL); /* Function successful */
}