单片机_中断函数调用
- 格式:doc
- 大小:47.00 KB
- 文档页数:4
的值已经改变,从而导致程序运行不正确,反过来亦然。
另一方面,func()与TaskB有直接的调用关系,因而其局部变量b与c不会被互相覆盖,但也不能保证func的局部变量c不会与TaskA或其他任务的局部变量形成可覆盖关系。
根据上述分析我们很容易就能够判断出TaskA和TaskB这两个函数是不可重入的(当然,func也不可重入)。
那么如何让函数成为可重入函数呢?C51编译器采用了一个扩展关键字reentrant作为定义函数时的选项,需要将一个函数定义为可重入函数时,只要在函数后面加上关键字reentrant即可。
厦门城论坛z' V- \0 L/ Z2 A. G) j与非可重入函数的参数传递和局部变量的存储分配方法不同,C51编译器为可重入函数生成一个模拟栈(相对于系统堆栈或是硬件堆栈来说),通过这个模拟栈来完成参数传递和存放局部变量。
模拟栈以全局变量?C_IBP、?C_PBP和?C_XBP作为栈指针(系统堆栈栈顶指针为SP),这些变量定义在DATA地址空间,并且可在文件startup.a51中进行初始化。
根据编译时采用的存储器模式,模拟栈区可位于内部(IDATA)或外部(PDATA或XDATA)存储器中。
如表1所示:表1s. h; j5 s) j- _4 @厦门电子城厦门城电子零件单片机电子,xmecity,电子制作,DIY,电脑元件,9 A/ c6 `2 `6 M4 |注意:51系列单片机的系统堆栈(也叫硬件堆栈或常规栈)总是位于内部数据存储器中(SP为 8位寄存器,只能指向内部),而且是“向上生长”型的(从低地址向高地址),而模拟栈是“向下生长”型的。
, g! c) @% u( z) M/ r: x7 w1、可重入函数参数传递过程剖析 T0 T$ T3 J. R# e在进入剖析之前,先简单讲讲c51函数调用时参数是如何传递的。
简单来说,参数主要是通过寄存器R1~R7来传递的,如果在调用时,参数无寄存器可用或是采用了编译控制指令“NOREGPARMS”,则参数的传递将发生在固定的存储器区域,该存储器区域称为参数传递段,其地址空间取决于编译时所选择的存储器模式。
单片机中断服务函数写法一、在开始写中断函数之前,我们来一起回顾一下,单片机的中断系统。
(1)中断源:中断请求信号的来源。
(8051有3个内部中断源T0,T1,串行口,2个外部中断源INT0,INT1(这两个低电平有效。
(2)中断响应与返回:CPU采集到中断请求信号,怎样转向特定的中断服务子程序,并在执行完之后返回被中断程序继续执行。
期间涉及到CPU响应中断的条件,现场保护,现场恢复。
(3)优先级控制:中断优先级的控制就形成了中断嵌套(8051允许有两级的中断嵌套,优先权顺序为INT0,T0,INT1,T1,串行口),同一个优先级的中断,还存在优先权的高低。
优先级是可以编程的,而优先权是固定的。
80C51的原则是①同优先级,先响应高优先权②低优先级能被高优先级中断③正在进行的中断不能被同一级的中断请求或低优先级的中断请求中断。
80C51的中断系统涉及到的中断控制有中断请求,中断允许,中断优先级控制(1)3个内部中断源T0,T1,串行口,2个外部中断源INT0,INT1(2)中断控制寄存器:定时和外中断控制寄存器TCON(包括T0、T1,INT0、INT1),串行控制寄存器SCON,中断允许寄存器IE,中断优先级寄存器IP具体的是什么,包括哪些标志位,在这里不讲了,所有书上面都会讲。
在这里我们讲下注意的事项(1)CPU响应中断后,TF0(T0中断标志位)和TF1由硬件自动清0。
(2)CPU响应中断后,在边沿触发方式下,IE0(外部中断INT0请求标志位)和IE1由硬件自动清零;在电平触发方式下,不能自动清楚IE0和IE1。
所以在中断返回前必须撤出INT0和INT1引脚的低电平,否则就会出现一次中断被CPU多次响应。
(3)串口中断中,CPU响应中断后,TI(串行口发送中断请求标志位)和RI(接收中断请求标志位)必须由软件清零。
(4)单片机复位后,TCON,SCON给位清零。
C51语言允许用户自己写中断服务子程序(中断函数)首先来了解程序的格式:void 函数名() interrupt m [using n]{}关键字interrupt m [using n] 表示这是一个中断函数m为中断源的编号,有五个中断源,取值为0,1,2,3,4,中断编号会告诉编译器中断程序的入口地址,执行该程序时,这个地址会传个程序计数器PC,于是CPU开始从这里一条一条的执行程序指令。
51单片机中断函数定义51单片机是一种广泛应用于嵌入式系统开发的单片机,其中断函数是其常用的编程方法。
本文将为读者介绍51单片机中断函数的定义及其编写方法。
一、中断函数的概念中断函数是指当51单片机运行时,某个特殊事件(如外部中断、定时器中断等)发生时,CPU自动调用的一段程序。
这段程序一般是由开发者自己编写的,用于完成特定的工作任务。
二、中断函数的定义在51单片机的开发中,需要用到中断函数时,就需要先进行中断函数的定义。
中断函数的定义包括以下几个方面:1. 定义函数名中断函数一般采用void类型,同时加上中断函数名称,以便CPU 识别该函数。
例如:void timer_ISR() {}2. 定义函数类型在编写中断函数时,需要定义其类型,以表明该函数为中断函数。
例如:void interrupt Timer() interrupt 1 {}其中,interrupt表示该函数为中断函数;Timer表示中断名称;1表示中断号,不同的中断有不同的中断号。
3. 定义中断向量因为51单片机有多个中断,每个中断都有自己的中断向量,需要在编写中断函数时定义中断向量。
例如:org 0BH针对不同的中断类型,中断向量有不同的取值位置,需要根据实际情况设定。
三、中断函数的编写方法编写中断函数时,需要注意以下几点:1. 禁止中断嵌套在编写中断函数时,必须要禁止中断嵌套。
因为中断函数执行期间若还发生新的中断,将影响程序的正常执行。
可以在中断函数的开始部分使用EA=0来禁止所有中断,而在中断函数结束时使用EA=1来允许中断。
2. 确定中断源在编写中断函数时,需要确定触发中断的中断源。
例如,寄存器TCON.0表示定时器1溢出中断,如果等于1表示中断发生。
因此,我们可以用if(TCON&0x01)来判断是否触发中断。
3. 处理中断当中断源发生时,中断函数被调用。
我们可以在中断函数中编写代码来处理中断,例如改变某个寄存器的值,或运行特定的代码等。
学习单片机的快速方法先介绍下单片机。
把单片机说成是电子信息类专业最重要的一门课程一点也不为过,你在街上看到的广告彩灯、烟花表演、红绿灯、自动开关门这些都可以用单片机实现。
有了单片机,你就可以写程序进单片机,控制单片机管脚输出的高低电平,从而你可以控制其他模块。
这就实现了自动控制。
我需要怎样的控制,我就写怎样的程序就可以了。
接下来介绍单片机的学习流程。
有的人学了两年才学会。
有的人一个月就学的很不错了。
告诉大家我学51单片机只用了两个星期。
普通的应用差不多都会了,可以自己设计一个国旗升降系统、温度自动控制系统之类的电路和程序。
当然想要这么短的时间内精通是不可能的。
学习单片机是有捷径可走的。
首先你得知道你要学习什么样的单片机,我建议从80C51核心学起,80C51是MCS-51系列中的一个典型品种;其它厂商以8051为基核开发出的CMOS工艺单片机产品统称为80C51系列。
当前常用的80C51系列单片机主要产品有:Intel 的80C31、80C51、87C51,80C32、80C52、87C52 ATMEL的89C51、89C52、89C2051 Philips、Dallas、华邦、STC Siemens等公司的产品。
之所以要从80C51学起,是因为目前很多公司都是用51核心的单片机。
而且51的资料很多,懂的人也比较多。
其实你学好了一种单片机,再学习其他的单片机会很轻松。
我就从C51说起,首先得准备一本单片机教材,只要是C51核心的都可以。
打开书看单片机的管脚各有什么功能,内部都有什么东西,用来干嘛。
这本书你当成小说来看个一天就可以了。
不要求你全部看懂。
知道都有些什么东西就行。
因为从我的学习过程来看,光看理论等于没学。
单片机必须是理论加实践,而且要大量实践,在实践的过程中寻找理论。
这才是最快捷的学习方法。
这好比你学习汉语,你不可能什么字都会写,遇到不懂的,查查字典就可以了。
1 / 2然后我们谈实践,花100来块钱买块单片机学习板,有做板经验的也可以自己做一块,原理图网上多得是。
stc单片机外部中断调用编码器
STC单片机是一种常用的微控制器,具有丰富的外设接口和功能。
外部中断和编码器是STC单片机常见的应用之一。
当STC单片机上的某个外部事件(如按键按下、传感器触发等)发生时,会触发一个中断。
这个中断可以是外部中断,也可以是定时器中断等。
在中断服务程序中,可以调用编码器的相关函数或处理程序来读取编码器的值,从而获取编码器的状态或位置信息。
具体实现上,首先需要在STC单片机的外部中断配置中,配置相应的中断源和触发方式(上升沿、下降沿或双边沿触发)。
然后在中断服务程序中,编写相应的代码来调用编码器的读取函数,获取编码器的当前值。
需要注意的是,编码器的接口和读取方式可能因不同型号的STC单片机和编码器而有所不同。
因此,在实际应用中,需要查阅相关资料或参考STC单片机的技术手册和编码器的数据手册,以了解具体的接口和读取方式。
总结来说,"STC单片机外部中断调用编码器"是指当STC单片机上的某个外部事件发生时,触发中断,并在中断服务程序中调用编码器的相关函数或处理程序来读取编码器的值,以获取编码器的状态或位置信息。
这是STC单片机应用中常见的处理方式之一,有助于实现实时、快速地处理外部事件和获取编码器的数据。
单片机函数单片机函数是一种用于编程控制的函数,主要用于单片机的内部功能和外部设备之间的交互。
当我们在单片机中编程时,可以使用已经定义好的函数来实现一些常见的功能,而不必每次都重复编写代码。
本文将介绍一些常见的单片机函数及其用法。
1.延时函数延时函数是单片机编程中最基本的函数之一、它用于在程序中添加延时,以控制程序的时间间隔。
延时函数可以通过软件实现,也可以通过硬件计数器来实现。
例如,对于某些需要精确控制时间的操作,我们可以使用硬件计数器来实现延时,而对于一些简单的延时操作,我们可以使用软件延时函数来实现。
2.输入输出函数输入输出函数用于读取输入设备或控制输出设备。
在单片机中,输入输出通常通过引脚来实现。
通过调用输入输出函数,我们可以读取或控制某个引脚的电平状态。
例如,如果我们希望读取一个传感器的数据,我们可以使用输入函数来读取传感器引脚的电平;如果我们想控制一个LED灯的亮灭,我们可以使用输出函数来控制LED引脚的电平状态。
3.中断函数中断函数是一种特殊的函数,它用于响应硬件中断。
当某个硬件事件发生时,中断函数会被自动调用,以便进行相应的处理。
例如,当一个按钮按下时,可以配置一个中断函数,以便在按钮按下时自动执行特定的操作。
中断函数通常是基于优先级的,可以设置不同的中断优先级来处理不同的中断事件。
4.串口通信函数串口通信函数是用于在单片机和外部设备之间进行串行通信的函数。
串行通信用于将数据以位的形式发送或接收,可以实现单片机与计算机、传感器、显示器等设备的数据传输。
串口通信函数通常包括初始化函数、发送函数和接收函数,通过调用这些函数,可以实现单片机与外部设备的数据交换。
5.定时器函数定时器函数是用于配置和控制单片机内部定时器模块的函数。
定时器可以用来产生特定时间间隔的中断,用于周期性地执行某个任务,例如定时发送数据、定时采集传感器数据等。
定时器函数通常包括配置函数、启动函数和停止函数,通过调用这些函数,可以实现定时器的设置和控制。
单片机_C语言函数_中断函数(中断服务程序)在开始写中断函数之前,我们来一起回顾一下,单片机的中断系统。
中断的意思(学习过微机原理与接口技术的同学,没学过单片机,也应该知道),我们在这里就不讲了,首先来回忆下中断系统涉及到哪些问题。
(1)中断源:中断请求信号的来源。
(8051有3个内部中断源T0,T1,串行口,2个外部中断源INT0,INT1(这两个低电平有效,上面的那个横杠不知道怎么加上去))(2)中断响应与返回:CPU采集到中断请求信号,怎样转向特定的中断服务子程序,并在执行完之后返回被中断程序继续执行。
期间涉及到C PU响应中断的条件,现场保护,现场恢复。
(3)优先级控制:中断优先级的控制就形成了中断嵌套(8051允许有两级的中断嵌套,优先权顺序为INT0,T0,INT1,T1,串行口),同一个优先级的中断,还存在优先权的高低。
优先级是可以编程的,而优先权是固定的。
80C51的原则是①同优先级,先响应高优先权②低优先级能被高优先级中断③正在进行的中断不能被同一级的中断请求或低优先级的中断请求中断。
80C51的中断系统涉及到的中断控制有中断请求,中断允许,中断优先级控制(1)3个内部中断源T0,T1,串行口,2个外部中断源INT0,INT1(2)中断控制寄存器:定时和外中断控制寄存器TCON(包括T0、T1,INT0、INT1),串行控制寄存器SCON,中断允许寄存器IE,中断优先级寄存器IP具体的是什么,包括哪些标志位,在这里不讲了,所有书上面都会讲。
在这里我们讲下注意的事项(1)CPU响应中断后,TF0(T0中断标志位)和TF1由硬件自动清0。
(2)CPU响应中断后,在边沿触发方式下,IE0(外部中断IN T0请求标志位)和IE1由硬件自动清零;在电平触发方式下,不能自动清楚IE0和I E1。
51单片机中断函数单片机的中断是指当单片机在正常运行的过程中,突然接收到来自外部设备或者其他源的信号时,能够立即停止正在执行的程序,转而执行一个特定的子程序,完成接收到的信号处理。
单片机中断函数是在中断发生时执行的一段程序代码。
下面将详细介绍51单片机中断函数的原理和使用方法。
首先,需要了解51单片机的中断原理。
51单片机有5个中断源,分别是外部中断0和1(INT0和INT1),定时器/计数器0和1的中断,以及串口中断(RI/TI)。
每个中断源都有自己的中断标志位,当中断源发生时,相应的中断标志位会被设置为1在单片机的中断函数中,需要首先设置中断使能位,使能相应的中断源。
然后,需要编写中断服务子程序(ISR)的函数体,该函数用于处理中断发生时需要完成的任务。
在ISR中,需要首先清除中断标志位,以防止重复中断。
然后,根据需要进行相关的处理,例如读取外部触发的信号或者发送/接收数据等。
以下是一个简单的外部中断0的中断函数示例:```C#include <reg52.h>void ExtInt0_ISR( interrupt 0//处理中断//...//清除中断标志位EX0=0;//使能外部中断0//...EX0=1;void main//设置中断使能位EA=1;//总中断使能位EX0=1;//使能外部中断0//...while (1)//主程序代码//...}```在上述代码中,`ExtInt0_ISR`函数是外部中断0的中断服务子程序,它使用`interrupt 0`关键字来声明,表示该函数用于处理外部中断0。
在`ExtInt0_ISR`函数体中,可以编写处理中断的代码。
在`main`函数中,首先使用`EA=1`来使能总中断,然后使用`EX0=1`使能外部中断0。
在主程序中的循环中,单片机会一直运行,直到外部中断0发生。
当外部中断0发生时,单片机会立即跳转到`ExtInt0_ISR`函数执行相应的任务。
stc8系列单片机前5个中断源的中断子函数框架中断是单片机中一种重要的事件处理机制,能够在系统发生某个指定的事件时,立即打断当前的程序执行,转而执行中断服务程序。
STC8系列单片机提供了多种中断源,本文将介绍其中前5个中断源的中断子函数框架。
一、外部中断0外部中断0是通过INT0引脚触发的中断源。
当INT0引脚的电平发生变化时,可触发外部中断0。
以下是外部中断0的中断子函数框架:```Cvoid INT0_ISR() interrupt 0{// 中断服务程序的代码// ...}```二、外部中断1外部中断1是通过INT1引脚触发的中断源。
当INT1引脚的电平发生变化时,可触发外部中断1。
以下是外部中断1的中断子函数框架:```Cvoid INT1_ISR() interrupt 2{// 中断服务程序的代码// ...}```三、定时器0中断定时器0中断是使用定时器0作为中断源。
定时器0可以设定一个计时周期,当计时器溢出时,会触发定时器0中断。
以下是定时器0中断的中断子函数框架:```Cvoid TIMER0_ISR() interrupt 1{// 中断服务程序的代码// ...}```四、定时器1中断定时器1中断是使用定时器1作为中断源。
定时器1可以设定一个计时周期,当计时器溢出时,会触发定时器1中断。
以下是定时器1中断的中断子函数框架:```Cvoid TIMER1_ISR() interrupt 3{// 中断服务程序的代码// ...}```五、串口中断串口中断是通过串口通信接收和发送数据时触发的中断源。
当接收到数据或发送完成时,可触发串口中断。
以下是串口中断的中断子函数框架:```Cvoid UART_ISR() interrupt 4{// 判断中断类型if (RI){// 接收中断// 中断服务程序的代码// ...}else if (TI){// 发送中断// 中断服务程序的代码// ...}}```总结:以上是STC8系列单片机前5个中断源的中断子函数框架。
引言:C51单片机中断是单片机开发中一个非常重要的概念。
通过中断,程序能够在运行过程中及时响应外部事件,提高系统的实时性和可靠性。
本文将进一步探讨C51单片机中断的相关知识,特别是中断优先级、中断嵌套、中断服务函数等方面的内容。
概述:C51单片机中断机制是通过改变程序的执行流程来实现的。
当中断事件发生时,CPU会暂停当前的执行任务,保存现场后转去执行中断服务程序,待中断服务程序执行完毕后,再恢复到之前的执行状态。
C51单片机中断机制通过这样的方式,有效地实现了对外部事件的及时响应。
正文内容:1. 中断优先级1.1 中断优先级的概念中断优先级是指在多个中断事件同时发生时,CPU按照一定的优先级顺序处理这些中断请求。
在C51单片机中,中断优先级是通过中断控制器来实现的。
中断控制器按照预先设定的优先级进行中断请求的响应,优先级越高的中断请求将被优先处理。
1.2 中断优先级的设置在C51单片机中,中断优先级的设置是通过特殊功能寄存器(SFR)来完成的。
通过设置SFR中的相关位,可以对不同的中断请求进行优先级设置。
具体的设置方法可以参考C51单片机的相关手册和数据手册。
2. 中断嵌套2.1 中断嵌套的概念中断嵌套是指在中断服务程序执行过程中,又发生了其他的中断事件,并且这些中断事件的优先级高于当前正在执行的中断服务程序。
在C51单片机中,中断嵌套是通过中断控制器的中断请求线来实现的。
当一个中断事件发生时,如果其优先级高于当前执行的中断服务程序,CPU会立即切换到新的中断服务程序中去执行。
2.2 中断嵌套的处理方法在C51单片机中,中断嵌套的处理是通过中断服务程序的堆栈来实现的。
当发生中断嵌套时,CPU将当前的现场信息保存到堆栈中,然后切换到新的中断服务程序中执行。
当新的中断服务程序执行完毕后,CPU会从堆栈中恢复之前的现场信息,并回到原来的中断服务程序继续执行。
3. 中断服务函数3.1 中断服务函数的概念中断服务函数是指用来处理中断事件的函数。
单片机C程序的中断函数调用子程序冲突问题在单片机或者ARM 的使用过程中,必会遇到使用片上中断资源的时候,中断单片机的灵魂和精髓所在,像定时/计数器一样有很重要的作用。
设置中断的作用是能及时响应重要的程序响应,以提高MCU 和MPU 的对重要资源的响应速度。
在响应中断的过程中,系统会自动保存断点(C 语言编程中),等到中断响应结束之后,程序会再次回到断点处继续执行main 函数。
这就出现了问题:有可能在中断函数中调用的子函数和main 函数中调用的子函数重复,比如,在main 函数执行到display()显示函数的时候,发生了ESUART 中断,这是程序需要保存现场和断点,将现在的main 正在执行的一些资源压入堆栈。
如果在interrupt()函数中也调用display()函数的话,会导致中断中的函数执行不正常,即显示乱码或者不显示,在返回main 函数时,也有可能导致之前压入堆栈的资源发生改变,导致main()显示异常,发生不可预料的结果。
但是若main 函数中没有执行display 函数时发生中断,则中断函数中的display 函数则能正常显示。
解决这一问题的一个办法是复制一套需要调用的子函数,给这些子函数重新命名,包括子函数中调用的子函数。
这样,主函数和中断函数调用的子函数就不会发生冲突,两边都可正常执行。
如void display(void)//供main 函数调用{ write_com(0x01); ; } void display_interrupt(void)//供interrupt 函数调用{ write_com_interrupt(0x01);//所有被调用的子函数都应备份; ; }tips:感谢大家的阅读,本文由我司收集整编。
仅供参阅!。
中断中调用函数与函数可重入问题一、中断函数是一个特殊的函数,没有参数,也没有返回值;但是程序中允不允许使用return呢?答案是允许的,不过只能用"return;",不能用"return(z);";用在一些需要快速返回的地方,对应的汇编会有多个ret语句,相对效率会高一些。
1 g& j; ^; r! @' ` 二、using的用法,using可以修饰任何函数,不过个人建议只用来修饰中断函数;简单的说,“using”会指定工作寄存器组,由于中断函数一般都是比较紧急的事情,有时一条语句都会斤斤计较,所以使用using切换寄存器组可以省去一些压栈7 g/ O F. @% A! k7 _9 的动作,由于51只有两级中断,同级中断不能被打断,因此,我们可以同级中断设成同样的寄存器组,从某种意义上来说,有一组寄存器是多余的。
同时个人建议中断函数应该使用using这个关键字。
9 V8 [! t0 y( l三、中断中调用函数,首先要讨论中断函数中调用函数的必要性,前天在论坛上我和别人争论过这个问题,现在我还是这个观点:有些情况中断中调用函数还是必要的,这个时候是不是该调用函数,其实和普通函数差不多,首先是这个函数如r5 X8 C; ^7 s2 g+ ]: }1 u$ `( {厦门E城论坛果调用多次,或者要带一些参数什么的就更加必要的;前天有人跟我叫劲,说假如只调用一次且无参数无返回的函数要直接写,因为如果用函数,至少会增加CALL和RET两条语句,我不敢苟同,我是实际调试发现的,当你程序比较复杂时,你将那部单独拉出来做成函数,可能代码和时间都会更好。
4 C4 h( A/ M8 [. u& Z& x. A. M6 四、中断中调用的函数最好不要被中断外的其它函数调用,因为会出现“重复调用”的警告,有时这种调用是很致命的,有人说这个函数可以用reentrant来修饰,是的,的确可以这样解决,不过个人不建议这么做,也许这样会跟你减少很多堆栈空间,并且整个程序的优化要差很多,个人建议出现这种情况就把这个函数写两遍,分成两个函数分别调用。
单片机中断函数一、介绍单片机中断是指在程序运行过程中,当某个事件发生时,CPU暂时停止正在执行的程序,转而去执行另一个与之相关的程序。
这种方式可以提高程序的响应速度和处理效率。
在单片机中,中断分为外部中断和内部中断两种。
二、外部中断1. 外部中断概述外部中断是指由外部设备产生的中断信号,例如按键、传感器等。
当这些设备产生信号时,会向CPU发送一个请求信号,CPU会立即停止当前执行的程序,并跳转到相应的中断服务程序进行处理。
2. 外部中断原理外部设备产生的信号经过滤波和放大后送到单片机的引脚上。
当引脚检测到高电平时,会触发外部中断,并向CPU发送一个请求信号。
CPU接收到请求信号后会立即停止当前执行的程序,并跳转到相应的中断服务程序进行处理。
3. 外部中断使用方法(1)设置引脚为输入模式,并使能对应引脚上的外部中断。
(2)编写相应的中断服务程序,在其中处理相应事件。
(3)在主函数中设置相应引脚上触发条件(例如下降沿触发、上升沿触发等)。
4. 外部中断实例以下是一个外部中断的实例,当按键按下时,LED灯会亮起:```c#include <reg52.h> //头文件sbit KEY = P3^2; //定义按键引脚sbit LED = P1^0; //定义LED引脚void KeyInterrupt() interrupt 0 //中断服务程序{if(KEY == 0) //判断按键是否按下 {LED = ~LED; //LED取反}}void main(){EX0 = 1; //使能外部中断0IT0 = 1; //设置为下降沿触发EA = 1; //总中断使能while(1){; //空循环}}```三、内部中断1. 内部中断概述内部中断是指由CPU内部产生的中断信号,例如定时器溢出、串口接收等。
当这些事件发生时,CPU会自动跳转到相应的中断服务程序进行处理。
2. 内部中断原理定时器和串口等模块在工作过程中会产生相应的标志位,当标志位被设置为1时,会向CPU发送一个请求信号。
STC15F2K60S2单片机中断编程在单片机的世界里,中断就像是一位特殊的“信使”,能够在关键时刻打断单片机的正常工作流程,让它优先处理一些紧急而重要的任务。
STC15F2K60S2 单片机作为一款功能强大的微控制器,其中断系统为我们提供了高效、灵活的事件处理方式。
接下来,让我们一起深入探索 STC15F2K60S2 单片机中断编程的奥秘。
一、中断的概念中断,简单来说,就是当单片机正在执行一个任务时,突然收到一个外部或内部的信号,这个信号会让单片机暂停当前任务,转而去处理更紧急的事情。
处理完紧急任务后,再返回原来被中断的地方继续执行之前的任务。
想象一下,你正在专心看书(单片机正在执行主程序),突然有人敲门(中断发生),你会先放下书去开门(处理中断),然后再回来继续看书(返回主程序)。
二、STC15F2K60S2 单片机的中断源STC15F2K60S2 单片机拥有丰富的中断源,包括外部中断、定时/计数器中断、串行口中断等。
外部中断可以通过引脚的电平变化或者边沿触发来产生中断请求。
比如,当连接在某个引脚的传感器检测到特定状态时,就会触发中断。
定时/计数器中断则可以用于实现精确的定时控制或者对外部脉冲进行计数。
当定时时间到或者计数器计满时,就会产生中断。
串行口中断则用于处理串行通信过程中的各种事件。
三、中断优先级在多个中断同时发生的情况下,中断优先级就显得尤为重要。
STC15F2K60S2 单片机为每个中断源都设置了不同的优先级。
高优先级的中断可以打断正在执行的低优先级中断。
就好像在医院里,病危的病人会优先得到医生的救治。
通过合理设置中断优先级,可以确保关键任务能够及时得到处理。
四、中断编程的步骤要进行 STC15F2K60S2 单片机的中断编程,通常需要以下几个步骤:1、开启中断允许在单片机的特殊功能寄存器中,有相应的控制位来允许或禁止中断。
我们需要将这些控制位置为允许状态,才能使中断生效。
2、配置中断源根据我们使用的中断源,设置相应的触发方式、工作模式等参数。
51单片机中断函数(原创版)目录1.51 单片机中断函数概述2.51 单片机中断函数的分类3.51 单片机中断函数的响应过程4.51 单片机中断函数的应用实例5.总结正文一、51 单片机中断函数概述在 51 单片机中,中断函数是一种在程序运行过程中,响应外部或内部事件的机制。
通过中断函数,单片机可以在执行过程中,暂停当前任务,转去处理其他更重要的任务,待处理完毕后,再回到原任务继续执行。
这种机制可以有效提高程序的实时性和响应速度,使得单片机更加智能化和灵活。
二、51 单片机中断函数的分类51 单片机的中断函数主要分为两大类:外部中断函数和内部中断函数。
1.外部中断函数:外部中断函数是由外部设备产生的中断请求信号触发的,例如按键、传感器等。
当外部设备产生中断请求时,单片机会暂停当前任务,转去处理外部中断,待处理完毕后,再回到原任务继续执行。
2.内部中断函数:内部中断函数是由单片机内部产生的中断请求信号触发的,例如定时器中断、串行通信中断等。
当单片机内部产生中断请求时,单片机会暂停当前任务,转去处理内部中断,待处理完毕后,再回到原任务继续执行。
三、51 单片机中断函数的响应过程当外部或内部事件产生中断请求时,51 单片机会进行如下响应过程:1.中断请求信号被捕获:当外部或内部事件产生中断请求时,单片机会捕获到该信号。
2.中断响应:单片机接收到中断请求信号后,会立即停止当前任务的执行,转去处理中断请求。
3.中断处理:单片机会根据中断类型,调用相应的中断服务函数进行处理。
4.中断返回:中断服务函数处理完毕后,单片机会返回原任务继续执行。
四、51 单片机中断函数的应用实例以定时器中断为例,定时器中断是一种常见的内部中断,当定时器计数值到达设定值时,会产生中断请求。
单片机接收到中断请求后,会调用定时器中断服务函数进行处理,例如更新计时器计数值、执行特定任务等。
处理完毕后,单片机会返回原任务继续执行。
五、总结51 单片机中断函数是一种在程序运行过程中,响应外部或内部事件的机制。
#if __VER__<200interrupt void Usart1_rxInt(void) //与电表/红外通讯接收记数#else#pragma vector=USART1RX_VECTOR__interrupt void Usart1_rxInt(void)#endif{uchar ch=RXBUF1 ;if(devState.doWriteIrDA)return;if(n645Counts==0){if(ch!=0x68)return;elsecommState.wireSta645= RXDOING645;}commCode_645[n645Counts++] = ch;if(n645Counts > 63)n645Counts = 0;rxOverTime645 = 8; //unit:16ms}#if __VER__<200interrupt void Usart1_txInt(void) //与电表通讯发送中断发送记数#else#pragma vector = USART1TX_VECTOR__interrupt void Usart1_txInt(void)#endif{TXBUF1 = commCode_645[n645Counts++];if(n645Counts < nFrame645Size)return ;if(devState.doWriteIrDA) //红外发送TxIrDAover = 0;else{commState.wireSta645 = WAITACK645 ;waitAckOverTime645 = 30; //unit:16ms}IE2 &= ~UTXIE1; //关发送中断n645Counts = 0; //发送完成,长度清零}#if __VER__<200interrupt void Usart0_rxInt(void) //与主站通讯接收记数#else#pragma vector=USCIAB0RX_VECTOR__interrupt void Usart0_rxInt(void)#endif{unsigned char c=UCA0RXBUF;BYTE* pCode = GPRS_mCode;if(devState.dolocalComm){ if(nCommCounts==0 ){if(c!=0x68)return;else commState.rxDoing=1;}commCode[nCommCounts++] = c;rxOverTime = 6; //unit:16ms //doLocalpro = 0;if(nCommCounts > COMCODELEN)nCommCounts = 0;}else{if(specialFlag.GPRSTxf==0){c=UCA0RXBUF;commState.rxDoing = 1;pCode[GPRS_Com.RTxLen++] = c;rxOverTime= 10;if(MC55_Call_process == 13||MC55_Call_process == 15)rxOverTime = 35;else if(MC55_Call_process == 14 || MC55_Call_process == 8)rxOverTime = 185;else if(MC55_Call_process == 3)rxOverTime = 65;else if(MC55_Call_process == 4)rxOverTime = 65;if(GPRS_Com.RTxLen > COMCODELEN + 64)GPRS_Com.RTxLen = 0;}}}#if __VER__<200interrupt void Usart0_txInt(void) //与主站通讯发送中断发送记数#else#pragma vector = USCIAB0TX_VECTOR__interrupt void Usart0_txInt(void)#endif{if(devState.dolocalComm){UCA0TXBUF = commCode[nCommCounts++];if( nCommCounts < nFrameSize) return ;IE2 &= ~UCA0TXIE; //关发送中断nCommCounts = 0; //发送完成,长度清零}else{UCA0TXBUF = GPRS_mCode[GPRS_Com.nPos++];if(GPRS_Com.nPos < GPRS_Com.RTxLen)return ;IE2 &= ~UCA0TXIE; //关发送中断memset(GPRS_mCode,0,GPRS_Com.RTxLen);if(devState.ConfirmSetGPRS){devState.ConfirmSetGPRS = 0;nConfirmGPRS = 3;}GPRS_Com.RTxLen = 0;specialFlag.GPRSTxf = 0;}if(devState.ReadyResetPower){devState.stop_cleardg = 1;devState.ReadyResetPower = 0;}}#if __VER__<200interrupt void WatchDog_Timer(void) //看门狗定时器中断,遥脉计数#else#pragma vector = WDT_VECTOR__interrupt void WatchDog_Timer(void)#endif{if(rxOverTime645) rxOverTime645--;if(waitAckOverTime645) waitAckOverTime645--;if(rxOverTime) rxOverTime--;/*if(P1IN&BIT0)PowerOff_Timer = 10;if(PowerOff_Timer)PowerOff_Timer--;*/if(devState.ResetMC55){if(devState.wirelessMode)MC55_Start();elseEM200_Start();}}#if __VER__<200interrupt void basic_timer(void) //基本定时器主要是产生时钟信号62.5ms #else#pragma vector=BASICTIMER_VECTOR //暂未用__interrupt void basic_timer(void)#endif{static int SysTimeCount=0;SysTimeCount++;devState.n62_5msFlag = 1;if(SysTimeCount >= 16){devState.SecondFlag = 1;SysTimeCount = 0;LEDFLASH;CalculateAddedPQ();if(TxGPRSOverTime){TxGPRSOverTime--;if(TxGPRSOverTime==0){GPRS_recallnum++;specialFlag.GPRScom_finish = 1;if(GPRS_recallnum >= 3){GPRS_recallnum = 0;WaitStateFlag = 1;InitModem();specialFlag.CalledNum++;}}}if(devState.doIrDA){doIrdapro++;if(doIrdapro >= 4)devState.doIrDAover = 1;}elsedoIrdapro = 0;}}void TimerAOut(){CCTL0&=~CCIE;TACTL&=~(MC0+MC1);CCTL0&=~CAP;P1SEL&=~BIT0;if(BD_data.Frequence >= 4500 && BD_data.Frequence <= 5500) CCR0 = (92160000L/BD_data.Frequence)>>6;elseCCR0=DEFAULTCCR0;Sam_Counter=0;TACCR1 = 100; // Trig for ADC12 sample & convertTACCTL1 = OUTMOD_3; // Set/resetTACTL |= TACLR+ MC0;//MC_1 ; // clear TAR, up modeADC12CTL0 |= ENC;}void TimerAStop(){CCTL0&=~CCIE;TACTL&=~(MC0+MC1);}#if __VER__<200interrupt void ADC(void)#else#pragma vector = ADC12_VECTOR__interrupt void ADC(void)#endif{ADC12CTL0 &= ~ENC;Ua_Data[Sam_Counter] = ADC12MEM0<<3;//将A/D值存入数组Ia_Data[Sam_Counter] = ADC12MEM1<<3;Ub_Data[Sam_Counter] = ADC12MEM2<<3;Ib_Data[Sam_Counter] = ADC12MEM3<<3;Uc_Data[Sam_Counter] = ADC12MEM4<<3;Ic_Data[Sam_Counter] = ADC12MEM5<<3;Sam_Counter++;if(Sam_Counter>=64){devState.SampleSta=SAMPLEFFT ;Sam_Counter=0;TimerAStop();}elseADC12CTL0 |= ENC;}#if __VER__<200interrupt void Port2(void)#else#pragma vector=PORT2_VECTOR__interrupt void Port2(void)#endif{if((P2IFG & BIT0)== BIT0){P2IFG &= ~BIT0;if(!devState.doIrDA){SXD_1;devState.doIrDA = 1;n645Counts = 0;SetComBTForIrDA();}}}Main(){初始化;While(1){处理;}}#if __VER__<200interrupt void USCIA0_Int(void) //与电表通讯接收/发送中断记数#else#pragma vector=USCI_A0_VECTOR //既能接收中断也能发送中断__interrupt void USCIA0_Int(void)#endif{unsigned char ch;switch(__even_in_range(UCA0IV,4)){case 0:break; // Vector 0 - no interruptcase 2: // Vector 2 - RXIFG 接收中断标志while (!(UCA0IFG&UCTXIFG)); // USCI_A3 TX buffer ready?ch=UCA0RXBUF ;if(devState.doWriteIrDA)return;if(commState.n645Counts==0){if(ch!=0x68)break;}commState.wireSta645= RXDOING645;commCode_645[commState.n645Counts++] = ch;if(commState.n645Counts > 63)commState.n645Counts = 0;rxOverTime645 = 10; //unit:16msbreak;case 4: //Vector 4 - TXIFG 发送中断标志//SpecialFlag.TxdIdleFlag=1;UCA0TXBUF = commCode_645[commState.n645Counts++];if(commState.n645Counts < commState.nFrame645Size)break;if(devState.doWriteIrDA) //红外发送TxIrDAover = 0;else{commState.wireSta645 = WAITACK645 ;waitAckOverTime645 = 20; //unit:16ms}UCA0IE &= ~UCTXIE; //关发送中断commState.n645Counts = 0; //发送完成,长度清零break;default:break;}}#if __VER__<200interrupt void USCIA1_Int(void) //与本地维护口通讯接收/发送中断记数#else#pragma vector=USCI_A1_VECTOR //既能接收中断也能发送中断__interrupt void USCIA1_Int(void)#endif{unsigned char c;switch(__even_in_range(UCA1IV,4)){case 0:break; // Vector 0 - no interruptcase 2: // Vector 2 - RXIFG 接收中断标志//while (!(UCA0IFG&UCTXIFG)); // USCI_A3 TX buffer ready?c=UCA1RXBUF;if(_1_nCommCounts==0){//if(c!=0x68)return;}_1_rxDoing=1;LocalComCode[_1_nCommCounts++] = c; //leon-10-3-18_1_rxOverTime = 6; //unit:16ms //if(_1_nCommCounts > COMCODELEN)_1_nCommCounts = 0;efrom_Com_1 = 1;break;case 4: //Vector 4 - TXIFG 发送中断标志UCA1TXBUF = LocalComCode[_1_nCommCounts++]; //leon-10-3-18if( _1_nCommCounts < commState.nFrameSize)return ;UCA1IE &= ~UCTXIE; //关发送中断efrom_Com_1 = 0;_1_nCommCounts = 0; //发送完成,长度清零if(devState.ReadyResetPower){devState.stop_cleardg = 1;devState.ReadyResetPower = 0;}break;default:break;}}#if __VER__<200interrupt void USCIA2_Int(void) //与载波模块通讯接收/发送中断记数#else#pragma vector=USCI_A2_VECTOR //既能接收中断也能发送中断__interrupt void USCIA2_Int(void)#endif{unsigned char c;// BYTE* pCode = GPRS_mCode;switch(__even_in_range(UCA2IV,4)){case 0:break; // Vector 0 - no interruptcase 2: // Vector 2 - RXIFG 接收中断标志c=UCA2RXBUF;CalCom[carrworkst.testPos++] = c;carrworkst.workstate = RXDOING645;carrworkst.rxOverTime = 30;break;case 4: //Vector 4 - TXIFG 发送中断标志UCA2TXBUF = CalCom[carrworkst.testPos++];if(carrworkst.testPos < carrworkst.Txlen)return;UCA2IE &= ~UCTXIE;carrworkst.testPos = 0;carrworkst.workstate = WAITACK645;break;default:break;}}#if __VER__<200interrupt void USCIA3_Int(void) // 串口3 与GPRS模块口通讯接收/发送中断记数#else#pragma vector=USCI_A3_VECTOR //既能接收中断也能发送中断__interrupt void USCIA3_Int(void)#endif{unsigned char c;BYTE* pCode = GPRS_mCode; // 指向指令区switch(__even_in_range(UCA3IV,4)) // UCA3IV 为几就执行case 几{case 0:break; // Vector 0 - no interrupt 无中断case 2: // Vector 2 - RXIFG 接收中断标志接收//while (!(UCA0IFG&UCTXIFG)); // USCI_A3 TX buffer ready? UCA0IFG=0 UCTXIFG=0 if(specialFlag.GPRSTxf==0){c=UCA3RXBUF; //接收到的数据全部放入缓存在放入变量C中(一个字节)_2_rxDoing = 1;pCode[GPRS_Com.RTxLen++] = c; //再放入命令区命令区长度加1_2_rxOverTime= 10;if(MC55_Call_process == 13||MC55_Call_process == 15)_2_rxOverTime = 35;if(MC55_Call_process == 15)_2_rxOverTime = 15;else if(MC55_Call_process == 14 || MC55_Call_process == 8)_2_rxOverTime = 200;else if(MC55_Call_process == 3)_2_rxOverTime = 65;else if(MC55_Call_process == 4)_2_rxOverTime = 65;if(GPRS_Com.RTxLen > COMCODELEN + 64)GPRS_Com.RTxLen = 0;}break;case 4: //Vector 4 - TXIFG 发送中断标志发送UCA3TXBUF = GPRS_mCode[GPRS_Com.nPos++]; //需要发送的数据放入缓存if(GPRS_Com.nPos < GPRS_Com.RTxLen) //发送未完成。
51单片机中断函数51单片机中断函数是一种用于处理外部事件的特殊函数。
当外部事件发生时,中断函数会被调用,以处理这些事件并采取相应的措施。
在51单片机中,中断函数起到了非常重要的作用,它可以让单片机在处理其他任务时及时响应外部事件,提高系统的实时性和可靠性。
中断函数的编写需要遵循一定的规范和流程。
下面将详细介绍51单片机中断函数的编写步骤及其应用。
第一步:中断向量的设置中断向量是用于保存中断函数入口地址的特殊存储单元。
在51单片机中,每个外部中断都对应一个中断向量。
中断向量的地址是固定的,它们的值存放在特定的RAM区域中。
需要根据具体的外部中断需要设置相关的中断向量。
第二步:中断控制寄存器的设置中断控制寄存器用于设置和控制中断的产生和响应。
其中,IE寄存器用于打开和关闭中断,EA寄存器用于全局控制中断的打开和关闭。
需要根据具体的需求设置相关的中断控制寄存器。
第三步:中断服务程序(ISR)的编写中断服务程序是中断函数的实际代码部分。
它需要根据具体的外部事件,实现相应的功能和处理逻辑。
在编写中断服务程序时,需要注意以下几点:1.入栈和出栈操作:中断服务程序在执行之前需要将CPU的现场保护起来,在执行完成后需要将CPU的现场恢复回去。
这就需要进行对应的入栈和出栈操作。
2.中断标志的清除:在中断服务程序执行期间,需要清除中断标志位,以确保不会再次触发中断。
具体的清除方法和寄存器的设置需根据具体的中断控制寄存器标志位来确定。
3.中断事件的处理:根据具体的需求,编写相应的中断处理逻辑。
可以在中断服务程序中实现对IO口的读写、定时器的操作、数据的处理等。
第四步:中断服务程序的调用中断服务程序需要在中断向量中设置的入口地址处调用,以确保在发生中断时能正确地调用中断服务程序。
中断函数的应用非常广泛。
例如,可以使用外部中断来处理按键输入,实现对按键的检测和相应操作;也可以使用定时器中断实现定时功能,如定时采集传感器数据、定时发送数据等;还可以使用串口中断实现数据的接收和发送等。
stc8系列单片机前五个中断源的中断子函数框架STC8系列单片机是广泛应用于嵌入式系统开发的一种单片机。
该系列单片机具有丰富的外设资源和强大的中断功能,可以通过中断实现对各类事件的处理。
接下来,我将为您详细介绍STC8系列单片机前五个中断源的中断子函数框架。
1.外部中断(INT0和INT1):外部中断是通过外部触发器(例如按钮或传感器)触发的中断。
需要在程序中使用`IE2`和`EX0/EX1`来使能和配置外部中断。
```Cvoid externalInterrupt( interrupt 0/2//在中断函数中处理外部中断的相关操作//...```在中断函数中,您可以处理外部中断所需的任何操作,比如修改变量、执行特定的代码等。
2.定时器/计数器中断(TIMER0和TIMER1):定时器/计数器中断是在定时器/计数器溢出时触发的中断。
需要在程序中使用`IE2`和`ET0/ET1`来使能和配置定时器/计数器中断。
```C//在中断函数中处理定时器/计数器中断的相关操作```在中断函数中,您可以处理定时器/计数器中断所需的任何操作,比如修改变量、执行特定的代码等。
3.串口中断(UART):串口中断是在接收到数据或完成数据发送时触发的中断。
需要在程序中使用`IE2`和`ES`来使能和配置串口中断。
```Cvoid uartInterrupt( interrupt 4//在中断函数中处理串口中断的相关操作//...```在中断函数中,您可以处理串口中断所需的任何操作,比如接收数据、发送数据、修改变量等。
4.ADC中断(ADC):ADC中断是在模数转换完成时触发的中断。
需要在程序中使用`IE2`和`ET2`来使能和配置ADC中断。
```Cvoid adcInterrupt( interrupt 7//在中断函数中处理ADC中断的相关操作```在中断函数中,您可以处理ADC中断所需的任何操作,比如读取模拟值、修改变量等。
中断函数的使用:《单片机C语言编程与实例》
中断函数通过使用interrupt关键字和中断编号0-4来实现。
使用该扩展属性的函数声明语法如下:
返回值函数名interrupt n
N对应中断源的编号
中断编号告诉编译器中断程序的入口地址,它对应者IE寄存器中的使能位,即IE寄存器中的0位对应着的外部中断0,相应的外部中断0的中断编号是0。
当正在执行一个特定任务是,可能有更紧急的事情需要CPU处理,这就涉及到终端优先级,搞优先级的中断可以中断正在处理的底有限级中断程序,因而最好给每种优先级分配不同的寄存器组。
在c51中可以使用using制定的寄存器组,using后的变量为0-3的长整数,分别表示51单片机内的四个寄存器组。
中断函数的完整语法及实例如下:
返回值函数名(【参数】)【模式】【重入】interrupt n [using n] Unsigned int interruptent;
Unsigned char second;
Void time0(void)interrupt 1 using 2
{
if(++interruptent==4000) %计数到4000
{second++; % 另一个计数器
Interruptent=0; %计数器清零
}
}
要是摸个中断源的申请得到相应,必须保证EA=1和相应的允许位为1
定义中断服务函数的一般形式为::
函数类型函数名(形式参数表)[interrupt n][using n]
Interrupt 后面的n是中断号,n的取值范围为0-31,编译器从8n+3处产生中断向量。
11.111111
外部中断
例题:通过P1.7口电量发光二极管,然后外部输入一脉冲串,则发光二极管亮、暗交替
#include <REGX51.H>
Sbit P1_7=P1^7;
Void tnterrupt0()interrupt 0 using 2//定义定时器0
{ P1_7=!P1^7;}
Void main()
{
EA=1;//开启总中断
IT0=1;//外部中断0低电平触发
EX0=1; //外部中断0
P1_7=0;
Do()while(1);
}
2222相套中断
外部中断INT1触发后,启动计数器0,计数达到10次后停止计数,启动定时器1,由定时器1控制定时,由P1.7输出周期为200ms的方波性能号,接受2次中断后关闭方波发生器,P1.7置低。
#include <REGX51.H>
#define uchar unsigned char
Uchar data a,b,c;
Void tnterrupt0()interrupt 2using 1//定义外部中断1
{ a++;}
Void time0()interrupt 1using 2//定义计数器0
{
TL0=0Xff;
B++;
}
Void time1()interrupt 3using 3//定义计时器1
{
TH1=0x06;
c--;
}
Sbit P1_7=P1^7;
Void main()
{
P1_7=1; //初始化
TCON=0x01; //外部中断为低电平出触发方式
TMOD=0x27; //启动定时器1和计数器0,工作方式2 IE=0x8B; //开中断
a=0;
do{}while(a!=1); //等待外部中断
P1_7=!P1_7;//取反
TL0=0xFF;//初值
TH0=0x06;//初值
b=0;
TR0=0;
TR1=1;
Do
{
C=0xC8;
Do{}while(c!=0);
P1_7=!P1_7;
}while(a!=3);
TR1=0;
P1_7=0;
EA=0;//关闭总中断
EX0=0; //禁止外部中断
}。