精华内容
下载资源
问答
  • c语言中断函数注意事项单片机_C语言函数_中断函数(中断服务程序)在开始写中断函数之前,我们来一起回顾一下,单片机的中断系统。中断的意思(学习过微机原理与接口技术的同学,没学过单片机,也应该知道),我们在...

    c语言中的中断函数注意事项

    单片机_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,显然不

    展开全文
  • LINUX系统调用原理-既应用层如何调用内核层函数之软件中断SWI:software interrupt 软件中断ARMLinux系统利用SWI指令来从用户空间进入内核空间,还是先让我们了解下这个SWI指令吧。SWI指令用于产生软件中断,从而...

    

    LINUX系统调用原理-既应用层如何调用内核层函数之软件中断

    SWI:software interrupt 软件中断

    ARMLinux系统利用SWI指令来从用户空间进入内核空间,还是先让我们了解下这个SWI指令吧。SWI指令用于产生软件中断,从而实现从用户模式变换到管理模式,CPSR保存到管理模式的SPSR,执行转移到SWI向量。在其他模式下也可使用SWI指令,处理器同样地切换到管理模式

    内核在执行系统调用的时候处于进程上下文,可以休眠,也可以被抢占,所以必须保证系统调用是可重入的。SWI软件中断也具上面特性,这时从硬件上确保了操作系统多线程多进程的正常运作,而不能因为执行一个SWI指令导致其它进程或线程流停下来了。而在系统调用的实现方式上SWI办演的角色是:应用层一个进程或线程调用用系统调用进入内核层(SWI陷入),这个时候CPU进入管理模式一个调度周期,同时其它进程或线程还是正常的调度的。如果这个时候内核层由于资源原因导致调用此系统调用的进程或线程(内核层只有进程概念,应用层有进程和线程概念)休眠或阻塞,在这个调度周期时间完之后会保存当前休眠或阻塞状态。当前资源满足后休眠或阻塞结束,等下个调度周斯,当时阻塞或休眠进程继续运行,根据运行结果从SWI陷入的管理模式软中断返回一个结果给调用此系统调用的应用线程或进程,此时应用层线程或进程继续运行根据返回结果。(应用层陷入内核说明在内核解度是同一个进程号,对于这个SWI调用事件的流程,(线程对于内核解度应该也是进程 ,不是清楚这儿。))。注意:多个系统用 多个SWI多个线程  都是同时由OS调度策略在多CPU上同时和时间片运行的。不会因一个SWI就打乱步伐。这个解度说明SWI只是应用层陷入内核的一个手段。它可以被中断 和休眠 和阻塞

    LINUX系统分两种模式:用户模式(USER模式) 和内核模式(管理模式) 这两种模式ARMCPU运行硬件上的不同模式。通用它调度器和定时器中断让进程和线程在这两种模式自己动动态运行。

    SWI命令格式:SWI{cond} immed_24

    Swi参数传递有两种格式:

    1)、指令中24位的立即数指定了用户请求的服务类型,参数通过通用寄存器传递。如:

    MOV R0,#34

    SWI 12

    2)、指令中的24位立即数被忽略,用户请求的服务类型有寄存器R0的只决定,参数通过其他的通用寄存器传递。如:

    MOV R0, #12

    MOV R1, #34

    SWI 0

    下面是看别人博客对LINUX系统一些经典总结:

    计算机工作的三大法宝(存储程序计算机、函数调用堆栈、中断)、计算机工作的两把宝剑(中断上下文和进程上下文)

    asmlinkage大都用在系统调用中。有一些情况下是需要明确的告诉编译器,我们是使用stack来传递参数的,比如X86中的系统调用,是先将参数压入stack以后调用sys_*函数的,所以所有的sys_*函数都有asmlinkage来告诉编译器不要使用寄存器来编译,

    linux内核中所有的系统调用函数都用sys_开头

    函数定义中的FASTCALL宏,用于通知编译器,使用寄存器来传递参数。

    如果上面两个宏都没有,则使用默认传参规则,前4个参数通过R0~R3寄存器传递,其余更多的参数通过栈传递。

    系统调用必须仔细检查传入参数的有效性,尤其是用户提供的指针,必须确保:

    *指针指向的内存区域属于用户空间,进程不能哄骗内核去读内核空间的数据。*指针指向的内存区域属于进程的地址空间,不能哄骗内核去读其他进程的数据。

    *进程不能绕过内存访问权限。内核在执行系统调用的时候处于进程上下文,可以休眠,也可以被抢占,所以必须保证系统调用是可重入的。

    内核在执行系统调用的时候处于进程上下文。current指针指向当前任务,即引发系统调用的那个进程。在进程上下文中,内核可以休眠并且可以被抢占。这表明即使是在内核空间中,当前进程也可以被其他进程抢占。因为新的进程可以执行相同的系统调用,所以必须保证系统调用是可重入的。当系统调用返回时,控制权仍然在system_call()中,它最终会负责切换到用户空间并让用户继续执行下去。

    进程状态:

    task_struct中的state描述进程的当前状态。进程的状态一共有5种,而进程必然处于其中一种状态:

    1)TASK_RUNNING(运行)——进程是可执行的,它或者正在执行,或者在运行队列中等待执行。这是进程在用户空间中执行唯一可能的状态;也可以应用到内核空间中正在执行的进程。

    2)TASK_INTERRUPTIBLE(可中断)——进程正在睡眠(也就是说它被阻塞)等待某些条件的达成。一旦这些条件达成,内核就会把进程状态设置为运行,处于此状态的进程也会因为接收到信号而提前被唤醒并投入运行。

    3)TASK_UNINTERRUPTIBLE(不可中断)——除了不会因为接收到信号而被唤醒从而投入运行外,这个状态与可打断状态相同。这个状态通常在进程必须在等待时不受干扰或等待事件很快就会发生时出现。由于处于此状态的任务对信号不作响应,所以较之可中断状态,使用得较少。

    4)TASK_ZOMBIE(僵死)——该进程已经结束了,但是其父进程还没有调用wait4()系统调用。为了父进程能够获知它的消息,子进程的进程描述符仍然被保留着。一旦父进程调用了wait4(),进程描述符就会被释放。

    TASK_STOPPED(停止)——进程停止执行,进程没有投入运行也不能投入运行。通常这种状态发生在接收到SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU等信号的时候。此外,在调试期间接收到任何信号,都会使进程进入这种状态。需要调整进程的状态,最好使用set_task_state(task, state)函数,在必要的时候,它会设置内存屏障来强制其他处理器作重新排序(SMP)。

    在Linux系统中,所有的进程都是PID为1的init进程的后代

    进程调度:

    1.什么是调度现在的操作系统都是多任务的,为了能让更多的任务能同时在系统上更好的运行,需要一个管理程序来管理计算机上同时运行的各个任务(也就是进程)。这个管理程序就是调度程序。它的功能说起来很简单:决定哪些进程运行,哪些进程等待决定每个进程运行多长时间此外,为了获得更好的用户体验,运行中的进程还可以立即被其他更紧急的进程打断。总之,调度是一个平衡的过程。一方面,它要保证各个运行的进程能够最大限度的使用CPU(即尽量少的切换进程,进程切换过多,CPU的时间会浪费在切换上);另一方面,保证各个进程能公平的使用CPU(即防止一个进程长时间独占CPU的情况)。

    2.调度实现原理2.1.关于进程的优先级进程的优先级有2种度量方法一种是nice值,nice值的范围是-20~+19,值越大优先级越低,也就是说nice值为-20的进程优先级最大。一种是实时优先级,实时优先级的范围是0~99,与nice值的定义相反,实时优先级是值越大优先级越高。实时进程都是一些对响应时间要求比较高的进程,因此系统中有实时优先级高的进程处于运行队列的话,它们会抢占一般的进程的运行时间。2.2.关于时间片有了优先级,可以决定谁先运行了。但是对于调度程序来说,并不是运行一次就结束了,还必须知道间隔多久进行下次调度。于是就有了时间片的概念。时间片是一个数值,表示一个进程被抢占前能持续运行的时间。也可以认为是进程在下次调度发生前运行的时间(除非进程主动放弃CPU,或者有实时进程来抢占CPU)。时间片的大小设置并不简单,设大了,系统响应变慢(调度周期长);设小了,进程频繁切换带来的处理器消耗。默认的时间片一般是10ms

    展开全文
  • 定时器中断函数的使用

    千次阅读 2021-05-19 18:41:36
    1.定时器与延时的区别大家可能会觉得我们用延时函数照样可以实现上一讲代码的实验现象,但是定时器与延时的概念不同,延时函数需要占用CPU的使用权,正在延时的时候其他任务没有CPU的使用权就会拖慢执行效率。...

    1.定时器与延时的区别

    大家可能会觉得我们用延时函数照样可以实现上一讲代码的实验现象,但是定时器与延时的概念不同,延时函数需要占用CPU的使用权,正在延时的时候其他任务没有CPU的使用权就会拖慢执行效率。

    而定时器是不需要占用CPU的使用权的,它是独立自己运行的,就像我们在第一讲的时候提到调好5分钟的闹钟,在这5分钟里我们可以随意执行任务,也可以什么事都不做,但是5分钟过后闹钟响了就要执行相关的任务了。

    所以上一讲的代码的实现原理就是每隔51微秒,有个变量会自加1,过了1000个51微秒的时候LED的状态才会改变,可以说CPU在51ms的时间里基本没什么事做,只是在51微秒到了的时候做了“cnt++;”这样简单的任务,然后又空闲地等下一个51微秒的到来再执行“cnt++;”。

    2.定时器中断函数

    与外部中断一样,定时器中断也有中断函数,同理,程序去执行中断函数就会把TF0的中断标志位自动清0,所以只要我们用了定时器中断函数,那么TF0就可以不用再出现在程序书写中了。

    还记得外部中断这个图吗

    518c0273a0367ab6b47e21d7f5ef6e9a.png

    同样定时器0的中断函数使能如下

    127a22cf341936aa049c2e49cba364b5.png

    至于“interrupt”后面的数字为什么是1,请再看我们以前给过大家的这个图的中断函数编号就明白了

    c8f14c29c09fd94f50f3d959c7cf8617.png

    这些编号是为了区分哪些硬件资源的相关中断函数,如果我们同时使用两个定时器,那么只能用“interrupt 1”和“interrupt 3”来区分谁是谁的中断函数了。

    使用“TIM0_IRQHandler”作为函数名也是模仿STM32定时器中断函数名的写法。

    如果我们使用的是工作模式1,每次触发中断函数的执行内容首先就是再次给TH0和TL0赋初值保证下次的定时时间还是一样。

    这里我们使用中断函数的执行方式来实现30ms的间隔流水灯,算出TH0和TL0合成的“16位的变量”要填充的值为37888=0x9400。

    在中断函数里也是可以定义局部变量的,当然如果这个变量是用来辅助流水灯的,那么肯定是要定义成静态变量的。

    3.代码#include 

    #include //详见第六章第8讲

    void main()

    {

    LED_Init();  //初始化LED硬件模块

    EA = 1;      //闭合总中断开关

    TMOD = 0x01; //设置定时器0为工作模式1

    TH0  = 0x94; //设置定时时间为30ms

    TL0  = 0x00;

    ET0  = 1;    //闭合定时器0中断的开关

    TR0  = 1;    //启动定时器0

    while(1);

    }

    void TIM0_IRQHandler() interrupt 1

    {

    static u8 i;

    TH0  = 0x94;  //重新设置定时时间为30ms

    TL0  = 0x00;

    P0=~(0x80>>i);//这一次让流水灯向右移

    i++;

    if(i>=8)i=0;

    }

    觉得30ms的流速太快,想改为300ms的话,修改一下中断函数即可,如下void TIM0_IRQHandler() interrupt 1

    {

    static u8 i,cnt;

    TH0  = 0x94;      //重新设置定时时间为30ms

    TL0  = 0x00;

    cnt++;

    if(cnt>=10)

    {

    cnt=0;

    P0=~(0x80>>i);//这一次让流水灯向右移

    i++;

    if(i>=8)i=0;

    }

    }

    展开全文
  • #endif 这样就可以用#include来包含调用这个C文件函数了哦!呵呵!for example: #include "serial.h" #include "reg52.h" #define uchar unsigned char #define uint unsigned int #define InBufferLong 20 ...

    适用范围:适用于大多数要求不高的数据通讯。

    应用例子:ic卡接口通讯、很多单片机系统的串口通讯都使用。

    ********************************************************************************/

    它对应的头文件如下:

    #ifndef __serial_H__

    #define __serial_H__

    void Init_SerialComm(void);

    void UartSendChar(unsigned char ch);

    void UartSendString(unsigned char *p,unsigned int strlong);

    //static void UartIntrruptService(void);

    #endif

    这样就可以用#include来包含调用这个C文件中的函数了哦!呵呵!for example:

    #include "serial.h"

    #include "reg52.h"

    #define uchar unsigned char

    #define uint unsigned int

    #define InBufferLong 20

    uchar counter;

    uchar trdata[InBufferLong];

    uchar checksum;

    uint i;

    bit Read_Flag=0;

    /***************************************************************************************

    *函数名称:int main(void)

    *函数描述:主函数

    *入口参数:无

    *出口参数:无

    *备 注:无

    *****************************************************************************************/

    int main(void)

    {

    Init_SerialComm();

    while(1)

    {

    if(Read_Flag==1)

    {

    UartSendString(trdata,InBufferLong);

    Read_Flag=0;

    }

    }

    }

    /****************************************************************************************

    *函数名称:void UartIntrruptService(void)

    *函数描述:串口中断服务函数

    *入口参数:无

    *出口参数:无

    *备 注:无

    *******************************************************************************************/

    static void UartIntrruptService(void) interrupt 4 using 3

    {

    if(RI)

    {

    RI=0;

    i=SBUF;

    if(i>127)//当接收到的数值大于127时

    {

    counter=0;

    trdata[counter]=i;//把接收到的数值保存在trdata[0]

    checksum=i-128; //和校验等于接收到的数值-128

    }

    else

    {

    counter++;

    trdata[counter]=i;

    checksum^=i;

    if((counter==(InBufferLong-1))&&(1)) //接收满并且checksum=0时

    {

    Read_Flag=1;

    counter=0;

    }

    }

    }

    }

    在这应注意:1.被调用的C文件中只包含头文件即可,每个函数都使用局部变量

    2.所有的全局变量都在主C文件中定义

    3.中断要放到主C文件中

    展开全文
  • 在开始写中断函数之前,我们来一起回顾一下,单片机的中断系统。中断的意思(学习过微机原理与接口技术的同学,没学过单片机,也应该知道),我们在这里就不讲了,首先来回忆下中断系统涉及到哪些问题。(1)中断源:...
  • 首先,调用子程序过程发生的时间是已知和固定的,即在主程序的调用指令(CALL)执行时发生主程序调用子程序,调用指令所在位置是已知和固定的。而中断过程发生的时间一般的随机的,CPU在执行某一主
  • 从汇编的角度解析函数调用过程看看下面这个简单函数的调用过程:1 int Add(int x,inty)2 {3 int sum = 0;4 sum = x +y;5 returnsum;6 }78 intmain ()9 {10 int a = 10;11 int b = 12;12 int ret = 0;13 ret =Add(a,b...
  • 从汇编的角度解析函数调用过程看看下面这个简单函数的调用过程:int Add(int x,int y){int sum = 0;sum = x + y;return sum;}int main (){int a = 10;int b = 12;int ret = 0;ret = Add(a,b);return 0;}今天主要用...
  • 中断系统的运行必须与中断服务程序配合才能正确使用。设计中断服务程序需要首先明确以下几个问题。中断服务程序设计的任务中断服务程序设计的基本任务有下列4条:(1)设置中断允许控制寄存器IE,允许相应的...
  • C语言(函数)调用过程IntroductionA calling sequence is the conventional sequence of instructions that call and return from a procedure. Because programs tend to make many procedure calls, a compiler ...
  • 求教各位大神,我编写了一个简单的独立按键防抖的子函数,程序如下,在定时中断调用这个函数没有效果。然后我把这段程序直接写到中断函数中,它是起作用的。bit INDRIVER(bit x){bit back;bit y;static uchar ...
  • 1 函数调用当一个函数调用另一个函数时,并不是去复制被调函数的全部代码到内存,而是采用代码共享的方式。也就是它们都是调用同一个函数的代码,而系统为每一次调用开辟一组存储单元,用来存放本次调用的返回地址...
  • 主程序怎样调用子程序

    千次阅读 2021-04-26 15:02:39
    快速导读:Q1:vbs怎么调用子程序?你可以这样操作比如你要调用C:\m.exe Set ws = CreateObject("Wscript.Shell") Set fs = CreateObject...Q2:matlab如何用主程序调用子程序形式必须有函数文件存在时,才能调用其...
  • 前言笔者在 《程序是如何在 CPU 运行的(二)》从 PC 指针寄存器的角度分析了一级函数调用和二级函数调用执行的过程,那么中断服务程序又是如何被执行的呢?两者的相同点和不同点是什么呢?该篇文章笔者将详细地...
  • 中断基本知识 中断过程: 芯片设计固化了能产生哪些中断,那么每个中断对应的处理地址(这个可以由用户自己指定,一般放在代码的最前面,意思是该中断一旦产生,程序无条件pc指针直接跳转到该处理地址执行,那么就...
  • 如何根据系统调用号(EAX寄存器储存)找到要执行的内核函数调用时的参数是储存到3环的堆栈,如何传递给内核函数? 2种调用方式入口(KiSystemService()、KiFastCallEntry())是不一样的,它们是如何返回到3环的...
  • 参考教程:野火 以串口1为例,在利用串口进行接受数据时,我们要对STM32进行串口的中断配置。 先对进行宏定义(起个别名),方便移植: #define DEBUG_USART_IRQ USART1_...以下是中断函数(有每一步操作的详细备.
  • Linux系统调用很多,但是再多也有几种不变的根本:创建,打开,写,读,关闭,删除,等最最基本的操作,就像人们所常说的,Linux上的一切我们都可以当做文件来处理,既然是文件,那么以上的几种操作就是必须的,...
  • 弹框出现组件 每次显示弹框时子组件调用一次create() (原本为进入多次,只有在第一次能调用create()) 解决方案: 在外层包一个div 添加属性v-if v-if为元素的创建和销毁 false时销毁;true为创建,则会调用...
  • 该楼层疑似违规已被系统折叠隐藏此楼查看此楼/*************************************************************************************** 外部中断0实验 *实现现象:下载程序后按下K3按键可以对D1小灯状态取反。...
  • *在计算机科学程序(英语:Subroutine, procedure, function, routine, method, subprogram, callable unit),是一个大型程序的某部份代码,由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他...
  • 浅析linuxopen系统调用作者:吴新武,从2.6.19的linux内核开始,内核的系统调用使用函数syscall,其函数原型为:int syscall(int number, ...)其中number是系统调用号,number后面应顺序接上该系统调用的所有参数。...
  • 程序是在需要的时候调用,在程序里可以预见它的使用。因为中断是由系统调用的,不知道什么时候中断,所以你可以选择允许中断或者不允许中断,这就好比你正在干工作时,电话铃响了,你可以选择接电话也可以选择不接...
  • 通过内核源码看函数调用之前世今生作者:杨小华栈(Stack):一个有序的积累或堆积韦氏词典对每一位孜孜不倦的程序员来说,栈已深深的烙在其脑海,甚至已经发生变异。栈可以用来传递函数参数、存储局部变量、以及...
  • 局部变量用static声明,则使该变量在整个程序执行期间不释放,分配的内存单元... 在②处调用cels的时候编译器可能选择用本文件内的inline版本,也有可能跑去调用外部定义的cels函数(c99没有规定此时的行为,不过编...
  • 项目里面调用 DLL 的接口,接口里面的 C 代码建立了与底层驱动程序的 socket 连接,发送一个取数据的请求以后,用 recv 函数等待返回值,在正确的值返回以前,发生了中断,recv 函数返回了 EINTR 的错误 errno(中断...
  • 其实一直出现在例子的 main()也算是一个函数,只不过它比较特殊,编译时以它做为程序的开始段。有了函数C 语言就有了模块化的优点,一般功能较多的程序,会在编写程序时把每项单独的功能分成数个子程序模块,每个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 131,966
精华内容 52,786
关键字:

中断函数中调用子函数