2015-09-05 16:26:35 yunfeiyang62 阅读数 19225
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4001 人正在学习 去看看 朱有鹏

51单片机 数码管的静态显示和动态显示

数码管(Segment Displays)由多个发光二极管封装在一起组成“8”字型的器件,引线已在内部连接完成,只需引出它们的各个笔划,公共电极。数码管实际上是由七个发光管组成8字形构成的,加上小数点就是8个。这些段分别由字母a,b,c,d,e,f,g,dp来表示。

数码管原理图:

数码管共阴极接法:

数码管共阳极接法:


数码管中有位选和段选,位选就是选择哪个数码管,段选就是被选择的数码管要显示什么数字!

根据数码管的段选,可以总结出数码管的显示数据表:

符号

不显示

0

1

2

3

4

5

6

7

8

9

A

B

C

D

E

F

.

编码

0x00

0x3F

0x06

0x5B

0x4F

0x66

0x6D

0x7D

0x07

0x7F

0x6F

0x77

0x7C

0x39

0x5E

0x79

0x71

0x80


数码管的静态显示:

/*======================================================*/
/*	时间:2015年8月3日 21:19:03 						*/
/*	功能:数码管的静态显示								*/
/*	目的:51单片机学习 									*/
/*		^_^……!											*/
/*======================================================*/

#include 
#include "commLib.h"

sbit WLE  = P2^7;		// 位选
sbit DLE  = P2^6;		// 段选

#define DIGITAL_ARR_NUM		18
unsigned char code digital[DIGITAL_ARR_NUM] = {				// 数码管显示数据表
/*	 0,    1,    2,    3,    4,     5,   6,    7,    8, 	*/
	0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 
/*	 9,    A,    B,    C,    D,    E,    F,    .,   不显示 	*/
	0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x80, 0x00
};

int main(void)
{
	unsigned int i;
	
	// 位选
	WLE = 1;		// 位选端锁存器置高,送数据
	P0 = 0xC0;		// 送数据
	WLE = 0;		// 位选端锁存器置低,保存数据
	
	while(1)
	{
		for (i = 0; i < DIGITAL_ARR_NUM; i++)
		{
			// 段选
			DLE = 1;			// 段选端锁存器置高,送数据
			P0 = digital[i];	// 送数据
			DLE = 0;			// 位选端锁存器置低,保存数据
			
			delay(500);			// 延时500ms
		}
	}

	return 0;
}

效果截图:


数码管的动态显示:
/*======================================================*/
/*	时间:2015年8月6日 20:45:09 						*/
/*	功能:数码管的动态显示								*/
/*	目的:51单片机学习 									*/
/*		^_^……!											*/
/*======================================================*/

#include 
#include "commLib.h"

sbit WLE  = P2^7;		// 位选
sbit DLE  = P2^6;		// 段选

#define DIGITAL_ARR_NUM		18
unsigned char code digital[DIGITAL_ARR_NUM] = {				// 数码管显示数据表
/*	 0,    1,    2,    3,    4,     5,   6,    7,    8, 	*/
	0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 
/*	 9,    A,    B,    C,    D,    E,    F,    .,   不显示 	*/
	0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71, 0x80, 0x00
};

int main(void)
{
	unsigned int i;
	
	while (1)
	{
		for (i = 0; i < 6; i++)
		{
			P0 = 0xFF;				// 消影(必须有)
			WLE = 1;				// 位选端锁存器置高,送数据
			P0 = ccCrol(0xFE, i);	// 送数据
			WLE = 0;				// 位选端锁存器置低,保存数据
			
			DLE = 1;				// 段选端锁存器置高,送数据
			P0 = digital[i];		// 送数据
			DLE = 0;				// 位选端锁存器置低,保存数据
			
			delay(1);
		}
	}
	
	return 0;
}

效果截图:



2019-03-05 00:08:59 moofoogoo 阅读数 468
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4001 人正在学习 去看看 朱有鹏

1、设计要求

用一个共阳极数码管循环显示数值“0~F”,显示变换时间为1s,由P1口输出要显示的数值

2、硬件设计

使用proteus Isis仿真,选择元器件,AT89C51、7SEG-COM-AN-GRN、RESPACK8

3、软件设计

源程序:

#include <reg51.h>
#include <intrins.h>

typedef	unsigned char u8;
typedef	unsigned int u16;

u8  smgduan[16] = {0x3f ,0x06 ,0x5b ,0x4f ,0x66 ,0x6d ,0x7d ,0x07 ,
                0x7f ,0x6f ,0x77 ,0x7c ,0x39 ,0x5e ,0x79 ,0x71 };  //共阴
 
void delay(u16 i)
 {
    u8 a,b;
    for( ;k>0 ;k--)
      for(b=142 ; b>0 ;b--)
        for(a=2 ;a>0 ;a--);
  }
 void main()
 {
	//u16 i;
	P1 = ~smgduan[0];
	//delay(1000);
    while(1)
   {
		 for(i=0;i<10;i++)  // 静态数码管数字动态输出
		 {
		   P1= ~smgduan[i];
		   delay(1000);
		 }
   }
  }

2008-08-21 17:13:00 dadalan 阅读数 1697
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4001 人正在学习 去看看 朱有鹏

c语言中静态全局变量的存储区是内存在程序编译的时候就已经分配好,而单片机c51的程序编译和运行的环境不是一样的,编译的时候是在windows集成开发环境uVision2下,而运行要程序在单片机中.  
  问题是我上述语句是要求它在外部RAM中分配一个静态全局数组,那么按c的说法,它应该在编译的时候就分配了静态存储区,但语句要求它在外部RAM中分配静态存储区,编译的时候是没有实际的外部RAM的,如何能在编译的时候就能得到在外部RAM中分配的静态存储区??  


编译是无需实际的环境的,变量的分配是程序加载的时候实现的,MCU这类无OS的应用,程序自己管理内存,分配空间。一般编译时编译器将自己的启动模块链接到程序中。

 

 static是C里的一个声明,表明些变量在全局数据区.任意的函数都能访问,但是具体是放在机器的什么地方,这是跟据编译自己计算的,但是你可以通过区域声明它的位置或用_at_来规定它放的地方...

2018-10-14 14:17:59 hpu_zhn 阅读数 6645
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4001 人正在学习 去看看 朱有鹏

     

       在对单片机编程以实现数码管静态显示数字之前,我们先来了解一下数码管的结构以及一些常识,对于数码管,有称八段数码管的,也有称七段数码管的,其实无非就是多在一个小数点h , 如上图所示,  我们就拿带小数点的八段数码管来说 , 其实我们没必要说对数码管很陌生,因为数码管无非就是八块发光二极管集成在了一起,另外数码管有共阴极和共阳极数码管之分,说起共阴,共阳,大家可能会有所陌生,这里我们简单介绍一下:

       共阴极数码管:    将八只发光二极管的负极通过一根总线连接在了一起 , 然后每只二极管的正极被引了出来,通过二极管的单向导通性可知,当对应数码管的二极管段接入高电平时,二极管点亮。(换句话说,也就是说想让哪一只二极管点亮,就给哪只二极管高电平。下面编程我们就以共阴数码管为例)

      共阳极数码管:    将八只发光二极管的正极通过一根总线连接在了一起 , 然后每只二极管的负极被引了出来,通过二极管的单向导通性可知,当对应数码管的二极管段接入低电平时,二极管点亮。

      好了,数码管的基本知识我们说完了,下面来说一些编程相关的,首先,我们知道数字数码管而言,那肯定是显示数字的,那么我们怎么编程实现呢?其实很简单,你想啊,数码管由八段发光二极管组成,那么我们就拿着上面的图,来画一画,比如说,显示数字 “1 ” ,那也就是让 b 和 c 亮,编程的话,即是0x06,0x06转换为二进制 ,是00000110,这样一来给了 b 和 c 段高电平,实现了点亮数字 “1”;下面我们就把数码管所能够显示的数字以及符号通过一个表格整理出来(以共阴极数码管为例);

显示数字 十六进制 二进制 显示数字 十六进制 二进制
0 0x3f 00111111 B 0x7c 01111100
1 0x06 00000110 C 0x39 00111001
2 0x5b 01011011 D 0x5e 01011110
3 0x4f 01001111 E 0x79 01111001
4 0x66 01100110 F 0x71 01110001
5 0x6d 01101101 H 0x76 01110110
6 0x7d 01111101 L 0x38 00111000
7 0x07 00000111 P 0x73 01110011
8 0x7f 01111111 n 0x37 00110111
9 0x6f 01101111 u 0x3e 00111110
A 0x77 01110111      

       这里附上一个LED代码查询小软件:

(链接: https://pan.baidu.com/s/1lCDKtCwwabfYE7dWZ2iA-g 提取码: 5fgm),需要的可以下载使用,很方便。

接下来我们还要来介绍一款芯片,也就是74HC573锁存器。

        你可能会问,我们静态显示数码管,直接对利用单片机的I/O口对数码管的引脚输出高低电平就好了嘛,为什么还要用到这款芯片?这里我们解释一下,单片机直接控制数码管确实很好,但是我们要明白一点,单片机一共也就 4 x 8 = 32个I/O口,而且我们单片机开发板上都不是只有单个数码管的,都是有六个八个数码管在一块的,如果都用单片机来控制,那一块单片机岂不是什么都干不了了吗,要知道,我们一块51单片机开发板上是由很多模块组成的,有很多功能需要实现,如果一个数码管显示模块就把我们的I/O口资源给用完了,那还有什么意义呢。相反,如果用上锁存器,我们只需要用到单片机的两个I/O口就可以了,完全足够了。

      下面,我们来简单介绍一下这款芯片: 对于74HC573,形象一点,我们只需要将其理解为一扇大门,只不过这扇大门是单向的,其中11引脚(LE)控制着门的开、关状态,高电平为大门打开,低电平为大门关闭。D0-D7为输入,Q0-Q7为输出,在LE = 1,即输入高电平时,输入端=输出端,输入是什么,输出也就原封不动的输出;在LE = 0 ,即输入高电平时,大门关闭,实现锁存,不再输出。了解之后,我们按照电路图,来进行编程,代码实现。

          

 

         如上图所示,在实现数码管的静态显示中,我们用到了两个锁存器,两个I/O口,P1.6和P1.7,分别是位选和段选。关于位选和段选我们解释一下:

         位选,位选,也就是位置的选择,一块单片机开发板上,有8个数码管,依次是1、2、3.....8, 这样的话,比如说我们想让第三个亮,就可以通过位选锁存器来实现;

       至于说段选,就很好理解了,就是我们常说的控制一个数码管中的  a,b,c...g 段,使其显示数字,这就是段选,即选择数码管的哪一笔段。好了,下面开始编程:

/* ***************************************************** */
// 工  程   : 51单片机开发板
// 文件名   : smg.c
// 处理器   : STC89C52RC
// 编译环境 : Keil4 C51 
// 系统时钟 : 11.0592MHZ
// 版    本 : V1.0 
// 设计者   :朱豪男
// 生成日期	: 2018-10-14	   					
// 修改日期	:  
// 简单描述 : 数码管静态显示程序
/* ***************************************************** */
#include <reg52.h>

#define uchar unsigned char
#define uint  unsigned int
#define data  P0		   				//P0口宏定义
/* ***************************************************** */
// 数码管位选数组定义
/* ***************************************************** */
uchar code  leddata[] = 
{               0x3F,  //"0"
                0x06,  //"1"
                0x5B,  //"2"
                0x4F,  //"3"
                0x66,  //"4"
                0x6D,  //"5"
                0x7D,  //"6"
                0x07,  //"7"
                0x7F,  //"8"
                0x6F,  //"9"
                0x77,  //"A"
                0x7C,  //"B"
                0x39,  //"C"
                0x5E,  //"D"
                0x79,  //"E"
                0x71,  //"F"
                0x76,  //"H"
                0x38,  //"L"
                0x37,  //"n"
                0x3E,  //"u"
                0x73,  //"P"
                0x5C,  //"o"
                0x40,  //"-"
                0x00,  //熄灭
                0x00  //自定义};
};
/* ***************************************************** */
// 位定义
/* ***************************************************** */
sbit du = P1^7;	  			//段选定义
sbit we = P1^6;	  			//位选定义
/* ***************************************************** */
// 函数名称:DelayMS()
// 函数功能:毫秒延时
// 入口参数:延时毫秒数(ValMS)
// 出口参数:无
/* ***************************************************** */
void delay(uint z)
{
	uint x,y;
	for(x = 0; x < z; x++)
		for(y = 0; y < 113; y++);
}
/* ***************************************************** */
// 函数名称:main()
// 函数功能:数码管静态显示
// 入口参数:无
// 出口参数:无
/* ***************************************************** */
void main(void)
{
	uchar i;
	we = 1;					//位选开
	data = 0x00;					//送入位选数据
	we = 0;					//位选关
	while(1)
	{ 
	    for(i = 0;i < 16 ; i++)
	    {
		    du = 1;		        //段选开
			data = leddata[i];	       //送入段选数据 
			du = 0;		       //段选关
		  	delay(500);			      //延时
	    }
	}
}

        代码很好理解,我们简单介绍一下,首先我们定义了个数码管位选数组,也就是十六进制代码,这便是后来数码管显示数字的核心,接着,我们用 sbit 定义了位选和段选端口,分别是 P1.6 和 P1.7 ,定义了一个延时函数,其实这一串代码很有意思,开关开关思想,贯穿始终,首先我们把位选打开,送入位选数据后,关闭锁存器,实现锁存,进入循环,随之打开段选锁存器,送入段选数据后,再次关闭段选,接下来,这个延时操作对于我们实际看到数码管的显示效果特别重要,因为程序在段选后之后,会马上消隐,显示的时间之后几个微秒,这显然不太合理,我们需要在关闭段选后加上延时,这样一来,才会让每位数码管亮度保持均匀。

(附上效果视频,链接: https://pan.baidu.com/s/1lAu0QkltthlfjndZ-DfX8g 提取码: 2hqs)

 

 

 

 

2011-11-18 15:31:10 WangSanHuai2010 阅读数 2711
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    4001 人正在学习 去看看 朱有鹏
    单片机系统经常需要存取一些少量的参数,如串口的地址码,波特率,等等,装这些参数通过PC机进行设置,并存储在本地,同时可以利用通讯端口来修改。
    参数可以存储在EEPROM中,可以放在外挂的存储器上,或者RTC的后备域中,这样是一种通用的方法。本处将参数存放于EEPROM中,因为现在大多数单片机都提供了片上EEPROM。参数按16位对齐,事实上可以格式化为任意类型。

 
/*------------------------------------------------------------
 Func: 加载参数到系统
 Time: 2011-11-13
 Ver.: V1.0
 Note:
------------------------------------------------------------*/
void WFS_LoadParams(uint16 Addr,uint16 *Buffer,uint16 Length)
{
	Addr<<=1;Length<<=1;
	EEPROM_Read(Addr+2,(uint8 *)Buffer,Length);
}


    参数按以上方法加载到内存,注意参数的起始地址为2,这是因为前两个字节区域要用来做校验用。

/*------------------------------------------------------------
 Func: 保存参数
 Time: 2011-11-13
 Ver.: V1.0
 Note:
------------------------------------------------------------*/
void WFS_SaveParams(uint16 Addr,uint16 *Buffer,uint16 Length)
{
	Addr<<=1;Length<<=1;
	EEPROM_Write(Addr+2,(uint8 *)Buffer,Length);
}


    以上方法保存参数到EEPROM中,实际上与Load方法一一对应。

/*------------------------------------------------------------
 Func: 参数系统初始化
 Time: 2011-11-13
 Ver.: V1.0
 Note:
------------------------------------------------------------*/
uint8 WFS_InitParams(void *DefaultValues,uint16 Length)
{
	uint16 D;
	EEPROM_Read(0,(uint8 *)(&D),2);
	if(D!=0x55AA){
		D=0x55AA;
		EEPROM_Write(0,(uint8 *)(&D),2);
		EEPROM_Write(2,(uint8 *)DefaultValues,Length);
		return 0xFF;
	}
	return 0x00;
}


    参数的初始化方法,首先读取EEPROM的0位置处的数据,判断是否为0x55AA合法标志,若不是0x55AA,则说明参数区为首次使用,需要进行初始化默认参数填充,于是将DefaultValues所指的默认值填入EEPROM中,并设置0x55AA标志,以后每次上电便会检测到参数的合法性。

    以下为使用示例,存储了地址码,波特率,数据位,停止位四个参数,以及一个18字的数组。

const uint16 WFS_ParmasValue_Default[]=
{
	1,9600,8,1,
	0,0,0,0,0,0,
	0,0,0,0,0,0,
	0,0,0,0,0,0,
};

    以下为参数进行初始化并加载到内存:

WFS_InitParams(WFS_ParmasValue_Default,sizeof(WFS_ParmasValue_Default));
WFS_LoadParams(0,&DevAddr,1);
WFS_LoadParams(1,&BaudRate,1);
WFS_LoadParams(2,&DataLength,1);
WFS_LoadParams(3,&StopBits,1);
WFS_LoadParams(4,Array,18);

    以下为参数修改后进行保存:

BaudRate=115200;
StopBits=2;
WFS_SaveParams(1,&BaudRate,1);
WFS_LoadParams(3,&StopBits,1);


   

数码管静态显示

博文 来自: codeleej
没有更多推荐了,返回首页