如何读取 ATmega16 上的数字输入?

电器工程 avr 大气压
2022-01-22 23:28:25

我需要做什么才能读取ATmega16上的数字输入(按钮) ?我必须启用上拉电阻还是可以使用 10 kohm 的电阻?一些简单的代码是什么?只是一个简单的“按下时打开 LED”。

有初学者教程吗?我试过谷歌搜索和AVR Freaks,但一切都演变成一场战斗,我没有得到答案。我真的没有找到任何关于这些东西的教程。很多具体的事情,但我的AVR微控制器并不简单......

4个回答

巴西问候!

首先感谢乔比的例子。其次,他的例子只是一个小错误。数字 0x20 不正确。它应该是 0x04。另外,作为一个建议,我不会在代码中使用像 0xFB、0x20 或 0x04 这样的十六进制数字。我建议使用 io.h 中的 PIN 端口定义和头文件引用的其他定义。我在下面重写了 Joby 的示例,并为初学者提供了一些评论。

# include <avr/io.h>

int main (void)
{
    // set all pins on PORTB for output
    DDRB = 0xFF;

    // set port pin PORTD2 as input and leave the others pins 
    // in their originally state (inputs or outputs, it doesn't matter)
    DDRD &= ~(1 << PD2);        // see comment #1

    while (1) 
    {
        if (PIND & (1<<PD2))    // see comment #2
            PORTB |= (1<<PB2);  // see comment #3
        else
            PORTB &= ~(1<<PB2); // see comment #4
    }
    return 0;
}

/*

初学者评论

评论#1: (1 << PD2) 生成二进制 00000100。操作“~”翻转所有数字,即二进制现在是 11111011。最后 &= 在 DDRD 和 11111011 之间应用逻辑“与”,结果再次放置在 DDRD 内存中。注意:运算符“AND”所做的是针对 DDRD 内存中的每个位,它与上面的二进制数进行比较。如果 DDRD 中的位为 0 且二进制中相同位位置的位为 1,则结果位为 0,如果 DDRD 为 1 且二进制中的位为 1,则结果位为 1,如果DDRD 中的位为 1 或 0,二进制中的位为 0,则结​​果位始终为 0。总之,命令 DDRD &= ~(1 << PD2) 仅将位 PD2 更改为零,而其他位(零或一)保持不变。看起来有点复杂,但是习惯了之后,在不改变其他位的情况下,一口换一个位是最好的办法。

注释 #2 : (1 << PD2) 生成二进制 00000100。使用注释 #1 中描述的相同逻辑“AND”,命令“PIND & 0000100”仅检查 PIND2(连接按钮的输入引脚) to) 是否设置为高。由于二进制位设置为 0,所有其他引脚将为 FALSE,并且由于二进制位 #2 设置为 1,因此仅当 PD2 输入设置为高时,IF 语句才会为 TRUE;如果 PD2 输入为设置为低。

注释#3:按照注释#1 中解释的逻辑,此命令将端口 PORTB 中的输出引脚 PINB2 设置为高电压。如果您的 LED 使用约 300 欧姆的电阻正确连接到此引脚端口,并且该电阻连接到地,则 LED 应该打开。

评论 #4:LED 应该关闭,原因与前面评论中解释的相同。

最后的考虑:

a)为避免未按下按钮时输入引脚 PD2 的电压振荡(开路),我强烈建议放置一个下拉电阻(1 kOhm 或更高),以免 LED 因意外点亮而导致到这个随机电压振荡。

b) 免责声明:此处描述的想法仅供教育使用,在咨询电子专家之前,不应在任何实际系统中使用它们。

*/

https://www.mainframe.cx/~ckuethe/avr-c-tutorial/

https://www.mainframe.cx/~ckuethe/avr-c-tutorial/#digital-in

#include <avr/io.h>

/*
 * Assumptions:
 *  - LED connected to PORTB.2
 *  - Switch connected to PORTD.2
 */

int main (void)
{
    /* set PORTB for output*/
    DDRB = 0xFF;
    /* set PORTD for input*/
    DDRD &= 0xFB;
    PORTD |= 0x04;

    while (1) {
        if (PIND & 0x04)
            PORTB &= ~0x20;
        else
            PORTB |= 0x20;
    }
    return 0;
}

好吧,这适用于 AT90Usb1287,一个 ATMega,但基本按钮的东西应该或多或少相同。只需更改 IO 名称即可。