如果你的蜂鸣器任务是定期执行的(例如每100毫秒调用一次),那我们可以用状态机来避免使用阻塞式的延时函数。通过在每次任务调用时检查蜂鸣器的状态、时间来实现非阻塞的控制逻辑。
下面是基于状态机的蜂鸣器驱动程序,适合在周期性任务中调用。
示例代码(非阻塞方式)
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
// 假设蜂鸣器连接到某个GPIO引脚上,例如GPIO_PIN
#define BUZZER_PIN 5
// 蜂鸣器状态
typedef enum {
BUZZER_OFF, // 蜂鸣器关闭状态
BUZZER_ON // 蜂鸣器开启状态
} buzzer_state_t;
// 蜂鸣器控制结构体
typedef struct {
buzzer_state_t state; // 当前蜂鸣器状态
uint32_t on_time_ms; // 蜂鸣器鸣叫持续时间
uint32_t off_time_ms; // 蜂鸣器关闭持续时间
uint32_t repeat_count; // 剩余重复次数
uint32_t elapsed_time_ms; // 当前状态已持续的时间
} buzzer_control_t;
// 初始化蜂鸣器控制器
void buzzer_init(buzzer_control_t* buzzer, uint32_t on_time_ms, uint32_t off_time_ms, uint32_t repeat_count) {
buzzer->state = BUZZER_OFF; // 初始状态为关闭
buzzer->on_time_ms = on_time_ms;
buzzer->off_time_ms = off_time_ms;
buzzer->repeat_count = repeat_count;
buzzer->elapsed_time_ms = 0;
}
// 模拟GPIO引脚操作,单片机上需要替换为实际GPIO设置函数
void gpio_set_level(uint8_t pin, uint8_t level) {
// 在此处添加设置GPIO引脚高或低电平的代码
printf("Setting pin %d to level %d\n", pin, level);
}
// 蜂鸣器状态机控制,每次调用该函数进行一次状态更新
void buzzer_update(buzzer_control_t* buzzer, uint32_t delta_time_ms) {
if (buzzer->repeat_count == 0) {
// 如果重复次数为0,保持关闭状态
gpio_set_level(BUZZER_PIN, 0);
return;
}
// 增加已持续时间
buzzer->elapsed_time_ms += delta_time_ms;
switch (buzzer->state) {
case BUZZER_ON:
if (buzzer->elapsed_time_ms >= buzzer->on_time_ms) {
// 如果已达到开启时长,关闭蜂鸣器并进入关闭状态
gpio_set_level(BUZZER_PIN, 0);
buzzer->state = BUZZER_OFF;
buzzer->elapsed_time_ms = 0; // 重置计时
}
break;
case BUZZER_OFF:
if (buzzer->elapsed_time_ms >= buzzer->off_time_ms) {
// 如果已达到关闭时长,且还有剩余次数,开启蜂鸣器并进入开启状态
gpio_set_level(BUZZER_PIN, 1);
buzzer->state = BUZZER_ON;
buzzer->elapsed_time_ms = 0; // 重置计时
buzzer->repeat_count--; // 减少剩余次数
}
break;
}
}
int main() {
buzzer_control_t buzzer;
// 初始化蜂鸣器:鸣叫100ms,静音200ms,重复5次
buzzer_init(&buzzer, 100, 200, 5);
// 模拟每100ms调用一次的任务
uint32_t delta_time_ms = 100;
for (int i = 0; i < 100; i++) { // 模拟100次任务调用(即100*100ms = 10s)
buzzer_update(&buzzer, delta_time_ms);
// 模拟任务调度器延时100ms,实际应用中不需要
}
return 0;
}
解释
-
状态机实现:通过
buzzer_state_t
定义两个状态:BUZZER_ON
和BUZZER_OFF
,来分别表示蜂鸣器的开启和关闭状态。每次任务调用时,根据当前状态和经过的时间决定是否切换状态。 -
非阻塞控制:每次调用
buzzer_update()
时,传递经过的时间delta_time_ms
(例如100ms),通过累加计时实现蜂鸣器的控制。不会阻塞主程序的其他任务,适用于定时任务调度器。 -
定时调用:
buzzer_update()
应由一个定期执行的任务调用,例如每100ms一次。你只需要确保在每次调用时传入的delta_time_ms
代表任务的周期时间。
这种设计不会因为延时阻塞主程序的运行,能够很好地与其他实时任务共享CPU时间。
如果你在实际应用中需要更复杂的逻辑,比如暂停或手动控制启动,可以在状态机的基础上进一步扩展功能。