产品选型

单片机定时函数 单片机C语言函数之中断函数(中断服务程序)

小编 2024-10-06 产品选型 23 0

单片机C语言函数之中断函数(中断服务程序)

在开始写中断函数之前,我们来一起回顾一下,单片机的中断系统。

中断的意思(学习过微机原理与接口技术的同学,没学过单片机,也应该知道),我们在这里就不讲了,首先来回忆下中断系统涉及到哪些问题。

(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开始从这里一条一条的执行程序指令。

n为单片机工作寄存器组(又称通用寄存器组)编号,共四组,取值为0,1,2,3

中断号 中断源

0 外部中断0

1 定时器0

2 外部中断1

3 定时器1中断

4 串行口中断

这5个中断源的中断入口地址为:(在上一篇文章中讲到的ROM前43个存储单元就是他们,这40个地址用来存放中断处理程序的地址单元,每一个类中断的存储单元只有8B,显然不是中断处理的程序,而是存放着中断处理程序的真正地址)

INT0:0003H 0

T0: 000BH 1

INT1:0013H 2

T1: 001BH 3

串口: 0023H 4

中断向量(中断入口地址)= 中断号x8 +3

前面m意思很清楚,不同的m值表示这个函数是针对不同的中断源,比如m为1是表示它是定时器0的中断函数,

如void time0() interrupt 1{}

那么后面的using n 又是什么意思呢?在正在执行一个特定任务时,有更紧急的事情需要CPU来处理,涉及到中断优先权。高优先权中断低优先权正在处理的程序,所以最好给每个优先程序分配不同的寄存器组。

CPU正在处理某个事件,突然另外一个事件需要处理,于是进入中断后,而你不想将现在执行的程序的各寄存器状态入栈,那么可以把这个中断程序放入另一个寄存器组,如切换到1组,然后退出中断时,再切回到0组(原来的程序在0组)。

为了更好的了解这里意思,你可以看看工作寄存器组的作用是什么。

下面的注意事项转自网络上其他朋友的文章(整理下,重复的去掉了,写的非常好):

(1)中断函数不能进行参数传递

(2)中断函数没有返回值

(3)在任何情况下都不能直接调用中断函数

(4)中断函数使用浮点运算要保存浮点寄存器的状态。

(5)如果在中断函数中调用了其它函数,则被调用函数所使用的寄存器必须与中断函数相同,被调函数最好设置为可重入的。

(6)C51编译器对中断函数编译时会自动在程序开始和结束处加上相应的内容,具体如下:在程序开始处对ACC、B、DPH、DPL和PSW入栈,结束时出栈。中断函数未加using n修饰符的,开始时还要将R0~R1入栈,结束时出栈。如中断函数加using n修饰符,则在开始将PSW入栈后还要修改PSW中的工作寄存器组选择位。

(7)C51编译器从绝对地址8m+3处产生一个中断向量,其中m为中断号,也即interrupt后面的数字。该向量包含一个到中断函数入口地址的绝对跳转。

(8)中断函数最好写在文件的尾部,并且禁止使用extern存储类型说明。防止其它程序调用。

(9)在设计中断时,要注意的是哪些功能应该放在中断程序中,哪些功能应该放在主程序中。一般来说中断服务程序应该做最少量的工作,这样做有很多好处。首先系统对中断的反应面更宽了,有些系统如果丢失中断或对中断反应太慢将产生十分严重的后果,这时有充足的时间等待中断是十分重要的。其次它可使中断服务程序的结构简单,不容易出错。中断程序中放入的东西越多,他们之间越容易起冲突。简化中断服务程序意味着软件中将有更多的代码段,但可把这些都放入主程序中。中断服务程序的设计对系统的成败有至关重要的作用,要仔细考虑各中断之间的关系和每个中断执行的时间,特别要注意那些对同一个数据进行操作的ISR.

单片机怎么做定时器矩阵,彻底解决各种定时问题?

大家好,我是无际。

定时功能非常常用,可以说是刚需,也可以说是很多人的痛点。

做LED闪烁效果要用定时、按键扫描要定时、数码管扫描要定时、滤波要定时等等。

曾经,我在产品开发的时候也被各种定时需求搞得焦头烂额。

还好,后面我自己写了一个定时器的程序架构,今天一步到位,,彻底解决各种定时的问题

最近无际单片机编程有几个学员在学习的时候搞不懂这个。

我借此写了这篇文章,然后基于这个文章内容来给学员们直播讲解。

一、为什么我要搞定时器矩阵

定时器矩阵这个概念是我自创的,简单来说就是很多不同定时时间的软件定时器组合。

因为产品开发这么多年,总有乱七八糟的精准定时需求,有50us的,有1ms的,有10ms的,有50ms的,有100ms的等等。

如果没有一个很好的程序架构的话,不同的精准定时需求一多,代码就会很混乱,而且也不好管理,移植性和可扩展性那些就更不用提了。

二、解决需求的思路

然后我就在想,我能不能设计一个定时器的程序架构,让它能够适应所有的精准定时需求。

我的思维雏形大概是这样的。

图左边是定时器时间源, 类似于我们的时钟源,一般我是用单片机定时器中断做个50us的定时,因为用定时器做时间比较精准。

为什么要用50us?因为我产品的RFD波形定时采集频率是50us采一次。

如果你产品没定时这么频繁的功能需求,你完全可以把定时时间源配置成10ms,甚至100ms,这个是根据不同的产品去调整的。

图右边的就是定时器矩阵, 就是各种乱七八糟的不同定时需求组合,比如LED特效定时功能的定时需求、RFD波形定时采集、RFD重复码滤波延时等等。

最终这些定时器矩阵都有一个时间单位/基准,这个时间单位/基准是由定时器时间源提供,如果我配置定时器中断是50us,那定时器矩阵的时间单位就是50us。

有了这种想法以后,剩下的就是考验你的经验和代码水平了。

三、代码设计思路

一个工程师工作越久,做过的项目越多,就要慢慢形成一个面向对象的思维

虽然上面雏形出来了,但是我相信很多人依然不知道怎么动手去写代码。

这个是正常的,最好的方法就是先抄后超

我是用面向对象的思维去做的 ,对于c语言来说,结构体是实现面向对象最好的方式

这里的对象不是你的男女朋友,而是世间万物皆可以当做一个对象。

比如说人是一个对象,这个对象有很多属性 ,比如说性别、年龄、身高、体重等等。

Ok,那在程序里,如何把这个对象的特征用结构体展现出来呢?

可以通过下面这个代码:

那回到我们定时器矩阵这里,我们把定时器矩阵当做一个对象

那这个定时器矩阵都需要具备哪些共同的特征

我总结了下面几个:

需要有个变量当做开关标志控制该定时器启动/停止 需要有个变量当做当前的定时值 需要有个变量当做该定时器的定时周期。 定时时间到了以后,需要去执行相应动作,为了灵活使用,需要一个函数指针。

那用结构体来表示代码如下:

这里很多人可能有点懵逼,我怎么想不到要这些东西呢?

这个是正常的,不用去纠结,我也不是一开始就把这几个成员都想到的,而是后面做功能的时候慢慢完善的,你刚开始抄我的思维就行了。

后面很多应用都是用这种套路去做的,比如说我们的任务管理、比如菜单这些,用多了自然就熟了,以后你自己也能设计别的对象了。

Ok,这样我们就把定时器矩阵这个对象的特征设计好了。

四、定时器代码实战

1.前面我们用结构体自定义了一个定时器的对象来,下面就要用这个定时器对象”生”出定时器矩阵。

我们直接用定义结构体数组的方式,T_SUM就是我们定时器矩阵的个数,也就是我产品有多少个定时器需求。

后面我们所有的操作都是围绕这个结构体来进行的。

2.配置定时器矩阵时间源,初始化定时器矩阵参数

A). 我们首先要给这个定时器矩阵一个时间源,也就是配置我们要去配置单片机定时器中断。

我们的定时频率配置的是50us,是因为我们产品有的功能最短需要50us的定时。

然后,我们需要写一个初始化函数,去调用这个定时器配置,以及初始化定时器矩阵参数。

B). 然后在这个50us定时器中断函数里,去实现给定时器矩阵定时代码。

这里,我单独写了一个函数。

然后我们在定时器中断函数里调用这个函数,实现给定时器矩阵定时。

3.附加功能

定时器矩阵时间源配置好了,但是我们还需要一些函数来操作定时器矩阵对吧?

A). 编写创建定时器

我希望定时器能像任务一样,想要的时候创建,所以就有了创建定时器函数。

我们创建定时器的时候这样调用就可以了。

B). 复位定时器

如果说我们需要循环定时的话,在定时时间到了以后就需要复位定时器,让定时器重新启动。

除了以上以外,其他功能可以自己去完善,比如说控制定时器状态、删除定时器、获取定时器时间,这里就不一一举例了。

完整的代码和视频教程,大家可以找无际单片机编程来拿。

有了这个定时器程序架构,以后开发产品再也不怕有各种定时需求啦,使用方便,移植性也强,如果加个动态分配,就更完美了。

相关问答

单片机 如何把 定时 器延时写成delay延时那样在主程序里随便调用?

你可以在调用函数时启动定时器,并通过中断服务函数判断中断次数是否达到,达到的话就置一个标志位,然后主函数中while判断,不过这太浪费系统资源了,有什么用...

51 单片机 ,有8个流水灯,每个之间延迟1秒,这个延迟用c程序编写怎么写?

1、用精确定时的方法,设置流水灯运行时的时间间隔,延时时间为500MS。2、#include"reg51.h"首先写出单片机的头函数。3、#include"int...

单片机 标准 函数 概念?

在单片机编程中,标准函数是指由单片机厂商提供的一组预定义函数,用于简化常见任务的实现。这些函数通常包含在单片机的开发环境或库文件中,可以直接调用和使用...

求一个51 单片机定时 闹钟程序。要C语言。能够调时间 - hL0lQS...

我来发一个C语言211351单片机时钟程序,希望5261能帮到你/*程序功能:4102带定时闹铃时钟*//*-------...

求一个51 单片机定时 闹钟程序。要C语言。能够调时间 - 小红薯...

我来发一个C语言211351单片机时钟程序,希望5261能帮到你/*程序功能:4102带定时闹铃时钟*//*-------...

有大佬知道 单片机 延时 函数 吗?

1、stm32有HAL_delay()该功能使用滴嗒时钟完成的,默认参数1毫秒,可以查看下HAL_InitTick函数。2、其他平台,一般都会有,一般用定时器(滴嗒时钟)做的功能...

单片机 怎么从 主函数 跳到中断 函数 中例如:#include#defineuint...

[最佳回答]对于单片机的硬件,你熟悉吗?时钟和CPU是独立的,时钟中断程序时这样的:在CPU执行指令时,计数器(计时器)同时在计时,当计时器溢出时,就向CPU申请中断,...

单片机定时 器在12M晶振下,方式二最长可定时多久?怎么算?

12M晶振,每个指令周期是1us,采用方式1定时,那么定时公式为:定时时间=(2^16-定时初值)×1us,当初值=0时,最大可以是2^16us=65536us即一次循环最多可以定时...1...

MCS-51 单片机定时 器/计数器作定时和计数作用时,其计算脉冲分别由谁提供?其定时时间与哪些因素有关?

计数的脉冲由外部提供..定时时是由外部晶振提供..定时加1的周期为一个机器周期...定时时间与初值和晶振有关..计数的脉冲由外部提供..定时时是由外部晶振...

求51 单片机定时 时间与计数初值关系式的推导过程?

不要去记什么公式,知道原理就行了。以16位方式计数为例,51单片机的计数方式是向上计数,16位计数器如果计数初值为0,则计数器从0计到65535,每计一个1微秒,...

猜你喜欢