2014-09-08 15:26:18 u013929023 阅读数 853
  • 静态和动态控制数码管-第1季第7部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第7个课程,全面讲解了静态数码管、无38译码器式动态数码管、有38译码器式动态数码管等各种数码管驱动方式,学完本课程将会对数码管的驱动方式彻底熟悉和掌握。

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

显示程序;

#include<reg52.h>
#define DIGIT P2
unsigned char code table[17] = {
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
sbit AP = P0^0;
sbit BP = P0^1;
sbit beef=P1^0;
void delay(int z)
{
 int x,y;
 for(x=z; x>0; x--)
  for(y=110; y>0; y--);
}
void main()
{
    int a=0, b=0;
 int j;
 int i;
 beef=0;
 for(i=0; i<100; i++)
 {
  j=1;
  while(j--)
  {
   BP=0;AP=0;
   DIGIT=table[a];
   delay(10);      //
   BP=0;AP=1;
   DIGIT=table[b];
   delay(10);
  } 
   BP=0;AP=0;
   DIGIT=0x00;
   BP=0;AP=1;
   DIGIT=0x00;
  
  b++;
  if(b==10)
  {
   b=0;
   a++;
  }
  if(a==9&&b==10)
  break;
 }  
  
 while(1)
 {
  j=100000;
  while(j--)   
  {
   BP=0;AP=0;
   DIGIT=table[0];
   BP=0;AP=1;
   DIGIT=table[0];
   beef=1;
  }
  j=100000;
  while(j--)
  {
   BP=0;AP=0;
   DIGIT=0x00;
   BP=0;AP=1;
   DIGIT=0x00;
   beef=0;
  }
 }
}

 

 

 

2018-08-27 21:49:25 zlllg 阅读数 7505
  • 静态和动态控制数码管-第1季第7部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第7个课程,全面讲解了静态数码管、无38译码器式动态数码管、有38译码器式动态数码管等各种数码管驱动方式,学完本课程将会对数码管的驱动方式彻底熟悉和掌握。

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

数码管作为最廉价的输出设备,在各种自动化设备中有很大的应用,最简单普通的显示方式为动态刷新显示,称为假动态显示,即通过分时扫描每一位,利于人眼的视觉停留现象,造成一种静态显示的效果,如下图所示:

C51单片机由于运行速度很慢,在高刷新频率下,单片机的资源耗费很厉害,这样单片机就不可以再进行大量的计算工作,实际上,单片机在刷新时,只需要周期性的改变GPIO口的状态就可以了,剩下的时间其实都是在空转的状态下,我们能不能将这个空转的状态拿来用呢?当然是可以的啦,这里,我们利用单片机的定时器周期地产能中断,在中断内进行数码管的刷新工作,就可以将等待中断的这个CPU时间拿来做别的事情了。

硬件电路:

代码贴过来:

主函数

#include "shumaguan.h"
#include "timer.h"


sbit sw_jdq=P1^0;//定义一位继电器操作
void main(void)
{
  int cnt=0;//设定初值
  timer_init();//初始化定时器
  while(1)
  {
    value_now = cnt;//送初值到显示缓存
    delay(50);
    cnt++;
    sw_jdq=~sw_jdq;//切换继电器状态
    if(cnt>9999)//数值超出界线,回归最小
      cnt=-999;
  }
}

数码管驱动函数

#include "shumaguan.h"

#define DType	1			//define the Digital LED type, 1: VCC in common, 0: GND in common
#if DType==1
/*--------------------------------------------------------
Set the digital LED display code 
From left to right for
0,1,2,3,4,5,6,7,8,9,a.b,c,d,e,f,dp,-, 
--------------------------------------------------------*/
uchar code DS_BUF[]={0xc0 , 0xf9 , 0xa4 , 0xb0 , 0x99 , 0x92 , 0x82 , 0xf8 , 0x80 , 0x90 , 0x88 , 
0x83 , 0xc6 , 0xa1 , 0x86 , 0x8e , 0x7f , 0xbf , 0xff };
#else
uchar code DS_BUF[]={0x3f , 0x06 , 0x5b , 0x4f , 0x66 , 0x6b , 0x7d , 0x07 , 0x7f , 0x6f , 0x77 , 
0x7c , 0x39 , 0x5e , 0x79 , 0x71 , 0x80 , 0x40 , 0x00 };
#endif
uchar xdata buf_sm[4];            //set display buffer
  
uchar frash_cnt=0;//刷新计数器
uchar wei_buf=0x10;//位输出计数器
 
/*--------------------------
Compute the number from Value
value: something to display, range from -999 to 9999, suport float
--------------------------*/
void calc_sm(float value)
{
	uint tmp=0;
	if(value>=0)//输入值为正数,不显示负号
	{
		if(value>9999)//输入值大于9999,显示----
		{
			buf_sm[0]=17;
			buf_sm[1]=17;
			buf_sm[2]=17;
			buf_sm[3]=17;
		}
		else if(value>=1000)//输入值大于999,只显示整数
		{
			tmp=value;
			buf_sm[0]=tmp/1000;
			buf_sm[1]=tmp%1000/100;
			buf_sm[2]=tmp%100/10;
			buf_sm[3]=tmp%10;
		}
		else if(value>=100)//显示一位小数
		{
			tmp=value*10;
			buf_sm[0]=tmp/1000;
			buf_sm[1]=tmp%1000/100;
			buf_sm[2]=(tmp%100/10)+20;
			buf_sm[3]=tmp%10;
		}
		else if(value>=10)//显示两位小数
		{
			tmp=value*100;
			buf_sm[0]=tmp/1000;
			buf_sm[1]=(tmp%1000/100)+20;
			buf_sm[2]=tmp%100/10;
			buf_sm[3]=tmp%10;
		}
		else//显示三位小数
		{
			tmp=value*1000;
			buf_sm[0]=(tmp/1000)+20;
			buf_sm[1]=tmp%1000/100;
			buf_sm[2]=tmp%100/10;
			buf_sm[3]=tmp%10;
		}
	}
	else//输入值小于0,显示负号,其余同上
	{
		if((value<0)&&(value>-10))
		{
			tmp=value*100;
			tmp=abs(tmp);
			buf_sm[0]=17;
			buf_sm[1]=(tmp/100)+20;
			buf_sm[2]=tmp%100/10;
			buf_sm[3]=tmp%10;
		}
		else if((value<=-10)&&(value>-100))
		{
			tmp=value*10;
			tmp=abs(tmp);
			buf_sm[0]=17;
			buf_sm[1]=(tmp/100);
			buf_sm[2]=tmp%100/10+20;
			buf_sm[3]=tmp%10;
		}
		else if((value<=-100)&&(value>-1000))
		{
			tmp=value;
			tmp=abs(tmp);
			buf_sm[0]=17;
			buf_sm[1]=(tmp/100);
			buf_sm[2]=tmp%100/10;
			buf_sm[3]=tmp%10;
		}
    
	}
  
}
/*
显示部分,每执行一次,显示的位左移一位,移到最左边时,重新回到最右边,开始下一次刷新。
定义有小数点的位+20,每次送断码,检查大于20,段与0x7f添加小数点。
*/
void display()
{
  if(frash_cnt<=3)
  {
    wei |=0xf0;//数码管的消隐
    
    if(buf_sm[3-frash_cnt]>=20)
    {
      duan = (DS_BUF[(buf_sm[3-frash_cnt])-20]&0x7f);//显示小数点
    }
    else
      duan = DS_BUF[buf_sm[3-frash_cnt]];//不显示小数点
    
    wei = ~wei_buf;
    wei_buf <<=1;//显示位左移一位
    frash_cnt++;
  }
  else
  {
    wei |=0xf0;//数码管的消隐
    frash_cnt=0;
    wei_buf=0x10;//显示位回到最右边
  }
}
/*
数码管自用延时
*/
void delay(uint i)
{
  uchar j;
  for(;i>0;i--)
  for(j=0;j<120;j++);

}

数码管头文件

#ifndef _shumaguan_h_
#define _shumaguan_h_
#include "math.h"
#include "reg52.h"
#define duan P0
#define wei P2

#define uchar unsigned char
#define uint unsigned int
  
extern uchar frash_cnt;
extern uchar wei_buf;

void calc_sm(float value);
void display();
void delay(uint i);


#endif

定时器配置及中断服务函数

#include "reg52.h"
#include "timer.h"
#include "shumaguan.h"


float xdata value=0 , value_now = 0;

void timer_init()
{
  TMOD = 0x02;                    //set timer0 as mode1 (16-bit)
  TL0 = T1MS;                     //initial timer0 low byte
  TH0 = T1MS;                //initial timer0 high byte
  TR0 = 1;                        //timer0 start running
  ET0 = 1;                        //enable timer0 interrupt
  EA = 1;                         //open global interrupt switch
}



/* Timer0 interrupt routine */
void tm0_isr() interrupt 1 using 1
{
    if(value!=value_now)//检测显示值与当前值是否匹配
    {
      value=value_now;//刷新显示值
      calc_sm(value_now);//重新计算显示值的输出缓冲区
    }
    display();//刷新数码管显示

}

定时器头文件

#ifndef _timer_h_
#define _timer_h_
#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
  
//-----------------------------------------------

/* define constants */
//#define FOSC 11059200L
#define FOSC 12000000L

#define T1MS 0   //1ms timer calculation method in 12T mode


//-----------------------------------------------

extern float xdata value , value_now;


void timer_init();


#endif

 

2019-11-09 12:24:56 weixin_43130546 阅读数 65
  • 静态和动态控制数码管-第1季第7部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第7个课程,全面讲解了静态数码管、无38译码器式动态数码管、有38译码器式动态数码管等各种数码管驱动方式,学完本课程将会对数码管的驱动方式彻底熟悉和掌握。

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

51单片机_数码管动态显示_数码管鬼影_数码管消影



以郭天祥单片机为例
wei 指 位&位锁存
duan 指 段&段锁存

1.鬼影的解决

1.1先送数,再开锁存

不好的方式:

duan = 1;//开锁存
P0 = 0x45;
duan = 0;//关锁存

好的方式:

P0 = 0x45;
duan = 1;//开锁存
duan = 0;//关锁存

1.2点亮必熄灭

如果先送wei,再送duan:送完duan后一定要清除duan。如果不清除,切换下一个wei时会显示上一个duan,出现鬼影。

P0 = 0x45;
wei = 1;
wei = 0;

P0 = 0x45;
duan = 1;
duan = 0;

P0 = 0x00;//清除duan
duan = 1;
duan = 0;

如果先送duan,再送wei:送完wei后一定要清除wei。如果不清除,此wei会显示下一个duan,出现鬼影。

P0 = 0x45;
duan = 1;
duan = 0;

P0 = 0x45;
wei = 1;
wei = 0;

P0 = 0xFF;//清除wei
wei = 1;
wei = 0;

1.3初始化

在单片机上电后,P0口输出值全部为1,此时数码管wei使能全部关闭,duan全部打开,也就是(8.)待亮,一旦wei使能打开就会亮(8.)。
如果先送wei,再送duan:在送wei的一瞬间,数码管就会亮(8. ),产生鬼影。解决方法:送wei前先初始化,使duan全部关闭,啥也不亮。

P0 = 0x00;//初始化,关闭断
duan = 1;
duan = 0;

wei_latch();

duan_latch();

如果先开duan_latch,再开wei_latch:不会产生鬼影。无需初始化。

duan_latch();

wei_latch();






2.数值分离的算法

			digitable[0] = duantable[sec/1%10];
			digitable[1] = duantable[sec/10%10];
			digitable[2] = duantable[sec/100%10];
			digitable[3] = duantable[sec/1000%10];
			digitable[4] = duantable[sec/10000%10];
			digitable[5] = duantable[sec/100000%10];






3.将动态扫描放在中断里,1ms扫一次,6ms扫完,1s数值加1,通过标志位,触发数值分离。将数值分离放在while(1)里,查询标志位,每1s触发一次。







4.代码示例:0-999999计数器

#include<reg52.h>

#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long

uchar code weitable[6] = 
{
	~0x20,~0x10,~0x08,~0x04,~0x02,~0x01
};

uchar code duantable[16] = 
{
	0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
	0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71
};

uchar digitable[6] = 
{
	0x00,0x00,0x00,0x00,0x00,0x00
};

sbit wei = P2^7;
sbit duan = P2^6;

ulong sec = 0;
bit flag = 0;
uchar i = 0;
uint cnt = 0;

void main(void)
{
	TH0 = 0xFC;
	TL0 = 0x67;
	EA = 1;
	ET0 = 1;
	TMOD &= ~(0xF<<0);
	TMOD |= 0x1<<0;
	TR0 = 1;

	while(1)
	{
		if(flag==1)
		{
			flag = 0;
			sec++;
			if(sec>=1000000)
			{
				sec = 0;
			}
			digitable[0] = duantable[sec/1%10];
			digitable[1] = duantable[sec/10%10];
			digitable[2] = duantable[sec/100%10];
			digitable[3] = duantable[sec/1000%10];
			digitable[4] = duantable[sec/10000%10];
			digitable[5] = duantable[sec/100000%10];
		}
	}
}

void timer0(void) interrupt 1
{
	TH0 = 0xFC;
	TL0 = 0x67;
	cnt++;
	if(cnt>=1000)
	{
		cnt = 0;
		flag = 1;
	}

	P0 = 0x00;
	duan = 1;
	duan = 0;

	switch(i)
	{
		case 0 : P0=weitable[0];wei=1;wei=0; P0=digitable[0];duan=1;duan=0; i++; break;
		case 1 : P0=weitable[1];wei=1;wei=0; P0=digitable[1];duan=1;duan=0; i++; break;
		case 2 : P0=weitable[2];wei=1;wei=0; P0=digitable[2];duan=1;duan=0; i++; break;
		case 3 : P0=weitable[3];wei=1;wei=0; P0=digitable[3];duan=1;duan=0; i++; break;
		case 4 : P0=weitable[4];wei=1;wei=0; P0=digitable[4];duan=1;duan=0; i++; break;
		case 5 : P0=weitable[5];wei=1;wei=0; P0=digitable[5];duan=1;duan=0; i=0; break;
		default : break;
	}
}
2019-04-04 23:24:37 weixin_44229819 阅读数 515
  • 静态和动态控制数码管-第1季第7部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第7个课程,全面讲解了静态数码管、无38译码器式动态数码管、有38译码器式动态数码管等各种数码管驱动方式,学完本课程将会对数码管的驱动方式彻底熟悉和掌握。

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

单片机的数码管动态实现


在这里插入图片描述
#单片机数码管实现其实很简单首先你注意两个问题
1:你要控制是哪一个数码管亮(74HC138)
2:你要控制数码管的那个位置亮(74HC245)

74HC138芯片

数码管的位

  1. 由单片机接口控制输出
    下面是单片机各个接口的真值表:
LED P2.2 P2.3 P2.4
LED1: 0 0 0
LED2: 0 0 1
LED3: 0 1 0
LED4: 0 1 1
LED5: 1 0 0
LED6: 1 0 1
LED7: 1 1 0
LED8: 1 1 1
  1. 这是单片机中74HC138芯片的接法
    在这里插入图片描述

74HC245芯片

数码管各位置代号 a b c d e f g
接口 P0.1 P0.2 P0.3 P0.4 P0.5 P0.6 P0.7

tip注意每个接口接低电位时,相应的位置为高亮
这是接口对应图

一段漂亮的代码片用于自研究,目前尚还不知道为啥数码管不亮—┭┮﹏┭┮
--------------------希望大神指导-------------------

#include <reg52.h>
int code table[]={0x3f,0x03,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f};
sbit HC138A=P2^2;
sbit HC138B=P2^3;
sbit HC138C=P2^4;
void led(int x)
{
 if   (x==1){    HC138A=0; HC138B=0; HC138C=0; };
 if   (x==2){    HC138A=0; HC138B=0; HC138C=1; };
 if   (x==3){    HC138A=0; HC138B=1; HC138C=0; };
 if   (x==4){    HC138A=0; HC138B=1; HC138C=1; };
 if   (x==5){    HC138A=1; HC138B=0; HC138C=0; };
 if   (x==6){    HC138A=1; HC138B=0; HC138C=1; };
 if   (x==7){    HC138A=1; HC138B=1; HC138C=0; };
 if   (x==8){    HC138A=1; HC138B=1; HC138C=1; };
 
 
}
void main()
{
 int x;
 while(1)
 {
 led(1);
 P0=table[0];
             P0=0Xff;
 led(2);
 P0=table[1];
             P0=0Xff;
 led(3);
 P0=table[2];
             P0=0Xff;
 led(4);
 P0=table[3];
             P0=0Xff;
 led(5);
 P0=table[4];
             P0=0Xff;
 led(6);
 P0=table[5];
             P0=0Xff;
 led(7);
 P0=table[6];
             P0=0Xff;
 led(8);
 P0=table[7];
             P0=0Xff;
 };
}

#其实现在我这代码还是有很多小瑕疵,希望大神能致电小白----万分感谢

2014-08-19 10:55:39 lanseliuxing 阅读数 2642
  • 静态和动态控制数码管-第1季第7部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第7个课程,全面讲解了静态数码管、无38译码器式动态数码管、有38译码器式动态数码管等各种数码管驱动方式,学完本课程将会对数码管的驱动方式彻底熟悉和掌握。

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

基于单片机STC89C52RC,使用定时器1,采用动态扫描的方法,在数码管前三位显示秒表,精确到0.01秒,比如5.03秒,一直循环。

首先设置显示刷新频率为6ms,每2ms刷新1个数码管,每10ms计算一次时间。

时间显示的3位采用结构体方式。

首先是电路结构,采用共阴极数码管,74573锁存器和138译码器。

然后是程序代码


/*********************************
@title:Óö¨Ê±Æ÷1ºÍ¶¯Ì¬É¨Ãè·½·¨£¬ÔÚÊýÂë¹ÜµÄÇ°Èýλ
                ÏÔʾ³öÃë±í£¬¾«È·µ½1%Ã룬¼´ºóÁ½Î»ÏÔʾ1%Ã룬
                Ò»Ö±Ñ­»·
@MCU:STC89C52
@name: Wang Yongxing
@date: 2014.08.18
**********************************/

# include "MacroAndConst.h"
# include <stc89c5xrc.h>
# include <intrins.h>


sbit LE_74573 = P1^0;
sbit LSA_74LS138 = P2^2;
sbit LSB_74LS138 = P2^3;
sbit LSC_74LS138 = P2^4;


//¹²ÒõÊýÂë¹Ü0-F dp-a£º0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
//0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
char SegLed[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
                                0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

void InitTimer1(void);
void SegLedDisplay(void);

struct
{
    char sec0;//Ãë±í×î¸ßλ
    char sec1;//Ãë±íСÊýµãºóµÚһλ
    char sec2;//Ãë±íСÊýµãºóµÚ¶þλ
}sec;

uchar num = 7;
char ms10flag = 0;


int main(void)
{
    
    
    InitTimer1();//¶¨Ê±Æ÷0³õʼ»¯
    EA = 1;//ʹÄÜϵͳ×ÜÖжÏ
    LE_74573 = 1;
    sec.sec0 = 0;
    sec.sec1 = 0;
    sec.sec2 = 0;
    while(1)
    {}    
    return 0;
}

void InitTimer1(void)
{
    TMOD = 0x10;//¶¨Ê±Æ÷0£¬16λ¶¨Ê±Æ÷
    TH1 = 0xF8;//¶¨Ê±Îª2ms£¬50*1000us
    TL1 = 0x2F;
    ET1 = 1;    //ʹÄܶ¨Ê±Æ÷0µÄÖжÏ
    TR1 = 1;//¶¨Ê±Æ÷0¿ªÊ¼ÔËÐÐ
}

void Timer1Isr() interrupt 3 using 1
{
    TH1 = 0xF8;//¶¨Ê±Îª2ms£¬50*1000us
    TL1 = 0x2F;
    ms10flag++;
    if(ms10flag == 5)
    {
        ms10flag = 0;
        P0 = 0X00;//Çå³ýÏÔʾ
            if(++sec.sec2 == 10)//¼ÆËãʱ¼ä
            {
                sec.sec2 = 0;
                if(++sec.sec1 == 10)
                {
                    sec.sec1 = 0;
                    if(++sec.sec0 == 10)
                    {
                        sec.sec0 = 0;
                    }
                }
            }        
    }    
    SegLedDisplay();
}    


void SegLedDisplay(void)
{

    
        switch(num)
        {
    //        case 0:LSC_74LS138 = 0;LSB_74LS138 = 0;LSA_74LS138 = 0;break;
    //        case 1:LSC_74LS138 = 0;LSB_74LS138 = 0;LSA_74LS138 = 1;break;
    //        case 2:LSC_74LS138 = 0;LSB_74LS138 = 1;LSA_74LS138 = 0;break;
    //        case 3:LSC_74LS138 = 0;LSB_74LS138 = 1;LSA_74LS138 = 1;break;
    //        case 4:LSC_74LS138 = 1;LSB_74LS138 = 0;LSA_74LS138 = 0;break;
            case 5:
            {
                LSC_74LS138 = 1;
                LSB_74LS138 = 0;
                LSA_74LS138 = 1;
                P0 = SegLed[sec.sec2];
                break;
            }
            case 6:
            {
                LSC_74LS138 = 1;
                LSB_74LS138 = 1;
                LSA_74LS138 = 0;
                P0 = SegLed[sec.sec1];
                break;
            }
            case 7:
            {
                LSC_74LS138 = 1;
                LSB_74LS138 = 1;
                LSA_74LS138 = 1;    
                P0 = SegLed[sec.sec0];
                P0 |= 0x80;//ÏÔʾСÊýµã
                break;
            }
        }    
        if(--num == 4)
        {
            num = 7;
        }
}



不知怎么回事,keil的代码中文注释全部成了乱码。

中间出现了一个问题,为了显示小数点,最高位显示使用了语句

P0 = 0x80|SegLed[sec.sec0];

最高位显示秒的数码管,在0,6,9时显示不正常,全闪

后来更改了语句为

                P0 = SegLed[sec.sec0];
                P0 |= 0x80;//ÏÔʾСÊýµã

方正常的,但依然不知道是什么原因。不过效果很好了。


没有更多推荐了,返回首页