/** * @brief * @note None * @param Non...
Создано: 22 апреля 2025 г.
Создано: 22 апреля 2025 г.
/**
@brief
@note None
@param None
@retval None
*/
static void Task6_hongwai(void * pvParameters)
{
uint32_t flag_num,num;
for (;;)
{
//分自动模式还是手动模式
if(led_auto_mode == 1) //自动
{
textif( Hongwai_Read_Data() == 1 ) //判断有人的时候 { LED1(ON); flag_num++; } if(Hongwai_Read_Data() == 0) //判断无人的时候 { if(flag_num == 0)//如果一直 { led_close_flag = 0;//不亮 LED1(OFF); } else if(flag_num != 0)//如果人走了 { delay_us(10000); num++; if(num == 50)//10s后蜂鸣器鸣响,然后关灯 { LED1(OFF); BUZZER(ON) ; delay_us(300000); BUZZER(OFF) ; led_close_flag = 0; } } } }
}
vTaskDelay(100);
}
Here are a few things that jump out immediately when I read this FreeRTOS task. Let me know which of them (or something else entirely!) you actually want help with and I can dive deeper or supply a cleaned‑up version.
flag_num
and num
start with garbagecuint32_t flag_num, num; /* never initialised */
Because they’re automatic variables, whatever random bits were on the stack become their first value.
That means the very first compare—if (flag_num == 0)
—is undefined.
cuint32_t flag_num = 0; uint32_t num = 0;
(or make them static
if you want them to survive a task restart) fixes that.
vTaskDelay(100)
is unreachableThe infinite for (;;)
never ends, so that call is dead code.
You probably meant:
cfor (;;) { ... vTaskDelay(pdMS_TO_TICKS(100)); /* 100 ms */ }
(Always convert milliseconds with pdMS_TO_TICKS()
so it still works if configTICK_RATE_HZ
changes.)
delay_us(10000)
and delay_us(300000)
spin‑wait for 10 ms and 300 ms, blocking the whole core.
If you’re already inside FreeRTOS, use vTaskDelay()
(or vTaskDelayUntil()
) instead, so other tasks can run:
cvTaskDelay(pdMS_TO_TICKS(10)); /* 10 ms */
Inside the “no person” branch you increment num
every 10 ms. When it reaches 50 you turn the light off and beep. That’s 500 ms, not “10 s” as the comment says:
10 ms * 50 = 0.5 s
Did you mean:
cif (num == 1000) /* 10 ms × 1000 = 10 s */
or to let the scheduler sleep longer each loop?
continue;
) can make the nested if
blocks flatter.LED1(ON)
, BUZZER(ON)
) in small functions so the task looks like business logic.flag_num
→ presenceCount
, num
→ idleTicks
(or whatever the intent is).If led_auto_mode
or led_close_flag
are written from other tasks or interrupts, protect them with a mutex or make them volatile
and use critical sections.
If you’d like: I can
Just let me know which direction you want to go!
用中文
下面把之前提到的几个关键问题和改进建议全部用中文整理一遍,并附上一段更易读、逻辑更清晰的参考代码供你对比。若还有别的需求,随时告诉我!
flag_num
、num
未初始化局部变量如果不给初值,第一次比较 if(flag_num == 0)
的结果就是随机的。
解决:
cuint32_t flag_num = 0; uint32_t num = 0;
或者干脆改名并初始化(见下方示例代码)。
vTaskDelay(100)
放在死循环外,永远不会执行需要把延时放到 for (;;)
内部,并用 pdMS_TO_TICKS()
做毫秒到节拍的转换,以免以后改 configTICK_RATE_HZ
时出问题。
delay_us()
会导致忙等delay_us(10000)
(10 ms)和 delay_us(300000)
(300 ms)都在占用 CPU;
在 FreeRTOS 里最好用
cvTaskDelay(pdMS_TO_TICKS(10)); // 10 ms
让调度器把时间片让给别的任务。
你每 10 ms 给 num
加 1,if(num == 50)
触发时仅过去
10 ms × 50 = 500 ms
如果真要 10 s,可以把阈值改成 1000,或者把主循环延时改成更长。
flag_num
→ presenceCount
(检测到人的次数)num
→ idleTicks
(无人时计数的节拍)LED1(ON)
➜ turnLed1On()
,业务逻辑就一目了然。continue;
减少嵌套层级。若其他任务或中断也会改 led_auto_mode
、led_close_flag
,请加 volatile
并配合临界段或互斥量。
cstatic void Task6_hongwai(void *pvParameters) { uint32_t presenceCount = 0; // 统计检测到“有人”的次数 uint32_t idleTicks = 0; // 无人状态计数(10 ms 为 1 个 tick) for (;;) { if (led_auto_mode) // 自动模式 { if (Hongwai_Read_Data()) // 有人 { LED1(ON); presenceCount++; idleTicks = 0; // 重新计时 } else // 无人 { if (presenceCount == 0) // 从未检测到人 { led_close_flag = 0; LED1(OFF); } else // 人离开后计时 { idleTicks++; if (idleTicks >= 1000) // 10 ms × 1000 = 10 s { LED1(OFF); BUZZER(ON); vTaskDelay(pdMS_TO_TICKS(300)); // 蜂鸣 300 ms BUZZER(OFF); led_close_flag = 0; presenceCount = 0; idleTicks = 0; } } } } vTaskDelay(pdMS_TO_TICKS(10)); // 主循环 10 ms 一次 } }
改动要点
vTaskDelay
:让循环真正睡眠。vTaskDelay
取代 delay_us
:避免忙等。idleTicks >= 1000
。希望这份中文版说明能帮你快速定位和修正问题!如需进一步优化、事件驱动改写、竞态保护示例或别的支持,请告诉我。
/**
@brief 自动模式检测是否有人。无人
@note None
@param None
@retval None
*/
static void Task6_hongwai(void * pvParameters)
{
uint32_t presenceCount = 0; // 统计检测到“有人”的次数
uint32_t idleTicks = 0; // 无人状态计数(10 ms 为 1 个 tick)
for (;;)
{
if (led_auto_mode) // 自动模式
{
if (Hongwai_Read_Data()) // 有人
{
LED1(ON);
LED5(ON);
presenceCount++;
idleTicks = 0; // 重新计时
}
else // 无人
{
if (presenceCount == 0) // 从未检测到人
{
led_close_flag = 0;
LED1(OFF);
}
else // 人离开后计时
{
idleTicks++;
if (idleTicks >= 1000) // 10 ms × 1000 = 10 s
{
LED1(OFF);
BUZZER(ON);
vTaskDelay(pdMS_TO_TICKS(300)); // 蜂鸣 300 ms
BUZZER(OFF);
textled_close_flag = 0; presenceCount = 0; idleTicks = 0; } } } } vTaskDelay(pdMS_TO_TICKS(10)); // 主循环 10 ms 一次
}
}
为什么led5不会亮,led五是外接的到面包板的led
下面按常见排查顺序,把 LED5 不亮 最可能的几类原因和对应的自检方法列出来;照着一步步核对,基本都能定位问题。
检查项 | 典型症状 | 解决办法 |
---|---|---|
LED5( ON ) 宏到底是“置高”还是“置低”?<br>许多开发板自带 LED1/LED2 是 低电平点亮(把 GPIO 拉低让电流流向 VCC)。如果你直接把同样的宏复制给外接 LED,就会出现 LED1 亮、LED5 反而灭的情况。 | 用示波器/万用表量 LED5 对应的 IO:调用 LED5( ON ) 后电平是 0 V 还是 VCC?<br> - 若是 0 V 而你的外接 LED 是“阳极接 VCC、阴极接 IO”,就点不亮。 | - 改宏:把 GPIO_ResetBits() ↔ GPIO_SetBits() 对调,或者干脆写两套 LED5_ON() / LED5_OFF() <br> - 改接线:把 LED 调成与 LED1 相同的“阴极接 IO” |
GPIO 模式配置:是否在 bsp_gpio.c (或 MX_GPIO_Init)里把 LED5 引脚配置成 推挽输出? | 电平长期悬空或始终拉不动 | 在初始化里加:<br>GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; <br>GPIO_InitStruct.Pull = GPIO_NOPULL; <br>GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; |
时钟未开:对应的 GPIO 端口时钟 (__HAL_RCC_GPIOx_CLK_ENABLE ) 是否打开? | IO 始终不受控,始终保持上电后的默认态 | 确认 CubeMX/手写代码已使能 |
textVCC ──[限流电阻]──|>|── GPIO LED(阴极)
LED5(ON)
语句Hongwai_Read_Data()
抖动
LED5(ON)
放到任务最前面 (for (;;)
顶部) 直接常亮试一试,确认软件能点亮 LED。cfor(;;) { LED5(ON); vTaskDelay(pdMS_TO_TICKS(500)); LED5(OFF); vTaskDelay(pdMS_TO_TICKS(500)); }
LED1 能亮,LED5 不亮 最大概率就是 宏极性不匹配 或 GPIO 没正确初始化。
把 LED5( ON ) 宏展开,看是GPIO_ResetBits
还是GPIO_SetBits
,再对照实际接线方向,就能解决 90% 的“面包板外接 LED 不亮”问题。
如果按上述步骤还有疑问,把 LED5 宏定义代码、CubeMX 引脚截图 或 实物接线照片 发过来,我帮你进一步诊断。
#define LED5(X) ((X)?(PBout(8)=0):(PBout(8)=1))
从这条 #define
可以看出两件关键信息:
c#define LED5(X) ((X)?(PBout(8)=0):(PBout(8)=1)) ▲ ▲ │ └─ 传入 1 时把 PB8 拉低 └─── 传入 0 时把 PB8 拉高
LED5(ON)
(ON
一般定义成 1)→ PBout(8) = 0
LED5(OFF)
(OFF
一般是 0)→ PBout(8) = 1
因此 PB8 被设计成灌电流输出:
LED 阴极接 PB8,阳极(通过限流电阻)接 3 V 或 3.3 V。
如果你的面包板 LED 接成了“阳极接 IO、阴极接地”(即要高电平才亮),那它永远收不到 3 V,就会不亮。
步骤 | 目的 | 如何做 |
---|---|---|
① 检查接线方向 | 确认极性 | 把 LED 的 长脚(阳极) 接 3 V → 电阻 → 短脚(阴极) 接 PB8。 |
② 测 PB8 电平 | 确认宏生效 | 在代码里反复调用<br>LED5(ON); delay_ms(500); LED5(OFF); delay_ms(500); <br>万用表量 PB8:ON 时≈0 V,OFF 时≈3.3 V。 |
③ 确认 PB8 已配置为推挽输出 | 排除 AF/I2C 影响 | 如果用的是 STM32,PB8 默认可能是 I^2C1_SCL(开漏)。<br>- 在 MX_GPIO_Init() 或手写初始化里加:<br>c<br>GPIO_InitStruct.Pin = GPIO_PIN_8;<br>GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;<br>GPIO_InitStruct.Pull = GPIO_NOPULL;<br>GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;<br>HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);<br> |
把宏改成:
c#define LED5(X) ((X)?(PBout(8)=1):(PBout(8)=0))
同时把 LED 阳极接 PB8、阴极经电阻接地。
结论:你的宏明确是“低电平点亮”。只要把 LED 以“阳极→电阻→3V3,阴极→PB8”的方式接好,并确保 PB8 已配置为推挽输出,就能正常点亮。如果接反或仍用 I^2C 功能复用,就会出现 LED1 亮但 LED5 不亮的现象。