C语言 C - AVR - 简单的 PORTB、DDRB、PINB 解释

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20993661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 10:35:09  来源:igfitidea点击:

C - AVR - Simple PORTB, DDRB, PINB explanation

cavratmega

提问by Mike_NotGuilty

I am working on school project and need to learn the basics of C with a AVR atmega controller.

我正在从事学校项目,需要使用 AVR atmega 控制器学习 C 的基础知识。

I don't understand how everything is set up. For example PORTB, PORTD, DDRB; DDRD, PINB, PIND and stuff like that. And I don't know how everything works with if statements, while loops, etc.

我不明白一切是如何设置的。例如PORTB、PORTD、DDRB;DDRD、PINB、PIND 之类的。而且我不知道 if 语句、while 循环等是如何工作的。

Can someone give me a short explanation please?

有人可以给我一个简短的解释吗?

I have a few code lines...

我有几行代码...

DDRB = 0b00000011; // I know that here DDRB is set to input/output

And an if statement:

还有一个 if 语句:

if (PINB & (1 << PINB0)){
    A = true;
}

Can someone explain me how this 'if statement' works? Why PINB & (1<< PINB0))?

有人可以解释一下这个“if 语句”是如何工作的吗?为什么PINB & (1<< PINB0))

Thanks

谢谢

回答by Grijesh Chauhan

Do you means what is if-condition PINB & (1<< PINB0))?

你的意思是 if-condition 是什么PINB & (1<< PINB0))

It checks whether PINB0 + 1number bit( from rhs) is ON (1) in PINBor OFF (0).

它检查PINB0 + 1数字位(来自rhs)是ON(1)PINB还是OFF(0)。

For example. (a & (1 << 2))checks whether 3rd bit is ON in aor OFF. In the expression two operators are used <<bitwise left shift and &bitwise and below I have explained for one byte example:

例如。(a & (1 << 2))检查第 3 位是 ONa还是 OFF。在表达式中使用了两个运算符<<按位左移和&按位,下面我解释了一个字节的例子:

  1. 1is 0000 0001
  2. 1 << 2after left shift gives 0000 0100
  3. abitwise and with 0000 0100gives either all zeros 0000 0000or 0000 0100

    3a. If all zeros then if condition is false (when third bit in ais zero).
    3b. If result of bitwise and is 0000 0100then if condition evaluates as true (when third bit in ais one).

  1. 10000 0001
  2. 1 << 2左移后给出 0000 0100
  3. a按位和 with0000 0100给出全零0000 00000000 0100

    3a. 如果全为零,则如果条件为假(当输入的第三位a为零时)。
    3b. 如果按位和的结果为0000 0100则 if 条件评估为真(当第三位a为 1 时)。

回答by Glenn

Microprocessors use a memory map to interface their hardware functionality with the software.

微处理器使用内存映射将其硬件功能与软件连接起来。

Basically, there are static addresses in memory that the hardware will use to determine its functionality. These are specific to the manufacturer, the part, and sometimes even how the part is configured.

基本上,硬件将使用内存中的静态地址来确定其功能。这些特定于制造商、部件,有时甚至是部件的配置方式。

The datasheet for the part will tell you the exact memory location to control different functionality. However, this is normally very tedious. As a result, the datasheet will also (almost) always give a name to that particular location in memory that describes its functionality. Once again, these names are manufacturer and part specific.

该部件的数据表将告诉您控制不同功能的确切内存位置。然而,这通常是非常乏味的。因此,数据表还将(几乎)总是为描述其功能的内存中的特定位置命名。同样,这些名称是特定于制造商和零件的。

To make this interface easier for programmers, people (the manufacturer or the community) will often create macros to these memory locations. For example, you could find

为了让程序员更容易使用这个界面,人们(制造商或社区)通常会为这些内存位置创建宏。例如,你可以找到

// Clock Prescalar Register for ATMega328p
#define CLKPR *0x61

in a header file associated with the part (such as AVR libc).

在与部件关联的头文件中(例如 AVR libc)。

Now, by writing OSCCAL = 0b10000000(or whatever else I want to write that is allowable by the specifications in the datasheet) I can directly access and change the clock prescalar module for this part.

现在,通过编写OSCCAL = 0b10000000(或我想编写的任何其他数据表中的规范允许的内容),我可以直接访问和更改此部分的时钟预标量模块。

But, often we are interested in the value of a single bit, not the entire byte. As a result, we use bitwise operators (such as &, |, ~, <<>>) to "mask" off bits that we are interested in manipulating.

但是,我们通常对单个位的值感兴趣,而不是整个字节。因此,我们使用按位运算符(例如&, |, ~, <<>>)来“屏蔽”我们有兴趣操作的位。

This offers the simultaneous advantage of allowing us to only read the value from the bit of interest, while not inadvertently changing any bits that we do not mean to toggle.

这同时提供了允许我们仅从感兴趣的位读取值的同时优势,而不会无意中更改我们不想切换的任何位。

Many bit positions are also given by macros as well. For instance, bit 7 in OSCCALis named CLKPCE(again, from the datasheet).

许多位位置也由宏给出。例如,第 7 位OSCCAL被命名CLKPCE(同样来自数据表)。

CLKPCE is most likely defined (at least in AVR libc - the standards vary) by:

CLKPCE 最有可能通过以下方式定义(至少在 AVR libc 中 - 标准各不相同):

#define CLKPCE 7

because it defines the bit shift needed to get to the desired bit inside OSCCAL.

因为它定义了到达内部所需位所需的位移位OSCCAL

In order to talk about the bit here, I can do several things.

为了说到这里,我可以做几件事。

Set the bit

设置位

To set the bit, we want to make it a 1, without affecting any of the other bits. To do this, we use an OR mask, as follows:

要设置该位,我们希望将其设为 1,而不影响任何其他位。为此,我们使用 OR 掩码,如下所示:

OSCCAL = (OSCCAL | (1 << CLKPCE));

I'll leave it to you to review bit operators and see how this works.

我将留给您查看位运算符并看看它是如何工作的。

Clear the bit

清除位

Here, we want to make it a 0, without affecting the other bits. It will look something like this:

在这里,我们希望将其设为 0,而不影响其他位。它看起来像这样:

OSCCAL = (OSCCAL & ~(1 << CLKPCE));

Query the bit

查询位

When querying, we want an expression that returns nonzero if the bit was set (1), and zero if the bit was cleared (0). It'll look like this:

查询时,我们想要一个表达式,如果位被设置 (1),则返回非零,如果位被清除 (0),则返回零。它看起来像这样:

(OSCCAL & (1 << CLKPCE));

The Takeaway

外卖

By using these different bitwise operations with predefined macros, we can directly control and query the state of the hardware by using this static memory map.

通过将这些不同的按位操作与预定义的宏一起使用,我们可以使用这个静态内存映射直接控制和查询硬件的状态。

However, to make sense of all of these macros, you will need to consult (and read, and re-read, and re-re-read) the datasheet for your part. Luckily, searchable PDFs are available for free from Atmel on your part's page!

但是,要理解所有这些宏,您需要查阅(并阅读、重读、重读)您的数据表。幸运的是,Atmel 可以在您零件的页面上免费获得可搜索的 PDF!

回答by glglgl

For the meaning of the registers, it is adviseable to consult

关于寄存器的含义,建议查阅

  • the data sheet of the device you are using and
  • the header file which is shipped with the C compiler you are using.
  • 您正在使用的设备的数据表和
  • 您正在使用的 C 编译器附带的头文件。

In short, the last letter (B, D) means the port you are accessing: the GPIO pins are grouped together 8-wise so that each port has 8 pins.

简而言之,最后一个字母 ( B, D) 表示您正在访问的端口:GPIO 引脚按 8 向组合在一起,因此每个端口有 8 个引脚。

DDRxis a means to set the direction of each port pin.

DDRx是一种设置每个端口引脚方向的方法。

PORTxand PINxare used for input and output, but as I am used to use PORTA.IN, PORTB.DDR, PORTD.OUTetc., I cannot tell by the heart which of them does what.

PORTxPINx用于输入和输出,但我习惯了使用PORTA.INPORTB.DDRPORTD.OUT等,我不能由他们做什么的心脏告诉。

For the basics of the language, there are books and tutorials which enable you to learn this language.

对于语言的基础知识,有一些书籍和教程可以让您学习这门语言。

回答by Chinna

if (PINB & (1 << PINB0)){
        A = true;
    }

This code checks whether PIN 0 in PORTBis HIGH or LOW. If it is high then assigns A = true;Here, PINB--> Reads data from PORTB, (1<<PINB0)--> Make 0th bit as 1 and AND's both values to know whether PIN 0 in PORTBis high or not.

此代码检查是否PIN 0 in PORTBHIGH or LOW。如果它是高然后分配A = true;Here, PINB--> Reads data from PORTB, (1<<PINB0)--> 使第 0 位为 1 和AND两个值来知道 PIN 0 in 是否PORTB为高。