【硬件设计】如何使用1个GPIO口控制2个LED灯显示四种状态

一、LED的两大特性
1.单向导电性
2.阈值特性:在LED两端加压到一定的阀值电压后才能导通(材料不同,阀值电压不同)

二、电路设计
并联
在这里插入图片描述
[图片来源:达尔闻]

三、原理详解
1.IO口为高阻态时,两个LED均熄灭
2.IO口为高电平的时候,红色LED点亮
3.IO口为低电平的时候,黄色LED点亮
4.IO口输出方波信号(频率大于100Hz),两个LED交替点亮,根据人眼视觉惰性,两个灯相当于都点亮
限制:电源电压只有5V,只有部分低阀值的LED可点亮
解决方法:
串联
在这里插入图片描述
[图片来源:达尔闻]

1.IO口为高阻态时,两个LED均熄灭(两个LED导通所需电压大于电源电压)
2.IO口为高电平的时候,蓝色LED点亮
3.IO口为低电平的时候,绿色LED点亮
4.IO口输出方波信号(频率大于100Hz),两个LED交替点亮,根据人眼视觉惰性,两个灯相当于都点亮

总结:当两个LED导通电压大于电源电压时,串联
当两个LED导通电压小于电源电压时,并联

如果不能使用 PWM,那么可以通过修改 GPIO 的输出频率来控制 LED 的亮度,这个方法也称为软件 PWM。 在 RT-Thread 中,可以使用硬件定时器和 GPIO 驱动来实现软件 PWM。具体步骤如下: 1. 在设备树中定义 GPIO 和定时器设备节点。 ``` led { compatible = "gpio-leds"; green { gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; label = "Green LED"; }; }; pwm-timer { compatible = "rtthread,pwm-timer"; #pwm-cells = <3>; }; ``` 其中,`gpio-leds` 是 GPIO 驱动的一个子驱动,用于控制 LED 状态;`rtthread,pwm-timer` 是定时器驱动的一个子驱动,用于控制 PWM 的输出频率。 2. 在应用程序中打开 GPIO 设备和定时器设备,并启动 PWM。 ``` #include <rtthread.h> #include <rtdevice.h> static rt_device_t led_device; static rt_device_t pwm_device; static void led_pwm_thread_entry(void *parameter) { rt_uint32_t count = 0; rt_uint32_t period = 100; /* PWM 周期为 100ms */ rt_uint32_t duty_cycle = 50; /* PWM 占空比为 50% */ rt_device_open(led_device, RT_DEVICE_FLAG_WRONLY); /* 打开 GPIO 设备 */ rt_device_open(pwm_device, RT_DEVICE_FLAG_WRONLY); /* 打开定时器设备 */ while (1) { count++; if (count % period < duty_cycle) { rt_device_write(led_device, 0, &RT_TRUE, 1); /* 设置 GPIO 输出高电平 */ } else { rt_device_write(led_device, 0, &RT_FALSE, 1); /* 设置 GPIO 输出低电平 */ } rt_thread_mdelay(1); /* 延时 1ms */ /* 启动 PWM */ rt_device_control(pwm_device, PWM_CMD_START, &period); } } int led_pwm_init(void) { led_device = rt_device_find("led0"); pwm_device = rt_device_find("timer3"); if (led_device == RT_NULL || pwm_device == RT_NULL) { rt_kprintf("failed to find devices\n"); return -1; } rt_thread_t thread = rt_thread_create("led_pwm", led_pwm_thread_entry, RT_NULL, 1024, 20, 10); if (thread != RT_NULL) { rt_thread_startup(thread); } return 0; } ``` 在这个例子中,我们使用一个线程来控制 LED 的亮度,每隔 1ms 更新一次 GPIO 的输出状态,并启动定时器来产生 PWM 信号。 需要注意的是,定时器的周期应该是 PWM 周期的整数倍,否则 PWM 的输出频率会有误差。 3. 修改定时器设备驱动来实现 PWM 的输出。 ``` #include <rtdevice.h> #include <rtthread.h> #define PWM_CMD_START RT_PWM_CMD_MAX #define PWM_CMD_STOP (RT_PWM_CMD_MAX + 1) static rt_uint32_t period; static rt_err_t pwm_timer_control(rt_device_t dev, int cmd, void *args) { switch (cmd) { case PWM_CMD_START: period = *(rt_uint32_t *)args; TIM3->ARR = period - 1; /* 设置定时器周期 */ TIM3->PSC = SystemCoreClock / (period * 1000) - 1; /* 设置定时器分频 */ TIM3->CCR1 = period / 2 - 1; /* 设置 PWM 占空比 */ TIM3->CCER |= TIM_CCER_CC1E; /* 启用定时器比较输出通道 */ TIM3->CR1 |= TIM_CR1_CEN; /* 启动定时器 */ break; case PWM_CMD_STOP: TIM3->CR1 &= ~TIM_CR1_CEN; /* 停止定时器 */ break; default: return -RT_ENOSYS; } return RT_EOK; } static struct rt_device pwm_timer_device = { .type = RT_Device_Class_Timer, .init = RT_NULL, .open = RT_NULL, .close = RT_NULL, .read = RT_NULL, .write = RT_NULL, .control = pwm_timer_control, .user_data = RT_NULL, }; int rt_hw_pwm_init(void) { rt_device_register(&pwm_timer_device, "timer3", RT_DEVICE_FLAG_WRONLY); return 0; } ``` 在这个例子中,我们添加了两个自定义的命令 `PWM_CMD_START` 和 `PWM_CMD_STOP`,用于启动和停止 PWM 输出。在启动 PWM 时,我们需要根据 PWM 周期计算定时器的分频和周期,并设置定时器的比较输出通道和 PWM 占空比。在停止 PWM 时,我们需要停止定时器的计数。 需要注意的是,这个例子只是一个简单的实现,实际使用中需要考虑更多的细节和异常情况。例如,需要对定时器的分频进行限制,以防止分频过大或过小导致 PWM 输出频率不准确;需要处理定时器溢出的情况,以防止 PWM 输出异常等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值