我们一般51单片机使用的流水灯–跑马灯绝大多多数都是通过–软件Delay延时实现,但是这样会非常占用MCU时间,MCU就没有太多时间来处理其他的事情了!!
那如何避免这种情况的发生呢?
答案当然有–我们可以使用单片机的定时中断来实现!
以下是我在Ptroteus仿真环境下,两个按键控制流水灯不同模式的实现
实验电路:
实验现象:
按键没有按下时,LED按每1s时间从上往下亮下来,当按键1按下后,LED按相反方向-每1s时间从下往上依次亮灭,当按键2按下时,LED加快从上往下亮下来的速度(大约200ms左右)
实验程序:/*
* 本次实验的系统主频率为11.0592MHZ
*/
#include
#include
typedef signed char sint8_t;
typedef signed short int sint16_t;
typedef signed long int sint32_t;
typedef unsigned char uint8_t;
typedef unsigned short int uint16_t;
typedef unsigned long int uint32_t;
uint8_t LED_Number[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
#define LED P1
#define NoKeyProcess 0
#define Key2_Press 2
uint8_t T0RH=0;
uint8_t T0RL=0;
bit Time_1s_Flag=0;
bit IT0_Flag=0;
sbit Key2=P3^4;
void Delayxms(uint16_t xms) //@11.0592MHz
{
unsigned char i, j;
while(xms--)
{
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
void TimerConfiger(unsigned int xms)
{
unsigned long temp;
temp=11059200/12;
temp=(temp*xms)/1000;
temp=65536-temp; //定时器重载值
TMOD&=0XF0;
TMOD|=0X01; //定时器模式1 16位定时器
T0RH=(uint8_t)(temp>>8);
T0RL=(uint8_t)temp;
TH0=T0RH;
TL0=T0RL;
ET0=1; //T0中断打开
TR0=1; //T0定时器打开
}
/*按键处理函数*/
void Key_Process(uint8_t key_value)
{
uint8_t i=0;
switch(key_value)
{
case Key2_Press:
for(i=0;i<8;i++)
{
LED=~(LED_Number[i]);
Delayxms(200); //流水灯速度加快
}
break;
default:break; //关闭LED
}
}
/*Key2 Key3 按键状态机扫描函数 --10ms定时器中扫描*/
void vKey_Scan(){
static uint8_t Key_Value=0,Key_status=0,priv_key_val =0;
Key_Value|=(Key2==1)? NoKeyProcess:Key2_Press;
switch(Key_status)
{
case 0: //Key pressed
if(Key_Value)
{
priv_key_val=Key_Value;
Key_status++;
}
break;
case 1: //Confirm key pressed
if(priv_key_val==Key_Value)
{
Key_status++;
Key_Process(priv_key_val); //按键处理函数
}
else
Key_status=0;
break;
case 2:// Wait to release
if(Key_Value == 0)
{
Key_status = 0;
}
break;
default:break;
}
}
void SystemInit()
{
EA=1; //中断总开关
IT0=1; //下降沿触发Interrput 0中断
EX0=1; //Interrput 0中断控制位
}
void main()
{
uint8_t i=0;
SystemInit();
/*Interrupt0 下降沿触发*/
TimerConfiger(10);
while(1)
{
if(Time_1s_Flag)
{
Time_1s_Flag=0;
LED=~(LED_Number[i]);
i++;
if(i==8)
i=0;
}
if(IT0_Flag) //Interrupt 0中断发生标志位
{
IT0_Flag=0;
i--;
for(i;i>0;i--)
{
LED=~(LED_Number[i]);
Delayxms(1000); //流水灯速度加快
}
}
}
}
void Timer0_ISR() interrupt 1 //TIM0 中断服务函数
{
static uint8_t timer_1s=0;
TH0=T0RH;
TL0=T0RL;
if(++timer_1s>=100)
{
timer_1s=0;
Time_1s_Flag=1;
}
vKey_Scan();
}
void IT0_ISR() interrupt 0 //Interrput 0 中断服务函数
{
IT0_Flag=1;
}
实验总结:
本次实验使用了Interrupt 0中断控制 P32引脚下降沿(从高电平到低电平触发Interrupt 0中断)和TImer0 定时中断 定时10ms(经典滤波时间!) --并在10ms定时中完成按键检测 --按键检测采用状态机的编程思想
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)