rt-thread信号量与互斥量
1. 最简单的信号量例程:按键点亮LED
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>/* 定义引脚 - 根据你的开发板修改 */
#define LED_PIN GET_PIN(C, 13) // LED引脚
#define KEY_PIN GET_PIN(A, 0) // 按键引脚static rt_sem_t key_sem; // 按键信号量/* 按键中断服务函数 */
static void key_isr(void *args)
{/* 在中断中释放信号量,通知主线程 */rt_sem_release(key_sem);
}/* LED控制线程 */
static void led_thread_entry(void *parameter)
{while (1){/* 等待按键信号 */rt_sem_take(key_sem, RT_WAITING_FOREVER);/* 按键按下,翻转LED状态 */rt_kprintf("📱 按键按下,切换LED状态\n");static rt_base_t led_state = PIN_HIGH;led_state = !led_state;rt_pin_write(LED_PIN, led_state);if (led_state == PIN_LOW) {rt_kprintf("💡 LED点亮\n");} else {rt_kprintf("🌙 LED熄灭\n");}}
}int simple_sem_example(void)
{/* 初始化硬件 */rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);rt_pin_mode(KEY_PIN, PIN_MODE_INPUT_PULLUP);/* 初始状态:LED熄灭 */rt_pin_write(LED_PIN, PIN_HIGH);/* 创建信号量 - 初始值为0,表示还没有按键 */key_sem = rt_sem_create("key", 0, RT_IPC_FLAG_FIFO);/* 设置按键中断 */rt_pin_attach_irq(KEY_PIN, PIN_IRQ_MODE_FALLING, key_isr, RT_NULL);rt_pin_irq_enable(KEY_PIN, PIN_IRQ_ENABLE);/* 创建LED控制线程 */rt_thread_t led_thread = rt_thread_create("led", led_thread_entry, RT_NULL, 1024, 25, 10);rt_thread_startup(led_thread);rt_kprintf("🎯 信号量例程启动成功!\n");rt_kprintf("💡 按下按键,LED会切换状态\n");return RT_EOK;
}/* 导出到FinSH命令 */
MSH_CMD_EXPORT(simple_sem_example, 简单信号量例程-按键控制LED);
2. 编译运行后的效果
在串口终端输入命令:
msh >simple_sem_example
🎯 信号量例程启动成功!
💡 按下按键,LED会切换状态
当你按下按键时,会看到:
📱 按键按下,切换LED状态
💡 LED点亮
📱 按键按下,切换LED状态
🌙 LED熄灭
📱 按键按下,切换LED状态
💡 LED点亮
3. 信号量在这里的作用
- 🔘 按键中断:检测到按键按下 →
rt_sem_release(key_sem) - 💡 LED线程:等待信号量 →
rt_sem_take(key_sem)→ 处理LED切换
就像门铃一样:
- 有人按门铃(按键中断释放信号量)
- 你听到门铃响(线程收到信号量)
- 你去开门(执行LED切换)
4. 另一个实用例程:定时数据采集
#include <rtthread.h>static rt_sem_t timer_sem; // 定时信号量/* 模拟读取传感器数据 */
static float read_sensor(void)
{return 25.0f + ((rt_tick_get() % 100) / 10.0f); // 模拟温度数据
}/* 数据处理线程 */
static void sensor_thread_entry(void *parameter)
{while (1){/* 等待定时信号(每2秒一次) */rt_sem_take(timer_sem, RT_WAITING_FOREVER);/* 读取并显示传感器数据 */float temperature = read_sensor();rt_kprintf("🌡️ 当前温度: %.1f°C\n", temperature);}
}/* 定时器回调函数 */
static void timer_callback(void *parameter)
{/* 定时时间到,释放信号量 */rt_sem_release(timer_sem);
}int sensor_example(void)
{rt_timer_t timer;/* 创建信号量 */timer_sem = rt_sem_create("timer", 0, RT_IPC_FLAG_FIFO);/* 创建定时器(每2000ms触发一次) */timer = rt_timer_create("sensor_timer", timer_callback, RT_NULL,RT_TICK_PER_SECOND * 2, // 2000msRT_TIMER_FLAG_PERIODIC); // 周期性定时器/* 启动定时器 */rt_timer_start(timer);/* 创建传感器线程 */rt_thread_t sensor_thread = rt_thread_create("sensor", sensor_thread_entry, RT_NULL, 1024, 20, 10);rt_thread_startup(sensor_thread);rt_kprintf("📊 定时数据采集启动!每2秒显示一次温度\n");return RT_EOK;
}MSH_CMD_EXPORT(sensor_example, 定时数据采集例程);
运行效果:
📊 定时数据采集启动!每2秒显示一次温度
🌡️ 当前温度: 25.3°C
🌡️ 当前温度: 26.7°C
🌡️ 当前温度: 24.8°C
🌡️ 当前温度: 25.9°C
5. 总结
这两个例程展示了信号量最常用的两种场景:
- 🔘 事件通知:按键中断通知主线程
- ⏰ 定时触发:定时器通知数据采集线程
信号量的核心作用:让一个线程等待某个事件发生,当事件发生时立即被唤醒执行任务。
互斥量保护串口资源
#include <rtthread.h>
#include <rtdevice.h>static rt_mutex_t uart_mutex; // 串口互斥锁/* 线程1:通过串口发送数据 */
static void thread1_uart_send(void *parameter)
{while (1){rt_kprintf("线程1: 想用串口发送数据...\n");// 获取串口互斥锁rt_mutex_take(uart_mutex, RT_WAITING_FOREVER);rt_kprintf("线程1: 🔒 获得串口锁,正在发送数据...\n");rt_device_write(uart_dev, 0, "Thread1: Hello\n", 15);rt_thread_mdelay(1000); // 模拟发送时间rt_kprintf("线程1: 发送完成,释放串口锁\n");rt_mutex_release(uart_mutex); // 释放互斥锁rt_thread_mdelay(2000);}
}/* 线程2:通过串口发送数据 */
static void thread2_uart_send(void *parameter)
{while (1){rt_kprintf("线程2: 想用串口发送数据...\n");// 获取串口互斥锁rt_mutex_take(uart_mutex, RT_WAITING_FOREVER);rt_kprintf("线程2: 🔒 获得串口锁,正在发送数据...\n");rt_device_write(uart_dev, 0, "Thread2: World\n", 15);rt_thread_mdelay(800); // 模拟发送时间rt_kprintf("线程2: 发送完成,释放串口锁\n");rt_mutex_release(uart_mutex); // 释放互斥锁rt_thread_mdelay(1500);}
}int mutex_uart_example(void)
{// 创建串口互斥锁uart_mutex = rt_mutex_create("uart_mutex", RT_IPC_FLAG_FIFO);rt_thread_t t1 = rt_thread_create("thread1", thread1_uart_send, RT_NULL, 1024, 20, 10);rt_thread_t t2 = rt_thread_create("thread2", thread2_uart_send, RT_NULL, 1024, 20, 10);rt_thread_startup(t1);rt_thread_startup(t2);return RT_EOK;
}MSH_CMD_EXPORT(mutex_uart_example, 互斥量保护串口示例);
