0

我使用的是 Fosc = 10MHz 的 PIC18。因此,如果我使用 Delay10KTCYx(250),我得到 10,000 x 250 x 4 x (1/10e6) = 1 秒。

如何使用 C18 中的延迟功能进行很长的延迟,比如 20 秒?我正在考虑只使用二十行Delay10KTCYx(250)。还有另一种更高效、更优雅的方式吗?

提前致谢!

4

2 回答 2

2

强烈建议您避免使用内置延迟函数,例如 Delay10KTCYx()

为什么你可能会问?

这些延迟函数非常不准确,它们可能会导致您的代码以意想不到的方式编译。这是一个这样的示例,其中使用 Delay10KTCYx() 函数可能会导致问题。

假设您有一个只有两个硬件定时器中断的 PIC18 微处理器。(通常他们有更多,但我们只是说只有两个)。

现在假设您手动将第一个硬件定时器中断设置为每秒闪烁一次,以驱动心跳监视器 LED。假设您将第二个硬件定时器中断设置为每 50 毫秒中断一次,因为您想在 50 毫秒内进行某种数字或模拟读数。

现在,最后,假设在您的主程序中您想要延迟 100,000 个时钟周期。因此,您在主程序中调用了 Delay10KTCYx(10)。你猜会发生什么?PIC18 如何神奇地计算 100,000 个时钟周期?

会发生两件事之一。它可能会“劫持”您的其他硬件定时器中断之一以获得正好 100,000 个时钟周期。这可能会导致您的心跳传感器无法准确计时 1 秒,或者导致您的数字或模拟读数发生在每 50 毫秒以外的某个时间。

或者,延迟函数只会调用一堆 Nop() 并声称 1 Nop() = 1 个时钟周期。没有考虑的是 Delay10KTCYx(10) 函数本身的“开销”。它必须增加一个计数器来跟踪事物,并且肯定需要超过 1 个时钟周期来增加计时器。由于 Delay10KTCYx(10) 不断循环,它无法为您提供正好 100,000 个时钟周期。根据许多因素,您可能会获得比预期更多或更少的时钟周期。

只有在您需要“近似”时间量时才应使用 Delay10KTCYx(10)。如果您已经将硬件定时器中断用于其他目的,则不应使用预先设定的延迟功能。当使用 Delay10KTCYx(10) 进行很长的延迟时,编译器甚至可能无法成功编译。

我强烈建议您设置一个计时器中断,以以已知的时间间隔中断您的硬件。假设 50,000 个时钟周期。然后,每次硬件中断时,在该定时器中断的 ISR 代码中,递增一个计数器并将定时器再次重置为 0 个周期。当足够的 50,000 个时钟周期到期等于 20 秒时(或者换句话说,在您的示例中,200 个定时器中断,每个中断 50,000 个周期),重置您的计数器。基本上我的建议是,您应该始终手动处理 PIC 中的时间,而不是依赖预先设定的延迟功能 - 而是构建您自己的延迟功能,集成到芯片的硬件计时器中。是的,这将是一项额外的工作——“但是为什么我不能使用这个简单而漂亮的内置延迟功能,如果有的话,他们为什么还要把它放在那里呢?”无论您是否使用它,都应该在启动时手动配置 PIC18 中的每个寄存器,以防止发生意外情况。

您将从 PIC18 获得更准确的计时方式以及更可预测的行为。使用预装的延迟函数是灾难的根源......它可能会起作用......它可能适用于多个项目......但迟早你的代码会在你身上出现所有错误,你会想知道为什么和我保证罪魁祸首将是预装延迟功能。

于 2015-09-29T15:24:35.893 回答
0

要创建很长时间,请使用内部计时器。这有助于避免应用程序中的阻塞,并且您可以检查运行时间。有关如何设置定时器及其中断的信息,请参阅 PIC 数据手册。

如果您想要一个非常高精度的 1S 时间,我建议您也考虑一个外部 RTC 设备或如果微型有一个内部 RTC。

于 2015-10-03T12:20:25.420 回答