1

我试图理解这段代码

但是我无法理解这部分代码。

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= -_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

sbi并且cbi稍后在代码中用作

void system_sleep()
{
  sbi(MCUCR,PUD);                                  //Disables All Internal Pullup Resistors
  sbi(GIMSK,PCIE);                                   //Enable Pin Change Interrupts Interrups
  sbi(PCMSK,PCINT0);                              //Changes Interrupt to PIN1 (PCINT1) 
  cbi(ADCSRA,ADEN);                              //switch Analog to Digital Converter OFF
  cbi(MCUCR,SM0);                                  //Power Down Mode
  sbi(MCUCR,SM1);                                  //Power Down Mode
  sbi(MCUCR,SE);   //sleep Mode Power down enable (Sleep_enable(); should set this-- not tested yet)
  sleep_enable();                      //Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
  sleep_mode();                                       //sleep begins here
  sleep_disable();                                     //Coming out of sleep
  sbi(ADCSRA,ADEN);                             //switch Analog to Digital Converter ON
  cbi(MCUCR,PUD); //Enables Pullup Resistors Again 
 }

代码是用于ATtiny85,我阅读了数据表,我知道所有这些类似MCCURADCSRA都是寄存器。它还指出有两种指令SBICBI.

我还阅读了一些关于使用 C 进行微控制器编程的教程,并了解每个寄存器都有8位。这些位中的每一个都可以使用针对不同功能的编程来设置。此外PUDPCIE这些寄存器的不同位是在system_sleep函数中设置的。所以我明白system_sleep函数在做什么,它正在设置寄存器中的位。

我唯一无法理解的部分是

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= -_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

数据表中没有类似_SFR_BYTE或的内容_BV。我查看了 AVR/libc 头文件,在那里我发现_BV但不确定它在做什么。

4

3 回答 3

3

宏的名称应该会给您一些提示。cbi代表Clear Bitsbi代表Set Bitcbi(sfr, bit)清除寄存器中指示的bit位数sfr。类似的解释sbi

如果你有整个项目,你可以搜索 和 的_SFR_BYTE定义_BV。但从本质上讲,它们大致转化为

#define  cbi(sfr, bit)   ((sfr) &= ~(1 << (bit)))

#define  sbi(sfr, bit)   ((sfr) |= (1 << (bit)))

阅读有关位掩码的更多信息。

于 2012-09-04T06:31:48.533 回答
1
#define _BV(bit)       (1 << (bit))
#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))

以第一个_BV为例,1<<0 您可以只编写_BV(0). 第二个_SFR_BYTE使用_MMIO_BYTE宏从寄存器 sfr 获取数据,该寄存器可以是 MCUCR 或 ADCSRA 或任何 8 位 IO 寄存器。

有关详细信息,请参阅avr/sfr_defs.h

于 2014-12-15T11:34:12.440 回答
0

可以使用 in 和 out 指令读取/写入从 0x00 到 0x1F 的 AVR ATMega 寄存器,此外还有适用于这些寄存器的特定指令。这些寄存器也可以使用内存指令读取。在这种情况下,这些寄存器地址必须取从 0x20 到 0x3F 的值。

宏 __SFR_xxxx 考虑了这种行为。

这些是 ATMega 2560 的“注册摘要”段落注释的引用:

-2。使用 SBI 和 CBI 指令可直接对地址范围 $00 - $1F 内的 I/O 寄存器进行位访问。在这些寄存器中,可以使用 SBIS 和 SBIC 指令检查单个位的值。

-4。使用 I/O 特定命令 IN 和 OUT 时,必须使用 I/O 地址 $00 - $3F。当使用 LD 和 ST 指令将 I/O 寄存器寻址为数据空间时,必须向这些地址添加 $20。ATmega640/1280/1281/2560/2561 是一个复杂的微控制器,其外围单元比操作码中为 IN 和 OUT 指令保留的 64 个位置所能支持的要多。对于 SRAM 中 $60 - $1FF 的扩展 I/O 空间,只能使用 ST/STS/STD 和 LD/LDS/LDD 指令。

于 2015-04-10T22:13:26.993 回答