找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6671|回复: 39
收起左侧

51单片机流水灯,逐个点亮,我不能全部都逐个点亮

  [复制链接]
ID:555516 发表于 2019-6-7 13:21 | 显示全部楼层 |阅读模式
捕获.PNG 可以实现闪烁、轮流点亮和逐个点亮,但暂停不行(实物不能暂停,仿真可以),求大佬改一下。
  1. #include<reg52.h>
  2. #define uchar unsigned char
  3. #define unit unsigned int
  4. void delay_ms(unsigned int);
  5. sbit LED1=P0^0;
  6. sbit LED2=P0^1;
  7. sbit LED3=P0^2;
  8. sbit LED4=P0^3;
  9. sbit LED5=P0^4;
  10. sbit LED6=P0^5;
  11. sbit LED7=P0^6;
  12. sbit LED8=P0^7;
  13. sbit LED9=P2^0;
  14. sbit LED10=P2^1;
  15. sbit LED11=P2^2;
  16. sbit LED12=P2^3;
  17. sbit LED13=P2^4;
  18. sbit LED14=P2^5;
  19. sbit LED15=P2^6;
  20. sbit LED16=P2^7;
  21. sbit  K=P3^4;
  22. sbit T=P1^0;
  23. sbit K1=P3^5;
  24. uchar num,num1;
  25. uchar loopled=0xfe;
  26. uchar flag=0;
  27. uchar code table0[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
  28. uchar code table1[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};


  29. void  init        (){
  30. TMOD = 0x00;   //定时器T0工作方式1
  31. TH0=(65536-50000)/256;   //TH0=(65536-50000)/256;
  32. TL0=(65536-50000)%256;   //TL0=(65536-50000)%256;
  33. EA=1;
  34. ET0=1;
  35. // TR0=1;

  36. }


  37. void  init1(){
  38. TMOD = 0x10;   //定时器T0工作方式1
  39. TH0=(65536-50000)/256;   //TH0=(65536-50000)/256;
  40. TL0=(65536-50000)%256;   //TL0=(65536-50000)%256;
  41. EA=1;
  42. ET1=1;
  43. //TR1=1;

  44. }

  45. void main(void){
  46.   int i;
  47.   IT0 = 1;  //设外部中断0为边缘触发
  48. EX0 = 1;  //开外部中断0
  49. EA = 1;   //开总中断
  50.   IT1=1;        //开外部中断INT1
  51.   EX1=1;        //开外部中断


  52.           init1();
  53.   init();

  54.             while(1){
  55.     if(K==0){//控制轮流点亮的开启
  56.            TR0=1;
  57. }
  58.     if(K1==0){//控制闪烁的开启
  59.            TR1=1;
  60. }                  
  61.               
  62.          
  63.           if(num==20){//轮流点亮程序
  64.           num=0; //num清零
  65.         for(i=0;i<8;i++){
  66.           P0=table0[i];        //
  67.           delay_ms(100);
  68.           P0=0XFF;        //关闭最后一盏灯
  69.            }
  70.         for(i=0;i<8;i++){
  71.           P2=table0[i];
  72.           delay_ms(100);
  73.           P2=0XFF; //关闭最后一盏灯
  74.            }
  75.         }
  76.                  if(num1==20){//闪烁程序
  77.           num1=0; //num1清零
  78.                   
  79.             LED1=~LED1; //将全部端口取反,实现闪烁功能
  80.          LED2=~LED2;
  81.    LED3=~LED3;
  82.    LED4=~LED4;
  83.    LED5=~LED5;
  84.    LED6=~LED6;
  85.    LED7=~LED7;
  86.    LED8=~LED8;
  87.    LED9=~LED9;
  88.    LED10=~LED10;
  89.    LED11=~LED11;
  90.    LED12=~LED12;
  91.    LED13=~LED13;
  92.    LED14=~LED14;
  93.    LED15=~LED15;
  94.    LED16=~LED16;
  95.          
  96.           }

  97.   }        



  98. while(1);

  99. }

  100.   int0() interrupt 0 { //暂停
  101.             delay_ms(200);
  102.                 ET0=~ET0;        //将开启中断的端口取反
  103.                  ET1=~ET1;
  104.                  EX1=~EX1;

  105.         }
  106.         


  107.     int1() interrupt 2                 //逐个点亮
  108. {        
  109.                            P0=loopled;//点亮P0组第一个灯
  110.         P2=0xFF; //关闭P2组

  111.                  loopled=loopled<<1;  //循环左移
  112.         loopled=loopled|1; // 最右补1,防止点亮最后一个LED

  113.   if (loopled==0xff) {
  114.                 flag++;// 一路循环完成场合,指向下一组

  115.                  loopled=0xFE; // 下一组最后一个LED点亮


  116.     if (flag==2) {        // 两组组循环完成了,重新指向第一组
  117.                         flag=0;
  118.                 }               
  119.         }

  120.         switch(flag) {            // 根据FLAG的情况开启/关闭P0/P2组
  121.                 case 0:// P0组
  122.                         P2=0xFF;  // 关闭P2组

  123.                         P0=loopled;                                
  124.                         break;
  125.                 case 1:// P2组
  126.                         P0=0xFF;  // 关闭P0组

  127.                         P2=loopled;
  128.                         break;

  129.         }

  130.                          }


  131.         



  132. time0() interrupt 3{//设定初值

  133.          TH0=(65536-50000)/256;        
  134.           TL0=(65536-50000)%256;
  135.          num1++;
  136.          
  137.          
  138. }

  139. time1() interrupt 1{

  140.          TH0=(65536-50000)/256;         //设定初值
  141.           TL0=(65536-50000)%256;
  142.          num++;
  143.          
  144.          
  145. }




  146.         void delay_ms(unsigned int dt)//延时函数
  147. {
  148. register unsigned char bt,ct;
  149. for (;dt;dt--)
  150.    for (ct=2;ct;ct--)
  151.        for (bt=250;--bt;);
  152. }
复制代码

附上完整代码

回复

使用道具 举报

ID:386367 发表于 2019-6-8 19:58 | 显示全部楼层
逐个点亮的部份,其实不用写得那麽难看懂,你写得简单一点,方便自己,也方便他人。
建议先检查,测试一下硬件连接有没问题,然後拆分逐个点亮的代码部份,逐一调试。
回复

使用道具 举报

ID:555516 发表于 2019-6-9 19:55 | 显示全部楼层
tt123 发表于 2019-6-8 19:58
逐个点亮的部份,其实不用写得那麽难看懂,你写得简单一点,方便自己,也方便他人。
建议先检查,测试一下 ...

呃,, 左移的代码是跟老师学的,,,我要做的效果是 按一下按钮就中断去点亮下一个灯,  你能帮我改一下吗  
回复

使用道具 举报

ID:517466 发表于 2019-6-10 00:18 | 显示全部楼层
/** 流水灯*/
#include<reg52.h>

#define uchar unsigned char
#define uint unsigned int
       
sbit button=P1^0;

/* 函数申明 -----------------------------------------------*/
void delay(uint z);
void led(void);

/*
********************************************************************************
** 函数名称 : main(void)
** 函数功能 : 主函数
********************************************************************************
*/

uchar loopled=0xfe;
uchar flag=0;

void main() {
        P0=loopled;
        P2=0xFF;
        P3=0xFF;
        while(1) {
                // 按钮按下了?
                if (button==0) {
                          delay(200);
                          // 等待按钮松开
                                while(button==0);
                                if (button==1) {
                                        // 按钮按下又抬起
                                        led();
                                }
                }
        }
}

// 流水灯
void led(void) {
        // 循环左移
        loopled=loopled<<1;
        // 最右补1,防止点亮最后一个LED
        loopled=loopled|1;
  if (loopled==0xff) {
                // 一路循环完成场合,指向下一组
                flag++;
                // 下一组最后一个LED点亮
                loopled=0xFE;
                // 三组循环完成了,重新指向第一组
    if (flag==3) {
                        flag=0;
                }               
        }
        // 将循环数据送给当前组
        switch(flag) {
                case 0:// P0组
                        P2=0xFF;  // 关闭P2组
                        P3=0xFF;  // 关闭P3组
                        P0=loopled;
                        break;
                case 1:// P2组
                        P0=0xFF;  // 关闭P0组
                        P3=0xFF;  // 关闭P3组
                        P2=loopled;
                        break;
                case 2:// P3组
                        P0=0xFF;  // 关闭P0组
                        P2=0xFF;  // 关闭P2组
                        P3=loopled;
                        break;
        }
}

/*
********************************************************************************
** 函数名称 : delay(uint z)
** 函数功能 : 延时函数
********************************************************************************
*/
void delay(uint z)
{
    uchar j;
    for(z;z>0;z--)
        for(j=100;j>0;j--);
}

流水灯.jpg

流水灯·.zip

9.1 KB, 下载次数: 10

回复

使用道具 举报

ID:517466 发表于 2019-6-10 00:21 | 显示全部楼层
我发给你的,没有接入LED。你只需要仿真,看到P0,P2,P3口随着按钮每按一次,只有一个口线输出0(视为点亮LED),并一直保持循环即可。
回复

使用道具 举报

ID:517466 发表于 2019-6-10 00:27 | 显示全部楼层
我的程序中没有使用中断。改成中断的话,需要调整按钮连接的口线,连接到P3口的外部中断管脚上(INT0或者INT1),同时把程序中P3组的循环改成P1。51的外部中断的设置,参照的例子很多,也很简单。
设置中断处理后,当按钮按下时,会自动产生中断。在中断处理中执行led()函数就可以的。
回复

使用道具 举报

ID:558594 发表于 2019-6-10 01:38 来自手机 | 显示全部楼层
逐个点亮不是可以用,循环左移_crol(0,1),我感觉可以用
回复

使用道具 举报

ID:555516 发表于 2019-6-10 20:25 | 显示全部楼层
suncat0504 发表于 2019-6-10 00:18
/** 流水灯*/
#include

很强,,,我代码写得有点差 ,,大佬你的代码很强,谢谢
回复

使用道具 举报

ID:555516 发表于 2019-6-10 21:53 | 显示全部楼层
文二 发表于 2019-6-10 01:38
逐个点亮不是可以用,循环左移_crol(0,1),我感觉可以用

我需要逐个点亮16个LED灯 所以要2个端口  ,直接用循环左移只能点亮一半或者2个端口一起逐个点亮
回复

使用道具 举报

ID:554109 发表于 2019-6-11 08:26 | 显示全部楼层
感觉你的代码也有一定的问题,while(1)中无论有没有语句好像都需要{}这个吧,即使是空循坏也是需要这个的
回复

使用道具 举报

ID:555516 发表于 2019-6-11 20:41 | 显示全部楼层
冰麒麟 发表于 2019-6-11 08:26
感觉你的代码也有一定的问题,while(1)中无论有没有语句好像都需要{}这个吧,即使是空循坏也是需要这个的

呃,,,这个我解释不了,这个代码是我老师说的  我并不理解,但他说没错的
回复

使用道具 举报

ID:517466 发表于 2019-6-11 22:09 | 显示全部楼层
while语句有没有{}无所谓的。有,表示条件为真时执行一段代码块,因为执行语句多,所以用{}包起来。没有{}的话,条件为真时,执行紧邻其后的一个有效语句,哪怕是一个“;”,表示空语句,什么也不做。楼主的代码中,所有处理都放在中断处理中执行,所以主处理中什么都不做,仅仅是一个死循环罢了。
回复

使用道具 举报

ID:557774 发表于 2019-6-12 00:03 来自手机 | 显示全部楼层
比我写的好多了,我还是个初学者
回复

使用道具 举报

ID:216226 发表于 2019-6-12 08:48 | 显示全部楼层
4楼的写的还可以了
回复

使用道具 举报

ID:560560 发表于 2019-6-12 09:14 | 显示全部楼层
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define led_8 P1
uchar m;
void ys (uint x)
{ uchar i;
while(x--)
for(i=0;i<120;i++);
}
void main()
{
uchar j,k;
while(1)
{
for(j=0;j<3;j++)
{
m=0x7f;
k=0;
while(k!=8)
{
m=_crol_(m,1);
led_8=m;
ys(500);
k++;
}

led_8=0xff;
ys(500);
for(j=0;j<3;j++)
{
led_8=0x55;
ys(500);
led_8=0xaa;
ys(500);
}
led_8=0xff;
ys(500);
k=0;
while(k!=8)
{
led_8<<=1;
ys(500);
k++;
}

}
}
}
回复

使用道具 举报

ID:560560 发表于 2019-6-12 09:16 | 显示全部楼层
如果不能的话,我建议你改一下图
回复

使用道具 举报

ID:559917 发表于 2019-6-12 09:26 | 显示全部楼层
suncat0504 发表于 2019-6-10 00:18
/** 流水灯*/
#include

我印象中我有做过流水灯
回复

使用道具 举报

ID:555516 发表于 2019-6-12 19:15 | 显示全部楼层
suncat0504 发表于 2019-6-11 22:09
while语句有没有{}无所谓的。有,表示条件为真时执行一段代码块,因为执行语句多,所以用{}包起来。没有{} ...

那我想问大佬个问题,我想要实现用中断去控制其他中断的暂停和开始该怎么做?
回复

使用道具 举报

ID:555516 发表于 2019-6-12 19:17 | 显示全部楼层
数据集 发表于 2019-6-12 09:14
#include
#include
#define uint unsigned int

谢谢了,楼上的大佬已经帮我搞定了,,,谢谢
回复

使用道具 举报

ID:517466 发表于 2019-6-12 20:46 | 显示全部楼层
czd175711 发表于 2019-6-12 19:15
那我想问大佬个问题,我想要实现用中断去控制其他中断的暂停和开始该怎么做?

利用中断控制位啊。建议你看看单片机原理。每个中断都有自己的控制位,比如51单片机中的ET0,ET1,ES等。通常控制位=0,就表示禁止那个中断的响应处理。控制位=1,表示允许那个中断来的时候,调用对应的中断处理。
回复

使用道具 举报

ID:517466 发表于 2019-6-12 20:54 | 显示全部楼层
czd175711 发表于 2019-6-12 19:15
那我想问大佬个问题,我想要实现用中断去控制其他中断的暂停和开始该怎么做?

中断处理中控制其它中断,还需要考虑优先级的问题。比如在低级中断中控制高级中断,会出现这样的情况:低级的在执行高级中断禁止的时候,还没来得及执行禁止语句的时候,高级中断发生了。也就是说,有时候,你觉得你已经禁止某个中断了,结果实际运行中,还是出现了那个被禁止的中断被执行过。这就是优先级有高低而产生的问题,在实际应用中要加以注意。
不忙的时候,多看看原理方面的书,对工作会有很大帮助的。
回复

使用道具 举报

ID:517466 发表于 2019-6-12 20:58 | 显示全部楼层
初学编程的人,给你们提一个建议:一点更要养成良好的编程习惯。比如加注释,变量、函数命名方式,对其缩进等等,开始可能觉得很烦,习惯了就好了。这样自己做的东西,别人也容易理解。自己以后修改或者代码重用,也不会出现摸不到头脑的情况。
回复

使用道具 举报

ID:555516 发表于 2019-6-13 11:01 来自手机 | 显示全部楼层
suncat0504 发表于 2019-6-12 20:46
利用中断控制位啊。建议你看看单片机原理。每个中断都有自己的控制位,比如51单片机中的ET0,ET1,ES等。 ...

这个我知道,我试过用中断,但是中断里面的代码应该是什么?把总中断EA取反吗?
回复

使用道具 举报

ID:561674 发表于 2019-6-13 12:07 | 显示全部楼层
suncat0504 发表于 2019-6-11 22:09
while语句有没有{}无所谓的。有,表示条件为真时执行一段代码块,因为执行语句多,所以用{}包起来。没有{} ...

应该会出错吧
回复

使用道具 举报

ID:517466 发表于 2019-6-13 12:50 | 显示全部楼层
czd175711 发表于 2019-6-13 11:01
这个我知道,我试过用中断,但是中断里面的代码应该是什么?把总中断EA取反吗?

尽量不要用取反,使用明确的赋值。比如在串口中断中,禁止使用计时器0 的中断时,
/*------------------------------------------------
                     串口中断程序
------------------------------------------------*/
void com_intr (void) interrupt 4 //串行中断服务程序
{
    unsigned char Temp;    //定义临时变量
    uchar i=0;
    ET=0;                  // 临时禁止Timer0的中断
    if(RI) {               //判断是接收中断产生
              RI=0;              //标志位清零
              Temp=SBUF;         //读入缓冲区的值
        SBUF=Temp;         //把接收到的值再发回电脑端
         }
   if(TI) {                //如果是发送标志位,清零
                 comio=~comio;
     TI=0;
   }
   ET0=1;                  // 允许Timer0的中断
}
回复

使用道具 举报

ID:561732 发表于 2019-6-13 13:48 | 显示全部楼层
我也在做这个
回复

使用道具 举报

ID:560178 发表于 2019-6-13 17:13 | 显示全部楼层
可以先一个一个点亮试试,再整合代码逐个点亮,加油!
回复

使用道具 举报

ID:555516 发表于 2019-6-17 14:00 | 显示全部楼层
suncat0504 发表于 2019-6-10 00:18
/** 流水灯*/
#include

有段代码不怎么理解 ,想问一下什么意思
// 循环左移
        loopled=loopled<<1;
        // 最右补1,防止点亮最后一个LED
        loopled=loopled|1;


loopled<<1// 循环左移 到最后loopled应该等于0X7F
那么最右补1 怎么能做到防止点亮最后一个LED


[// 最右补1,防止点亮最后一个LED
        loopled=loopled|1;】这个代码是怎么理解的

回复

使用道具 举报

ID:555516 发表于 2019-6-17 14:19 | 显示全部楼层
suncat0504 发表于 2019-6-13 12:50
尽量不要用取反,使用明确的赋值。比如在串口中断中,禁止使用计时器0 的中断时,
/*------------------ ...

有个问题想问,,,,为什么要用串口来实现中断?INT0的优先级是最高的,,那用INT0会不会更好,而且我小白,,,这个代码有点看不懂。   我用INT0中断去将EX1  ET0  ET1 取反  在仿真上可以实现暂停,但我将代码烧录进实物  却实现不了,想问下为什么
回复

使用道具 举报

ID:555516 发表于 2019-6-17 15:29 来自手机 | 显示全部楼层
suncat0504 发表于 2019-6-10 00:18
/** 流水灯*/
#include


哦,,,我好像理解了,|表示的应该是或的意思吧,
回复

使用道具 举报

ID:517466 发表于 2019-6-17 16:36 | 显示全部楼层
czd175711 发表于 2019-6-17 14:00
有段代码不怎么理解 ,想问一下什么意思
// 循环左移
        loopled=loopled

循环左移场合,字节的Bit0会自动补入0,不或上‘1’的话,会导致bit0对应的LED也被点亮。
对于数据FF,不断左移后的变化是:FE,FC, F8, F0, E0,C0,80, 00
回复

使用道具 举报

ID:517466 发表于 2019-6-17 16:41 | 显示全部楼层
czd175711 发表于 2019-6-17 14:19
有个问题想问,,,,为什么要用串口来实现中断?INT0的优先级是最高的,,那用INT0会不会更好,而且我小 ...

我是给你举个在中断中禁止其他中断的例子。你的程序仿真没有问题,写入芯片后不执行,需要调试。通过管脚输出数据或者通过串口向PC发数据,来观察中间的处理过程。没有你的程序,我也只能告诉你这么做。
回复

使用道具 举报

ID:564818 发表于 2019-6-17 17:28 | 显示全部楼层
用汇编比较简单 左移右移
回复

使用道具 举报

ID:555516 发表于 2019-6-17 21:37 | 显示全部楼层
suncat0504 发表于 2019-6-17 16:41
我是给你举个在中断中禁止其他中断的例子。你的程序仿真没有问题,写入芯片后不执行,需要调试。通过管脚 ...

我现在附上完整代码了   可以帮我看看,,谢谢
回复

使用道具 举报

ID:555516 发表于 2019-6-17 21:42 | 显示全部楼层
suncat0504 发表于 2019-6-17 16:36
循环左移场合,字节的Bit0会自动补入0,不或上‘1’的话,会导致bit0对应的LED也被点亮。
对于数据FF, ...

但是loopled=0xfe   循环左移 不应该是 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f 这样吗?   
回复

使用道具 举报

ID:555516 发表于 2019-6-17 21:45 | 显示全部楼层
1441 发表于 2019-6-17 17:28
用汇编比较简单 左移右移

汇编,,,我不怎么会汇编,,,而且汇编的可看性不好,,我一个小白还是先用C语言来学比较好
回复

使用道具 举报

ID:564631 发表于 2019-6-18 16:29 | 显示全部楼层
你暂停了之后没有保存当前的值,当开启之后丢失了当前值,还有一个就是你暂定后,只是中断停止了,但是外面的while循环还在执行LED
回复

使用道具 举报

ID:517466 发表于 2019-6-18 21:49 | 显示全部楼层
czd175711 发表于 2019-6-17 21:42
但是loopled=0xfe   循环左移 不应该是 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f 这样吗?

在我印象中,汇编语言的左移有两种,一种是含进位的,RLC A;一种是不含进位C的左移 RL A,都是循环模式。对于循环左移一次,Bit7变成Bit0;其他的,顺序左移。
但是在C语言中,只有<<左移,>>右移,是不具有循环方式的(抱歉没有说清楚),也就是说,在C语言中,使用<<一次后,最右侧Bit0补零;使用>>移位一次后,最左侧Bit7补零。
回复

使用道具 举报

ID:517466 发表于 2019-6-18 21:52 | 显示全部楼层
czd175711 发表于 2019-6-17 21:37
我现在附上完整代码了   可以帮我看看,,谢谢

在你的代码中,我没有看到中断处理中,对其他中断做禁止和许可的操作啊
回复

使用道具 举报

ID:555516 发表于 2019-7-11 16:21 来自手机 | 显示全部楼层
suncat0504 发表于 2019-6-18 21:52
在你的代码中,我没有看到中断处理中,对其他中断做禁止和许可的操作啊

我在外部中断INT0那里将 ET0  ET1 EX1都取反来实现中断的禁止和开启(我之前说我仿真可以实现暂停和开始,但实物不行,后来我发现是我焊接的问题,事实上仿真和实物都可以实现),但是都只能在按下暂停键后让正在实施的中断的代码全部运行完了之后才暂停,想问下怎么实现按下暂停键就将正在运行中断的实物停在那里,就是说按下暂停键后就停止在那个灯的位置(前段时间在期末考试没有时间上论坛)
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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