独立按键控制跑马灯的速度

#include "REG52.H"

#define const_voice_short 40 //蜂鸣器短叫的时间
#define const_key_time1 15  //按键去抖动延时的时间
#define const_key_time2 15  //按键去抖动延时的时间
#define const_key_time3 15  //按键去抖动延时的时间

void initial_myself();
void initial_peripheral();
void delay_short(unsigned int uiDelayShort);
void delay_long(unsigned int uiDelayLong);

void led_flicker_09_16(); //第9个至第16个LED跑马灯程序,逐个亮且每次只能亮一个
void hc595_drive(unsigned char ucLedStatusTemp16_09);
void led_updata(); //LED更新函数
void T0_time(); //定时中断函数

void key_service(); //按键服务应用程序
void key_scan(); //按键扫描程序

sbit hc595_sh_dr=P3^6;  //上升沿时,数据寄存器数据移位
sbit hc595_st_dr=P3^5;  //上升沿时移位寄存器的数据进入数据寄存器,下降沿时数据不变。当移位结束后,会产生一个正脉冲,用于更新显示数据。 
sbit hc595_ds_dr=P3^4;  //串行数据输入端,级联的话接上一级的Q7

sbit beep_dr=P1^5;
sbit key_sr1=P0^0;
sbit key_sr2=P0^1;
sbit key_sr3=P0^2;
sbit key_gnd_dr=P0^4;

unsigned char ucKeySec=0; //被触发的按键编号
unsigned int uiKeyTimeCnt1=0; //按键去抖动延时计数器
unsigned char ucKeyLock1=0;  //按键触发后自锁的变量标志

unsigned int uiKeyTimeCnt2=0; //按键去抖动延时计数器
unsigned char ucKeyLock2=0;  //按键触发后自锁的变量标志

unsigned int uiKeyTimeCnt3=0; //按键去抖动延时计数器
unsigned char ucKeyLock3=0;  //按键触发后自锁的变量标志

unsigned int uiVoiceCnt=0;  //蜂鸣器鸣叫的持续时间计数器

unsigned char ucLed_dr1=0; //代表16个灯的亮灭状态,0灭,1亮
unsigned char ucLed_dr2=0;
unsigned char ucLed_dr3=0;
unsigned char ucLed_dr4=0;
unsigned char ucLed_dr5=0;
unsigned char ucLed_dr6=0;
unsigned char ucLed_dr7=0;
unsigned char ucLed_dr8=0;
unsigned char ucLed_dr9=0; 
unsigned char ucLed_dr10=0;
unsigned char ucLed_dr11=0;
unsigned char ucLed_dr12=0;
unsigned char ucLed_dr13=0;
unsigned char ucLed_dr14=0;
unsigned char ucLed_dr15=0;
unsigned char ucLed_dr16=0;

unsigned char ucLed_updata=0; //刷新变量。每次更改LED灯的状态都要更新一次

unsigned char ucLedStep_09_16=0; //第9个至第16个LED跑马灯的步骤变量
unsigned int uiTimeCnt_09_16=0;  //第9个至第16个LED跑马灯的统计定时中断次数的延时计数器

unsigned char ucLedStatus16_09=0; //代表底层74HC595输出状态的中间变量

unsigned char ucLedDirFlag=0;  //方向变量,把按键与跑马灯关联起来的核心变量,0代表正方向,1代表反方向
unsigned int uiSetTimeLevel_09_16=300; //速度变量,此数值越大速度越慢,此数值越小速度越快

void main()
{
 initial_myself();
 delay_long(100);
 initial_peripheral();
 while(1)
 {
  led_flicker_09_16(); //第二路独立运行的任务,第9个至第16个LED跑马灯程序,逐个亮且每次只能亮一个 
  led_updata(); //LED更新函数
  key_service(); //按键服务的应用程序
 }
}

void key_scan()  //按键扫描函数,放在定时中断里
{
 if(key_sr1==1) //IO是高电平,说明按键没有被按下,这时要及时清除一些标志位
 {
  ucKeyLock1=0; //按键自锁标志清零
  uiKeyTimeCnt1=0; //按键去抖动计数器清零,防止电压波动引起的误按
 }
 else if(key_sr1==0) //有按键按下,且是第一次按下
 {
  uiKeyTimeCnt1++; //累加定时中断次数
  if(uiKeyTimeCnt1>const_key_time1)
  {
   uiKeyTimeCnt1=0;
   ucKeyLock1=1;  //自锁按键置位,防止一直触发
   ucKeySec=1;   //触发1号按键
  }
 }
 
 if(key_sr2==1) //IO是高电平,说明按键没有被按下,这时要及时清除一些标志位
 {
  ucKeyLock2=0; //按键自锁标志清零
  uiKeyTimeCnt2=0; //按键去抖动计数器清零,防止电压波动引起的误按
 }
 else if(key_sr2==0) //有按键按下,且是第一次按下
 {
  uiKeyTimeCnt2++; //累加定时中断次数
  if(uiKeyTimeCnt2>const_key_time2)
  {
   uiKeyTimeCnt2=0;
   ucKeyLock2=1;  //自锁按键置位,防止一直触发
   ucKeySec=2;   //触发2号按键
  }
 }
 
 if(key_sr3==1) //IO是高电平,说明按键没有被按下,这时要及时清除一些标志位
 {
  ucKeyLock3=0; //按键自锁标志清零
  uiKeyTimeCnt3=0; //按键去抖动计数器清零,防止电压波动引起的误按
 }
 else if(key_sr3==0) //有按键按下,且是第一次按下
 {
  uiKeyTimeCnt3++; //累加定时中断次数
  if(uiKeyTimeCnt3>const_key_time3)
  {
   uiKeyTimeCnt3=0;
   ucKeyLock3=1;  //自锁按键置位,防止一直触发
   ucKeySec=3;   //触发3号按键
  }
 }
 
}

void key_service() //按键服务应用程序
{
 switch(ucKeySec) //按键服务状态切换
 {
  case 1:  //改变跑马灯方向的按键  
   if(ucLedDirFlag==0) //通过中间变量改变跑马灯的方向
    ucLedDirFlag=1; 
   else
    ucLedDirFlag=0; 
   
   uiVoiceCnt=const_voice_short; //按键声音触发,嘀一声就停
   ucKeySec=0;  //响应按键服务应用后,按键编号清零,避免一直触发
   break;
   
  case 2:  //加速按键
   uiSetTimeLevel_09_16=uiSetTimeLevel_09_16-10;
   if(uiSetTimeLevel_09_16<50)  //速度最快限定在50
    uiSetTimeLevel_09_16=50;
   
   uiVoiceCnt=const_voice_short; //按键声音触发,嘀一声就停
   ucKeySec=0;  //响应按键服务应用后,按键编号清零,避免一直触发
   break;
   
  case 3:  //减速按键
   uiSetTimeLevel_09_16=uiSetTimeLevel_09_16-10;
   if(uiSetTimeLevel_09_16>550)  //速度最慢限定在550
    uiSetTimeLevel_09_16=550;
   
   uiVoiceCnt=const_voice_short; //按键声音触发,嘀一声就停
   ucKeySec=0;  //响应按键服务应用后,按键编号清零,避免一直触发
   break; 
 }
}

void led_updata() //LED更新函数
{
 if(ucLed_updata==1)
 {
  ucLed_updata=0;  //及时清零,避免一直更新
  if(ucLed_dr9==1)
   ucLedStatus16_09=ucLedStatus16_09&0xfe;    //确保第1位为0  亮
  else
   ucLedStatus16_09=ucLedStatus16_09|0x01;  //确保第1位为1 灭
 
  if(ucLed_dr10==1)
   ucLedStatus16_09=ucLedStatus16_09&0xfd;   
  else
   ucLedStatus16_09=ucLedStatus16_09|0x02; 
 
  if(ucLed_dr11==1)
   ucLedStatus16_09=ucLedStatus16_09&0xfb;   
  else
   ucLedStatus16_09=ucLedStatus16_09|0x04;
 
  if(ucLed_dr12==1)
   ucLedStatus16_09=ucLedStatus16_09&0xf7;   
  else
   ucLedStatus16_09=ucLedStatus16_09|0x08;
 
  if(ucLed_dr13==1)
   ucLedStatus16_09=ucLedStatus16_09&0xef;   
  else
   ucLedStatus16_09=ucLedStatus16_09|0x10;
 
  if(ucLed_dr14==1)
   ucLedStatus16_09=ucLedStatus16_09&0xdf;   
  else
   ucLedStatus16_09=ucLedStatus16_09|0x20;
 
  if(ucLed_dr15==1)
   ucLedStatus16_09=ucLedStatus16_09&0xbf;   
  else
   ucLedStatus16_09=ucLedStatus16_09|0x40;
 
  if(ucLed_dr16==1)
   ucLedStatus16_09=ucLedStatus16_09&0x7f;   
  else
   ucLedStatus16_09=ucLedStatus16_09|0x80;
 
  hc595_drive(ucLedStatus16_09);  //74HC595底层驱动程序
 }
}

void hc595_drive(unsigned char ucLedStatusTemp16_09)
{
 unsigned char i;
 unsigned char ucTempData;
 hc595_sh_dr=0;
 hc595_st_dr=0;
 
 ucTempData=ucLedStatusTemp16_09; //先送高8位
 for(i=0;i<8;i++)
 {
  if(ucTempData>=0x80) //更新一次数据,移一次位
   hc595_ds_dr=1;//串行数据输入,如果是多片联级的话,更新一次,输入一次数据。(我的单片机只用了一个74HC595芯片)
  else
   hc595_ds_dr=0;
 
  hc595_sh_dr=0;
  delay_short(15);
  hc595_sh_dr=1;//SH引脚的上升沿把数据送入寄存器
  delay_short(15);
 
  ucTempData=ucTempData<<1;//左移一位
 }
 
 hc595_st_dr=0;
 delay_short(15);
 hc595_st_dr=1;  //ST引脚负责把寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来。上升沿时更新显示数据。
 delay_short(15);
 
 hc595_sh_dr=0; //拉低,抗干扰就增强
 hc595_st_dr=0;
 hc595_ds_dr=0;
}

/*switch状态机,进行程序切换*/
void led_flicker_09_16() //第1个至第8个LED跑马灯程序,逐个灭且每次只能灭一个
{
 switch(ucLedStep_09_16)
 {
  case 0:
   if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16)  //LED灯延时时间到
   {
    uiTimeCnt_09_16=0;  //时间计数器清零
    
    if(ucLedDirFlag==0) //正方向
    {
     ucLed_dr16=0;  //第16个灯亮
     ucLed_dr9=1;  //第9个灯灭
     ucLed_updata=1;  //更新显示
     ucLedStep_09_16=1; //切换到下一个步骤
    }
    else    //反方向
    {
     ucLed_dr16=0;  //第16个灯亮
     ucLed_dr15=1;  //第15个灯灭
     ucLed_updata=1;  //更新显示
     ucLedStep_09_16=7; //切换到上一个步骤
    }
   }
   break;
   
  case 1:
   if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16)
   {
    uiTimeCnt_09_16=0;
    
    if(ucLedDirFlag==0)
    {
     ucLed_dr9=0;  //第9个灯亮
     ucLed_dr10=1;  //第10个灭
     ucLed_updata=1;
     ucLedStep_09_16=2;
    }
    else
    {
     ucLed_dr9=0;  //第9个灯亮
     ucLed_dr16=1;  //第16个灭
     ucLed_updata=1;
     ucLedStep_09_16=0;
    }
   }
   break;
   
  case 2:
   if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16)
   {
    uiTimeCnt_09_16=0;
    
    if(ucLedDirFlag==0)
    {
     ucLed_dr10=0;  //第10个灯亮
     ucLed_dr11=1;  //第11个灭
     ucLed_updata=1;
     ucLedStep_09_16=3;
    }
    else
    {
     ucLed_dr10=0;  //第10个灯亮
     ucLed_dr9=1;  //第9个灭
     ucLed_updata=1;
     ucLedStep_09_16=1;
    }
   }
   break;

case 3:
   if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16)
   {
    uiTimeCnt_09_16=0;
    
    if(ucLedDirFlag==0)
    {
     ucLed_dr11=0;  //第11个灯亮
     ucLed_dr12=1;  //第12个灭
     ucLed_updata=1;
     ucLedStep_09_16=4;
    }
    else
    {
     ucLed_dr11=0;  //第11个灯亮
     ucLed_dr10=1;  //第10个灭
     ucLed_updata=1;
     ucLedStep_09_16=2;
    }
   }
   break;

case 4:
   if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16)
   {
    uiTimeCnt_09_16=0;
    
    if(ucLedDirFlag==0)
    {
     ucLed_dr12=0;  //第12个灯亮
     ucLed_dr13=1;  //第13个灭
     ucLed_updata=1;
     ucLedStep_09_16=5;
    }
    else
    {
     ucLed_dr12=0;  //第12个灯亮
     ucLed_dr11=1;  //第11个灭
     ucLed_updata=1;
     ucLedStep_09_16=3;
    }
   }
   break;

case 5:
   if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16)
   {
    uiTimeCnt_09_16=0;
    
    if(ucLedDirFlag==0)
    {
     ucLed_dr13=0;  //第13个灯亮
     ucLed_dr14=1;  //第14个灭
     ucLed_updata=1;
     ucLedStep_09_16=6;
    }
    else
    {
     ucLed_dr13=0;  //第13个灯亮
     ucLed_dr12=1;  //第12个灭
     ucLed_updata=1;
     ucLedStep_09_16=4;
    }
   }
   break;

case 6:
   if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16)
   {
    uiTimeCnt_09_16=0;
    
    if(ucLedDirFlag==0)
    {
     ucLed_dr14=0;  //第14个灯亮
     ucLed_dr15=1;  //第15个灭
     ucLed_updata=1;
     ucLedStep_09_16=7;
    }
    else
    {
     ucLed_dr14=0;  //第14个灯亮
     ucLed_dr13=1;  //第13个灭
     ucLed_updata=1;
     ucLedStep_09_16=5;
    }
   }
   break;

case 7:
   if(uiTimeCnt_09_16>=uiSetTimeLevel_09_16)
   {
    uiTimeCnt_09_16=0;
    
    if(ucLedDirFlag==0)
    {
     ucLed_dr15=0;  //第15个灯亮
     ucLed_dr16=1;  //第16个灭
     ucLed_updata=1;
     ucLedStep_09_16=0;
    }
    else
    {
     ucLed_dr15=0;  //第15个灯亮
     ucLed_dr14=1;  //第14个灭
     ucLed_updata=1;
     ucLedStep_09_16=6;
    }
   }
   break;
 }
}

void T0_time() interrupt 1
{
 TF0=0; //清除中断标志
 TR0=0; //关中断
  
 if(uiTimeCnt_09_16<0xffff) //设定这个条件,防止uiTimeCnt超范围
  uiTimeCnt_09_16++; 
  
 key_scan();

if(uiVoiceCnt!=0)
 {
  uiVoiceCnt--;
  beep_dr=0;  //PNP三极管控制,低电平开始鸣叫
 }
 else
 {
  ;
  beep_dr=1; 
 }  
  
 TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f
 TL0=0x2f;
 TR0=1; //开中断 
}

void delay_short(unsigned int uiDelayShort)
{
 unsigned int i;
 for(i=0;i<uiDelayShort;i++)
  ;
}

void delay_long(unsigned int uiDelayLong)
{
 unsigned int i;
 unsigned int j;
 for(i=0;i<uiDelayLong;i++)
  for(j=0;j<500;j++)
   ;
}

void initial_myself() //第一区  初始化单片机
{
 key_gnd_dr=0;
 beep_dr=1;
 
 TMOD=0x01;  //设置定时器0工作方式为1
 TH0=0xf8;
 TL0=0x2f;
}

void initial_peripheral()
{
 EA=1; //开总中断
 ET0=1; //允许定时中断
 TR0=1; //启动定时中断
}

原文地址:https://www.cnblogs.com/TheFly/p/12066813.html

时间: 2024-11-07 02:36:09

独立按键控制跑马灯的速度的相关文章

自定义TextView跑马灯

本篇主要介绍TextView的可控制跑马灯效果实现. Android自带的TextView添加几个属性就可以实现跑马灯效果,大概是这样 android:ellipsize="marquee" android:focusable="true" android:focusableInTouchMode="true" 就实现了TextView获取焦点时出现跑马灯效果. 本篇要实现的是一种不用获取焦点并且可以控制跑马灯开始和结束的方法. 1.主要利用vo

[51单片机学习笔记FIVE]----独立按键

一.8个按键控制8个LED灯 1 /******************************************************************************* 2 实验名称: 8个独立按键控制8盏LED灯(按下哪个键,那个键对应的LED亮) 3 实验时间: 2015/1/20 4 *******************************************************************************/ 5 #include

2、按下按键S1控制LED1.LED2.LED3实现跑马灯效果(CC2540开发寄存器设置)

按下按键S1控制LED1.LED2.LED3实现跑马灯效果 1 /**************************************************************************** 2 * 文 件 名: main.c 3 * 作 者: Amo [ www.amoMcu.com 阿莫单片机] 4 * 修 订: 2014-04-08 5 * 版 本: 1.0 6 * 描 述: 按下按键S1控制LED1.LED2.LED3实现跑马灯效果 7 ***********

[Android TV 按键响应]listview的textview跑马灯在鼠标控制下失效的问题

问题:遥控按键选中的选项有跑马灯效果,但是鼠标事件来说,没有跑马灯效果 解题过程:重写一个类继承textview,永远获取焦点,不行.即使我再OnhoverListener里面实现onHover并且对textview获取了焦点,但是仍旧不行 解决方法:最后重写一个类继承textview,永远获取焦点,并且对textview调用了setSelected(true)之后就可以了. public class MarqueeTextView extends TextView { public Marqu

android 自定义文字跑马灯 支持拖拽,按住停止滚动,自定义速度

android的textview自带跑马灯效果,一般使用足够了.不过也有不一般的情况,所以我实现了一个自定义textview控件,用来针对这种不一般情况下的跑马灯效果实现. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

(四)开关控制的 跑马灯 以及流水灯 电路图以及程序

电路图: 目的: K1  开始跑马灯 左->右 K2  停止 K3   跑马灯  右-> 左 K4   流水灯 参考程序: #include<reg52.h> #include<intrins.h> #define uchar8 unsigned char #define uint16 unsigned int #define LED P1 sbit key1=P2^0; sbit key2=P2^1; sbit key3=P2^2; sbit key4=P2^3; /

51单片机:独立按键与矩阵按键控制数码管

一,独立按键注意一下几点 >按下的时候,电压被拉低,所以IO口要传低电平( 0x0 ) >按下的时候要消除抖动 ( 延时10ms ),在判断,是否还是低电平,再做业务处理 下面这段程序,就是通过一个独立按键连接到p1口,控制静态数码管的 一段 进行亮和灭的切换. #include <reg52.h> sbit key_control = P1^0; sbit led = P0^0; typedef unsigned char u8; typedef unsigned int u16

android ViewPager实现 跑马灯切换图片+多种切换动画

近期在弄个项目.要求有跑马灯效果的图片展示. 网上搜了一堆,都没有完美实现的算了还是自己写吧! 实现原理利用 ViewPager 控件,这个控件本身就支持滑动翻页非常好非常强大好多功能都能用上它.利用mViewPager.setCurrentItem(currentIndex); 来实现切换当前显示的view 在加一个定时器不断设置setCurrentItem 来实现跑马灯效果. 一.主要实现类 凝视非常具体了 一看就知道了 package com.example.marqueeimage; i

STM32_GPIO配置及库函数讲解——独立按键

STM32_GPIO配置及库函数讲解——独立按键 2013-02-26 13:21:30|  分类: STM32F103VBT6 |  标签:stm32_gpio_key  |举报|字号 订阅 User Button硬件连接如下图所示:当按键被按下,PB9检测到低电平,相反PB9被3.3V电源拉高. LED硬件连接如下图所示:高电平点亮LED. 要想将PB9管脚配置成输入模式,程序所需如下步骤:(必须的) 第一步:配置系统时钟.见STM32F103x RCC寄存器配置 除此之外,还需将GPIO外