AVR单片机8位数码管显示的程序实现

 
2016-10-26 16:30

我们接着来完成 数码管的显示实验。现在我们开始动手编写程序;

根据前面的介绍,我们应该已经能够知道编写一个 的C语言程序的基本步骤和方法了。

下面给出这个程序的主程序文件,在这个程序中我们应该能够知道这个程序都包含了那几块,具体来说我们应该能够在这个程序中把以下几个部分找出来:预编译语句、 的定义、函数的声明、主函数、函数定义。如果你还不能够准确找出这几部分,那么需要把前面的内容再详细阅读一下。

主程序代码

#include < /io.h> //io端口寄存器配置文件,必须包含

#include <util/delay.h> //GCC中的延时函数头文件

#include "hc .h"

//unsigned char Led_Disbuf[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //共阴极

unsigned char Led_Disbuf[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; //共阳极

unsigned char ComBuf[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

//函数声明

extern void Delayus(unsigned int lus); //us延时函数

extern void Delayms(unsigned int lms); //ms延时函数

int main(void) //GCC中main文件必须为返回整形值的函数,没有参数

{

unsigned char i;

PORTB = 0xff; //PORTB输出低电平,使 熄灭

DDRB = 0xFF; //配置端口PB全部为输出口

HC595_port_init();

while(1)

{

for(i = 0; i < 8;i++)

{

PORTB = Led_Disbuf; //送段码

HC595_Send_Data(ComBuf); //选通位选端口

Delayus(70); //延时

HC595_Send_Data(0x00); //位选通关闭

}

}

}

//us级别的延时函数

void Delayus(unsigned int lus)

{

while(lus--)

{

_delay_loop_2(4); //_delay_loop_2(1)是延时4个时钟周期,参数为4则延时16

//个时钟周期,本实验用16M晶体,则16个时钟周期为16/16=1us

}

}

//ms级别的延时函数

void Delayms(unsigned int lms)

{

while(lms--)

{

Delayus(1000); //延时1ms

}

}

在这个主程序文件中有人可能会注意到有一些我们前面没有介绍过的内容,比如extern这个单词,它在这里起什么作用?

这就牵涉到C语言的关键字了,关于C语言的关键字,我们可以到相关的C语言教材中去做详细了解,在这里我们只针对extern这个关键字作出解释,我们注意到extern用在一个函数声明的地方,它的作用就是把这个函数声明为外部函数,这样我们在整个项目的所有文件中就都可以调用这个函数了。同理extern也可以用来声明一个变量为外部变量。

我们可能还会有一个疑惑:#include "hc595.h"这个头文件包含语句中的hc595.h有什么作用,它是GCC提供的还是我们自己编写的?

这里我们就要学习C语言中的一个重要的概念:模块化程序设计。何为模块化程序设计?它实现什么功能?如果要铺开来讲的话,可能需要一本书的内容。我们耗不起这个时间和精力。其实我们只需要知道,模块化程序设计是为了简化程序容量而采取的一种将一个程序分成不同的模块,然后通过特定的方法将这些模块组合起来共同完成同一个目标。通俗的说就是化整为零。

在我们刚开始学习 的时候,我们编写的程序都很简单,程序量也不大,所以往往涉及不到模块化程序设计,但是这是一种很好的编程思路,我们有必要掌握。本实例就是采用的这种方法。

模块化程序设计的思路是:将实现相同功能的程序单独编写,然后实现一个综合的功能,举个例子,我们想实现一个液晶显示的温度测量程序,那么我们可以把液晶显示相关的程序放在一个文件中,把温度测量的程序放在另一个文件中,最后在主程序中调用这两个文件来实现整体的功能。

通常我们在进行模块化程序设计的时候,常常将 ,端口设置,函数声明等部分保存在一个.h文件中,而将函数定义部分放在一个.c文件中,在编写主程序文件的时候,用预处理命令#include将.h文件包含起来,而在编译的时候将所有用到的.c文件一起编译。这样就实现了模块化文件的整合。

在本实例中,我们将74HC595相关的变量定义,端口定义,函数声明放在74HC595.h文件中,而主程序中的#include "hc595.h"这句话实现了将这个文件包含到主程序中的功能。

下面是本实例中模块化程序设计的.h文件

/*****************************

.h

***********************************/

/*74hc595与 的引脚连接

/MR(10脚) VCC 低点平时将 的数据清零。通常将它接Vcc

/OE(13脚) PG4 高电平时禁止输出(高阻态)。

如果 的引脚不紧张,用一个引脚控制它,

可以方便地产生闪烁和熄灭效果。比通过数据端移位控制要省时省力。

ST_CP(12脚) PG1 上升沿时移位寄存器的数据进入数据存储寄存器,

下降沿时存储寄存器数据不变。通常将RCK置为低电平,

当移位结束后,在RCK端产生一个正脉冲(5V时,大于几十纳秒就行了。

通常都选微秒级),更新显示数据。

SH_CP(11脚) PG0 上升沿时数据寄存器的数据移位。QA-->QB-->QC-->...-->QH;

下降沿移位寄存器数据不变。(脉冲宽度:5V时,大于几十纳秒就行了。

通常都选微秒级)

DS(14) PG2 串行数据输入端。

*/

#ifndef __HC595_H__

#define __HC595_H__

#include <avr/io.h> //io端口寄存器配置文件,必须包含

#include <util/delay.h> //GCC中的延时函数头文件

#define HC595_latch (1 << PG1) //上升沿数据打入8位锁存器,下降沿锁存器数据不变

#define HC595_sclk (1 << PG0) //上升沿数据移位,下降沿数据不变

#define HC595_oe (1 << PG4) //低电平,8位数据锁存器输出,高电平输出高组态

#define HC595_data (1 << PG2) //串行数据输入端

#define SET_HC595_latch (PORTG |= (1 << PG1))

#define CLR_HC595_latch (PORTG &= ~(1 << PG1))

#define SET_HC595_sclk (PORTG |= (1 << PG0))

#define CLR_HC595_sclk (PORTG &= ~(1 << PG0))

#define SET_HC595_data (PORTG |= (1 << PG2))

#define CLR_HC595_data (PORTG &= ~(1 << PG2))

#define SET_HC595_oe (PORTG |= (1 << PG4))

#define CLR_HC595_oe (PORTG &= ~(1 << PG4))

void HC595_port_init(void); //595端口初始化

void HC595_Send_Data(unsigned char byte); //发送一个字节

void HC595_Output_Data(unsigned char data); //发送字符串

#endif

同时我们将与74HC595相关的函数定义部分放在74HC595.c文件中,如下

/********************************

74hc595.c

**************************************/

#include "hc595.h"

//595端口初始化

void HC595_port_init(void)

{

PORTG = 0x00;

DDRG |= (1 << PG0) | (1 << PG1) | (1 << PG2) | (1 << PG4);

}

//发送一个字节

void HC595_Send_Data(unsigned char byte)

{

unsigned char i;

//CLR_HC595_latch;

for(i = 0;i < 8;i++)

{

if(byte & 0x80)

{

SET_HC595_data;

}

else

{

CLR_HC595_data;

}

byte <<=1;

SET_HC595_sclk; //上升沿数据移位

CLR_HC595_sclk;

}

SET_HC595_latch;

CLR_HC595_latch;

}

//发送字符串

void HC595_Output_Data(unsigned char data)

{

CLR_HC595_latch; //下降沿锁存器数据不变

HC595_Send_Data(data);

SET_HC595_latch; //上升沿数据打入8位锁存器

}

在主程序中我们使用预定义语句将.h文件包含到了主程序文件中,那么我们怎样实现将.c文件编译到整个项目程序中呢?在这里我们只要在makefile文件中将这个.c文件加进去就可以了,如下图所示,在SRC = $(TARGET).C的后面空一格,然后输入我们所定义的.c文件的名称,然后保存makefile文件的更改。最后进行编译就可以了,编译的时候如果我们仔细观察编译器的输出信息,会发现不但编译了main.c文件,同时也编译了74hc595.c文件。

AVR单片机8位数码管显示的程序实现的更多相关文章

  1. #51单片机#8位数码管(74HC595芯片)的使用方法

    数码管基本属性:1.采用2片595驱动数码管,需要单片机3路IO口,根据数码管动态扫描原理进行显示:2.宽工作电压3.3V到5V:3.PCB板尺寸:71mm*22mm4.数码管型号:0.36 4位共阳 ...

  2. AVR单片机教程——走向高层

    本文隶属于AVR单片机教程系列.   在系列教程的最后一篇中,我将向你推荐3个可以深造的方向:RTOS.C++.事件驱动.掌握这些技术可以帮助你更快.更好地开发更大的项目. 本文涉及到许多概念性的内容 ...

  3. AVR单片机教程——数码管

    先解答之前一个思考题:如果不把引脚配置为输出而写高电平,连接LED会怎样? 实验结果是,LED会亮,但相比于输出高电平的情况,亮度很低.这是为什么呢? 通过上一篇教程我们知道,引脚输入输出模式是由寄存 ...

  4. 实验1 单片机IO口应用及数码管显示

    1.   单片机驱动蜂鸣器的实验: a)         说明:Lab51单片机实验板的蜂鸣器连接到单片机的P1.5 b)        基本要求:控制蜂鸣器每2秒响0.5秒. #include &l ...

  5. 音响音箱/恒温壶/电量显示/电子数字时钟等LED数码管显示驱动IC-VK1640B 8段12位/12段8位显示

    市面上最常用的数码管为七段/八段显示,八段数码管比七段数码管多一个发光二极管单元(比七段数码管多一个点),又按能显示多少个"8"可分为1位.2位.4位等等.数码管又分为共阳极驱动/ ...

  6. AVR单片机教程——开发板介绍

    本教程使用EasyElectronics开发板: EasyElectronics是一款基于AVR单片机的开发板.AVR单片机是基于改进的哈佛架构.8~32位的一系列RISC微控制器,最初由Atmel公 ...

  7. AVR单片机教程——EasyElectronics Library v1.0手册

    更新:EasyElectronics Library v1.1手册 索引: bit.h delay.h pin.h tone.h pwm.h uart.h adc.h led.h rgbw.h seg ...

  8. AVR单片机教程——定时器中断

    本文隶属于AVR单片机教程系列.   中断,是单片机的精华. 中断基础 当一个事件发生时,CPU会停止当前执行的代码,转而处理这个事件,这就是一个中断.触发中断的事件成为中断源,处理事件的函数称为中断 ...

  9. AVR单片机教程——PWM调光

    本文隶属于AVR单片机教程系列.   PWM 两位数码管的驱动方式是动态扫描,每一位都只有50%的时间是亮的,我们称这个数值为其占空比.让引脚输出高电平点亮LED,占空比就是100%. 在驱动数码管时 ...

随机推荐

  1. COLLECTL LINUX 监控

    http://blog.csdn.net/leichelle/article/details/23590289

  2. scp、paramiko、rsync复制文件的区别

    1.paramiko只能复制文件,而不能复制目录,复制时,已经存在的会被覆盖;要想复制目录,只能把目录里的文件一个一个复制过去 2.scp可以复制文件.目录,复制时,已经存在的会被覆盖:可以模糊匹配: ...

  3. golang time.Duration()的问题解疑

    原文:  How to multiply duration by integer? 看到golang项目中的一段代码, ---------------------------------------- ...

  4. MapReduce Cross 示例

    MapReduce Cross 示例 package com.bsr.cross; import java.io.IOException; import org.apache.hadoop.conf. ...

  5. 007 Vlan config

    sw0(config)#vlan 2 sw0(config-vlan)#name Sales sw0(config-vlan)#vlan 3 sw0(config-vlan)#name Tech sw ...

  6. Codeforces Round #271 (Div. 2) D. Flowers (递推 预处理)

    We saw the little game Marmot made for Mole's lunch. Now it's Marmot's dinner time and, as we all kn ...

  7. OBIEE开发手冊

    Creating a Repository Using the Oracle BI 11g Administration Tool cid=5690&ssid=0">http: ...

  8. FFmpeg解码视频帧为jpg图片保存到本地

    FFmpeg解码视频帧为jpg图片保存到本地 - CSDN博客 https://blog.csdn.net/qq_28284547/article/details/78151635

  9. android获取手机的IMSI码

    android--获取手机的IMSI码,并判断是中国移动\中国联通\中国电信转载 TelephonyManager telManager = (TelephonyManager) getSystemS ...

  10. Tarjan求桥

    传送门(poj3177) 这道题是Tarjan求桥的模板题.大意是要求在原图上加上数量最少的边,使得整张图成为一个边双联通分量. 具体的做法是,先在图中求出所有的桥,之后把边双联通分量缩成点,这样的话 ...