色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

按鍵中斷實驗是什么

汽車電子技術 ? 來源:程序猿搬磚 ? 作者:壞人 ? 2023-03-02 16:21 ? 次閱讀

前面的按鍵實驗是通過死循環一直讀取按鈕電平值來判斷是否有按下按鈕,接下來將使用另外一個更優雅的方式實驗按鍵按下功能-中斷。

CPU在正常處理指令的時候會遇到外設打斷當前執行邏輯,我們稱為異常中斷。一系列中斷處理集中在一起管理,我們稱為異常中斷向量表。

中斷向量表

Coretex-A系列的中斷向量表就是存放在程序起始位置(鏈接起始地址)的一組由4字節組成的一組數據,Coretex-A 32位處理器每一條指令長度就是4個字節,所以本質上這個中斷向量表是一組固定地址的指令。Coretext-A系統CPU總共支持8個中斷:

圖片圖片

這8個中斷里面需要特別注意也是需要開發的主要是復位中斷IRQ中斷復位中斷在上電或者按下Reset按鈕后硬件加載程序同時PC寄存器位置重置為0x0或者鏈接起始地址時觸發,IRQ中斷則是外設觸發。每一個中斷發生時PC寄存器會被設置成一個固定的地址,而這個地址則對應中斷向量表中一條指令。

中斷向量表添加到匯編最開始的位置:

/* 從鏈接起始地址開始,8條4字節的指令組成了ARM的中斷向量表 */
/* 中斷向量表放在最開始的位置,每一條指令對應了具體的中斷處理 */
/* 當發生對應中斷時,硬件會把對應的地址設置到pc寄存器,從而執行對應的中斷服務函數 */
ldr pc, =Reset_Handler                          /* 0x00: 復位中斷 */
ldr pc, =Undefine_Instruction_Handler           /* 0x04: 未定義中斷指令 */
ldr pc, =Software_Interrupt_Handler             /* 0x08: 軟中斷, SVC特權模式 */
ldr pc, =Prefetch_Abort_Handler                 /* 0x0c: 指令預取中止中斷 */
ldr pc, =Data_Abort_Handler                     /* 0x10: 數據訪問中止中斷 */
ldr pc, =Not_Used_Handler                       /* 0x14: 未使用的中斷 */
ldr pc, =IRQ_Handler                            /* 0x18: 外部設備中斷 */
ldr pc, =FIQ_Handler                            /* 0x1c: 快速中斷 */

復位中斷服務函數

上電后第一個要觸發的則是復位中斷,通過向量表中定義的指令可以將程序切換到Reset_Handler處開始執行

  • 關閉IRQ
  • 關閉I,D Cache,以及MMU
  • 設置中斷的起始地址,即設置成鏈接起始地址(因為程序是從鏈接起始地址開始運行的)
  • 設置IRQ,SVC以及SYS模式下C語言的運行環境(C語言的SP指針棧頂)
  • 打開IRQ
  • 調轉到C語言的main函數開始運行
cpsid i                             /* 關閉IRQ,  此時IRQ還沒有配置完成,所以關閉*/

/* 
    在設備上電啟動時,執行的代碼訪問的外設都是實際地址,
    mmu與cache此時的意義不大,
    這個時候為了防止cache與mmu可能導致的問題會先將mmu與cache關閉 
*/
/* CP15: SCTLR */
/* 關閉 I-Cache, D-Cache, MMU */
MRC p15, 0, r0, c1, c0, 0            /* 將SCTLR寄存器讀取到r0寄存器 */
bic r0, r0, #(1 << 0)                /* 關閉MMU */
bic r0, r0, #(1 << 1)                /* 關閉對齊 */
bic r0, r0, #(1 << 11)               /* 關閉分支預測 */
bic r0, r0, #(1 << 12)               /* 關閉i-cache */
bic r0, r0, #(1 << 2)                /* 關閉d-cache */
MCR p15, 0, r0, c1, c0, 0            /* 將r0寄存器數據寫入到SCTLR寄存器 */

/* 設置中斷向量偏移,在發生中斷之前設置即可,也可以在C語言中設置 */

ldr r0, =0x87800000                 /* 將0x87800000這個立即數寫入到 r0寄存器, 也就是鏈接起始地址*/
dsb                                 /* 這里涉及到了改變讀取內存的地址起始地址,需要使用內存屏障指令進隔斷,保證前后讀取指令都是正常的地址 */
isb                                  /* 這里涉及到了改變讀取內存的地址起始地址,需要使用內存屏障指令進隔斷,保證前后讀取指令都是正常的地址 */
MCR p15, 0, r0, c12, c0, 0          /* 將r0的數據寫入到VBAR寄存器中,表示向量偏移地址是0x87800000 */
dsb                                 /* 這里涉及到了改變讀取內存的地址起始地址,需要使用內存屏障指令進隔斷,保證前后讀取指令都是正常的地址 */
isb                                 /* 這里涉及到了改變讀取內存的地址起始地址,需要使用內存屏障指令進隔斷,保證前后讀取指令都是正常的地址 */

/* 設置不同模式下的sp指針,每一個模式的sp對應不同的物理地址,當進入不同工作模式時C語言會在不同的物理sp指針指向的棧內存上工作 */
/* 進入IRQ模式 */
mrs r0, cpsr
bic r0, r0, #0x1f                  /* 將r0寄存器中的低5位清零,也就是cpsr的M0~M4  */
orr r0, r0, #0x12                  /* r0或上0x12,表示使用IRQ模式     */
msr cpsr, r0                  /* 將r0 的數據寫入到cpsr_c中      */
ldr sp, =0x80600000                 /* 設置棧指針    */

/* 進入SYS模式 */
mrs r0, cpsr
bic r0, r0, #0x1f                  /* 將r0寄存器中的低5位清零,也就是cpsr的M0~M4  */
orr r0, r0, #0x1f                  /* r0或上0x1f,表示使用SYS模式     */
msr cpsr, r0                  /* 將r0 的數據寫入到cpsr_c中      */
ldr sp, =0x80400000                 /* 設置棧指針    */

/* 進入SVC模式 */
mrs r0, cpsr
bic r0, r0, #0x1f                  /* 將r0寄存器中的低5位清零,也就是cpsr的M0~M4  */
orr r0, r0, #0x13                  /* r0或上0x13,表示使用SVC模式     */
msr cpsr, r0                  /* 將r0 的數據寫入到cpsr_c中      */
ldr sp, =0x80200000                 /* 設置棧指針    */

cpsie i                             /* 打開IRQ */
b main                    /* 跳轉到C語言main函數    */

IRQ外設中斷服務函數

當一個外設觸發中斷(比如按鍵按下后)會執行IRQ_Handler函數。

  • 中斷發生是首先保護現場(lr, r0-r12寄存器, 保存spsr寄存器數據)
  • 讀取GIC寄存器組的起始地址
  • 通過對GIC寄存器組基地址偏移得到CPU Interface寄存器組
  • 通過對CPU Interface基地址進行偏移得到GICC_IAR寄存器,它保存了觸發中斷的CPU號與中斷號
  • 讀取中斷號(目前只有一個CPU內核,可以不管CPU號)放入r0寄存器,調用對應的C語言函數執行中斷
  • 在執行中斷前,首先需要將模式切換到SVC,這樣在執行中斷的時候可以允許新的IRQ中斷觸發
  • 執行C語言的中斷邏輯后切換到IRQ模式,繼續完成中斷收尾工作
  • 恢復spsr寄存器數據
  • 恢復中斷執行前的現場(lr, r0-r12)
  • 將lr地址減4字節再給到pc寄存器,恢復中斷前的執行指令
/* 
    中斷發生時, IRQ模式下的lr(LR_svc物理)寄存器保存中斷時刻的PC寄存器
    通過使用push命令將lr的值壓入棧,這樣的目的是為了在執行完當前中斷服務函數
    后可以順利的返回到中斷前的執行位置,因為在執行中斷服務函數的時候lr里面的值可能發生變化
    比如: 在內部使用了blx調用其它函數,新的IRQ中斷進入
*/
push {lr}    
/*
    保存中斷發生時的執行現場(r0-r12)
    從User/Sys模式切換到IRQ模式,r0-r12寄存器是通用的,所以需要將這些寄存器都壓入棧保存起來,
    由于在執行IRQ中斷函數時模式已經切換,此時的sp指針已經是IRQ模式下的棧地址了,所以r0-r12保存到了
    IRQ對應的棧空間中,恢復現場的時候只需要入棧即可
 */   
push {r0-r12}
// push {r0-r3, r12}
/* 
    將spsr(SPSR_irq)寄存器的值壓入棧,spsr保存了中斷發生時的cpsr寄存器的值,
    中斷執行完成之后需要恢復
*/
mrs r0, spsr        
push {r0}

/* GIC寄存器組的基地址(起始地址,通過起始地址可以訪問得所有的GIC寄存器) */
/* 將GIC基地址讀取到r1寄存器中 */
MRC p15, 4, r1, c15, c0, 0          // Read Configuration Base Address Register

/* 0x2000 - 0x3FFF 是GIC中CPU Interface的范圍 */
/* 將r1中保存的GIC基地址偏移0x2000再保存到r1中 */
/* 此時r1中保存的是CPU Interface的基地址 */
add r1, r1, #0x2000
/*
    r1(CPU Interface基地址)偏移0x0c得到GICC_IAR寄存器地址,
    將GICC_IAR寄存器的值讀取到r0中,
    GICC_IAR保存了IRQ中斷的中斷號與CPU號(多核時使用),
    通過中斷號即可明確具體的中斷來源并對中斷進行響應
 */
ldr r0, [r1, #0x0c]
/*
    由于要進入到SVC模式了,需要將r0, r1兩個通用寄存器的數據保存到棧里,
    防止在SVC模式下后r0,r1數據丟失
    此時r0, r1保存到的是IRQ模式下的棧空間,
 */
push {r0, r1}
/*
    將CPSR寄存器的M[4:0]值改成10011, 讓CPU進入到SVC模式,
    進行SVC模式之后,當我們處理當前中斷時,
    系統可以再次響應IRQ中斷
 */
cps #0x13                       // 進入到SVC
/*
    進入到svc模式后先將lr的數據壓入棧,執行完后再恢復
    因為接下來要使用blx調用C語言函數,會改變lr寄存器的數據
 */
push {lr} 
ldr r2, =system_irq_handler     // 將C語言寫的中斷服務函數的地址加載到r2寄存器
blx r2                          // 調用C語言的中斷處理函數, r0為函數參數
pop {lr}                        // 調用完具體中斷處理函數后,lr恢復
cps #0x12                       // 進入到IRQ,執行完中斷服務函數后進入IRQ不能再次響應IRQ中斷,直到當前的IRQ中斷完成
pop {r0, r1}                    // 恢復IRQ模式下r0,r1寄存器的數據
/*
    此時r0保存的是GICC_IAR寄存器的數據,
    將GICC_IAR的數據寫入到GICC_EOIR寄存器,表示當前IRQ中斷處理完成
 */
str r0, [r1, #0x10]

pop {r0}                        // 將棧頂的數據(此時棧頂保存的是spsr寄存器的值)出棧到r0寄存器
/// spsr_cxsf其中(cxsf表示4個不同的8bit位數據,后續表示此次命令影響的數據位), spsr_cxsf等于spsr
msr spsr_cxsf, r0               // 恢復spsr寄存器數據
pop {r0-r12}                    // 恢復r0-r12寄存器的數據
pop {lr}                        // 恢復lr寄存器的數據
subs pc, lr, #4                 // 將lr - 4字節賦值給lc, 恢復中斷前的執行命令繼續執行

IRQ中斷服務通用邏輯處理函數

我們需要編寫一個通用的中斷處理函數,從參數(r0寄存器中的GICC_IAR寄存器的數據)中提取中斷號,根據對應的中斷號再調用注冊進來的具體的中斷函數,比如: 按鍵中斷函數

void system_irq_handler(unsigned int gicciar)
{
    uint32_t irqNum = gicciar & 0x3FF;
    if (irqNum >= NUMBER_OF_INT_VECTORS)
        return;
    Interrupt_Irq_Count++;
    Interrupt_Irq_Data iid = _irqInterruptTables[irqNum];
    iid.handler(irqNum, iid.context);
    Interrupt_Irq_Count--;
}

外設中斷驅動

  • GPIO復用以及配置電氣屬性
  • 配置GPIO的輸入與輸出
  • 初始化GPIO中斷
void GPIO_Init_Interrupt(GPIO_Type *base, int pin, GPIO_INTERRUPT_MODE mode)
{
    /// 首先將GPIO的edge_sel寄存器對應pin位清0,如果為1則會使ICR寄存器的配置無效
    base->EDGE_SEL &= ~(1 << pin);
    /// 對應ICR的索引(按2位為一個單元)
    int icrOffset = pin;
    /// 具體的icr寄存器地址
    __IO uint32_t *p_icr = NULL;
    if (pin < 16)
    {
        p_icr = &(base->ICR1);
    }
    else
    {
        p_icr = &(base->ICR2);
        icrOffset -= 16;
    }

    switch (mode)
    {
    case GPIO_INTERRUPT_MODE_NO_INTERRUPT:
        break;
    case GPIO_INTERRUPT_MODE_LOW:
        *p_icr &= ~(3 << (2 * icrOffset));
        break;
    case GPIO_INTERRUPT_MODE_HIGH:
        *p_icr &= ~(3 << (2 * icrOffset));
        *p_icr |= 1 << (2 * icrOffset);
        break;
    case GPIO_INTERRUPT_MODE_RISING_EDGE:
        *p_icr &= ~(3 << (2 * icrOffset));
        *p_icr |= 2 << (2 * icrOffset);
        break;
    case GPIO_INTERRUPT_MODE_FALLING_EDGE:
        *p_icr &= ~(3 << (2 * icrOffset));
        *p_icr |= 3 << (2 * icrOffset);
        break;
    case GPIO_INTERRUPT_MODE_RISING_AND_RALLING_EDGE:
        *p_icr &= ~(3 << (2 * icrOffset));
        base->EDGE_SEL |= (1 << pin);
        break;
    }
}
  • I.MX6ULL的GIC使能對應中斷ID的中斷
/// 使用GPIO1的IO18對應的IRQ中斷ID(GPIO1_Combined_16_31_IRQn)
GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn);
  • 注冊對應中斷ID的中斷服務處理函數
/// 注冊對應IRQ中斷號的中斷服務函數
Interrupt_Irq_Handler_Register(GPIO1_Combined_16_31_IRQn, (Interrupt_Irq_Handler)Key0_Interrupt_Irq_Handler, NULL);
/// 使用GPIO01_IO18中斷
  • GPIO使能中斷
/// 使用GPIO01_IO18中斷
GPIO_Enable_Interrupt(GPIO1, 18);
  • 在中斷服務處理函數中處理中斷
void Key0_Interrupt_Irq_Handler(unsigned int gicciar, void *context)
{
    /// 中斷服務函數要求快進快出,這里沒有定時器
    /// 為了處理抖動暫時使用Delay來解決
    /// 以后使用定時器來處理
    Delay(10);
    if (GPIO_ReadValue(GPIO1, 18) == 0)
    {
        Beep_On();
        Led_On();
        Delay(350);
        Beep_Off();
        Led_Off();
    }
    /// 中斷處理完成后,清楚中斷標志位
    GPIO_Clean_Interrupt_Flag(GPIO1, 18);
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
收藏 人收藏

    評論

    相關推薦

    基于RoboMasterC板的RT-Thread使用分享—按鍵中斷實驗

    說起中斷,我們常常就會提到一個經典的例子,就是我們在家里處理手頭上事情的時候,熱水煮開了,這時候我們就需要放下手頭的事情,去關掉煤氣爐。這個就是中斷
    的頭像 發表于 10-16 15:31 ?1734次閱讀
    基于RoboMasterC板的RT-Thread使用分享—<b class='flag-5'>按鍵</b><b class='flag-5'>中斷</b><b class='flag-5'>實驗</b>

    《DNK210使用指南 -CanMV版 V1.0》第十五章 按鍵中斷實驗

    第十五章 按鍵中斷實驗 本章實驗將介紹如何使用CanMV讓Kendryte K210通過中斷的方式獲取板載
    發表于 10-12 09:20

    #硬聲創作季 #Linux 學Linux-4.13.4 按鍵中斷實驗驅動編寫1-1

    Linux
    水管工
    發布于 :2022年11月10日 20:52:33

    #硬聲創作季 #Linux 學Linux-4.13.4 按鍵中斷實驗驅動編寫1-2

    Linux
    水管工
    發布于 :2022年11月10日 20:52:54

    #硬聲創作季 #Linux 學Linux-4.13.5 按鍵中斷實驗驅動編寫2-1

    Linux
    水管工
    發布于 :2022年11月10日 20:53:22

    #硬聲創作季 #Linux 學Linux-4.13.5 按鍵中斷實驗驅動編寫2-2

    Linux
    水管工
    發布于 :2022年11月10日 20:53:57

    第13.4講 Linux中斷實驗 按鍵中斷實驗驅動編寫上 - 第1節 #硬聲創作季

    電路電容LINUX內核
    充八萬
    發布于 :2023年08月14日 19:52:14

    【正點原子FPGA連載】第四章GPIO之MIO按鍵中斷實驗-領航者 ZYNQ 之嵌入式開發指南

    原子公眾號,獲取最新資料第四章GPIO之MIO按鍵中斷實驗中斷是一種當滿足要求的突發事件發生時通知處理器進行處理的信號。中斷可以由硬件處理單
    發表于 08-29 16:21

    【正點原子FPGA連載】第四章按鍵中斷實驗--摘自【正點原子】達芬奇之Microblaze 開發指南

    官方B站:https://space.bilibili.com/3946208905)對正點原子FPGA感興趣的同學可以加群討論:9056247396)關注正點原子公眾號,獲取最新資料第四章按鍵中斷實驗
    發表于 10-17 18:24

    STM32按鍵中斷實驗

    按鍵中斷實驗實驗2是按鍵查詢一、實驗原理1、按鍵使
    發表于 08-13 06:05

    按鍵中斷實驗概述

    按鍵中斷實驗概述1.1 資源概述開發板:正點原子STM32F103zet6精英開發板控芯片型號:STM32F103ZET6開發板資料1.2實現功能key1:紅燈亮,再按一下紅燈滅key2:綠燈亮
    發表于 01-11 08:08

    鍵盤與按鍵中斷實驗相關資料推薦

    這里寫自定義目錄標題鍵盤與按鍵中斷實驗代碼圖像使用控件鍵盤與按鍵中斷實驗4X4鍵盤(
    發表于 01-13 06:18

    INT0中斷實驗

    INT0中斷實驗。 1、按鍵中斷實驗。低電平中斷,在
    發表于 06-30 11:22 ?3117次閱讀

    STM32——中斷、EXTI、按鍵中斷實驗

    STM32中斷——總結及實操一、中斷是什么?1.1 中斷的含義1.2 中斷的作用(了解即可)1.3 中斷的流程二、
    發表于 01-14 15:48 ?4次下載
    STM32——<b class='flag-5'>中斷</b>、EXTI、<b class='flag-5'>按鍵</b><b class='flag-5'>中斷</b><b class='flag-5'>實驗</b>

    Vision Board系列教程 | 按鍵中斷實驗

    準備工作win10/11系統的電腦建議自備1根Type-C數據線在正式進行開發前,需要安裝紅色框中的三個軟件!!!安裝RT-ThreadStudioIDE1.進入下面網站,
    的頭像 發表于 10-11 08:06 ?271次閱讀
    Vision Board系列教程 | <b class='flag-5'>按鍵</b><b class='flag-5'>中斷</b><b class='flag-5'>實驗</b>
    主站蜘蛛池模板: 伊人久久大香线蕉综合网站| 青青操久久| 狠狠插影院| 国产午夜亚洲精品一区| 国产精品成人不卡在线观看 | 老熟女重囗味HDXX| 九九电影伦理片| 精品国产成人系列| 黄色大片久久| 久久艹综合| 久久综合久久鬼色| 美女gif趴跪式动态图| 免费被靠视频动漫| 免费看黄色小说| 免费毛片a在线观看67194| 男同志在线观看| 欧美最猛12teevideos欧美| 欧美一区二区三区久久综| 人人听力网mp3下载| 日本孕妇大胆孕交| 偷偷鲁手机在线播放AV| 午夜一级毛片看看| 亚洲国产综合久久久无码色伦| 亚洲精品AV一二三区无码| 亚洲va在线va天堂XX xX| 亚洲美女视频高清在线看| 在线观看国产精美视频| 97在线视频免费人妻| 补课H湿 1V1 PLAY| 国产精选视频在线观看| 精品AV亚洲乱码一区二区| 麻豆精选2021| 热中文热国产热综合| 无人区乱码1区2区3区网站| 亚洲欧美成人在线| 影音先锋av电影| 99热国产这里只有精品免费| 动漫美女被h动态图| 国产午夜人做人免费视频中文| 精品久久中文字幕有码| 免费看男人J放进女人J无遮掩|