研究AVR时,看到一段用内联汇编写的延时程序,于是想着记录下来。当然,我肯定看不懂,但好在现在有ai这种神器,帮助我学习和理解。
void
_delay_loop_1(uint8_t __count)
{
asm volatile (
"1: dec %0" "\n\t"
"brne 1b"
: "=r" (__count)
: "0" (__count)
);
}
这段代码是什么
这段代码写了一个名为_delay_loop_1
的函数,用于在AVR微控制器上进行延时。
数的参数是一个无符号8位整数 (uint8_t __count
),表示要进行的延时时间(循环次数)。
-
void _delay_loop_1(uint8_t __count)
: 这是函数的定义。函数接受一个参数__count
,用于确定延时的循环次数。
-
__asm__ volatile (...)
: 这是内联汇编语句块。volatile
关键字告诉编译器这个汇编代码具有副作用(会修改或使用输入、输出操作数),所以编译器不应该对其进行优化。它确保函数每次都执行相同的操作。 -
汇编代码块中,使用两个指令:
1: dec %0
: 这是一个标签1:
和一个汇编指令dec %0
。dec
是减量指令,用于将寄存器%0
的值减1。brne 1b
:brne
是一种分支指令,意思是 "如果零标志为0则跳转"。即当%0
不为0时,跳转到标签1:
继续执行循环。-
: "=r" (__count)
: 这是汇编代码块的输出操作数部分,表示__count
会被作为一个寄存器 (=r
) 的输出操作数。最终结果将写回到变量__count
中。 -
: "0" (__count)
: 这是汇编代码块的输入操作数部分,表示__count
将被作为一个寄存器 (0
) 的输入操作数,传递给汇编代码块中的%0
。
综上所述,该函数通过循环减量 __count
参数来实现延时。循环次数由 __count
的初始值确定,循环在 __count
不为0时持续执行。
这那么到底延时了多长时间,也就是一个count是多少?
要准确确定该函数的延时时间,需要知道 AVR 微控制器的时钟频率以及每个循环迭代的执行时间。假设每个循环迭代的执行时间可以忽略不计,那么该函数的总延时时间取决于 __count
参数的值以及 AVR 微控制器的时钟频率。
如果假设在每个循环迭代中,执行时间可以忽略不计,那么每次循环的延时时间将主要由循环的执行次数决定。在这种情况下,循环体中的指令 dec %0
和 brne 1b
将会重复执行,直到 %0
的值为零。
但是,要准确确定总的延时时间,我们需要知道 AVR 微控制器的时钟频率。通常情况下,AVR 微控制器的时钟频率在几十 MHz 到几百 MHz 之间,不同型号的微控制器具有不同的时钟频率。知道了时钟频率之后,我们可以根据循环迭代的次数和时钟频率来计算总的延时时间。
一般来说,延时时间可以通过以下公式计算:
延时时间 = 循环次数 × 每次循环的执行时间
每次循环的执行时间可以用时钟周期来表示,通常以纳秒 (ns) 或微秒 (μs) 为单位。
注释
看到了这个函数的注释
/** \ingroup util_delay_basic
Delay loop using an 8-bit counter \c __count, so up to 256
iterations are possible. (The value 256 would have to be passed
as 0.) The loop executes three CPU cycles per iteration, not
including the overhead the compiler needs to setup the counter
register.
Thus, at a CPU speed of 1 MHz, delays of up to 768 microseconds
can be achieved.
*/
翻译过来就是:使用一个8位计数器 \c __count 来进行延时循环,因此最多可以进行256次迭代。(值256必须作为0传递)。每次循环执行三个CPU周期,不包括编译器设置计数器寄存器所需的开销。
因此,在CPU速度为1 MHz时,可以实现长达768微秒的延时。
我的理解
也就是1/1MHZ = 1us,不知道对不对,这里所说的循环执行3个时钟周期也就是每次调用就会延时3us,即_delay_loop_1(1)就是3us,但是最多执行256次,也就是传参最大值是256,所以_delay_loop_1(256) = 768us。