美文网首页C语言&嵌入式嵌入式学习笔记C语言
带你AVR入个门:1.点亮LED(上)

带你AVR入个门:1.点亮LED(上)

作者: 乱世工人 | 来源:发表于2017-02-25 20:23 被阅读104次

    先打开上一篇文章新建的那个啥也不干的项目。想要单片机干点啥,你先要准备好 datasheet。

    一般编程语言的第一个程序是打印 hello world,而单片机的第一个程序是点亮 LED。本质上是通过 IO 来控制芯片引脚电平的高低。

    假如你的开发板有一排 LED,那么电路图一般长这样:



    电源经过排阻再经过 LED 连接到芯片的引脚。假如,PC7输出的是低电平,则对应的L1灯点亮。

    现在打开 ATmega16 的 datasheet 看一下引脚配置图:



    ATmega16 的 IO 有4组:PA、PB、PC、PD,括号里面的是该引脚除了 IO 功能以外的其它功能。

    每组IO都有3个寄存器:DDRx、PORTx、PINx(x对应A到D),4组IO一共是12个:






    这三个寄存器是这么用的:



    简单的说:DDR控制引脚是输入还是输出,1为输出,0为输入。

    而当引脚被设置为输出的时候,PORT控制引脚输出的电平高低,1为高电平,0为低电平。

    而PIN,则是输入的时候用来读取该引脚的电平。

    我们再回到这个电路图,现在需要做的是把PC组的引脚设置为输出低电平。


    可以这么用16进制赋值:

    PORTC = 0x00;
    DDRC = 0xFF;
    

    项目模版含了头文件

    #include <avr/io.h>
    

    里面定义了AVR寄存器的名字。

    整个程序长这样:

    #include <avr/io.h>
    
    
    int main(void)
    {
        PORTC = 0x00;
        DDRC = 0xFF;
        while (1) 
        {
        }
        return 0;
    }
    

    编译、下载、开发板重新上电……bling~,8盏LED点亮了。

    PORTC = 0x00;
    DDRC = 0xFF;
    

    换成2进制的写法等价为:

    PORTC = 0b00000000;
    DDRC = 0b11111111;
    

    8位,每个引脚对应1位。

    假如你想要只点亮其中1盏LED呢?比如只点亮L3?

    L3对应的引脚为PC5,你可以这么写:

    PORTC = 0b11011111;
    DDRC = 0b11111111;
    

    当然你也可以写成16进制:

    PORTC = 0xDF;
    DDRC = 0xFF;
    

    但是这种编程风格对阅读代码毫无帮助。

    一种比较优雅的写法是:

    PORTC =  ~(1 << PC5);
    

    PC5在avr/io.h里定义好了,其实就是5。

    上面那句代码翻译过来就是:

    PORTC =  ~(1 << 5);
    

    再翻译:

    PORTC = ~(0b00000001 << 5);
    

    再翻译:

    PORTC = ~0b00100000 ;
    

    再翻译:

    PORTC = 0b11011111 ;
    

    看,又变回来了。

    这么直接赋值有一个问题,除了PC5对应的L3点亮以外,所有LED都灭了。

    假如我事先不知道其它LED的亮灭情况,在不影响其它LED的情况下单独点亮L3呢?

    优雅的写法是:

    PORTC &=  ~(1 << PC5);
    

    相当于:

    PORTC =  PORTC & 0b11011111;
    

    无论PORTC寄存器原来的值是什么(想象为0b????????),跟0b11011111进行&运算之后,就变成了0b??0?????,无论其它位是什么,反正PC5是0。

    假如我要同时点亮PC3跟PC5呢?这么写:

    PORTC &=  ~((1 << PC5)|(1 << PC3));
    

    0b00100000跟0b00001000进行|运算后变成了0b00101000,剩下的自己推导。

    假如我要同时熄灭PC3跟PC5呢?这么写:

    PORTC |= (1 << PC5)|(1 << PC3);
    

    恭喜你已经上道了,请记住上面两种写法,当要单独将某个寄存器的某一位置0或者置1的时候,就是用这种与或非(&、|、~)的组合。

    最后放一下我的公众号二维码

    相关文章

      网友评论

        本文标题:带你AVR入个门:1.点亮LED(上)

        本文链接:https://www.haomeiwen.com/subject/iszwwttx.html