精华内容
下载资源
问答
  • 怎么函数中判断中断执行并且把调用指向另一个函数,根据函数名的判断?怎么传递给新的函数参数并且关闭自身函数执行
  • 而在这些争论中,我们常常会忽略掉所有语言和平台都是基于一些核心问题来批判的,就是我们怎么去使用这些平台。无论使用 Node.js 编写可靠的代码有多难,而编写高并发代码又是多么的简单,这个平台终究是有那么一段...

    前言

    自 Node.js 面世以来,它获得了大量的赞美和批判。这种争论会一直持续,短时间内都不会结束。而在这些争论中,我们常常会忽略掉所有语言和平台都是基于一些核心问题来批判的,就是我们怎么去使用这些平台。无论使用 Node.js 编写可靠的代码有多难,而编写高并发代码又是多么的简单,这个平台终究是有那么一段时间了,而且被用来创建了大量的健壮而又复杂的 web 服务。这些 web 服务不仅拥有良好的扩展性,而且通过在互联网上持续的时间证明了它们的健壮性。

    然而就像其它平台一样,Node.js 很容易令开发者犯错。这些错误有些会降低程序性能,有些则会导致 Node.js 不可用。在本文中,我们会看到 Node.js 新手常犯的十种错误,以及如何去避免它们。

    错误1:阻塞事件循环

    Node.js(正如浏览器)里的 JavaScript 提供了一种单线程环境。这意味着你的程序不会有两块东西同时在运行,取而代之的是异步处理 I/O 密集操作所带来的并发。比如说 Node.js 给数据库发起一个请求去获取一些数据时,Node.js 可以集中精力在程序的其他地方:

    // Trying to fetch an user object from the database. Node.js is free to run other parts of the code from the moment this function is invoked..db.User.get(userId, function(err, user) {// .. until the moment the user object has been retrieved here})复制代码

    然而,在一个有上千个客户端连接的 Node.js 实例里,一小段 CPU 计算密集的代码会阻塞住事件循环,导致所有客户端都得等待。CPU 计算密集型代码包括了尝试排序一个巨大的数组、跑一个耗时很长的函数等等。例如:

    function sortUsersByAge(users) {users.sort(function(a, b) {return a.age < b.age ? -1 : 1})}复制代码

    在一个小的“users” 数组上调用“sortUsersByAge” 方法是没有任何问题的,但如果是在一个大数组上,它会对整体性能造成巨大的影响。如果这种事情不得不做,而且你能确保事件循环上没有其他事件在等待(比如这只是一个 Node.js 命令行工具,而且它不在乎所有事情都是同步工作的)的话,那这没有问题。但是,在一个 Node.js 服务器试图给上千用户同时提供服务的情况下,它就会引发问题。

    如果这个 users 数组是从数据库获取的,那么理想的解决方案是从数据库里拿出已排好序的数据。如果事件循环被一个计算金融交易数据历史总和的循环所阻塞,这个计算循环应该被推到事件循环外的队列中执行以免占用事件循环。

    正如你所见,解决这类错误没有银弹,只有针对每种情况单独解决。基本理念是不要在处理客户端并发连接的 Node.js 实例上做 CPU 计算密集型工作。

    错误2:多次调用一个回调函数

    一直以来 JavaScript 都依赖于回调函数。在浏览器里,事件都是通过传递事件对象的引用给一个回调函数(通常都是匿名函数)来处理。在 Node.js 里,回调函数曾经是与其他代码异步通信的唯一方式,直到 promise 出现。回调函数现在仍在使用,而且很多开发者依然围绕着它来设置他们的 API。一个跟使用回调函数相关的常见错误是多次调用它们。通常,一个封装了一些异步处理的方法,它的最后一个参数会被设计为传递一个函数,这个函数会在异步处理完后被调用:

    module.exports.verifyPassword = function(user, password, done) {if(typeof password !== ‘string’) {done(new Error(‘password should be a string’))return} computeHash(password, user.passwordHashOpts, function(err, hash) {if(err) {done(err)return}done(null, hash === user.passwordHash)})}复制代码

    这里注意到除了最后一次,每次“done” 方法被调用之后都会有一个 return 语句。这是因为调用回调函数不会自动结束当前方法的执行。如果我们注释掉第一个 return 语句,然后传一个非字符串类型的 password 给这个函数,我们依然会以调用 computeHash 方法结束。根据 computeHash 在这种情况下的处理方式,“done” 函数会被调用多次。当传过去的回调函数被多次调用时,任何人都会被弄得措手不及。

    避免这个问题只需要小心点即可。一些 Node.js 开发者因此养成了一个习惯,在所有调用回调函数的语句前加一个 return 关键词:

    if(err) {return done(err)}复制代码

    在很多异步函数里,这种 return 的返回值都是没有意义的,所以这种举动只是为了简单地避免这个错误而已。

    错误3:深层嵌套的回调函数

    深层嵌套的回调函数通常被誉为“ 回调地狱”,它本身并不是什么问题,但是它会导致代码很快变得失控:

    function handleLogin(..., done) {db.User.get(..., function(..., user) {if(!user) {return done(null, ‘failed to log in’)}utils.verifyPassword(..., function(..., okay) {if(okay) {return done(null, ‘failed to log in’)}session.login(..., function() {done(null, ‘logged in’)})})})}复制代码

    越复杂的任务,这个的坏处就越大。像这样嵌套回调函数,我们的程序很容易出错,而且代码难以阅读和维护。一个权宜之计是把这些任务声明为一个个的小函数,然后再将它们联系起来。不过,(有可能是)最简便的解决方法之一是使用一个 Node.js 公共组件来处理这种异步 js,比如 Async.js:

    function handleLogin(done) {async.waterfall([function(done) {db.User.get(..., done)},function(user, done) {if(!user) {return done(null, ‘failed to log in’)}utils.verifyPassword(..., function(..., okay) {done(null, user, okay)})},function(user, okay, done) {if(okay) {return done(null, ‘failed to log in’)}session.login(..., function() {done(null, ‘logged in’)})}], function() {// ...})}复制代码

    Async.js 还提供了很多类似“async.waterfall” 的方法去处理不同的异步场景。为了简便起见,这里我们演示了一个简单的示例,实际情况往往复杂得多。

    (打个广告,隔壁的《ES6 Generator 介绍》提及的 Generator 也是可以解决回调地狱的哦,而且结合 Promise 使用更加自然,请期待隔壁楼主的下篇文章吧:D)

    错误4:期待回调函数同步执行

    使用回调函数的异步程序不只是 JavaScript 和 Node.js 有,只是它们让这种异步程序变得流行起来。在其他编程语言里,我们习惯了两个语句一个接一个执行,除非两个语句之间有特殊的跳转指令。即使那样,这些还受限于条件语句、循环语句以及函数调用。

    然而在 JavaScript 里,一个带有回调函数的方法直到回调完成之前可能都无法完成任务。当前函数会一直执行到底:

    function testTimeout() {console.log(“Begin”)setTimeout(function() {console.log(“Done!”)}, duration * 1000)console.log(“Waiting..”)}复制代码

    你可能会注意到,调用“testTimeout” 函数会先输出“Begin”,然后输出“Waiting..”,紧接着几秒后输出“Done!”。

    任何要在回调函数执行完后才执行的代码,都需要在回调函数里调用。

    错误5:给“exports” 赋值,而不是“module.exports”

    Node.js 认为每个文件都是一个独立的模块。如果你的包有两个文件,假设是“a.js” 和“b.js”,然后“b.js” 要使用“a.js” 的功能,“a.js” 必须要通过给 exports 对象增加属性来暴露这些功能:

    // a.jsexports.verifyPassword = function(user, password, done) { ... }复制代码

    完成这步后,所有需要“a.js” 的都会获得一个带有“verifyPassword” 函数属性的对象:

    // b.jsrequire(‘a.js’) // { verifyPassword: function(user, password, done) { ... } } 复制代码

    然而,如果我们想直接暴露这个函数,而不是让它作为某些对象的属性呢?我们可以覆写 exports 来达到目的,但是我们绝对不能把它当做一个全局变量:

    // a.jsmodule.exports = function(user, password, done) { ... }复制代码

    注意到我们是把“exports” 当做 module 对象的一个属性。“module.exports” 和“exports” 这之间区别是很重要的,而且经常会使 Node.js 新手踩坑。

    错误6:从回调里抛出错误

    JavaScript 有异常的概念。在语法上,学绝大多数传统语言(如 Java、C++)对异常的处理那样,JavaScript 可以抛出异常以及在 try-catch 语句块中捕获异常:

    function slugifyUsername(username) {if(typeof username === ‘string’) {throw new TypeError(‘expected a string username, got '+(typeof username))}// ...} try {var usernameSlug = slugifyUsername(username)} catch(e) {console.log(‘Oh no!’)}复制代码

    然而,在异步环境下,tary-catch 可能不会像你所想的那样。比如说,如果你想用一个大的 try-catch 去保护一大段含有许多异步处理的代码,它可能不会正常的工作:

    try {db.User.get(userId, function(err, user) {if(err) {throw err}// ...usernameSlug = slugifyUsername(user.username)// ...})} catch(e) {console.log(‘Oh no!’)}复制代码

    如果“db.User.get” 的回调函数异步执行了,那么 try-catch 原来所在的作用域就很难捕获到回调函数里抛出的异常了。

    这就是为什么在 Node.js 里通常使用不同的方式处理错误,而且这使得所有回调函数的参数都需要遵循 (err, ...) 这种形式,其中第一个参数是错误发生时的 error 对象。

    错误7:认为 Number 是一种整型数据格式

    在 JavaScript 里数字都是浮点型,没有整型的数据格式。你可能认为这不是什么问题,因为数字大到溢出浮点型限制的情况很少出现。可实际上,当这种情况发生时就会出错。因为浮点数在表达一个整型数时只能表示到一个最大上限值,在计算中超过这个最大值时就会出问题。也许看起来有些奇怪,但在 Node.js 中下面代码的值是 true:

    Math.pow(2, 53)+1 === Math.pow(2, 53)复制代码

    很不幸的是,JavaScript 里有关数字的怪癖可还不止这些。尽管数字是浮点型的,但如下这种整数运算能正常工作:

    5 % 2 === 1 // true5 >> 1 === 2 // true复制代码

    然而和算术运算不同的是,位运算和移位运算只在小于 32 位最大值的数字上正常工作。例如,让“Math.pow(2, 53)” 位移 1 位总是得到 0,让其与 1 做位运算也总是得到 0:

    Math.pow(2, 53) / 2 === Math.pow(2, 52) // trueMath.pow(2, 53) >> 1 === 0 // trueMath.pow(2, 53) | 1 === 0 // true复制代码

    你可能极少会去处理如此大的数字,但如果你需要的话,有很多实现了大型精密数字运算的大整数库可以帮到你,比如 node-bigint。

    错误8:忽略了流式 API 的优势

    现在我们想创建一个简单的类代理 web 服务器,它能通过拉取其他 web 服务器的内容来响应和发起请求。作为例子,我们创建一个小型 web 服务器为 Gravatar 的图像服务。

    var http = require('http')var crypto = require('crypto') http.createServer().on('request', function(req, res) {var email = req.url.substr(req.url.lastIndexOf('/')+1)if(!email) {res.writeHead(404)return res.end()} var buf = new Buffer(1024*1024)http.get('http://www.gravatar.com/avatar/'+crypto.createHash('md5').update(email).digest('hex'), function(resp) {var size = 0resp.on('data', function(chunk) {chunk.copy(buf, size)size += chunk.length}).on('end', function() {res.write(buf.slice(0, size))res.end()})})}).listen(8080)复制代码

    在这个例子里,我们从 Gravatar 拉取图片,将它存进一个 Buffer 里,然后响应请求。如果 Gravatar 的图片都不是很大的话,这样做没问题。但想象下如果我们代理的内容大小有上千兆的话,更好的处理方式是下面这样:

    http.createServer().on('request', function(req, res) {var email = req.url.substr(req.url.lastIndexOf('/')+1)if(!email) {res.writeHead(404)return res.end()} http.get('http://www.gravatar.com/avatar/'+crypto.createHash('md5').update(email).digest('hex'), function(resp) {resp.pipe(res)})}).listen(8080)复制代码

    这里我们只是拉取图片然后简单地以管道方式响应给客户端,而不需要在响应它之前读取完整的数据存入缓存。

    错误9:出于 Debug 的目的使用 Console.log

    在 Node.js 里,“console.log” 允许你打印任何东西到控制台上。比如传一个对象给它,它会以 JavaScript 对象的字符形式打印出来。它能接收任意多个的参数并将它们以空格作为分隔符打印出来。有很多的理由可以解释为什么开发者喜欢使用它来 debug 他的代码,然而我强烈建议你不要在实时代码里使用“console.log”。你应该要避免在所有代码里使用“console.log” 去 debug,而且应该在不需要它们的时候把它们注释掉。你可以使用一种专门做这种事的库代替,比如 debug。

    这些库提供了便利的方式让你在启动程序的时候开启或关闭具体的 debug 模式,例如,使用 debug 的话,你能够阻止任何 debug 方法输出信息到终端上,只要不设置 DEBUG 环境变量即可。使用它十分简单:

    // app.jsvar debug = require(‘debug’)(‘app’)debug(’Hello, %s!’, ‘world’)复制代码

    开启 debug 模式只需简单地运行下面的代码把环境变量 DEBUG 设置到“app” 或“*” 上:

    DEBUG=app node app.js复制代码

    错误10:不使用监控程序

    不管你的 Node.js 代码是跑在生产环境或是你的本地开发环境,一个能协调你程序的监控程序是十分值得拥有的。一条经常被开发者提及的,针对现代程序设计和开发的建议是你的代码应该有 fail-fast 机制。如果发生了一个意料之外的错误,不要尝试去处理它,而应该让你的程序崩溃然后让监控程序在几秒之内重启它。监控程序的好处不只是重启崩溃的程序,这些工具还能让你在程序文件发生改变的时候重启它,就像崩溃重启那样。这让开发 Node.js 程序变成了一个更加轻松愉快的体验。

    Node.js 有太多的监控程序可以使用了,例如:

    pm2

    forever

    nodemon

    supervisor

    所有这些工具都有它的优缺点。一些擅长于在一台机器上处理多个应用程序,而另一些擅长于日志管理。不管怎样,如果你想开始写一个程序,这些都是不错的选择。

    总结

    你可以看到,这其中的一些错误能给你的程序造成破坏性的影响,在你尝试使用 Node.js 实现一些很简单的功能时一些错误也可能会导致你受挫。即使 Node.js 已经使得新手上手十分简单,但它依然有些地方容易让人混乱。从其他语言过来的开发者可能已知道了这其中某些错误,但在 Node.js 新手里这些错误都是很常见的。幸运的是,它们都可以很容易地避免。我希望这个简短指南能帮助新手更好地编写 Node.js 代码,而且能够给我们大家开发出健壮高效的软件。

    加入我们一起学习吧!

    079e583f2dcf8c1c2c1d7cbff13b3cfc.png
    3f0202e38049819b9a077df83ae36a40.png
    b240e44efd62d01e86f27fefe1063855.png
    展开全文
  • 在开始写中断函数之前,我们来一起回顾一下,单片机的中断系统。 中断的意思(学习过微机原理与接口技术的同学,没学过单片机,也应该知道),我们在这里就不讲了,首先来回忆下中断系统涉及到哪些问题。 (1)...

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

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

         (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.

    展开全文
  • TM32使能定时器更新中断和捕获中断同时发生那么CPU会先因为哪个中断源进入中断呢?这是一个中断的内部不同的中断源,如果同时发生怎么处理?...若在中断函数执行到xxx处时,标志A与B同时置位,那么这次中断只...

    TM32使能定时器更新中断和捕获中断同时发生那么CPU会先因为哪个中断源进入中断呢?这是一个中断的内部不同的中断源,如果同时发生怎么处理?

    答案是:在中断处理函数中,分别判读挂起位就可以了,你编程先查询那个标识位,先处理哪个中断了,即便同时挂起也没关系。这部分优先处理权交给编程者自己了

                 :懂了。就是在中断函数中查询中断标识位,按照查询的顺序和中断标识位的情况进行对应的语句处理。

    回答1

    即然同时发生,就不存在因为谁了。
    在我印象中,只要有中断标志未清除,就会不断的进中断。
    假如中断函数如下:
    void TIM3_IRQHandler(void)
    {
    if(标志A置位)
    {
      清除标志A;
      ...
    }
    xxx;
    if(标志B置位)
    {
      清除标志B;
      ...
    }
    }
    若在中断函数执行到xxx处时,标志A与B同时置位,那么这次中断只会清除标志B,然后退出中断,由与A置位,中断函数会再次进入,然后处理A。

    自己补充1

    懂了。就是在中断函数中查询中断标识位,按照查询的顺序和中断标识位的情况进行对应的语句处理。
    这也是为什么
    //定时器3中断服务程序
    void TIM3_IRQHandler(void)   //TIM3中断
    {
            if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
                    {
                    TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志
                    LED1=!LED1;
                    }
    }
    中断函数中添加中断标识位判断的原因。开始不理解为什么还添加更新中断标识,之前的中断子程序里面不添加标识位判断的。现在明白因为定时器全局中断内部多个中断源,同理还有外部中断中断线 5-9 共用中断函数 EXTI9_5_IRQHandler,中
    断线 10-15 共用中断函数 EXTI15_10_IRQHandler,内部需添加区分多个中断引脚的中断标识

    还有串口和SPI等全局中断都是这样处理的

    http://www.openedv.com/forum.php?mod=viewthread&tid=323692

    展开全文
  • 将外部中断IRQ10与中断函数OnInterrupt挂钩,中断10触发时进入OnInterrupt函数进行端口的处理操作。 问题:IoConnectInterrupt函数执行不成功,返回错误,谁帮我看看代码怎么改。...
  • 今天在练习51单片机的嵌套中断时,发现了一个奇怪的点,就是中断服务函数执行的时候,无论优先级的高低,都不能被打断。嗯,就是外部中断0和外部中断1都不能打断定时器0的中断服务函数。(优先级:外部中断0>...

     

    
    

     

     

    今天在练习51单片机的嵌套中断时,发现了一个奇怪的点,就是中断服务函数在执行的时候,无论优先级的高低,都不能被打断。嗯,就是外部中断0和外部中断1都不能打断定时器0的中断服务函数。(优先级:外部中断0>定时器0>外部中断1.

    我本来想开启定时器0,外部中断0和外部中断1,实现中断嵌套.

    比如外部中断0到达时,执行中断服务函数Int0,因为它的优先级高,所以当外部中断1和定时器0到达时,不会打断外部中断0的中断服务函数。而当定时器0中断时,外部中断0到达可以打断其执行,外部中断1到达不可打断。

    但是很难实现,因为开启三个中断后,每个中断的服务函数执行函数超级短,当出现现象的时候(我设置了LED灯状态翻转表示中断到达),即小灯亮起或熄灭中断函数就已经执行完了,很难控制让中断同时到达。。。

     

    所以我这样写了代码测试:

    interrupt.c

     

    #include<reg52.h>
    #include<interrupt.h>
    
    //外部中断0初始化
    void Int0_Init()
    {    IT0=1;
        EX0=1;
        EA=1;
    }
    //外部中断1初始化
    void Int1_Init()
    {
        IT1=1;
        EX1=1;
        EA=1;
    }
    //定时器0初始化,模式1,16位计数模式,1ms
    void Timer0_Init()
    {    TMOD|=0x01;
        TH0=0xfc;//
        TL0=0x18;
        ET0=1;
        EA=1;
        TR0=1;
    }
    //中断服务函数
    void Int0() interrupt 0
    {    delay(1000);
        if(key1==0)
        {    led1=~led1;
        }
    }
    void Int1() interrupt 2
    {    delay(1000);
        if(key2==0)
        {    led1=~led1;
        }
    }
    void Timer0() interrupt 1
    {    
        TH0=0xfc;
        TL0=0x18;
        i++;
        if(i==10000)
        {
            led1=~led1;
            i=0;
            while(1);
        }
        
    }
    //延时函数,为了消抖
    void delay(u16 j)
    {    while(j--);
    }

     

     

     

     interrupt.h

    #include<reg52.h>
    
    typedef unsigned char u8;
    typedef unsigned int  u16;
    
    //初始化函数
    void Int0_Init();
    void Int1_Init();
    void Timer0_Init();
    void Timer1_Init();
    //中断服务函数
    void Int0();
    void Int1();
    void Timer0();
    void Timer1();
    
    
    void delay(u16 j);
    
    static u16 i=0;
    
    sbit key1=P3^2;
    sbit key2=P3^3;
    sbit led1=P0^0;

     main.c

    #include<reg52.h>
    #include<interrupt.h>
    
    int main()
    {    Int0_Init();
        Int1_Init();
        led1=0;
        Timer0_Init();
    //    Timer1_Init();
        while(1)
        ;
    }

    嗯,这样写完后,我以为能实现我想要的结果,但是现象 是这样的:

    我在定时器0的中断服务函数中加入的while(1)循环,Timer0函数就不会退出。但是实验结果是Timer0不能被打断,即当定时器0的中断未到达时,外部中断0和外部在中断1都能控制LED1的亮灭,当定时器1中断达到时,在中断服务函数Timer0执行时 ,外部中断0和外部中断1的到达不能中断定时器0的服务函数。

    那么问题来了,51单片机怎能实现中断嵌套呢?或者说是怎样控制外部中断和定时器中断的同时到达以便确认中断的优先级排序?困扰的很啊。。。

    转载于:https://www.cnblogs.com/lemon-wahahah/p/11214832.html

    展开全文
  • 首先我便开始了解了这一问题,即从电脑开机加电到main函数执行干了什么? 通过自己这几日没事看看书终于了这个过程分了三步,其目的是实现从启动盘加载操作系统程序,完成执行main函数所需要的准备工作。 【第1步...
  • 在计算机程序中,分支[Branch]具有很重要的意义。函数调用、中断产生时程序的跳转、OS中的Multiple Task的切换等等这些均属于分支...跳转前如有执行的环境怎么原封不动地保存?这样返回时才能继续之前的工作。程序执...
  • 51的中断程序用C怎么

    千次阅读 2012-12-06 12:46:48
    用c语言的话中断程序是单独写在中断服务函数中的,51单片机的中断...进入中断执行中断子程序,不同的中断源要进入不同的中断子程序。对于51的C编程,可以用中断标号,如‘interrupt 0 ’来使中断进入不同的中断中断
  • 先说表象,S32K144的FLASH中的SDK函数(FLASH_DRV_EraseSector)不能正常执行 我的需求是擦除PFLASH中的一个扇区,之后在这个上面写东西,可是照着官方的例子操作怎么都好用,但是移植到自己的工程中怎么都不好用。...
  • 其实写这篇文章的目的是这样的:在基本的网络库中,经常看到有注册回调这么一说,让回调函数做真正去做的事情,...还有就是,在执行回调函数的部分时,是不是流程和回调函数的内容顺序执行的,想执行中断那样,不管怎么
  • 前段时间调试一款芯片的时候,碰到一个奇怪的问题:只要在板卡上插入一个PS2键盘,启动内核时系统就可能会进入串口中断函数执行,过一会系统就panic不往下继续执行。后来经过分析出现问题时的panic的堆栈,借助...
  • 如果一个函数的执行期间被中断后,到重新恢复到断点进行执行的过程中,函数所依赖的环境没有发生改变,那么这个函数就是可重入的,否则就不可重入。 在中断前后不都要保存和恢复上下文吗,怎么会出现函数所依赖的...
  • 串口接收中断和连续发送的矛盾!

    千次阅读 2015-10-10 11:08:10
    暂时想到的原因:因为串口接收中断服务程序也是需要时间来执行的,所以试想一下: MCU的串口外设在接收到二个数据的时候,MCU的主核正在执行第一个数据触发的中断服务程序,所以第二个数据触发的中断函数并未执行!...
  • linux的底层中断处理分析

    千次阅读 2012-06-25 15:26:40
    而是对应到FIQ或IRQ,需要在IRQ或FIQ中断处理程序里进一步判断是哪个外设中断产生了,另外我们还知道,linux里有中断号的概念,在中断发生时,linux会执行所有注册在该中断号上的所有函数。 那么linux里的中断向量...
  • 第一层引导程序的开始部分如下,正常启动的情况下程序从_start入口执行(config.mk定义,地址为0x00000000)。 但是开始有个疑问:就是_...(中断函数在其他地方也没有执行、或定义过,只有此地方)。 经查,根据s...
  • sleep函数是比较常用的api,那么在arm平台下它是怎么实现的呢? 要实现sleep函数必须要有三个方面的支持,中断系统,timer和wfi指令。这是无需多言的,sleep需要有时间参数,能够准确定位时间的就只有timer了,要让...
  • 他没有接收的中断函数啊。。难道接收的中断可以在发送中断中执行??为什么我把最后几行接收的弄出来,放到接收中断中就不行了????、typedef unsigned char uchar;uchar I2CSendBuffer[2],I2CRecvBuffer;int I2...
  • 一、STM32的启动过程:1、复位第一条指令:Reset_Handler PROC,这里指定为 LDR R0, =__main...二、如何跑到中断入口地址我们也知道怎么跳到main函数了,那么,中断发生后,又是怎么跑到中断入口地址的呢?从stm32f...
  • 一个可重入的函数简单来说就是可以被中断函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如...
  • CListView中ontimer()怎么只能执行两次或一次,就中断,这是怎么回事,该怎么解决,大神帮忙啊!!急!!!用回调可以么,用类的成员回调函数可以么?请大神帮忙啊,尽快啊!!!!!!!!!!!!
  • 这一期虽然也是按键控制数码管,但这次是利用IO脚产生外部中断执行中断服务函数来实现的。剧透一下:这次的实现效果和上一期按键扫描的效果不太一样,希望细心的你看过视频后可以发现。(文末公布答案)一、前置...
  • 这一期虽然也是按键控制数码管,但这次是利用IO脚产生外部中断执行中断服务函数来实现的。剧透一下:这次的实现效果和上一期按键扫描的效果不太一样,希望细心的你看过视频后可以发现。(文末公布答案)一、前置...
  • [Linux]不可重入函数

    2019-04-02 14:37:00
    如果一个函数的执行期间被中断后,到重新恢复到断点进行执行的过程中,函数所依赖的环境没有发生改变,那么这个函数就是可重入的,否则就不可重入。 在中断前后不都要保存和恢复上下文吗,怎么会出现函数所依赖的...
  • * 我们知道当串口接收到数据的时候,会触发串口中断,触发串口...此时,就不会再出现中断被触发两次的情况,但是发送数据连续两个 FF FF也是不可避免的,要怎么解决这个问题,即使发送两个 FF FF也只触发一次中断??
  • 如果一个函数的执行期间被中断后,到重新恢复到断点进行执行的过程中,函数所依赖的环境没有发生改变,那么这个函数就是可重入的,否则就不可重入。 在中断前后不都要保存和恢复上下文吗,怎么会出现函数所依赖的...
  • ARM+Linux中断系统详细分析

    千次阅读 2017-03-29 11:07:23
    Linux中断系统到底是否支持优先级,可否嵌套,中断号又是怎么来确定的,中断产生时又是如何一步步执行中断处理函数的。为了彻底搞懂Linux中断系统,我决定从最原始材料出发,一探究竟。(s3c244
  • 内核控制路径就是内核里面的代码,即位于0xc000 0000以上的函数代码,包括中断处理...异常处理函数:比如应用层执行的系统调用,触发cpu执行这个函数 内核线程:和其他用户线程一样,参与cpu的优先级调度。 *********
  • <ol><li>同样不可预期的函数中断,因为<code>require可能代表着一个或一系列的<code>factory的执行,且这个执行时间很可能和用户的操作路径相关,函数执行时间变得不那么可控,性能监控的...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 155
精华内容 62
关键字:

中断函数怎么执行的