求助,51单片机无法进入外部中断的问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求助,51单片机无法进入外部中断的问题相关的知识,希望对你有一定的参考价值。
keil C51 代码如下:要实现的功能是按P1.1 给串口发送字符串 set:mode0按P1.2 给串口发送字符串 set:mode1接收到外部中断,给串口发送字符串 man:trig现在遇到的问题是,如果上电后,先按外部中断,能发送字符串,但是按了 P1.1 或者 P1.2 之后,再按外部中断就不起作用了。#include<reg52.h>#define uchar unsigned char#define uint unsigned intsbit Singleshot = P1^1; sbit Continue = P1^2; bit setss=0;bit setct=0;void send_char_com(uchar c) SBUF=c; while(TI==0); TI=0;void send_string_com(uchar *s) while(*s!='\0') send_char_com(*s); s++; void delay_50us(int x) int i,j; for(i=0;i<x;i++) for(j=1;j<=6;j++); void main() TMOD=0x20; PCON=0x80; SCON=0x50; TL1=0xfd; TH1=0xfd; TR1=1; REN = 1; SM0 = 1; SM1 = 1; EA = 1; ES = 1; TR1 = 1; IT0=1; IT1=1; EX0=1; EX1=1;while (1) if (Singleshot==0) delay_50us(1); if (Singleshot==0) while(!Singleshot) setss=1; if (setss==1) send_string_com("set:mode1\r"); setss=0; if (Continue==0) delay_50us(1); if (Continue==0) while(!Continue) setct=1; if (setct==1) send_string_com("set:mode0\r"); setct=0; void intsvr0(void) interrupt 0 using 1 EX0 = 0; send_string_com("man:trig\r"); delay_50us(10); EX0 = 1;
问题出在主程序初始化void main()
TMOD=0x20;
PCON=0x80;
SCON=0x50;
TL1=0xfd;
TH1=0xfd;
TR1=1;
//REN = 1;//多余了
//SM0 = 1;//多余了
//SM1 = 1;//多余了
EA = 1;
//ES = 1;//这行必须打掉,串口采用查询方式发送的
//TR1 = 1;//多余了
IT0=1;
//IT1=1;//多余了
EX0=1;
//EX1=1;//多余了 参考技术A 初始化这里改一下:
TMOD=0x20;
PCON=0x80;
SCON=0x50;
TL1=0xfd;
TH1=0xfd;
TR1=1;
EA = 1;
TR1 = 1;
IT0=1;
EX0=1; 参考技术B 串口中断如果用不上的话,关闭它
还有接收允许,也用不上,让其为0好了; 参考技术C 按下按键后串口发送完数据,要把串口中断标志清除
用C51单片机的外部中断设计1s定时器
徐浩宇 川师工学院电气2018级 2021.4.27
51单片机给我们提供了2个计时器中断,分别是计时器0和计时器1,他们对应的优先级分别是1和3,开启计时器并允许其中断后,计时器会从给定的初始值开始,每个指令周期加1,直到加到65535,再加一时计时器溢出,计时器此时会进入中断,并执行中断服务函数。
- 虽然书上讲的很清楚了,但实际使用还是有些许差别,我自己是这样理解的
65536-50000的由来
- 假设我使用的单片机的晶振为12MHZ,其机器周期是1us,即每1us产生一次计数
- 如果设计一个1s的定时器,理论上是需要1*10^6个机器周期,但定时器T0只能对机器周期能进行最大65536次计数,很明显已经超过了,并不能直接采用T0的默认值
- 转下思维模式,取个65535之内的整数值,经过简单倍数关系即可转换为1s。很明显,50ms符合要求。即一次中断5 * 104次,中断20次即为1s
- 但根据中断原理,T0中断器溢出时计数1次,但5 * 104<65536,根本不会发生溢出。此时有需要转下思维模式,如果我给T0定时器附上初始值,使其从初试值开始计数,最终读数为65536发生溢出,中断一次。这个初始值就是65536和5 * 104的差值
/256 和 %256 的由来
- T0中断器由两个8位构成,低8位,即28,满打满算也只能计数256个机械周期,当大于256个机械周期就必须采用高8位了。换而言之,高8位每增加1,低八位就装满一次。
- 故用初始值除以256取整,存入高8位。取余,即小于256次数,放入低8位。
TH0=(65536-50000)/256; // (65536-50000)/256=60.6875
TL0=(65536-50000)%256;
- 这就是这两句话的由来
以下附上C51程序代码
#include<reg51.h>
#include<intrins.h>
int flag=0;
sbit LED = P2^0;
void main()
TMOD=0x10; //工作于方式1
//0 0 方式0 13位计数器 TMOD=0x00
//0 1 方式1 16位计数器 TMOD=0x01
//1 0 方式2 自动重装8位计数器 TMOD=0x02
//1 1 方式3 T0分为2个8位独立计数器,T1为无中断重装8位计数器 TMOD=0x03
EA=1; // 中断允许
ET1=1; // 中断1打开
TH1=(65536-50000)/256; // (65536-50000)/256=60.6875
TL1=(65536-50000)%256;
TR1=1;
while(1)
void timer1(void) interrupt 3
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
flag++;
if (flag==20) //达到1s
flag =0;
LED=~LED;
实验原理图
- 很简单,只是在P2^0口加入了LED灯
拓展一下
如果要求做成流水灯呢?
有两种流水灯
- 一种是移位流水灯,采用移位方式,同时只能亮一个灯。
思路:在定时1s完成后加上自增量,该自增量随着秒数累次增加,当达到设计计数时清零。
代码如下:
#include<reg51.h>
#include<intrins.h>
int flag=0;
sbit ledPort = P2;
void main()
TMOD=0x10; //工作于方式1
EA=1; // 中断允许
ET1=1; // 中断1打开
TH1=(65536-50000)/256; // (65536-50000)/256=60.6875
TL1=(65536-50000)%256;
TR1=1;
while(1)
void timer1(void) interrupt 3
unsigned char i;
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
flag++;
if (flag==20) //达到1s
i++;
flag =0;
ledPort = ~(1<<i) ;
i=(i+1)%8;
原理图如下所示:
- 另外一种是累计流水灯,采用累增方式,同时亮多个灯。
思路:在定时1s完成后加上自增量,该自增量随着秒数累次增加,当达到设计计数时清零。同时设置多重判断,根据自增量的值判断执行哪一种循环。 - 其实我这里的写法很蠢,像是没学过 c 的人,可惜实验的时间不够,就采用笨办法了,达到效果就行(狗头)。
- 高效率的写法应该与C输出九九表类似,采用双重For循环嵌套构成。
代码如下:
#include<reg51.h>
#include<intrins.h>
#define ledPort P2
int flag = 0;
sbit LED1 = P2^0;
sbit LED2 = P2^1;
sbit LED3 = P2^2;
sbit LED4 = P2^3;
sbit LED5 = P2^4;
sbit LED6 = P2^5;
sbit LED7 = P2^6;
sbit LED8 = P2^7;
unsigned char i ;
void main()
TMOD=0x10; //工作于方式1
EA=1; // 中断允许
ET1=1; // 中断1打开
TH1=(65536-50000)/256; // (65536-50000)/256=60.6875
TL1=(65536-50000)%256;
TR1=1;
i=0; //用于控制流水灯跳转
while(1)
void timer1(void) interrupt 3
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
flag++;
if (flag==20) //达到1s
i++;
flag = 0;
if(i==1)
LED1=0;
if(i==2)
LED1=0;
LED2=0;
if(i==3)
LED1=0;
LED2=0;
LED3=0;
if(i==4)
LED1=0;
LED2=0;
LED3=0;
LED4=0;
if(i==5)
LED1=0;
LED2=0;
LED3=0;
LED4=0;
LED5=0;
if(i==6)
LED1=0;
LED2=0;
LED3=0;
LED4=0;
LED5=0;
LED6=0;
if(i==7)
LED1=0;
LED2=0;
LED3=0;
LED4=0;
LED5=0;
LED6=0;
LED7=0;
if(i==8)
LED1=0;
LED2=0;
LED3=0;
LED4=0;
LED5=0;
LED6=0;
LED7=0;
LED8=0;
if(i==9)
LED1=0;
LED2=0;
LED3=0;
LED4=0;
LED5=0;
LED6=0;
LED7=0;
LED8=1;
if(i==10)
LED1=0;
LED2=0;
LED3=0;
LED4=0;
LED5=0;
LED6=0;
LED7=1;
LED8=1;
if(i==11)
LED1=0;
LED2=0;
LED3=0;
LED4=0;
LED5=0;
LED6=1;
LED7=1;
LED8=1;
if(i==12)
LED1=0;
LED2=0;
LED3=0;
LED4=0;
LED5=1;
LED6=1;
LED7=1;
LED8=1;
if(i==13)
LED1=0;
LED2=0;
LED3=0;
LED4=1;
LED5=1;
LED6=1;
LED7=1;
LED8=1;
if(i==14)
LED1=0;
LED2=0;
LED3=1;
LED4=1;
LED5=1;
LED6=1;
LED7=1;
LED8=1;
if(i==15)
LED1=0;
LED2=1;
LED3=1;
LED4=1;
LED5=1;
LED6=1;
LED7=1;
LED8=1;
if(i==16)
LED1=1;
LED2=1;
LED3=1;
LED4=1;
LED5=1;
LED6=1;
LED7=1;
LED8=1;
if(i==17)
i=0;
- 实验效果图如下所示:
以上是关于求助,51单片机无法进入外部中断的问题的主要内容,如果未能解决你的问题,请参考以下文章
单片机外部中断有两种信号方式,即电平方式和脉冲方式.啥叫电平方式啥叫脉冲方式
STM32外部中断无法进入中断程序,请问下面的程序哪里不对呀???
将单片机的外部中断1、定时器中断0打开,要求定时器0的中断优先级高于外部中断1,外部中断1采用边沿?