单片机的延时与中断问题及解决方法
电动机转动,同时黄灯亮,1秒右边转动,蓝灯亮,以此循环下去,但是这个程序用上去后,左边转》右边转》左边转》之后就一直是左边了,不切换了,谁能帮我解决下问题,感激不尽!!
#include
sbit m=P2^0;
sbit b=P2^6;
sbit y=P2^7;
unsigned char count;
void main()
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
ET0=1;
EA=1;
count=0;
m=!0;
b=!1;
y=!0;
while(1)
{
if(TF0==1)
{
count++;
if(count==20)
{
m=0;
b=1;
y=0;
}
if(count==40)
{
m=!0;
b=!1;
y=!0;
}
TF0=0;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
}
}
}
答案
#include
sbit m=P2^0;
sbit b=P2^6;
sbit y=P2^7;
unsigned char count;
void main()
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
count=0;
m=!0;
b=!1;
y=!0;
while(1) {
if(TF0==1) {
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TF0=0;
count++;
if(count==20) {
m=0; b=1; y=0;
}
if(count==40) {
count=0; //加上这句.
m=!0; b=!1; y=!0;
}
}
}
}!
用T0定时50ms,溢出20次,溢出40次,分别代表了具体的时间。 溢出40次之后,应该从头开始统计溢出次数,所以,此处应该有count=0;。 楼主原来的程序,缺少count=0;,那么它就会继续增加,直到65536,才自动回到0。 这样,时间,就难以控制了。
11、求助关于51单片机外部中断的问题,小弟最近在学单片机,刚做了一个键盘扫描程序。发现如果外部中断为电平触发,程序能正常运行。但如果改为边沿触发,在将键值送给显示重开中断指令为EX0=1后,中断竟然还会被触发一次,这之后,再按键就不能触发中断了。如果将中断程序中关中断语句去掉,按键能被扫描,但引起中断的次数不好说了。请大侠们看看哪出问题了。谢谢
uchar keynum,//定义全局变量按键时的键值
dpnum,//显示值
time1,//延时计数值
topen,//延时计数控制
keyin;//外部中断0向主程序传递有中断标识,有键按下
keydeal;//按键程序调用标志
uchar keytable[4][4]={7,8,9,/,4,5,6,*,1,2,3,-,c,0,=,+};//按实际键盘编值
uchar keyboard();//键盘扫描程序,负责键值扫描,判断键释放由主函数完成
void display(uchar,uchar);// 显示子程序,
sbit keysign=P3^2;//P3.2为中断0入口,此定义用于程序判断是否真有键按下及键是否释放
void main()
{uchar keybiao,keybiao1;//有键按下标志,键放开标志
IE=0x89;//开总中断,外部中断0,定时器中断1
IT0=1;//中断触发方式
PT1=1;//中断优先级
TMOD=0x90;//定时器1工作方式1
TH1=(65536-5000)/256;//定时器初值高8位(定时5ms)
TL1=(65536-5000)%256;
TR1=1;//开始计时
P2=0xf0;//给键盘列高电平,行低电平
keydeal=0x00;//让键处理初值为0,既未处理
while(1)
{if(keyin==1) //可能有键按下
{
if(time1>=2)//已延时10ms;计数2次,
{if(keysign==0&&keydeal==0)
{keynum=keyboard();
keybiao=1;
keydeal=1;
topen=0;//关延时计数
}//判断是否真有键按下,调用键盘扫描程序
else if(keybiao==0&&time1>=2&&keybiao1==0)
{EX0=1;
keyin=0;
topen=0;
}//如果没键按下,重开外部中断0,中断标志清0
}
if(keybiao==1&&keysign!=0)
{keybiao=0;
time1=0;
keybiao1=1;//为防止前一次time1的影响而设的标志
topen=1;
}
if(keybiao1==1&&time1>=2)
{keybiao1=0;
topen=0;
EX0=1;
keyin=0;//重开外部中断0,中断标志清0
keydeal=0;//重开键未处理,让程序可调用处理程序
dpnum=keynum;//将键值传给显示
}
}
}
}
void display(uchar x,uchar i)//中断控制显示,显示一直持续到下次中断到
uchar keyboard()
{uchar con1,con2,i,j;
con1=P2|0x0f;//只保留P2口高四位,便于switch
switch(con1)//通过cp可得到列为0的位
{case 0x7f:j=3;break;//j为列值
case 0xbf:j=2;break;
case 0xdf:j=1;break;
case 0xef:j=0;break;
}
for(i=0;i<=3;i++)
{P2=_crol_(0xfe,i);//依次给行赋0
con2=P2|0x0f;// 只保留P2口高四位,便于比较
if(con2!=0xff) break;
}
P2=0xf0;//给键盘列高电平,行低电平
return(keytable[i][j]);
}
void T1_time()interrupt 3
{TH1=(65536-5000)/256;//定时器初值高8位(定时5ms)
TL1=(65536-5000)%256;
time1++;
if(topen!=1) time1=0;//如果延时标志不为1,不开始计时
display(dpnum,5);
}
void int0()interrupt 0
{EX0=1;
keyin=1;//向主程序传递键按下
topen=1;//10ms延时计数开始
}
由于字数有限,有部分程序给删了,显示等部分程序应该没问题,我在其它地方能正常运行。
答:
不需要每次在进入中断程序后开一次中断;EX0=1可以去掉。
实际上,外部中断工作在边沿触发方式的时候,第一次电平跳变触发后进入中断程序,然后硬件自动清除IE0中断标志位。但是在执行中断程序的过程中,如果中断引脚再次检测到电平跳变(负到高),那么IE0会被再次置1 。如果在退出中断程序之前没及时清0,那么就会再次引发一次中断。
而按键的过程,不包括按下和松开时的电平抖动,至少会产生两次电平跳转。
因此,只需在你中断程序里适当加一点延迟,再将EX=1, 改成IE0=0 。
12、我用的单片机是8051F的单片机,在程序中我用了两个中断。一个是
单片机延时中断问 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)