V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ALLROBOT
V2EX  ›  程序员

嵌入式单片机 Arduino,在 loop 函数内多次使用过滤器会输出异常?

  •  
  •   ALLROBOT · 2022-04-13 20:19:48 +08:00 · 1275 次点击
    这是一个创建于 954 天前的主题,其中的信息可能已经有所发展或是发生改变。

    说明

    如果 loop 只运行一个模拟引脚,并且使用一个过滤器,即可正常输出( 0~500 ),但是创建数组储存多个过滤后的模拟引脚数值就有问题了,输出异常(1000~20000)

    输出正常的代码

    #include "EMGFilters.h"
    const int SensorInputPin[] = {A0, A1, A2, A3, A4, A5};
    EMGFilters myFilter;
    SAMPLE_FREQUENCY sampleRate = SAMPLE_FREQ_500HZ;
    NOTCH_FREQUENCY humFreq = NOTCH_FREQ_50HZ;
    void setup() 
    {
      myFilter.init(sampleRate, humFreq, true, true, true);
      Serial.begin(115200);
    }
    void loop() 
    {
        Serial.println(square(myFilter.update(analogRead(SensorInputPin[0]))));
    }
    long unsigned int square(unsigned int x)
    {
        return (x * x);
    }
    

    正常输出

    2022-04-13--16-59-08_fps=8_scale=720_max_colors=128|404x500

    输出异常的代码

    只修改 loop

    void loop()
    {
        int envelops[12] = {0};
        for (int i = 0; i < 2; i++)
        {
            for (int x = 0; x < 6; x++)
            {
                envelops[i * 6 + x] = square(myFilter.update(analogRead(SensorInputPin[x])));
            }
            delayMicroseconds(50);
            Serial.println(envelops[i * 6 + 1]);
        }
    }
    

    异常输出

    检查

    我搞不懂了,逐次打印看看变量名

    void loop() 
    {
        int envelops[12];
        for (int i = 0; i < 2; i++)
        {
            int ii = 0;
            for (int x = 0; x < 6; x++)
            {
                Serial.printf("i:%d  x:%d\n", i, x);
                envelops[((i * 6) + x)] = square(myFilter.update(analogRead(SensorInputPin[x])));
                Serial.printf("Output:%d index: %d\n", envelops[((i * 6) + x)], ((i * 6) + x));
            }
            ii++;
            delay(1000);
        }
    
    }
    long unsigned int square(unsigned int x) {
        return (x*x);
    }
    

    输出

    搞不明白,咋输出上万的值了呢?

    再看看正常输出的

    void loop() 
    {
        int x1= square(myFilter.update(analogRead(SensorInputPin[0])));
        Serial.printf("analogRead:%d\n",analogRead(SensorInputPin[0]));
        Serial.printf("output:%d\n",x1);
        delay(1000);
    
    }
    

    输出

    这很正常啊,怎么一用 for 循环函数就有问题了😂

    然后尝试

    void loop() 
    {
        int x1= square(myFilter.update(analogRead(SensorInputPin[0])));
        int x2=square(myFilter.update(analogRead(SensorInputPin[1])));
        int x3=square(myFilter.update(analogRead(SensorInputPin[2])));
        int x4=square(myFilter.update(analogRead(SensorInputPin[3])));
        int x5=square(myFilter.update(analogRead(SensorInputPin[4])));
        int x6= square(myFilter.update(analogRead(SensorInputPin[5])));
            Serial.printf("analogRead:%d\n",analogRead(SensorInputPin[0]));
        Serial.printf("output:%d\n",x1);
        delay(1000);
    
    }
    

    输出

    发现原本输出动辄几万的,已经下降到一千左右了,但仍然是异常输出

    过滤器就是一个函数计算输出的,怎么调用的时候出现问题了?

    loop 仅用一条指令Serial.println(square(myFilter.update(analogRead(每个模拟引脚输入)))),正常输出 0~500 的值,如果用多个变量或 for 啥,就输出上万的值了。。。我尝试创建多个过滤器,给每个输入单独用Filter1,Filter2等等,问题依旧。。。

    过滤器代码链接:https://github.com/oymotion/EMGFilters/blob/master/EMGFilters.cpp

    咋解决啊😂

    第 1 条附言  ·  2022-04-14 00:10:10 +08:00
    尝试一个个的增加过滤器以及模拟引脚,输出第一个和第二个没什么问题

    ```C
    \\略
    EMGFilters out1;
    out1.init(sampleRate, humFreq, true, true, true);
    \\略
    void loop()
    {
    int x[2]= {square(out1.update(analogRead(SensorInputPin[0]))), square(out2.update(analogRead(SensorInputPin[1])))};
    Serial.printf("%d %d\n", x[0], x[1]);
    }
    ```




    我发现模拟输入当增加到第三个时输出异常

    ```C
    void loop()
    {
    int x[3]= {square(out1.update(analogRead(SensorInputPin[0]))), square(out2.update(analogRead(SensorInputPin[1]))), square(out3.update(analogRead(SensorInputPin[2])))};
    Serial.printf("%d %d %d\n", x[0], x[1], x[2]);
    }
    ```



    loop 函数只使用第三个模拟输入,不使用其它模拟引脚的过滤器转换输出,是正常输出的

    Eiden
        1
    Eiden  
       2022-04-13 20:33:21 +08:00
    每一路输入都需要新建一个过滤器对象吧
    ALLROBOT
        2
    ALLROBOT  
    OP
       2022-04-13 20:39:42 +08:00
    @Eiden #1 我曾经尝试这么做,EMGFilters myFilters[6]; 先初始化然后在 loop 使用 envelops[i * 6 + x] = square(myFilters[x].update(analogRead(SensorInputPin[x])));,问题依旧
    Eiden
        3
    Eiden  
       2022-04-13 20:40:01 +08:00
    @Eiden #1 没看到后面...
    villivateur
        4
    villivateur  
       2022-04-13 21:15:10 +08:00
    具体是什么单片机啊?如果有 FPU 的话尝试把 FPU 关掉试试看
    ALLROBOT
        5
    ALLROBOT  
    OP
       2022-04-13 22:08:12 +08:00
    @villivateur #4 用的 Seeeduino XIAO

    微控制器 XIAO 一般说明: https://wiki.seeedstudio.com/Seeeduino-XIAO/

    微控制器 XIAO 说明手册: https://files.seeedstudio.com/wiki/Seeeduino-XIAO/res/ATSAMD21G18A-MU-Datasheet.pdf

    我是硬件半吊子的,所以才学 Arduino😂,图它 Arduino 原型设计快的,我不知道 XIAO 的 MCU 是否有 FPU
    ALLROBOT
        6
    ALLROBOT  
    OP
       2022-04-14 00:13:23 +08:00
    @Eiden #1 @villivateur #4 发现在 loop 函数使用 1,2 个传感器的过滤器,是正常输出的,但增加过滤器时就异常输出了

    是单片机自己的问题吗?实在解决不了,推荐啥 Arduino 采集 MCU ?😂在 XIAO 浪费了太多时间
    DataSheep
        7
    DataSheep  
       2022-04-14 08:23:51 +08:00 via iPhone
    跟单片机应该没关系,每个滤波器新建一个实例对象是应该的,另外这个滤波器库既然有采样频率参数你应该需要控制采样间隔,好像没看到有写,注意滤波计算也是需要毫秒级时间的,根据运算能力差异非常大。根据你的描述很可能是这个原因。

    btw ,这个东西你好像捣鼓蛮久了😀
    ALLROBOT
        8
    ALLROBOT  
    OP
       2022-04-14 11:42:01 +08:00
    @DataSheep #7 不好意思,嵌入式很少涉及(没学过数电模电),每月只有几天的空闲时间来研究 Arduino 的,没能折腾出什么结果

    https://gist.github.com/allrobot/1d105671a5186adb792bfbc5d8bd5030

    我曾经为每个输出添加 500 微秒、1 毫秒、或 5 毫秒来控制采样频率,但均为输出异常😂



    上面的黄线似乎是随机的,如果 index 为 4 个,即输出 4 个滤波计算的值,第 2 ,4 个输出异常; index 为 3 个的话,第 3 个输出异常; index 再次为 4 个,第 3 个和第 4 个模拟引脚输出异常。。。
    sujin190
        9
    sujin190  
       2022-04-14 13:38:42 +08:00
    不滤波也异常的那那就是读取问题?似乎看不出来是滤波异常还是读取异常啊
    ALLROBOT
        10
    ALLROBOT  
    OP
       2022-04-14 14:51:26 +08:00
    @sujin190 #9 两个开发板都试了,每个 ADC 读数都不一致,应该是读数的问题
    DataSheep
        11
    DataSheep  
       2022-04-14 15:01:54 +08:00 via iPhone
    @ALLROBOT 你没理解我意思,你既然选择的频率是 500 ,那么采样间隔需要控制在 2 毫秒。
    也就是 update 间隔需要严格控制在 2 毫秒,而且一般也是用定时器中断来控制,不过 arduino 一般不用中断。所以如果你要用我 delay 来控制采样间隔的话,需要把函数运行时间也加进去,那么延时时间会在 0-2 毫秒之间,具体需要计算一下你的函数运行时间是多久。
    darkengine
        12
    darkengine  
       2022-04-14 21:32:01 +08:00
    应该把 square(myFilter.update(analogRead(SensorInputPin[x]))) 这里每个调用的中间结果打出来,才知道是哪个函数调用出的问题吧。
    ALLROBOT
        13
    ALLROBOT  
    OP
       2022-04-14 22:17:41 +08:00
    @DataSheep #11 这样的话,也只是在 loop 函数加 long time=millis();在执行过滤器语句的下面( loop 函数末尾)增加 while((millis()-time)<2){delayMicroseconds(100);}

    对于异常输出没有什么太大改善

    就这样暂时将就吧,肌肉运动能看到一点起伏
    DataSheep
        14
    DataSheep  
       2022-04-14 22:30:19 +08:00 via iPhone
    @ALLROBOT 如果还有问题,确认 ad 读取没问题的话滤波函数可以自己写的。
    这东西看你踩的坑太多了,不如上个树莓派用 python 早搞定了
    ALLROBOT
        15
    ALLROBOT  
    OP
       2022-04-14 22:36:25 +08:00
    @darkengine #12 7 小时前用 analogread 函数读数已经检测出问题所在,是 ADC 读数不一致产生了问题



    只要连续读取 A0 ,A1 模拟引脚没问题,连续读取 A0,A1,A2,A3,A4 就产生了问题,不知道为啥
    ALLROBOT
        16
    ALLROBOT  
    OP
       2022-04-14 22:43:29 +08:00
    @darkengine #12 噢,好吧,收回之前的话,这是中午的测试图,现在的测试图如下:


    Serial.printf("%d %d %d %d %d %d\n",analogRead(A0),analogRead(A1),analogRead(A2),analogRead(A3),analogRead(A4),analogRead(A5));

    模拟输出太莫名其妙了。。。中午的电路接线结构没啥变动,到了现在输出乱七八糟了😂


    @DataSheep #14 也许你说得对。。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   969 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 20:10 · PVG 04:10 · LAX 12:10 · JFK 15:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.