栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

stm32 按键外部中断开发代码 可对照database理解,汇编代码看中文注释即可

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

stm32 按键外部中断开发代码 可对照database理解,汇编代码看中文注释即可

#include 

#include 

#include 

#include 

void hal_gpio_init(void);

void hal_exti_init(void);

void hal_gicd_init(void);

void hal_gicc_init(void);

extern void printf(const char *fmt, ...);



 

void mydelay_ms(int ms)

{

    int i, j;

    while(ms--)

    {

        for (i = 0; i < 10000; i++)

            for (j = 0; j < 10000; j++);

    }

}


 

void do_irq(void)

{

    unsigned int irq_num;

    irq_num = GICC.IAR & (0x3FF);

    switch(irq_num)

    {

        case 38:

            // 中断处理程序,此处只打印一条语句

            printf("put on n");

            EXTI.FPR1 |= (0x1 << 0);          //下降边沿挂起寄存器  写0防止一直进入

            GICD.ICPENDR[1] |= (0x1 << 6);      // 清除GICD层中断 挂起清除

            break;

        case 39:

            break;

    }

    // 清除GICC层中断 将38号写进去结束

    GICC.EOIR = (GICC.EOIR & (~0x3FF)) | irq_num;

}



 

void hal_gpio_init(void)

{

    // 使能GPIOA组的时钟使能, 在  RCC_MP_AHB4ENSETR

    RCC.MP_AHB4ENSETR |= (0x1 << 0);

    GPIOA->MODER &= (~0x3 << 0);                   //按键配置      输入功能

    GPIOA->PUPDR &= ~(0x3 << 0);                   //无上、下拉

}

void hal_exti_init(void)

{

    // 设置为下降沿触发选择寄存器

    EXTI.FTSR1 |= (0x1 << 0);

    // 设置外部中断选择寄存器 连接到PA0上

    EXTI.EXTICR1 &= (~(0xff << 0));

    // 设置EXTI CPU1唤醒中断屏蔽寄存器

    EXTI.C1IMR1 |= (0x1 << 0);

    // 设置EXTI CPU1唤醒事件屏蔽寄存器

//  EXTI.C1EMR1 |= (0x1 << 0);

}

void hal_gicd_init(void)

{

    GICD.ISENABLER[1] |= (0x1 << 6);                                                //中断号为38  GICD中断使能

    GICD.IPRIORITYR[9] &= ~(0x1f << 19);

    GICD.IPRIORITYR[9] |=  (0x10 << 19);                                            //中断优先级,设置为16

    GICD.ITARGETSR[9] |= (0x3 << 16);     //选择处理器处理控制器转发的中断  但是为啥写0x3                                          //中断处理器目标寄存器

    GICD.CTLR |= (0x1 << 0);                                                        //全局使能

    //由于默认38号外部中断用group 0 处理所以这里不用设置组别

}

void hal_gicc_init(void)

{

    GICC.CTLR |= (0x1 << 0);        // 设置GICC层 中断全局使能寄存器  enable group 0 interrupts

    GICC.PMR |= (0x1f << 3);        // 设置GICC层 中断屏蔽寄存器 

}




 

int main()

{

    hal_gpio_init();

    hal_gicc_init();

    hal_gicd_init();

    hal_exti_init();


 

    while(1)

    {

    }

    return 0;

}

汇编代码:

.text

.global _start

_start:

        b       reset

        ldr     pc,_undefined_instruction

        ldr     pc,_software_interrupt

        ldr     pc,_prefetch_abort

        ldr     pc,_data_abort

        ldr     pc,_not_used

        ldr     pc,_irq //跳转到_irq标志处

        ldr     pc,_fiq

_undefined_instruction: .word  _undefined_instruction

_software_interrupt:    .word  _software_interrupt

_prefetch_abort:        .word  _prefetch_abort

_data_abort:            .word  _data_abort

_not_used:              .word  _not_used

_irq:                   .word  irq_handler  //跳转到irq_handler标志处

_fiq:                   .word  _fiq

//    mrc p15,0,r0,c1,c1,2

//  movw      r1, #0x3fff

//  movt      r1, #0x0004

//  orr  r0,r0,r1

//    mcr  p15,0,r0,c1,c1,2

reset:

    ldr r0,= _start

    mcr p15,0,r0,c12,c0,0       // 通过协处理器将中断向量表地址定向到最前面的_start,如果一有IRQ发生,就跳到_start寻找irq异常

        mrs     r0,cpsr

        bic     r0,r0,#0x1f

        orr     r0,r0,#0xd3

        msr     cpsr,r0        //  Enable svc mode of cpu


 

init_stack:

        ldr     r0,stacktop         

    

        mov     sp,r0

        sub     r0,#128*4          

    

        msr     cpsr,#0xd2

        mov     sp,r0

        sub     r0,#128*4          

    

        msr     cpsr,#0xd1

        mov     sp,r0

        sub     r0,#0

    

        msr     cpsr,#0xd7

        mov     sp,r0

        sub     r0,#0

    

        msr     cpsr,#0xdb

        mov     sp,r0

        sub     r0,#0

   

        msr     cpsr,#0x10

        mov     sp,r0             


 

    bl main

    .align  4

    


 

    

irq_handler:

    sub  lr,lr,#4   //因为三级流水线的原因,中断模式lr保存的地址的下下条指令的地址,如果我们从中断回来后想跳到下一条指令,那么这里需要人为的

    //对lr进行-4操作

    stmfd sp!,{r0-r12,lr}//对r0-r12寄存器为IRQ和user模式的共有寄存器,转到IRQ模式之后需要将她们压栈保护现场,对lr进行压栈防止在下面指令中lr被修改就回不去中断之前的地方了

    .weak do_irq

    bl  do_irq  //跳到中断处理函数中  这个处理函数是用c语言写的

    ldmfd sp!,{r0-r12,pc}^ //1.将r0-r12出栈 2.将lr直接压到PC返回中断前的位置 3.^符号是将spsr寄存器中存好的中断之前的cpsr状态

    //给到user模式中的cpsr寄存器

stacktop:    .word      stack+4*512

.data

stack:   .space  4*512

loop:

    b loop

    .end





 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/892908.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号