硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1020|回复: 5
收起左侧

[FreeRTOS] freertos下的蜂鸣器发声问题

[复制链接]

1

主题

3

回帖

6

积分

新手上路

积分
6
发表于 2024-12-2 11:13:22 | 显示全部楼层 |阅读模式
本帖最后由 lamplight 于 2024-12-2 11:19 编辑

平台:stm32l071 cortex-M0+
背景:原本项目是使用裸机跑,现在修改为freertos跑。问题出现在蜂鸣器发声那里,蜂鸣器的发声是用TIM6基本定时器的的定时器去翻转波形生成一个pwm,周期为400us,加入freertos后,发声就变得奇怪,有那种断断续续的感觉。
测试:我这边测试发现,在发声函数(设置pwm持续时间,等待定时器的持续时间到)里面加了挂起全部任务也不行,后面发现,将任务数量减少,任务的执行频率拉长就会改善这个问题,目前猜测是上下文切换导致频繁开关中断,各位有什么看法

发声函数大概裸机如下:

void buzzer_setTone(u32 times, u32 buzzer_freq)
{
    //设置频率,持续时间参数
    vTaskSuspendAll();
    buzzer_time = times;
    TIM6->CNT = buzzer_freq;

    //等待发声完毕
    while(buzzer_ToneWork);
    xTaskResumeAll();
}


回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115434
QQ
发表于 2024-12-2 11:29:53 | 显示全部楼层
这个驱动实现不太好。还是个阻塞式的,可以参考下我们的bsp_beep.c
回复

使用道具 举报

2

主题

65

回帖

71

积分

初级会员

积分
71
发表于 2024-12-2 11:45:29 | 显示全部楼层
定时器翻转不太好,最好用pwm外设,中断打断不影响发声频率
回复

使用道具 举报

1

主题

3

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 2024-12-3 19:24:17 | 显示全部楼层
今天看到回复,就想去用定时器输入捕获生成pwm。奈何开会的时候被否了,原因是要改硬件
然后自己排查发现问题所在:
我用的是定时器翻转生成pwm,并且我是用的是M0+内核的处理器,M0+内核没有可屏蔽中断处理器BASEPRI,所以设置无法设置可管理中断。查看freertos的源码发现,上下文的切换全都是开关总中断(__disable_irq和__enable_irq)。所以这就可以解释为什么任务频率设置的越快,蜂鸣器发声越断断续续。
目前采用在定时器中断里面增加了一个发声结束的标志位。伪代码如下:
void TIM6_IRQHandler(void)
{
        //是否开启蜂鸣器
        if(work_enable)
        {
               
                IO_TOGGLE();
                //计算频率,周期
                //
                //
                //
        }
       
        //次数计算
        if(time-- == 0)
        {
                //结束
                stop_flag = 1;
        }
}

void beef_start()
{
        //开始发声
        //开启中断
       
        vTaskSuspendAll();
        while(stop_flag == 0);
        xTaskResumeAll();
}
这种做法在发声的时候会卡主一段时间,发声结束才会继续。这种做法感觉不太好,能将就将就。
我想的是,如果重新封装__disable_irq和__enable_irq,在里面只关闭systick的中断,这样定时器不就不会受到影响了吗?这样可行吗,感觉工作量有点大
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
115434
QQ
发表于 2024-12-4 10:03:36 | 显示全部楼层
lamplight 发表于 2024-12-3 19:24
今天看到回复,就想去用定时器输入捕获生成pwm。奈何开会的时候被否了,原因是要改硬件
然后自己排 ...

这个地方修改下
vTaskSuspendAll();
        while(stop_flag == 0);
        xTaskResumeAll();

不要这样思路,这个还是裸机式的用法。可以弄个信号量等待。
回复

使用道具 举报

1

主题

3

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 2024-12-4 13:33:24 | 显示全部楼层
现在只能用裸机的方式了,不然切换任务会导致开关中断影响到pwm输出
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-4-26 00:26 , Processed in 0.250791 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表