我使用的是 Fosc = 10MHz 的 PIC18。因此,如果我使用 Delay10KTCYx(250),我得到 10,000 x 250 x 4 x (1/10e6) = 1 秒。
如何使用 C18 中的延迟功能进行很长的延迟,比如 20 秒?我正在考虑只使用二十行Delay10KTCYx(250)。还有另一种更高效、更优雅的方式吗?
提前致谢!
强烈建议您避免使用内置延迟函数,例如 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 获得更准确的计时方式以及更可预测的行为。使用预装的延迟函数是灾难的根源......它可能会起作用......它可能适用于多个项目......但迟早你的代码会在你身上出现所有错误,你会想知道为什么和我保证罪魁祸首将是预装延迟功能。
要创建很长时间,请使用内部计时器。这有助于避免应用程序中的阻塞,并且您可以检查运行时间。有关如何设置定时器及其中断的信息,请参阅 PIC 数据手册。
如果您想要一个非常高精度的 1S 时间,我建议您也考虑一个外部 RTC 设备或如果微型有一个内部 RTC。