完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
一个定时器,多个程序用,(如主程序中让每进20次定时中断(1秒),让灯亮一下,这样循环着,当触发外部中断时,可以是1秒也可以大于1秒,响应另一个触发事件)
|
|
相关推荐
11个回答
|
|
你可以弄一个变量假设是N,每中断一次对N计数,根据N的数值来判断执行那个程序
|
|
|
|
本帖最后由 auqyygtj 于 2013-8-13 22:09 编辑
大家帮我分析一下问题如下:1、现在是主程序动显在那0至7,我要的是1-8动显在那;2、触发外部中断后,加数器不动,可能是一个定时器,两个地方用,什么地方没用正确,外部中断的部分计时器没起作用;3、编译程序时出现一个警告。其它正常 #include //载入51单片机头文件 #include //载入51涵数头文件 #define uchar unsigned char //宏定义unsigned char为 uchar #define uint unsigned int //宏定义unsigned int 为uint ***it wela=P3^7; //位定义,控制数码管有几个数量的373锁存器端口接在该I/O ***it dula=P2^0; //位定义,控制数码管显示什么字符的373锁存器端口接在该I/O uchar k,j,temp,led,dd,tt,qian,bai,shi,ge; //单字节全局变量 uint ptemp; //双字节全局变量 uchar code dutable[]={ //定义数码管显示,code为表格的意思,该表格取名为dutable 0xc0,0xf9,0xa4,0xb0,0x99, 0x92,0x82,0xf8,0x80,0x90 //根据数码管硬件连接图写出0-9的16进制数 }; uchar code wetable[]={ 0x01,0x02,0x04,0x08, 0x10,0x20,0x40,0x80 }; //根据数码管硬件连接图写出1-8个数码管亮的位 //…………以下延时程序………… void delay(uint z) // 这里为什么用uint(双字节),而不是用uchar(单字节,值范围256) { uint x,y; for(x=z;x>0;x--) for(y=1000;y>0;y--); } //…………以上延时程序………… //………………子程序…………………… void zuchngxiu() { if(dd==1) /*这里进入定时器次和触发定时器的时间一起控制显示速度,现在这样就属于动太扫描*/ { dd=0; /*如果进入到20次定时器,那么将定时器里的变量dd清0,便于下一次计时*/ tt++;//用于外部中断时间判断 if(j==8) //检测j是否等于9 j=0; //如果是等于9就置0 //…………………………………… P1=0x00;//P1口全部送低电平,目的是将这低电平保存在点阵的高电平脚上,使用其不亮; P3=0x07;/*P3口关闭高位开关(00000111)其中有三个脚接点阵高点位的锁存端,其中还有外部中断*/ P2=0x00; /*P2口接了三种类型,点阵低电平的锁存端5个,点阵高点位的锁存端2个,还一个是控制 8个数码管段选的锁存端,这样点阵高电平脚全部由锁器端锁存为低电平了*/ //……………关闭点阵………………… wela=1; //打开位选 P1=wetable[j]; //P1口取wetable位码表 wela=0;//关闭位选 j++; //每取一次位码表自加1 if(k>=8) /*检测k是否大于等于11,而不是k=10(0-9)数显示,为会下面会用到*/ k=0; //如果上面K大于等于11,就将K清0 ,这样做的目的是让其显示0-9的10个数,不然后一直加上去了 dula=1; //打开段选,是显示数字 P1=dutable[k]; //P1端口取dutable数码表中值, dula=0; //关闭段选 k++; //k自加1,如果不自加1怎么知道它现在取的是第几位数了 } } //…………………………………… //………………以下是累加显示子程序………………………… void display(uchar qian,uchar bai,uchar shi,uchar ge) { wela=1; P1=0x01; wela=0; dula=1; P1=dutable[qian]; dula=0; delay(5); //……………………………… wela=1; P1=0x02; wela=0; dula=1; P1=dutable[bai]; dula=0; delay(15); //……………………………… wela=1; P1=0x04; wela=0; dula=1; P1=dutable[shi]; dula=0; delay(15); //……………………………… wela=1; P1=0x08; wela=0; dula=1; P1=dutable[ge]; dula=0; delay(5); } //………………以上是累加显示子程序……………… //……………………以下初始化程序…………………… void init() { ptemp=0; //给累加器一个初值 EA=1; //开总中断 ET0=1;//定时器/计数器0中断 TMOD=0x01; //设为定时器,单触发,01工作方式; TH0=(65536-5000)/256; //装高位初值 TL0=(65536-5000)%256; //装低位初值 TR0=1;//启动定时器 } //…………………以上初始化程序……………………… //………………………以下主程序…………………………… void main() { init();//初始化子程序 EX0=1;//开外部中断0 IT0=0;//外部中断0以电平方式触发 PX0=0;//设外部中断0为最低优先级 PT0=1;//设该定时器为最高级优先级 P2=0x00;//程序入口就关闭点阵锁存端,要是不关闭一会数码管语句时会让点阵也显示着内容 P3=0x04;//给P3口除外部中断0高点平外,都低电平。 外部中断0是低平电有效的 wela=1; //打开控制数码管工作的373端口,输入高电平有效,相当于输入与输出端直通 P1=0xff; //送入让那几个数码管亮的16进制数 wela=0; //关闭控制数码管工作373端口,这样373就保持住输入端上一次输入的值 dula=1; //打开控制数码管显示什么数字的373端口 P1=0x00; /*输入让数码管显示什么数,这里是全部亮就是日字,作为检测一下数码管 有无坏点*/ dula=0; //关闭控制数码管显示什么数字的373端口 P1=0xff;//P1送入高电平 P2=0x3e; //打开低位开关 P1=0x00; //P1送入低电平 P2=0xc0;//关闭位开关 P3=0x6f; //打开高位开关 P1=0xff;//P1送入高电平 led=P0=0xfe; //这里给led赋个初值这样下面定时器里led左移才知道从什么数开始移 delay(15); //这里加延时程序,某值是时段肯定会和其它地方冲突造成不定时延时现象 //调用延时子程序 while(1) { zuchngxiu(); //调用子程序 } } // ……………………定时器0……………………………… void exter1() interrupt 1 /*exter1是中断名,后面1是单片机中断中该定时器/计数器0的中断序号 */ { TH0=(65536-5000)/256;//求抹,将整数部分装入高8位中 TL0=(65536-5000)%256; //求余,将余数部分装入低8位中 //这里的50000就是50ms(毫秒) dd++; // 这里的dd时50ms触发一次中断,每到50ms计一次数,便于其它调用 led=_crol_(led,1); //将上面的led值进入左移1位 P0=led; //左移一位得到的值,赋予给P0口 } //…………………………这里定时器中断优先等级比外部中断0高………… //……………触发外部中断0后始终循环………… void exter0() interrupt 0 /*exter0是断名,后面0是单片机中断中该外部中断0的中断序号 */ { //1 init(); ptemp=0; //给加累数初值0 while(1) { //2 if(tt>=1)//判断tt是否大于等于1,这里tt就是主程序里dd=20,tt自加1 { //3 tt=0; //置0重新计时 ptemp++;//初值自加1 if(ptemp==10000) { //4 ptemp=0; if(ptemp==0) { //5 wela=1; //打开位选 P1=0xff; //将P1口置数11111111全部高电平, 打开8个数码管 wela=0; //关闭位选 dula=1;//打开段选 temp=0xfe; //赋temp值为11111110 ,也就是数码管的a段 P1=temp; //将temp的值赋予给P1口 delay(10); //调用延时程序 while(1) { //6 if(temp==0xdf) /*检测temp是否等于(高位11011111低位),因为数码管七段加一个DP点 我们不要DP(P1.7)点和G段(P1.6)亮*/ temp=0x7f; //置位到DP(P1.7)点,也就是P1.6和P1.7跳过(高位0111 1111低位) temp=_crol_(temp,1); //左移一位 P1=temp; //移位后的值赋予给P1口 delay(8); //调用延碧 } //6 qian=temp/1000; bai=temp%1000/100; shi=temp%1000%100/10; ge=temp%10; display(qian,bai,shi,ge); } } } } } |
|
|
|
中断里怎么还有While(1)啊 ,程序怎么中断返回啊
|
|
|
|
3楼说的对 中断里面 不应该有while(1)语句吧 要不就该无线循环了
|
|
|
|
找到问题了,还加了一小部分其它循环
|
|
|
|
本帖最后由 auqyygtj 于 2013-8-14 13:38 编辑
/* 正确的如下:还有一个问题就是触发外部中断后进入第三状态时,怎么退出来, 进入中断后第1状态:每隔1秒加1,加到100数,跳到 第2状态:8个数码管各自点亮口字,循环5次后进入第3状态:8个数码管组成的大口子,循环5次后, 让其再回到第1状态这样循环着除非单片机复位,现在问题停在第3状态循环出不来,没有可调用的涵数, 待学习请助中,请高手们指点一下迷区*/ #include //载入51单片机头文件 #include //载入51涵数头文件 #define uchar unsigned char //宏定义unsigned char为 uchar #define uint unsigned int //宏定义unsigned int 为uint ***it wela=P3^7; //位定义,控制数码管有几个数量的373锁存器端口接在该I/O ***it dula=P2^0; //位定义,控制数码管显示什么字符的373锁存器端口接在该I/O ***it kk=P3^2; uchar k,j,temp,led,dd,tt,qian,bai,shi,ge,rr,yj,ee; //单字节全局变量 uint ptemp; //双字节全局变量 uchar code dutable[]={ //定义数码管显示,code为表格的意思,该表格取名为dutable 0xc0,0xf9,0xa4,0xb0,0x99, 0x92,0x82,0xf8,0x80,0x90 //根据数码管硬件连接图写出0-9的16进制数 }; uchar code wetable[]={ 0x01,0x02,0x04,0x08, 0x10,0x20,0x40,0x80 }; //根据数码管硬件连接图写出1-8个数码管亮的位 //…………以下延时程序………… void delay(uint z) // 这里为什么用uint(双字节),而不是用uchar(单字节,值范围256) { uint x,y; for(x=z;x>0;x--) for(y=1000;y>0;y--); } //…………以上延时程序………… //………………子程序…………………… void zuchngxiu() { if(dd==1) /*这里进入定时器次和触发定时器的时间一起控制显示速度,现在这样就属于动太扫描*/ { dd=0; /*如果进入到20次定时器,那么将定时器里的变量dd清0,便于下一次计时*/ tt++;//用于外部中断时间判断 //…………………………………… P1=0x00;//P1口全部送低电平,目的是将这低电平保存在点阵的高电平脚上,使用其不亮; P3=0x07;/*P3口关闭高位开关(00000111)其中有三个脚接点阵高点位的锁存端,其中还有外部中断*/ P2=0x00; /*P2口接了三种类型,点阵低电平的锁存端5个,点阵高点位的锁存端2个,还一个是控制 8个数码管段选的锁存端,这样点阵高电平脚全部由锁器端锁存为低电平了*/ //……………关闭点阵………………… wela=1; //打开位选 P1=wetable[j]; //P1口取wetable位码表 wela=0;//关闭位选 j++; //每取一次位码表自加1 if(j==8) //检测j是否等于9 j=0; //如果是等于9就置0 dula=1; //打开段选,是显示数字 P1=dutable[k]; //P1端口取dutable数码表中值, dula=0; //关闭段选 k++; //k自加1,如果不自加1怎么知道它现在取的是第几位数了 if(k>=9) /*检测k是否大于等于9,因为要显示的数是1-8的数*/ k=1; /*如果上面K大于等于9,就将K清1 ,而不是将K清0,这样做的目的是让其显示从1数开始显示9位数(1-8), 如果清0,那就会从0开始显数*/ } } //…………………………………… //………………以下是累加显示子程序………………………… void display(uchar qian,uchar bai,uchar shi,uchar ge) { wela=1; P1=0x01; wela=0; dula=1; P1=dutable[qian]; dula=0; delay(1); //……………………………… wela=1; P1=0x02; wela=0; dula=1; P1=dutable[bai]; dula=0; delay(1); //……………………………… wela=1; P1=0x04; wela=0; dula=1; P1=dutable[shi]; dula=0; delay(1); //……………………………… wela=1; P1=0x08; wela=0; dula=1; P1=dutable[ge]; dula=0; delay(1); } //………………以上是累加显示子程序……………… //……………………以下循环8位数码管组成的口子子程序………………………… void xunhuankou() { dula=1; //打开段选, P1=0xfe; //显示a段,这时8个数码管都显示a段的,所以在这前要先选好位 dula=0; delay(10); wela=1; P1=wetable[yj]; //P1口取wetable位码表 也就是第一们数码管 delay(3); P1=0x02; delay(3); P1=0x04; delay(3); P1=0x08; delay(3); P1=0x10; delay(3); P1=0x20; delay(3); P1=0x40; delay(3); P1=0x80; delay(3); wela=0; //…………………… dula=1; P1=0xfd; delay(3); P1=0xfb; delay(3); P1=0xf7; dula=0; delay(3); //…………………… wela=1; P1=0x80; delay(3); P1=0x40; delay(10); P1=0x20; delay(3); P1=0x10; delay(3); P1=0x08; delay(3); P1=0x04; delay(3); P1=0x02; delay(3); P1=0x01; wela=0; delay(3); //………………………… dula=1; P1= 0xef; delay(3); P1= 0xdf; delay(3); dula=0; //……………………………… } //……………………以上循环8位数码管组成的口子子程序……………………………… //……………………以下初始化程序…………………… void init() { kk=1; //给外部中断0由软件置高电平 ptemp=0; //给累加器一个初值 EA=1; //开总中断 ET0=1;//定时器/计数器0中断 TMOD=0x01; //设为定时器,单触发,01工作方式; TH0=(65536-5000)/256; //装高位初值 TL0=(65536-5000)%256; //装低位初值 TR0=1;//启动定时器 } //…………………以上初始化程序……………………… //……………………以下是外部中断中循环子程序…………………………………… void zhongduan() { init();//初始化程序 ptemp=0; //给加累数初值0 while(1) { if(tt>=1)//判断tt是否大于等于1,这里tt就是主程序里dd=20,tt自加1 tt=0; //置0重新计时 ptemp++;//初值自加1 if(ptemp==101) //给累加数定一个最大数 { ptemp=0; if(ptemp==0) { wela=1; //打开位选 P1=0xff; //将P1口置数11111111全部高电平, 打开8个数码管 wela=0; //关闭位选 dula=1;//打开段选 temp=0xfe; //赋temp值为11111110 ,也就是数码管的a段 P1=temp; //将temp的值赋予给P1口 delay(10); //调用延时程序 while(1) { temp=_crol_(temp,1); //左移一位 P1=temp; //移位后的值赋予给P1口 delay(8); //调用延碧 rr++;//自加1,便于下面调用(rr=6刚好循环一次口字) if(temp==0xdf) /*检测temp是否等于(高位11011111低位),因为数码管七段加一个DP点 我们不要DP(P1.7)点和G段(P1.6)亮*/ temp=0x7f; //置位到DP(P1.7)点,也就是P1.6和P1.7跳过(高位0111 1111低位) if(rr>=30)//就是循环5个口字 { while(1) { xunhuankou();//调用循环8位数码管组成的口子子程序 ee++;//每循环一次自加1 //…………………………………………………………………………………… //…………………有待解决小循环里的死循环………………………………… //if(ee==5)//让8位数码管组成的口子循环5次 //问题来了,到5次后没有返回函数了,待解决(最好还是返回到外部中断一开始的地方) //……………………………………………………………………………………………… //……………………………………………………………………………………………… } /// } } } } qian=ptemp/1000; bai=ptemp%1000/100; shi=ptemp%1000%100/10; ge=ptemp%10; display(qian,bai,shi,ge); } } //……………………以上是外部中断中循环子程序…………………………………… //………………………以下主程序…………………………… void main() { init();//初始化子程序 EX0=1;//开外部中断0 IT0=0;//外部中断0以电平方式触发 PX0=0;//设外部中断0为最低优先级 PT0=1;//设该定时器为最高级优先级 P2=0x00;//程序入口就关闭点阵锁存端,要是不关闭一会数码管语句时会让点阵也显示着内容 P3=0x04;//给P3口除外部中断0高点平外,都低电平。 外部中断0是低平电有效的 wela=1; //打开控制数码管工作的373端口,输入高电平有效,相当于输入与输出端直通 P1=0xff; //送入让那几个数码管亮的16进制数 wela=0; //关闭控制数码管工作373端口,这样373就保持住输入端上一次输入的值 dula=1; //打开控制数码管显示什么数字的373端口 P1=0x00; /*输入让数码管显示什么数,这里是全部亮就是日字,作为检测一下数码管 有无坏点*/ dula=0; //关闭控制数码管显示什么数字的373端口 P1=0xff;//P1送入高电平 P2=0x3e; //打开低位开关 P1=0x00; //P1送入低电平 P2=0xc0;//关闭位开关 P3=0x6f; //打开高位开关 P1=0xff;//P1送入高电平 led=P0=0xfe; //这里给led赋个初值这样下面定时器里led左移才知道从什么数开始移 delay(15); //这里加延时程序,某值是时段肯定会和其它地方冲突造成不定时延时现象 //调用延时子程序 j=0; //给初值0 k=1; /*给初值1,这里为什么不是给初值0,因为k段码表也就是显示数字的表,我们现在 让程序1开始显,而utable表第一位数0xc0是数为0数,*/ while(1) { zuchngxiu(); //调用子程序 } } // ……………………定时器0……………………………… void exter1() interrupt 1 /*exter1是中断名,后面1是单片机中断中该定时器/计数器0的中断序号 */ { TH0=(65536-5000)/256;//求抹,将整数部分装入高8位中 TL0=(65536-5000)%256; //求余,将余数部分装入低8位中 //这里的50000就是50ms(毫秒) dd++; // 这里的dd时50ms触发一次中断,每到50ms计一次数,便于其它调用 led=_crol_(led,1); //将上面的led值进入左移1位 P0=led; //左移一位得到的值,赋予给P0口 } //…………………………这里定时器中断优先等级比外部中断0高………… //……………触发外部中断0后始终循环………… void exter0() interrupt 0 /*exter0是断名,后面0是单片机中断中该外部中断0的中断序号 */ { zhongduan();//调用外部中断循环子程序 } |
|
|
|
问题原因:
1、现在是主程序动显在那0至7,我要的是1-8动显在那; 因为j和k没给初值,默认给的是0,我要的是从1开始,而k就是显示数字的码表从0开始的变量名,所以一开始的时候就给k初值为1,显示1-8就是9位数,再置1重新开始这样循环; 2、触发外部中断后,加数器不动,可能是一个定时器,两个地方用,什么地方没用正确,外部中断的部分计时器没起作用; 3、编译程序时出现一个警告。其它正常 2和3问题是同一个,在外部中断程序中,有大括号,括错位了; |
|
|
|
谢谢。因为刚学,中断里加循环,只是想让一个程序两种或多种效果变化的效果,还没有到那么完美的水平。练习一些思路和用法,一步一步加深运用
|
|
|
|
再用一个中断啊
|
|
|
|
上面的问题解决了,触发外部中断后把while(1) 死循环换成for就可以了
//……………………以下是外部中断中循环子程序…………………………………… void zhongduan() { init();//初始化程序 ptemp=0; //给加累数初值0 while(1) //这个循环是让它在满足条件的情况下循环累加数显示,关系量ptemp // for(ptemp=0;ptemp<101;ptemp++) //如果这里启用for,而禁用while,执行完后会返回到主函数 { if(tt>=1)//判断tt是否大于等于1,这里tt就是主程序里dd=20,tt自加1 tt=0; //置0重新计时 ptemp++;//初值自加1 if(ptemp==101) //给累加数定一个最大数 { ptemp=0; if(ptemp==0) { wela=1; //打开位选 P1=0xff; //将P1口置数11111111全部高电平, 打开8个数码管 wela=0; //关闭位选 dula=1;//打开段选 temp=0xfe; //赋temp值为11111110 ,也就是数码管的a段 P1=temp; //将temp的值赋予给P1口 delay(10); //调用延时程序 for(rr=0;rr<61;rr++) // while(1) //这个循环是让它满足条件下循环小口字关系量rr { temp=_crol_(temp,1); //左移一位 P1=temp; //移位后的值赋予给P1口 delay(8); //调用延碧 rr++;//自加1,便于下面调用(rr=6刚好循环一次口字) if(temp==0xdf) /*检测temp是否等于(高位11011111低位),因为数码管七段加一个DP点 我们不要DP(P1.7)点和G段(P1.6)亮*/ temp=0x7f; //置位到DP(P1.7)点,也就是P1.6和P1.7跳过(高位0111 1111低位) if(rr>=60)//就是循环5个口字 { for(ee=0;ee<10;ee++) //这里要是用while(1)就会死循环 // while(1) //这个循环是让它满足条件下循环大口字 ,关系量ee { xunhuankou();//调用循环8位数码管组成的口子子程序 ee++;//每循环一次自加1 } } } } } qian=ptemp/1000; bai=ptemp%1000/100; shi=ptemp%1000%100/10; ge=ptemp%10; display(qian,bai,shi,ge); } } //……………………以上是外部中断中循环子程序…………………………………… |
|
|
|
建议楼主 把中断程序写的简短 最好只设置中断标志 然后在主函数调用处理函数,不然中断停留时间太长,下次终端到来会导致数据丢失。。。。。
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
952 浏览 0 评论
【每周推荐】采用11代Intel CPU,基于youyeetoo X1开发板搭建少儿AI智能STEAM积木平台
897 浏览 0 评论
2755 浏览 2 评论
【youyeetoo X1 windows 开发板体验】+ 影音处理和AI模型移植
2372 浏览 5 评论
I.MX6ULL-飞凌 ElfBoard ELF1板卡- 移植zbar的方法
1722 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
5977 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-4-29 02:06 , Processed in 0.379808 second(s), Total 50, Slave 42 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号