找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4779|回复: 18
收起左侧

关于单片机跑马灯的问题(不简单)

  [复制链接]
ID:275111 发表于 2018-5-29 16:22 | 显示全部楼层 |阅读模式
求助。问题如下,实现跑马灯,但是MCU的口是这样的。从左向右,P31 P00 P01 P02 P03 P06 P07 P34.
要求是这样的,第一下按键:P02 P03亮;然后P01 P06亮;P00 P07亮;P31 P34亮。(每一对灯依次亮,每次只有一对灯亮)
                     第二下按键:反向;
                     第三下按键:同时闪烁;
                     地四下按键:全灭。

高人指点,特别有2点,我很困惑解决不了,1,两个IO口拼成一个8bit的,怎么处理?
                                                           2,怎么调节灯闪烁的速度;(我试了delay,循环等方法都不好)

请高手写程序出来,我好学习,调试。非常感谢。

评分

参与人数 1黑币 +3 收起 理由
Yshysh + 3 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:329253 发表于 2018-5-29 17:52 来自手机 | 显示全部楼层
不是你说的两个IO口拼成八位的数,这个程序应该是用中断处理比较好
回复

使用道具 举报

ID:213173 发表于 2018-5-29 19:36 | 显示全部楼层
这是两个问题;
1.由异组端口映射到一个8位变量,操作这个变量就是操作相应端口。可以查找我在此区的回帖。异组端口组成矩阵键盘的读写操作
2.由按键控制的花样流水灯。
回复

使用道具 举报

ID:123289 发表于 2018-5-29 22:39 | 显示全部楼层
很简单,要点:
1、做一个1-4的计数器RJ,每次按键让RJ+1,再用RJ决定显示的四个方式。
2、用T0作为改变显示状态的时钟,做一个调整器RT,用RT决定T0的中断时间,改变RT的大小,就达成了调速的目的。
3、每次T0中断后置一个标记BJ=1。
4、当BJ=1时,根据RJ的值,进行显示的切换,切换完成后清除BJ=0。
回复

使用道具 举报

ID:216258 发表于 2018-5-30 08:58 | 显示全部楼层
请參考下靣的帖子,樓主的问題跟这个类似,这是我當初发问的問題,也是 wulin 大神回复指导的帖子,
不过蛮乱的,请直接看 wulin 大神 写的程序,
(如有不懂请请教 wulin 大神,我也是菜鳥級的,只是每天會進論壇看看別人写的程序)

http://www.51hei.com/bbs/dpj-93120-1.html
回复

使用道具 举报

ID:275111 发表于 2018-5-30 10:45 | 显示全部楼层
wulin 发表于 2018-5-29 19:36
这是两个问题;
1.由异组端口映射到一个8位变量,操作这个变量就是操作相应端口。可以查找我在此区的回帖 ...

非常感谢高人指导。但是现在有一个问题,就是我现在用的这款单片机51的,自己带库,P31 P00 P01 P02 P03 P06 P07 P34 这些是它自己定义过的,要求必须用这些来写,而且最好是能对它们“像一个端口”一样操作,我考虑了“位段”但是具体操作及其失败,我也不会定义结构。第二个问题是,跑马灯要循环的,这个要怎么实现?
我是小白,如果有弱智的问题,请高人明确指出,千万别觉的问题简单,非常感谢。
回复

使用道具 举报

ID:195836 发表于 2018-5-30 11:33 | 显示全部楼层
P31 P00 P01 P02 P03 P06 P07 P34这八个口是吧,那就是P0跟P3口咯
首先是P02,P03亮,此时P0=0x06,P3=0x00
然后P01,P06亮,此时P0=0x42,P3=0x00
然后P00,P07亮,此时P0=0x81,P3=0x00
然后P31,P34亮,此时P0=0x00,P3=0x12
这不就ok了吗是吧,你就在循环中,每次把数组a赋给P0口,数组b赋给P3口,一次操作这两个口就ok了吧

至于改变闪烁速度,简单的方法就是按键触发中断,中断改变定时参数,然后反映在主程序中。当然有别的方法,而且可能更好
回复

使用道具 举报

ID:216258 发表于 2018-5-30 11:33 | 显示全部楼层
请參考下靣程序看看,這也是 wulin 大神写的;


这是不同端口组合8位流水灯演示程序
#include <AT89X52.H>
#include <intrins.h>
#define uint unsigned int                         //宏定义数据类型uint
#define uchar unsigned char                 //宏定义数据类型uchar

sbit code0=P2^0;        
sbit code1=P2^1;
sbit code2=P2^2;
sbit code3=P3^0;
sbit code4=P3^1;
sbit code5=P3^2;        
sbit code6=P1^0;
sbit code7=P1^1;        

uchar Cnt50ms=0;                        //中断计时变量
uchar LED=0xfe;                        //8个发光管列阵

void Timer0Init()                //50毫秒@12.000MHz
{
        TMOD= 0x01;                //设置定时器模式
        TL0 = 0xB0;                //设置定时初值
        TH0 = 0x3C;                //设置定时初值
        TF0 = 0;                        //清除TF0标志
        TR0 = 1;                        //定时器0开始计时
        EA=1;                                //开总中断
        ET0=1;                        //开定时器0中断        
}

void PX(uchar i)                                        //写入8位数据
{   
    code0=i&0x01;i>>=1;        
    code1=i&0x01;i>>=1;
    code2=i&0x01;i>>=1;
    code3=i&0x01;i>>=1;
    code4=i&0x01;i>>=1;
    code5=i&0x01;i>>=1;
    code6=i&0x01;i>>=1;
    code7=i&0x01;
}

void main()
{
        PX(LED);
        Timer0Init();
        while(1)
        {
                if(Cnt50ms>=20)//1秒        
                {
                        Cnt50ms=0;
                        PX(LED=_crol_(LED,1));//循环左移1位
                }
        }
}
void timer0() interrupt        1
{
        TL0 = 0xB0;                //设置定时初值
        TH0 = 0x3C;                //设置定时初值
        Cnt50ms++;                //中断变量Cnt50ms自+1
}

回复

使用道具 举报

ID:341279 发表于 2018-5-30 12:00 | 显示全部楼层
感谢各位大佬!
回复

使用道具 举报

ID:275111 发表于 2018-5-30 16:36 | 显示全部楼层
karyboa 发表于 2018-5-30 11:33
请參考下靣程序看看,這也是 wulin 大神写的;

我擦哩。好。
回复

使用道具 举报

ID:275111 发表于 2018-5-30 16:37 | 显示全部楼层
struct Port_MakeUp
{
  volatile char P31:1;       
  volatile char P00:1;       
  volatile char P01:1;                          
  volatile char P02:1;       
  volatile char P03:1;       
  volatile char P06:1;       
  volatile char P07:1;       
  volatile char P34:1;                                                         
};
typedef struct Port_MakeUp LED;
这是我的想法。但是下一步怎么试都不灵,是不是这个方法有问题?
回复

使用道具 举报

ID:213173 发表于 2018-5-30 17:18 | 显示全部楼层
tianqi911 发表于 2018-5-30 10:45
非常感谢高人指导。但是现在有一个问题,就是我现在用的这款单片机51的,自己带库,P31 P00 P01 P02 P03  ...

给你写了参考程序,按键端口按你的实际电路重新定义。
#include <AT89X52.H>
#define uint unsigned int
#define uchar unsigned char
  
sbit code0=P3^1;         //定义发光管端口      
sbit code1=P0^0;
sbit code2=P0^1;
sbit code3=P0^2;
sbit code4=P0^3;
sbit code5=P0^6;        
sbit code6=P0^7;
sbit code7=P3^4;        
sbit key=P3^7;                //定义按键端口
uchar code table1[]={0xe7,0xdb,0xbd,0x7e};//花样跑马灯数组       
uchar code table2[]={0x7e,0xbd,0xdb,0xe7};
uchar code table3[]={0x00,0xff,0x00,0xff};
uchar Cnt50ms=0;                        //中断计时变量
uchar KeySec=0;                                                        //键值变量(花样选择)       
uchar j=0;                                                                //流水顺序变量

void Timer0Init()                //50毫秒@12.000MHz
{
        TMOD= 0x01;                //设置定时器模式
        TL0 = 0xB0;                //设置定时初值
        TH0 = 0x3C;                //设置定时初值
        TF0 = 0;                        //清除TF0标志
        TR0 = 1;                        //定时器0开始计时
        EA=1;                                //开总中断
        ET0=1;                        //开定时器0中断        
}

void PX(uchar i)               //写8位数据函数
{   
    code0=i&0x01;i>>=1;        
    code1=i&0x01;i>>=1;
    code2=i&0x01;i>>=1;
    code3=i&0x01;i>>=1;
    code4=i&0x01;i>>=1;
    code5=i&0x01;i>>=1;
    code6=i&0x01;i>>=1;
    code7=i&0x01;
}

void keyscan()       
{
        static uchar count=0;        //计数变量                       
        static bit key_sign;                //按键状态标志
        if(!key)                                        //检测输入如果为0
        {
                count++;                                        //计数延时消抖
                if((count>=200)&&(key_sign==0))
                {                       
                        key_sign=1;                //按键状态标志置1,防止重复响应
                        j=0;                                //流水顺序变量清0
                        KeySec++;                //键值变量自+1
                        if(KeySec>=4)
                                KeySec=0;
                }
        }
        else
        {
                count=0;                                //计数变量清0
                key_sign=0;
        }
}

void main()
{
        Timer0Init();
        while(1)
        {
                keyscan();
                if(Cnt50ms>=10)//0.5秒        
                {
                        Cnt50ms=0;
                        switch(KeySec)
                        {
                                case 0: PX(0xff); break;
                                case 1: PX(table1[j]); break;
                                case 2: PX(table2[j]); break;
                                case 3: PX(table3[j]); break;
                        }
                        j++;                //流水顺序变量自+1
                        if(j>=4)
                                j=0;
                }
        }
}
void timer0() interrupt        1
{
        TL0 = 0xB0;                //设置定时初值
        TH0 = 0x3C;                //设置定时初值
        Cnt50ms++;                //中断变量Cnt50ms自+1
}
回复

使用道具 举报

ID:341548 发表于 2018-5-30 17:25 来自手机 | 显示全部楼层
感觉和我们最近做的实验有点像…
回复

使用道具 举报

ID:275111 发表于 2018-5-31 09:47 | 显示全部楼层
wulin 发表于 2018-5-30 17:18
给你写了参考程序,按键端口按你的实际电路重新定义。
#include
#define uint unsigned int

谢谢。就像把它们弄到一起去,搞的像一个端口那样操作。那个函数PX的方法写的太赞了。
回复

使用道具 举报

ID:275111 发表于 2018-5-31 11:42 | 显示全部楼层
wulin 发表于 2018-5-30 17:18
给你写了参考程序,按键端口按你的实际电路重新定义。
#include
#define uint unsigned int

高人,有2个问题求助。
1,是您写的PX()能不能简单写几句注释,就几句就行;我看不太懂,(我用的国产的这个51单片机,不能调试,我只能看结果);
2,是一个超级弱智的问题,sbit P37 = P3^7;      sfr P3 = 0xb0;我怎么异或也实现不了单独取第7位的功能,0b1011_0000^0b0000_0111=0b1011_0111=0xb7.这是咋回事?不是应该是只有第7位是1,其他都是0才对吗?
回复

使用道具 举报

ID:213173 发表于 2018-5-31 17:21 | 显示全部楼层
tianqi911 发表于 2018-5-31 11:42
高人,有2个问题求助。
1,是您写的PX()能不能简单写几句注释,就几句就行;我看不太懂,(我用的国产 ...

1.这样写比较容易理解sbit LED0=P3^1;         //定义发光管端口      
sbit LED1=P0^0;
sbit LED2=P0^1;
sbit LED3=P0^2;
sbit LED4=P0^3;
sbit LED5=P0^6;        
sbit LED6=P0^7;
sbit LED7=P3^4;

void PX(uchar i)//写8位数据函数,假设此时参数i=0xaa,1010 1010
{   
    LED0=i&0x01;//10101010按位与00000001得0,赋值LED0
        i>>=1;                //右移后高位补0,i的值已变化为01010101
    LED1=i&0x01;//01010101按位与00000001得1,赋值LED1
        i>>=1;                //右移后高位补0,i的值已变化为00101010
    LED2=i&0x01;//00101010按位与00000001得0,赋值LED2
        i>>=1;                //右移后高位补0,i的值已变化为00010101
    LED3=i&0x01;//以下以此类推,8位数据逐位赋值LED0~LED7,
        i>>=1;
    LED4=i&0x01;
        i>>=1;
    LED5=i&0x01;
        i>>=1;
    LED6=i&0x01;
        i>>=1;
    LED7=i&0x01;
}

2.由于关键词sfr sbit的存在,其后面的等式含义不同 。
sfr P3 = 0xb0;                是P3寄存器地址定义。
sbit P37 = P3^7;    是自定义名称指向P3寄存器地址的最高位而不是异或运算。
回复

使用道具 举报

ID:275111 发表于 2018-6-1 16:04 | 显示全部楼层
wulin 发表于 2018-5-31 17:21
1.这样写比较容易理解sbit LED0=P3^1;         //定义发光管端口      
sbit LED1=P0^0;
sbit LED2=P0^1;

高人。我已经用了2个月了,但是这个基本的知识我都一直算不明白,很痛苦。你一句话就搞定了。非常感谢。
回复

使用道具 举报

ID:343067 发表于 2018-6-1 18:31 | 显示全部楼层
我也用到了这个模块,感谢楼上各位大佬!!
回复

使用道具 举报

ID:642699 发表于 2019-11-18 16:12 | 显示全部楼层
感谢楼上各位大佬~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表