美文网首页嵌入式C语言&嵌入式单片机学习
带你AVR入个门:2.点亮LED(下)

带你AVR入个门:2.点亮LED(下)

作者: 乱世工人 | 来源:发表于2017-02-28 23:52 被阅读154次

上回提到,通过与或非的组合使用可以控制特定寄存器的特定某个位,接下来玩点花样。

让灯闪烁咋整?

闪烁就是:亮灯、灭灯、亮灯、灭灯……

一直闪的话,放在while(1) 循环里面就好了。

比如让PC7的灯闪烁:

while(1)
{
    PORTC &= ~(1 << PC7);//亮灯
    PORTC |= (1 << PC7);//灭灯
}

编译下载运行,发现啥事都没发生,程序没运行?不是,程序正在运行,而且是以一种快到肉眼看不见的速度在闪烁。

因为亮灯跟灭灯之间要加延时。

普遍的延时函数就是两层循环语句在狂跑,这里介绍一个 Atmel Studio 自带的延时函数。

首先你要包含头文件

#include <util/delay.h>

然后跟着我做一个小小的设置:

菜单栏 Project > 你的项目名字 Properties > Toolchain > AVR/GCC C Compiler

在 Defined symbols 新增一行

F_CPU=7372800UL

这里的7372800UL指的是你MCU的晶振频率,UL表示该数据是无符号长整型常量,假如你用的是8M的晶振,相应要写成

F_CPU=8000000UL

这样你就可以用自带的官方延时函数:

_delay_ms()

_delay_us()

顾名思义,一个是毫秒延时,一个是微秒延时。

把延时1秒(即1000毫秒)加到程序上:

while(1)
{
    _delay_ms(1000);
    PORTC &= ~(1 << PC7);//亮灯
    _delay_ms(1000);
    PORTC |= (1 << PC7);//灭灯
}

现在你就可以看到L1以1秒的间隔在一闪一闪亮晶晶了。

但目前的代码还只是玩具级别,接下来我教你用工程的思维来组建程序。

首先,像

PORTC &= ~(1 << PC7);//亮灯

这样的语句是不应该出现在主程序里面的,不但可读性不好,可移植性也不好。

既然这个程序有点灯功能,我们给项目新增一个专门的light.c文件和与之配套的light.h。

在右侧Solution Explorer的项目名称右键菜单选择Add>New Item:



在弹出的窗口选择C File类型,文件名为light.c



再Add一遍,这次文件类型选择Include File,文件名为light.h

在main.c的#include <avr/io.h>下添加一行#include "light.h"

#include <avr/io.h>
#include "light.h"

这样,main.c跟light.c就联系起来了。

接下来的步骤是:

在light.c里边写函数,在light.h里边声明函数,在main.c里边调用函数。

首先,在light.c里添加一行

#include <avr/io.h>

接下来写个亮灯的函数。函数命名一般按照主谓或者主谓宾的结构:这是什么器件、它要操作什么、它要操作的对象是什么。

在这里,一号灯,点亮,这么写:

void light1_on(void)
{
    PORTC &= ~(1 << PC7);
    DDRC |= (1 << PC7);
}

灭掉,这么写:

void light1_off(void)
{
    PORTC |= (1 << PC7);
    DDRC |= (1 << PC7);
}

接下来在light.h里写这两个函数的声明:

#ifndef LIGHT_H_
#define LIGHT_H_

void light1_on(void);
void light1_off(void);

#endif /* LIGHT_H_ */

现在main.c里边就可以直接调用了:

while(1)
{
    _delay_ms(1000);
    light1_on();
    _delay_ms(1000);
    light1_off();
}

看,我现在注释已经去掉了,但并不影响阅读,一份写得好的程序,是可以自注释的。

可读性是有了,但还不具备可移植性。

可移植性是在特定的范围下讨论的,有跨编译器的可移植性,跨芯片的可移植性,在这里,我们讨论的是同样编译器同样芯片的前提下,电路图稍微改变,如何在尽量少改动代码的前提下移植程序。

目前的light1_on和light1_off函数都是控制PC7引脚的LED,假如换成了接在PB3呢?把程序里出现的PC7全部换成PB3?

优雅的做法是:用宏定义把具体的标识符换个名字。

在light.c开头这么写:

#define LIGHT1_PORT PORTC
#define LIGHT1_DDR DDRC
#define LIGHT1 PC7

然后重写两个函数:

void light1_on(void)
{
    LIGHT1_PORT &= ~(1 << LIGHT1);
    LIGHT1_DDR |= (1 << LIGHT1);
}

void light1_off(void)
{
    LIGHT1_PORT |= (1 << LIGHT1);
    LIGHT1_DDR |= (1 << LIGHT1);
}

把这个程序移植到另一个LED接在PB3的电路板时,只需要把

#define LIGHT1_PORT PORTC
#define LIGHT1_DDR DDRC
#define LIGHT1 PC7

改成

#define LIGHT1_PORT PORTB
#define LIGHT1_DDR DDRB
#define LIGHT1 PB3

就可以了。

最后放一下我的公众号:

相关文章

网友评论

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

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