0

所以,我是 C 的新手,来自 Java/C# 背景,到目前为止我还不能完全理解它。

我要做的是对微控制器(在这种情况下运行 atmega32u4 的 Adafruit Feather)进行编程,以充当 Nintendo Switch 的 USB 耦合控制器并运行自动命令。

我试图扩展的项目是使用这样的命令结构数组:

typedef struct {
    Buttons_t button;
    uint16_t duration; // 1 equals 0.025s on ATmega32u4 => 1s = 40
} command;

static const command loop[] = {
    // do stuff
                        { NOTHING,  150 },
    { TRIGGERS,   15 }, { NOTHING,  150 },
    { TRIGGERS,   15 }, { NOTHING,  150 },
    { A,          5 },  { NOTHING,  250 }
};

现在最初这就是它的全部内容,程序将循环执行命令,向控制台发送一个按钮并在定义的时间段内“按住”它。当程序运行到数组的末尾时,它会简单地重置索引并重新开始。

现在我正在尝试基于一些简单的 if..else 查询向控制台发送不同的命令。具体来说,该程序将从日、月和年变量(Switch 控制台当前设置的日期)开始,并分别向前滚动天以到达未来的设定日期。为此,我想在每个“步骤”检查日期 +1 天是否有效,如本教程中所述,并根据结果滚动一天、一天和一个月或一天、一个月和一年向前。然后我希望它在设定的天数后结束。

我编写了几个命令数组来表示设置控制器所需的不同步骤,移动到它应该循环的地方,滚动一天,一个月或一年,如下所示:

static const command setupController[] = {
    // Setup controller
    ...
};

static const command moveToLoop[] = {
    // Go into date settings
    ...
};

static const command rollDay[] = {
    //roll to next day
    ...
};

static const command rollMonth[] = {
    //roll to next month
    ...
};

static const command rollYear[] = {
    //roll to next year
    ...
};

我想将另一个数组复制成这样:

#define COMMANDMAXSIZE 100
static command activeCommand[COMMANDMAXSIZE];

我知道这(非常)浪费内存,但我在 C 语言方面肯定还不够好,无法提出更漂亮、更保守的解决方案。

然后我进入我的程序,它看起来像这样:

int main(void) {
    SetupHardware(); //Irrelevant, because it is exactly like I downloaded it and it works even with the bumbling changes I've made
    GlobalInterruptEnable(); //Ditto

    RunOnce(setupController);

    RunOnce(moveToLoop);

    while (daysSkipped != stopDay)
    {
        if (datevalid((dayOfMonth + 1), month, year)) {
            dayOfMonth++;
            RunOnce(rollDay);
        }
        else if (datevalid(1, (month + 1), year)) {
            dayOfMonth = 1;
            month++;
            RunOnce(rollMonth);
        }
        else if (datevalid(1, 1, (year + 1))) {
            dayOfMonth = 1;
            month = 1;
            year++;
            RunOnce(rollYear);
        }

        daysSkipped++;
    }
}

最后(我发誓我很快就会完成),RunOnce 的开始看起来像这样

void RunOnce(command stepsToRun[]) {
    memcpy(activeCommand, stepsToRun, sizeof(activeCommand)); //set the setup commands to be active
    activeBounds = sizeof(stepsToRun) / sizeof(stepsToRun[0]);
    ...

在程序的后期,将命令转换为控制台按钮按下的任务实际上运行一个固定数组,所以我想我只是将命令“标记”为活动运行,并且只运行活动数组。只是,它没有按预期工作:

程序运行,设置控制器,移动到日期设置并确实开始滚动日期,但是,无论第二天是否有效,它都会前滚一个月,然后是一年,然后它会卡住移动向上模拟模拟摇杆并无限期按下 A。

我认为问题在于我的 memcpy 用我接下来要运行的步骤覆盖活动数组,但我想不出解决它的方法。我尝试编写一个函数,该函数应该使用 for 循环逐个元素覆盖活动数组元素,但这样控制器甚至不会正确设置自己,实际上什么也没发生。通常使用任何类型的输出功能,我都会尝试在感兴趣的点进行打印,但我几乎无法获得关于我的微控制器的反馈。

任何帮助将不胜感激。

4

2 回答 2

1

忽略对数据进行硬拷贝是非常缓慢和浪费的,这确实也是不正确的。

memcpy(activeCommand, stepsToRun, sizeof(activeCommand));

这里你需要复制你传递的数据的大小,而不是目标缓冲区的大小!现在你最终复制的数据比你拥有的更多,因为所有这些声明static const command rollDay[]等都会根据初始化列表中的项目数获得可变大小。

解决您当前问题的快速而肮脏的方法是传递大小:

void RunOnce(size_t size, command stepsToRun[size])
{
    memcpy(activeCommand, stepsToRun, size);

然后用RunOnce(sizeof rollDay, rollDay);etc调用这个函数。

activeBounds = sizeof(stepsToRun) / sizeof(stepsToRun[0]);部分也是不正确的,但不是错误的直接原因。请参阅如何找到“sizeof”(指向数组的指针)?什么是指针衰减数组?等等

于 2020-05-13T14:01:54.690 回答
0

当您将数组传递给函数时,它会衰减为指针。

    RunOnce(rollYear);

因此

void RunOnce(command stepsToRun[]) {
    memcpy(activeCommand, stepsToRun, sizeof(activeCommand)); //set the setup commands to be active
    activeBounds = sizeof(stepsToRun) / sizeof(stepsToRun[0]);
}

sizeof(stepsToRun)不会产生您预期的正确结果,因为它现在sizeof(pointer)正在运行。

您必须将数组的大小作为额外参数传递给RunOnce函数。

于 2020-05-13T14:01:24.127 回答