我是嵌入式开发的新手,很久以前我发布了一些关于PIC24xxxx的代码。
void i2c_Write(char data) {
while (I2C2STATbits.TBF) {};
IFS3bits.MI2C2IF = 0;
I2C2TRN = data;
while (I2C2STATbits.TRSTAT) {};
Nop();
Nop();
}
您如何看待 while 条件?微芯片没有使用大量CPU吗?
我问自己这个问题,并在网上看到了很多类似的代码。
有没有更好的方法呢?
Nop()
怎么样,为什么还有两个?
答案 0 :(得分:3)
通常,为了与硬件进行交互,有两种方法:
在您的情况下,为了与I2C器件进行交互,您的软件首先等待TBF位清零,这意味着I2C器件已准备好接受要发送的字节。 然后,您的软件实际上是将字节写入器件并等待TRSTAT位清零,这意味着您的I2C器件已正确处理数据。
您显示的代码是使用忙等待循环编写的,这意味着CPU正在主动等待HW。这确实是浪费资源,但在某些情况下(例如,您的I2C中断线未连接或不可用),这是唯一的方法。
如果您使用中断,您会要求硬件在发生特定事件时告诉您。例如,TBF位清零等... 这样做的好处是,虽然硬件正在做它的东西,你可以继续做其他事情。或者只是睡觉以节省电池。
我不是I2C方面的专家,所以我所描述的中断事件很可能不准确,但是这可以让你知道为什么你得到2循环。
现在关于中断基本实现和忙等待实现的优缺点,我会说基于中断的实现更有效但更难编写,因为你必须处理来自HW的异步事件。繁忙的等待实现很容易写,但速度较慢;但这对你来说可能还是足够快。
最终,我不知道为什么那里需要2个NoP。很可能需要进行调整,因为不知何故,CPU仍会过快。
答案 1 :(得分:1)
在进行这类交易时(i2c / spi),您会发现自己处于两种情况之一,即爆炸或某种形式的硬件辅助。 bit bang更容易实现,读取和调试,并且通常可以从一个芯片/系列移植到下一个芯片/系列。但烧掉了很多cpu。但微控制器主要是定制硬件,如cpld或fpga,更容易编程。他们在那里烧掉假装是硬件设计的cpu周期。使用i2c或spi,您试图在器件上的某些I / O引脚上创建特定波形,并有时锁存输入。总线有一个规格,有时比你的CPU慢。有时候没有,有时当你添加软件和编译器开销时,你可能最终不需要计时器来延迟,你可能只是足够慢。但理想情况下,您可以查看波形并创建它,将引脚X延迟n ms,引脚Y延迟n ms,引脚Y延迟2 * n ms,依此类推。这些延迟可以来自调谐循环(从0到1341计数)或轮询定时器,直到它达到某个时钟的Z个滴答数。大量的CPU浪费,但关键是你真的只是可编程的硬件和硬件也会等待等待。
如果你的mcu中有一个外设可以帮助它可能会为你做很多/大部分时间但可能不是全部,可能你必须断言/取消置位芯片选择然后spi逻辑执行时钟和数据为您安排时间。这些外设通常非常特定于一个芯片供应商的一个系列,可能在芯片供应商中很常见,但从不供应商供应商,因此非常不便携,并且存在学习曲线。也许在你的情况下,如果cpu足够快,你可能会以违反公交车时间的方式做下一件事,所以你必须要花更多的时间(也许你为什么要有那些Nops())
将mcu视为软件可编程CPLD或FPGA,这种浪费更有意义。不幸的是,与CPLD或FPGA不同,你是单线程的,所以你不能在时钟精确定时的同时做几件微不足道的事情(正是这么多时钟任务一个开关状态并改变输出)。中断有用但不完全相同,更改一行代码和时间更改。
在这种情况下,特别是使用nops,您可能应该使用示波器来查看i2c总线,并且当您在示波器上使用它时可以尝试使用和不使用这些调用以查看它如何影响波形。它也可能是外设中的一个错误或一个功能,也许你不能太快打中一些寄存器,否则外围设备会中断。或者它可能是5年前芯片中的一个错误而且编写的代码是因为bug早已不复存在,但他们只是不断重复使用代码,你会在供应商库中看到很多。
答案 2 :(得分:0)
您如何看待这种状况?微芯片没有使用大量CPU吗?
不,因为发送缓冲区不会长时间保持满状态。
我问自己这个问题,并在网上看到了很多类似的代码。
你会建议什么?
有没有更好的方法呢? (我讨厌疯狂的循环:D)
不是我,你,或者显然是其他任何人都知道的。你认为它会以什么方式变得更好?发送缓冲区不会保持足够长的时间,以便重新调用CPU。
Nop()也是如此,为什么还有两个呢?
Nop确保信号保持稳定足够长的时间。这使得在所有条件下都可以安全地调用此代码。没有它,如果你在调用之后没有立即弄乱i2c总线,那么调用这段代码是安全的。但在大多数情况下,无论如何都会在循环中调用此代码,因此使其本身安全更有意义。