娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

S3C2440—12.按鍵中斷

發布者:數字沖浪最新更新時間:2021-09-01 來源: eefocus關鍵字:S3C2440  按鍵中斷 手機看文章 掃描二維碼
隨時隨地手機看文章

一. 總體

要驅動按鍵中斷控制LED亮滅,程序要進行如下幾部分操作:


在start.S中對CPSR寄存器中清除I位,使能IRQ,這是大前提

根據原理圖找出按鍵對應的外部中斷,對外部中斷對應引腳做相應配置,使能相應的外部中斷:EINTMASK

開啟中斷使能:INTMSK要設置

編寫C中斷處理函數,通過INTOFFSET、EINTPEND確定哪個中斷觸發,并做相應處理,還要清除中斷標志位

編寫start.S中的IRQ異常處理函數


二. CPSR設置

在這里插入圖片描述

CPSR的IRQ中斷使能位不使能,都行不通,我就找bug找了一天。。。


在代碼重定位之后就對CPSR的I位清零,并且分配棧指針,如下:


mrs r0, cpsr         /* 讀出cpsr */

bic r0, r0, #0xf     /* 修改M4-M0為0b10000, 進入usr模式 */

bic r0, r0, #(1<<7)  /* 清除I位, 使能中斷 */

msr cpsr, r0


/* 設置 sp_usr */

ldr sp, =0x33f00000


CPU再運行程序的時候,會自動使用棧,棧指針sp在調用C程序之前就要設定。 CPU的內存RAM空間存放規律一般是分段的,從地址向高地址,依次為:程序段(.text),BSS段,然后上面還可能會有堆空間,然后最上面才是堆棧段,這樣安排堆棧,是因為堆棧的特點決定的,所以堆棧的指針SP初始化一般在堆棧段的高地址,也就是內存的高地址,然后讓堆棧指針向下增長(其實就是遞減)。這樣做的好處就是堆棧空間遠離了其他段,不會跟其他段重疊,造成修改其他段數據,而引起不可預料的后果,還有設置堆棧大小的原則,要保證棧不會下溢出到數據空間或者程序空間。所謂堆棧溢出,是指堆棧指針SP向下增長到其他段空間,如果棧指針向下增長到其他段空間,稱為堆棧溢出。堆棧溢出會修改其他空間的值,嚴重情況下可造成死機.


三. 中斷源設置

中斷源的設置,主要是三點:


配置按鍵引腳為外部中斷模式

配置外部中斷的觸發方式:上升沿、下降沿都觸發

使能相應的外部中斷線(EINT0~3默認開啟使能)

通過查看板子的原理圖獲取按鍵對應的引腳,以及對應的外部中斷線,中斷源配置的代碼如下:


/* 中斷源(按鍵引腳)初始化 

 * EINT0  EINT2  EINT11  EINT19

 * GPF0   GPF2   GPG3    GPG11

 *  S2     S3     S4      S5

 * 說明:配置按鍵對應的引腳、配置中斷觸發方式

*/

void Exti_SoucreKeyInit( void )

{

    /* GPF0、2配置為外部中斷引腳模式 */

    GPFCON &= ~( (3<<0)|(3<<4) );

    GPFCON |=  ( (2<<0)|(2<<4) ); 


    /* GPG3、11配置為外部中斷引腳模式 */

    GPGCON &= ~( (3<<6)|(3<<22) );

    GPGCON |=  ( (2<<6)|(2<<22) );


    /* EXTINTx 外部中斷控制寄存器設置中斷觸發模式:上升沿、下降沿都觸發 配置相應位為11x */

    EXTINT0 |= ( (7<<0)|(7<<8) );   //EXINT0、2

    EXTINT1 |=  (7<<12);            //EXINT11

    EXTINT2 |=  (7<<12);            //EXINT19


        /* EINTMASK 外部中斷使能寄存器,開啟對應的外部中斷,清零開啟 */

    EINTMASK &= ~( (1<<11)|(1<<19) ); //EINT0~3默認開啟使能 

}


四. 中斷控制器設置

根據中斷的流程圖來配置,先分析一下各個寄存器:

在這里插入圖片描述

MODE用來配置中斷的模式,可以選擇中斷模式為FIQ,這里我們只使用IRQ,所以MODE寄存器不需要設置,如圖:默認是IRQ

在這里插入圖片描述

MASK相當于使能位(默認是屏蔽的),所以要清零INTMASK寄存器使能相應的中斷。設置INTMASK來使能:

在這里插入圖片描述

讀取INTPND可以得到當前正在處理的中斷是哪一個,因為可能存在多個中斷請求在排隊,優先級問題。配合OFFSET寄存器使用效果更加。


而且不需要手動清除INTPND,在清除SRCPND的時候,INTPND會自動清除


SRCPND寄存器用來產看發生請求的中斷控制線(中斷源):

外部中斷是without sub-register的,所以中斷的請求直達SRCPND,所以可以通過SRCPND寄存器來顯示是否有中斷請求,相當于中斷標志位,所以在處理中斷之后需要清除SRCPND。


所以在初始化中斷控制器的時候,只要打開使能位即可,就是配置一下INTMASK就可以。SRCPND和INTPND是在中斷處理函數里使用的,判斷是哪一個中斷請求的


中斷控制器有關的初始化代碼如下:


/* 中斷控制器初始化 

 * 說明:開啟中斷使能,在EINTMASK、INTMSK中,只有EINT0~3是默認不屏蔽的

 */

void Exti_InterruptControlInit( void )

{

    /* 開啟中斷使能 */

    INTMSK &= ~( (1<<0)|(1<<2)|(1<<5) );

}


五. C中斷處理函數

在C中斷處理函數中,要分辨中斷請求,根據相應的中斷請求做出回應,我使用按鍵來控制三個LED的亮滅狀態,具體代碼如下:


#define LED1_ON  GPFDAT &= ~(1<<4)

#define LED2_ON  GPFDAT &= ~(1<<5)

#define LED3_ON  GPFDAT &= ~(1<<6)


#define LED1_OFF  GPFDAT |= (1<<4)

#define LED2_OFF  GPFDAT |= (1<<5)

#define LED3_OFF  GPFDAT |= (1<<6)


/* 中斷處理函數 

 * 說明:觸發外部中斷后,進入中斷處理函數,通過SRCPND來判斷觸發了哪一個中斷,從而進行相應的操作。退出時要清理中斷

 */

void Exti_ProcessingInterrupt( void )

{


      unsigned int temp = INTOFFSET;

    unsigned int reset = 0;//用來清零up,

    puts("nrIRQ!nr");

    /*  可以通過INTOFFSET寄存器的值來直接判斷哪個中斷觸發了 */

    if( temp==0 )      //EINT0

    {

        if(GPFDAT&(1<<0))  //引腳高電平,按鍵按下,點亮LED

        {

            LED1_ON;

        }

        else

        {

            LED1_OFF;

        }

        reset |= (1<<0);

    }

    else if( temp==2 ) //EINT2

    {

        if(GPFDAT&(1<<2)) //GPF2

        {

            LED2_ON;

        }

        else

        {

            LED2_OFF;

        }

        reset |= (1<<2);

    }

    else if( temp==5 ) //EINT8_23

    {

        if( EINTPEND&(1<<11) )

        {

            if(GPGDAT&(1<<3)) //GPG3

            {

              LED3_ON;

            }

          else

          {

             LED3_OFF;

          }

        }

        

        else if( EINTPEND&(1<<19) )

        {

            if(GPGDAT&(1<<11)) //GPG11

        {

            LED1_ON;

            LED2_ON;

            LED3_ON;

        }

        else

        {

            LED1_OFF;

            LED2_OFF;

            LED3_OFF;

        }

        }

        

        reset |= (1<<5);

    }


    /* 清除SRCPND、INTPND標志位 */

    EINTPEND |= ( (1<<11)|(1<19) );//寫1清除


    SRCPND |= ( (1<<0)|(1<2)|(1<<5) );

    INTPND |= ( (1<<0)|(1<2)|(1<<5) ); 


}


最后還要清除EINTPEND、SRCPND、INTPND中的標志位,不然程序會一直處于中斷中。


六. 匯編IRQ異常處理程序

當觸發外部中斷時,CPU會去中斷向量表中IRQ的指令位置,跳轉到IRQ的處理程序中,所以首先得在_start之后的0X18處寫一個跳轉指令,跳轉至IRQ處理程序,如下:


_start:

/* 異常向量表 */

bl reset   /* 0X0  Reset 上電復位,從0地址開始執行程序,依次:關閉看門狗、配置時鐘系統、初始化sdram、拷貝代碼到sdram(重定位)、清除.bcc段、進入mian函數 */

bl halt     /* 0X4  Undefined instruction */

bl halt     /* 0X8  Software Interrupt */

bl halt      /* 0XC  Abort(prefetch) */

bl halt      /* 0X10 Abort(data) */

bl halt      /* 0X14 Reserved */

ldr pc, =irq_addr      /* 0X18 IRQ */

bl halt              /* 0X1C FIQ */ 


.align 4

irq_addr:

.word do_irq


在do_irq程序中,首先指定棧指針,然后保存現場(注意返回的值是lr-4),然后調用C處理函數,然后恢復現場,如下:


.align 4

do_irq:

ldr sp, =0x33d00000


sub lr, lr, #4            /* 發生中斷時,返回值是lr-4 */

stmdb sp!, {r0-r12,lr}


bl Exti_ProcessingInterrupt


ldmia sp!, {r0-r12,pc}^

在這里插入圖片描述

七. 源碼

start.S


.text

.global _start


_start:

/* 異常向量表 */

bl reset   /* 0X0  Reset 上電復位,從0地址開始執行程序,依次:關閉看門狗、配置時鐘系統、初始化sdram、拷貝代碼到sdram(重定位)、清除.bcc段、進入mian函數 */

bl halt     /* 0X4  Undefined instruction */

bl halt     /* 0X8  Software Interrupt */

bl halt      /* 0XC  Abort(prefetch) */

bl halt      /* 0X10 Abort(data) */

bl halt      /* 0X14 Reserved */

ldr pc, =irq_addr      /* 0X18 IRQ */

bl halt              /* 0X1C FIQ */ 


.align 4

irq_addr:

.word do_irq


.align 4

do_irq:

ldr sp, =0x33d00000


sub lr, lr, #4            /* 發生中斷時,返回值是lr-4 */

stmdb sp!, {r0-r12,lr}


bl Exti_ProcessingInterrupt


ldmia sp!, {r0-r12,pc}^


.align 4

reset:

/* 關閉看門狗 */

ldr r0, =0x53000000

ldr r1, =0

str r1, [r0]


/* 設置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */

/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */

ldr r0, =0x4C000000

ldr r1, =0xFFFFFFFF

str r1, [r0]


/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */

ldr r0, =0x4C000014

ldr r1, =0x5

str r1, [r0]


/* 設置CPU工作于異步模式 */

mrc p15,0,r0,c1,c0,0

orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA

mcr p15,0,r0,c1,c0,0


/* 設置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 

*  m = MDIV+8 = 92+8=100

*  p = PDIV+2 = 1+2 = 3

*  s = SDIV = 1

*  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M

*/

ldr r0, =0x4C000004

ldr r1, =(92<<12)|(1<<4)|(1<<0)

str r1, [r0]


/* 一旦設置PLL, 就會鎖定lock time直到PLL輸出穩定

* 然后CPU工作于新的頻率FCLK

*/


/* 設置內存: sp 棧 */

/* 分辨是nor/nand啟動

* 寫0到0地址, 再讀出來

* 如果得到0, 表示0地址上的內容被修改了, 它對應ram, 這就是nand啟動

* 否則就是nor啟動

*/

mov r1, #0

ldr r0, [r1] /* 讀出原來的值備份 */

str r1, [r1] /* 0->[0] */ 

ldr r2, [r1] /* r2=[0] */

cmp r1, r2   /* r1==r2? 如果相等表示是NAND啟動 */

ldr sp, =0x40000000+4096 /* 先假設是nor啟動 */

moveq sp, #4096  /* nand啟動 */

streq r0, [r1]   /* 恢復原來的值 */


/* 代碼重定位的時候,首先初始化SDRAM,然后拷貝代碼,然后清除.bss段(防止內存訪問出錯),最后執行main函數,main就在重定位的SDRAM中去執行 */

bl sdram_init


/* 重定位text, rodata, data段整個程序 */

bl copy2sdram


/* 清除BSS段 */

bl clean_bss


mrs r0, cpsr         /* 讀出cpsr */

bic r0, r0, #0xf     /* 修改M4-M0為0b10000, 進入usr模式 */

bic r0, r0, #(1<<7)  /* 清除I位, 使能中斷 */

msr cpsr, r0


/* 設置 sp_usr */

ldr sp, =0x33f00000


//bl main  /* 使用BL命令相對跳轉, 程序仍然在NOR/sram執行 */

ldr pc, =main  /* 絕對跳轉, 跳到SDRAM */


.align 4

halt:

b halt


exti.c


#include "s3c2440_soc.h"

#include "uart.h"


/* LED引腳低電平點亮 */

#define LED1_ON  GPFDAT &= ~(1<<4)

#define LED2_ON  GPFDAT &= ~(1<<5)

#define LED3_ON  GPFDAT &= ~(1<<6)


#define LED1_OFF  GPFDAT |= (1<<4)

#define LED2_OFF  GPFDAT |= (1<<5)

#define LED3_OFF  GPFDAT |= (1<<6)


/* 中斷控制器初始化 

 * 說明:開啟中斷使能,在EINTMASK中,只有EINT0~3是默認不屏蔽的

 */

void Exti_InterruptControlInit( void )

{

    /* 開啟中斷使能 */

    INTMSK &= ~( (1<<0)|(1<<2)|(1<<5) );

}



/* 中斷源(按鍵引腳)初始化 

 * EINT0  EINT2  EINT11  EINT19

 * GPF0   GPF2   GPG3    GPG11

[1] [2]
關鍵字:S3C2440  按鍵中斷 引用地址:S3C2440—12.按鍵中斷

上一篇:LPC2000系列學習筆記4--存儲器映射控制
下一篇:S3C2440—11.und異常

小廣播
設計資源 培訓 開發板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統推廣工作。

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京B2-20211791 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 聂荣县| 庆云县| 永善县| 阿鲁科尔沁旗| 保康县| 连州市| 陆河县| 陆川县| 名山县| 云安县| 清丰县| 鞍山市| 安西县| 易门县| 确山县| 根河市| 林芝县| 荣成市| 静海县| 祁阳县| 宁武县| 芜湖县| 富蕴县| 凤阳县| 左贡县| 满洲里市| 黔南| 宜丰县| 福海县| 崇礼县| 微山县| 邵阳县| 泸溪县| 绥江县| 旬邑县| 阳泉市| 淮安市| 临邑县| 松阳县| 南康市| 商丘市|