打印

数码管的动态显示

[复制链接]
6776|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
冰封小肥牛|  楼主 | 2013-1-8 23:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 冰封小肥牛 于 2013-1-9 21:40 编辑

此程序的思想是让六个数码管同时显示123456789这几个数字,本人决定不用定时器,但是他发现要在数字变化时加个延时函数(例如1变化为2),但是当我加在shuaxin();这个函数下时这个程序运行起来只有第六个数码管在变化,减少延时时间则都显示8;请问如何才能控制数字变换的速度但又不影响他的刷新的频率。  #include <reg52.h>
typedef unsigned char uchar;
typedef unsigned int uint;sbit ENLED1 = P1^4;
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
uchar code table[] = {0xc0,0xf9,0xa4,0xb0,0x99,       //定义的数码管数组
       0x92,0x82,0xf8,0x80,0x90};
uchar t = 0,i;void delay(uint xms)  //延时函数
{
uint i,j;
for(i = xms;i>0;i--)
  for(j = 110;j>0;j--);
}void shuaxin()  //数码管的动态刷新
{
static uint j = 0;
switch(j)
{
  case 0:ADDR0 = 0;ADDR1 = 0;ADDR2 = 0;j++;  P0 = table[t];break;
  case 1:ADDR0 = 1;ADDR1 = 0;ADDR2 = 0;j++;  P0 = table[t];break;
  case 2:ADDR0 = 0;ADDR1 = 1;ADDR2 = 0;j++;  P0 = table[t];break;
  case 3:ADDR0 = 1;ADDR1 = 1;ADDR2 = 0;j++;  P0 = table[t];break;
  case 4:ADDR0 = 0;ADDR1 = 0;ADDR2 = 1;j++;  P0 = table[t];break;
  case 5:ADDR0 = 1;ADDR1 = 0;ADDR2 = 1;j = 0;  P0 = table[t];break;
  default:break;  
}
}void main()            //主函数
{
uchar j = 0;
ENLED1 = 0;ADDR3 = 1;
while(1)
{  
  shuaxin();  
delay(100);  
if(t <10)
  {
   t ++;
  }
else {t = 0;}
}
}

相关帖子

沙发
fp123123| | 2013-1-8 23:52 | 只看该作者
只用ADDR0 ADDR1 ADDR2怎么实现选择6个数码管?什么扩展芯片?如果没有扩展芯片,单片机直连的话,3个PIN只能控制3个数码管

使用特权

评论回复
板凳
ayb_ice| | 2013-1-9 09:32 | 只看该作者
本帖最后由 ayb_ice 于 2013-1-10 08:04 编辑

定时中断+又缓冲就对了

不好意思,是双缓冲...

使用特权

评论回复
地板
lzqxs89| | 2013-1-9 09:55 | 只看该作者
fp123123 发表于 2013-1-8 23:52
只用ADDR0 ADDR1 ADDR2怎么实现选择6个数码管?什么扩展芯片?如果没有扩展芯片,单片机直连的话,3个PIN只 ...

它可能用的3-8译码器。

使用特权

评论回复
5
lzqxs89| | 2013-1-9 10:10 | 只看该作者
我好像看到的显示的数据table[t],没有变化(t一直为0)。
数码管显示注意事项:
1、数码与IO口正确连接,abcdefg与单片机IO口(0123456位)要对应,不然那个通用的段码就不正确了
2、先送数据在开位选,在位选的时候,请保持每次只打开一个;
3、注意数据刷新的频率大于50HZ,以避免出现闪烁;
如果有什么不对得地方,请大家帮忙指出。

使用特权

评论回复
6
lzqxs89| | 2013-1-9 10:10 | 只看该作者
我好像看到的显示的数据table[t],没有变化(t一直为0)。
数码管显示注意事项:
1、数码与IO口正确连接,abcdefg与单片机IO口(0123456位)要对应,不然那个通用的段码就不正确了
2、先送数据在开位选,在位选的时候,请保持每次只打开一个;
3、注意数据刷新的频率大于50HZ,以避免出现闪烁;
如果有什么不对得地方,请大家帮忙指出。

使用特权

评论回复
7
冰封小肥牛|  楼主 | 2013-1-9 21:28 | 只看该作者
ayb_ice 发表于 2013-1-9 09:32
定时中断+又缓冲就对了

能不能不用,我的目标是不用定时器实现六个数码管动态显示。

使用特权

评论回复
8
fp123123| | 2013-1-9 22:41 | 只看该作者
冰封小肥牛 发表于 2013-1-9 21:28
能不能不用,我的目标是不用定时器实现六个数码管动态显示。

不用定时器是可以的,我的一个项目就没有用定时器,给你参考一下,只要在主程序里不断调用display即可,这个是3位显示,稍微改一下多少位都可以

// 共阴数码管显示
void display()
{
  // 修改300成其他数值可以修改刷新频率
  // 需要根据实际运行速度选择
  static uint16_t count = 300;
  static uint8_t n = 0;

  count--;
  if(count==0)
  {
    // 全部关闭
    numPin3 = 1;
    numPin2 = 1;
    numPin1 = 1;

    // 设置数字
    n = ((n+1)%3);
    ShowOneNum(第n个数字);

    // 打开对应的位
    if(n==0) numPin3 = 0;
    else if(n==1) numPin2 = 0;
    else numPin1 = 0;
               
    count = 300;
  }
}

使用特权

评论回复
9
ZOUWEN1| | 2013-1-9 22:48 | 只看该作者
不用定时器是可以的,主要是你有两个动作要做:1.多少时间改变显示的数字;2.通过查表取出的数据,花多少时间来刷新你的六个数据管,你可以使用系统主循环来计数。你确定了上面的参数,我想你能完成的,另外你现在写的代码,离实际工程使用还差得远。

使用特权

评论回复
10
ayb_ice| | 2013-1-10 08:03 | 只看该作者
冰封小肥牛 发表于 2013-1-9 21:28
能不能不用,我的目标是不用定时器实现六个数码管动态显示。

当然是可以的,只是扩展性很差,受主循环增加减少代码影响大,更受其它中断的影响,不能用在复杂的项目中,只能用在特定的简单的项目中,意义不大

使用特权

评论回复
11
xppx1987| | 2014-11-27 09:21 | 只看该作者
ayb_ice 发表于 2013-1-9 09:32
定时中断+又缓冲就对了

不好意思,是双缓冲...

双缓冲?大侠能否具体解释一下呢?

使用特权

评论回复
12
ayb_ice| | 2014-11-27 09:35 | 只看该作者
xppx1987 发表于 2014-11-27 09:21
双缓冲?大侠能否具体解释一下呢?

缓冲也叫缓存吧

因为使用定时中断实现显示,驱动只从特定的缓存取数据显示,

只要将要显示的数据送到缓存就可以实现显示,这是单缓存,

但要显示的数据有时需要较长时间,而且可能中间处理是有错误的,如果直接往缓存里送数据,
会造成显示错误,比如任务A要显示0000,后面的任务又要显示1111,如果直接发送到缓冲区,则会出现

显示错误,但使用双缓冲就不会出现此问题,因为后面的1111取代了前面的0000,最后再送显示就可以了

使用特权

评论回复
13
ayb_ice| | 2014-11-27 09:35 | 只看该作者
xppx1987 发表于 2014-11-27 09:21
双缓冲?大侠能否具体解释一下呢?

缓冲也叫缓存吧

因为使用定时中断实现显示,驱动只从特定的缓存取数据显示,

只要将要显示的数据送到缓存就可以实现显示,这是单缓存,

但要显示的数据有时需要较长时间,而且可能中间处理是有错误的,如果直接往缓存里送数据,
会造成显示错误,比如任务A要显示0000,后面的任务又要显示1111,如果直接发送到缓冲区,则会出现

显示错误,但使用双缓冲就不会出现此问题,因为后面的1111取代了前面的0000,最后再送显示就可以了

使用特权

评论回复
14
xppx1987| | 2014-11-27 09:54 | 只看该作者
ayb_ice 发表于 2014-11-27 09:35
缓冲也叫缓存吧

因为使用定时中断实现显示,驱动只从特定的缓存取数据显示,

感谢您的解答!我在定时动态扫描数码管的时候就是在主循环中将要显示的数据送入到缓冲数组中,然后在定时中断中将缓冲数组数据送入驱动中扫描显示,这是像您所说的单缓冲吧,像一般简单的任务这样处理没有问题吧,如果任务复杂那么将要处理显示的数据先放入到一个缓冲数组中,然后再将这个数组数据一起再赋给另一个数组,再在定时中断中将后一个缓冲数组数据扫描显示。这样理解对么?

使用特权

评论回复
15
ayb_ice| | 2014-11-27 10:02 | 只看该作者
xppx1987 发表于 2014-11-27 09:54
感谢您的解答!我在定时动态扫描数码管的时候就是在主循环中将要显示的数据送入到缓冲数组中,然后在定时 ...

基本差不多吧

假设有两个缓存A,B

中断只从B取数据,
主循环只往A里送数据,最后一次性将A传送给B就可以了,如果要求更严格,应该在中断显示第一位时一次性将A传送给B

使用特权

评论回复
16
叶伤| | 2014-11-27 10:35 | 只看该作者
void shuaxin()  //数码管的动态刷新
{

static unsigned char j;
static unsigned char Count;
static unsigned char times;
if(times>=FlashTime)//FlashTime为宏定义的数据更新时间
{
    times=0;Count++;
    if(Count>=4) Count=0;//第一位显示0~4,因为有1个数码管,效果就跟整体显示0~9一样了
}
j=Count;//用Count保护第一位数据,这样j怎么变都不会影响到显示状态,因为你在switch里总要改变j
//其实显示display(num[j+1])的话就可以不用Count,凑合吧。
………//这里是原来的switch
}

延时函数设置为10ms。
FlashTime定义为
#define FlashTime 99
这样就可以差不多一秒刷一个数了


使用特权

评论回复
17
叶伤| | 2014-11-27 10:42 | 只看该作者
本帖最后由 叶伤 于 2014-11-27 10:44 编辑

你开始只有最后一位是因为前5位显示一瞬间就消失了。后一位显示是因为延时时只有那一位在显示(其它已在上面消失。)

后来显示全8是因为刷新太快,眼睛跟不上。

我上面的就是让刷新时数据更新慢下来,比如刷新99次后数据才变化。

上面程序还有问题,我看错了你的switch用法,以为你是要轮流显示0~9

上面的Count>=4请改为>=6。

【第三次更新:没看发帖时间,我又坑了。。。好吧,保留回复,提醒自己以后一定要看好发帖时间再说话。。。】

使用特权

评论回复
18
piaoyiliu03| | 2015-8-26 09:13 | 只看该作者
fp123123 发表于 2013-1-8 23:52
只用ADDR0 ADDR1 ADDR2怎么实现选择6个数码管?什么扩展芯片?如果没有扩展芯片,单片机直连的话,3个PIN只 ...

ADDR0,ADDR1,ADDR2通过控制位来控制六位数码管
138芯片是个扩展芯片,它是节约IO口,
直接联可以的,但是如果位数多的话驱动能力达不到,可能也不会亮,51单片机IO总的驱动电流50mA左右

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

27

主题

201

帖子

1

粉丝