当前位置: 首页 > news >正文

泰安高品质网站建设dw代码大全基础

泰安高品质网站建设,dw代码大全基础,住建局领导班子成员分工,巩义网站建设费用目录 前言整体文件结构源码分析#xff08;保姆级讲解#xff09;中断初始化部分初始化GIC控制器初始化中断向量表设置中断向量表偏移 系统时钟初始化部分使能所有的时钟部分led初始化部分beep初始化部分key初始化部分按键中断初始化部分按键中断服务函数部分 while循环部分 … 目录 前言整体文件结构源码分析保姆级讲解中断初始化部分初始化GIC控制器初始化中断向量表设置中断向量表偏移 系统时钟初始化部分使能所有的时钟部分led初始化部分beep初始化部分key初始化部分按键中断初始化部分按键中断服务函数部分 while循环部分 最终编译验证结束语 前言 首先我们在使用开发板开发的过程中难免会碰到使用中断的场景即判断是哪种中断并且进入对应的中断服务函数所以我们接下来开始学习这种机制。 整体文件结构 源码分析保姆级讲解 中断初始化部分 初始化GIC控制器 首先我们使用中断需要先对中断进行初始化。 GIC_Init(); 该函数讲解开始 //这个函数主要对GIC进行初始化那什么是GIC呢我们在stm32的开发过程中配置中断会使用到NVIC这个中断管理机构全称叫做 Nested Vectored Interrupt Controller那么对应的在I.MX6U中的中断管理机构叫做GIC全称是 general interrupt controller。当 GIC 接收到外部中断信号以后就会报给 ARM 内核但是ARM 内核只提供了四个信号给 GIC 来汇报中断情况VFIQ、VIRQ、FIQ 和 IRQ如下图所示 在这四个中断中我们只会使用到一个中断即上图中的IRQ中断外部中断。 接下来我们就看看是如何对GIC这个中断管理机构进行配置的 好按照老样子接下来开始详细讲解每行代码的用处以及为什么这样写 GIC_Type *gic (GIC_Type *)(__get_CBAR() 0xFFFF0000UL);//结构体 GIC_Type 就是 GIC 控制器列举出了 GIC 控制器的所有寄存器可以通过结构体 GIC_Type 来访问 GIC 的所有寄存器。 其中GIC_Type结构体如下所示 typedef struct {uint32_t RESERVED0[1024];__IOM uint32_t D_CTLR; /*! Offset: 0x1000 (R/W) Distributor Control Register */__IM uint32_t D_TYPER; /*! Offset: 0x1004 (R/ ) Interrupt Controller Type Register */__IM uint32_t D_IIDR; /*! Offset: 0x1008 (R/ ) Distributor Implementer Identification Register */uint32_t RESERVED1[29];__IOM uint32_t D_IGROUPR[16]; /*! Offset: 0x1080 - 0x0BC (R/W) Interrupt Group Registers */uint32_t RESERVED2[16];__IOM uint32_t D_ISENABLER[16]; /*! Offset: 0x1100 - 0x13C (R/W) Interrupt Set-Enable Registers */uint32_t RESERVED3[16];__IOM uint32_t D_ICENABLER[16]; /*! Offset: 0x1180 - 0x1BC (R/W) Interrupt Clear-Enable Registers */uint32_t RESERVED4[16];__IOM uint32_t D_ISPENDR[16]; /*! Offset: 0x1200 - 0x23C (R/W) Interrupt Set-Pending Registers */uint32_t RESERVED5[16];__IOM uint32_t D_ICPENDR[16]; /*! Offset: 0x1280 - 0x2BC (R/W) Interrupt Clear-Pending Registers */uint32_t RESERVED6[16];__IOM uint32_t D_ISACTIVER[16]; /*! Offset: 0x1300 - 0x33C (R/W) Interrupt Set-Active Registers */uint32_t RESERVED7[16];__IOM uint32_t D_ICACTIVER[16]; /*! Offset: 0x1380 - 0x3BC (R/W) Interrupt Clear-Active Registers */uint32_t RESERVED8[16];__IOM uint8_t D_IPRIORITYR[512]; /*! Offset: 0x1400 - 0x5FC (R/W) Interrupt Priority Registers */uint32_t RESERVED9[128];__IOM uint8_t D_ITARGETSR[512]; /*! Offset: 0x1800 - 0x9FC (R/W) Interrupt Targets Registers */uint32_t RESERVED10[128];__IOM uint32_t D_ICFGR[32]; /*! Offset: 0x1C00 - 0xC7C (R/W) Interrupt configuration registers */uint32_t RESERVED11[32];__IM uint32_t D_PPISR; /*! Offset: 0x1D00 (R/ ) Private Peripheral Interrupt Status Register */__IM uint32_t D_SPISR[15]; /*! Offset: 0x1D04 - 0xD3C (R/ ) Shared Peripheral Interrupt Status Registers */uint32_t RESERVED12[112];__OM uint32_t D_SGIR; /*! Offset: 0x1F00 ( /W) Software Generated Interrupt Register */uint32_t RESERVED13[3];__IOM uint8_t D_CPENDSGIR[16]; /*! Offset: 0x1F10 - 0xF1C (R/W) SGI Clear-Pending Registers */__IOM uint8_t D_SPENDSGIR[16]; /*! Offset: 0x1F20 - 0xF2C (R/W) SGI Set-Pending Registers */uint32_t RESERVED14[40];__IM uint32_t D_PIDR4; /*! Offset: 0x1FD0 (R/ ) Peripheral ID4 Register */__IM uint32_t D_PIDR5; /*! Offset: 0x1FD4 (R/ ) Peripheral ID5 Register */__IM uint32_t D_PIDR6; /*! Offset: 0x1FD8 (R/ ) Peripheral ID6 Register */__IM uint32_t D_PIDR7; /*! Offset: 0x1FDC (R/ ) Peripheral ID7 Register */__IM uint32_t D_PIDR0; /*! Offset: 0x1FE0 (R/ ) Peripheral ID0 Register */__IM uint32_t D_PIDR1; /*! Offset: 0x1FE4 (R/ ) Peripheral ID1 Register */__IM uint32_t D_PIDR2; /*! Offset: 0x1FE8 (R/ ) Peripheral ID2 Register */__IM uint32_t D_PIDR3; /*! Offset: 0x1FEC (R/ ) Peripheral ID3 Register */__IM uint32_t D_CIDR0; /*! Offset: 0x1FF0 (R/ ) Component ID0 Register */__IM uint32_t D_CIDR1; /*! Offset: 0x1FF4 (R/ ) Component ID1 Register */__IM uint32_t D_CIDR2; /*! Offset: 0x1FF8 (R/ ) Component ID2 Register */__IM uint32_t D_CIDR3; /*! Offset: 0x1FFC (R/ ) Component ID3 Register */__IOM uint32_t C_CTLR; /*! Offset: 0x2000 (R/W) CPU Interface Control Register */__IOM uint32_t C_PMR; /*! Offset: 0x2004 (R/W) Interrupt Priority Mask Register */__IOM uint32_t C_BPR; /*! Offset: 0x2008 (R/W) Binary Point Register */__IM uint32_t C_IAR; /*! Offset: 0x200C (R/ ) Interrupt Acknowledge Register */__OM uint32_t C_EOIR; /*! Offset: 0x2010 ( /W) End Of Interrupt Register */__IM uint32_t C_RPR; /*! Offset: 0x2014 (R/ ) Running Priority Register */__IM uint32_t C_HPPIR; /*! Offset: 0x2018 (R/ ) Highest Priority Pending Interrupt Register */__IOM uint32_t C_ABPR; /*! Offset: 0x201C (R/W) Aliased Binary Point Register */__IM uint32_t C_AIAR; /*! Offset: 0x2020 (R/ ) Aliased Interrupt Acknowledge Register */__OM uint32_t C_AEOIR; /*! Offset: 0x2024 ( /W) Aliased End Of Interrupt Register */__IM uint32_t C_AHPPIR; /*! Offset: 0x2028 (R/ ) Aliased Highest Priority Pending Interrupt Register */uint32_t RESERVED15[41];__IOM uint32_t C_APR0; /*! Offset: 0x20D0 (R/W) Active Priority Register */uint32_t RESERVED16[3];__IOM uint32_t C_NSAPR0; /*! Offset: 0x20E0 (R/W) Non-secure Active Priority Register */uint32_t RESERVED17[6];__IM uint32_t C_IIDR; /*! Offset: 0x20FC (R/ ) CPU Interface Identification Register */uint32_t RESERVED18[960];__OM uint32_t C_DIR; /*! Offset: 0x3000 ( /W) Deactivate Interrupt Register */ } GIC_Type;从上述代码中可知该GIC寄存器中分为两部分分别是分发器端和CPU接口端。比如我们想要访问C_CTLR该寄存器相对于GIC基地址的偏移为0x2000同样的获取到GIC基地址之后只需要加上0x2000即可访问GIC的CPU接口段寄存器。那么问题来了GIC控制器的寄存器基地址在哪里这里我们就需要用到 Cortex-A 的 CP15 协处理器了。那什么是CP15协处理器 CP15 协处理器一般用于存储系统管理但是在中断中也会使用到CP15 协处理器一共有16 个 32 位寄存器。CP15 协处理器的访问通过如下另个指令完成 CP15协处理器有16个32位寄存器c0~c15由于我们在本例中使用到GPIO中断所以我们暂时先看c0、c1、c12 和 c15 这四个寄 存器。具体怎么使用会结合着代码进行讲解。 进入__get_CBAR()这个函数中 这个函数的作用为获取GIC的基地址我们使用到c15这个寄存器具体含义如下 由上图可知当op1 4 crm c0op2 0时代表此c15寄存器为CBAR寄存器。 /* C语言实现MRC指令 */ #define __MRC(coproc, opcode_1, CRn, CRm, opcode_2) \({ \uint32_t __dst; \__ASM volatile (MRC __STRINGIFY(p##coproc) , __STRINGIFY(opcode_1) , \%0, __STRINGIFY(c##CRn) , __STRINGIFY(c##CRm) , \__STRINGIFY(opcode_2) \: r (__dst) ); \__dst; \})CBAR寄存器如下图所示 从上图可知通过MRC设置c15为CBAR寄存器后需要获取该寄存器的高16位所以在代码中需要和0xFFFF0000UL进行“与”操作。 获取到GIC基地址后使用gic指针指向该基地址。并且该指针的类型为GIC_Type。 irqRegs (gic-D_TYPER 0x1FUL) 1;其中(gic-D_TYPER 0x1FUL) 用来获取其中断数量即获取该寄存器的低5位。具体寄存器如下 加1是因为比如我们实际获取的中断数是128个但是由于是从0开始计数所以实际输出值为127所以我们需要加1。 for (i 0; i irqRegs; i)gic-D_ICENABLER[i] 0xFFFFFFFFUL;//我们家来需要看看实际情况的内部GIC控制器是什么样子的 上图中的左侧部分是中断源中间部分是GIC控制器最右侧就是中断控制器向处理器内核发送中断信息。其中GIC将众多的中断源分为三类并且已经在上图中用红框标出。 所以上述代码就是在对所有的PPISGI和SPI这三种中断源进行不使能操作。并且该寄存器如下图所示 gic-C_PMR (0xFFUL (8 - __GIC_PRIO_BITS)) 0xFFUL;//其中 所以上述代码相当于 gic-C_PMR (0xFFUL 3) 0xFFUL;相当于 gic-C_PMR 0xF8;其中C_PWR寄存器具体配置如下图所示 所以由上图可知将优先级等级设置为32。 gic-C_BPR 7 - __GIC_PRIO_BITS;上述代码相当于 gic-C_BPR 2;并且该寄存器如下图所示 即设置没有子优先级所有优先级级别都允许抢占。 gic-D_CTLR 1UL;其中该寄存器具体配置如下所示 启用group0分发器。 gic-C_CTLR 1UL;其中该寄存器具体配置如下所示 启用group0接口端。 至此GIC_Init函数讲解完毕 初始化中断向量表 system_irqtable_init(); 该函数讲解开始 void system_irqtable_init(void) {unsigned int i 0;irqNesting 0;/* 先将所有的中断服务函数设置为默认值 */for(i 0; i NUMBER_OF_INT_VECTORS; i){system_register_irqhandler((IRQn_Type)i,default_irqhandler, NULL);} }好按照老样子接下来开始详细讲解每行代码的用处以及为什么这样写 #define NUMBER_OF_INT_VECTORS 160 /** Number of interrupts in the Vector table *///这里为什么是160呢 由上图GIC控制器可知需要去处理很多中断源为了区分这些不同的中断源肯定要给他们分配一个唯一 ID这些 ID 就是中断 ID。每一个cpu最多支持1020个中断ID。中断 ID 号为 ID0~ID1019。这 1020 个 ID 包含了 PPI、SPI 和 SGI那么这三类中断是如何分配这 1020 个中断 ID 的呢这 1020 个 ID 分配如下 ID0~ID15这 16 个 ID 分配给 SGI。 ID16~ID31这 16 个 ID 分配给 PPI。 ID32~ID1019这 988 个 ID 分配给 SPI像 GPIO 中断、串口中断等这些外部中断。 至于具体到某个 ID 对应哪个中断那就由半导体厂商根据实际情况去定义了。比如 I.MX6U 的总共使用了 128 个中断 ID加上前面属于 PPI 和 SGI 的 32 个 IDI.MX6U 的中断源共有 12832160个所以设置为160个。 system_register_irqhandler((IRQn_Type)i,default_irqhandler, NULL);void system_register_irqhandler(IRQn_Type irq, system_irq_handler_t handler, void *userParam) {irqTable[irq].irqHandler handler;irqTable[irq].userParam userParam; }所以就需要针对每一个中断源进行配置。 该函数的参数主要有三个分别是IRQn_Type irqsystem_irq_handler_t handler和void *userParam。 IRQn_Type irq其中IRQn_Type是关于160个中断源的结构体。irq是要注册的中断号。 system_irq_handler_t handler其中system_irq_handler_t是一个中断服务函数形式。 void *userParam中断服务处理函数参数 irqTable[irq].irqHandler handler;传入该函数的hander等于default_irqhandler void default_irqhandler(unsigned int giccIar, void *userParam) {while(1) {} }由于只是初始化部分所以该中断服务函数里面什么也不做。 irqTable[irq].userParam userParam;传入该函数的参数userParam等于NULL。 至此system_irqtable_init();函数讲解完毕 设置中断向量表偏移 __set_VBAR((uint32_t)0x87800000); 该函数讲解开始 设置中断向量表的偏移时期偏移到起始地址即0x87800000即程序起始运行地址。 系统时钟初始化部分 void imx6u_clkinit(void) {unsigned int reg 0;/* 1、设置ARM内核时钟为792MHz *//* 1.1、判断当前ARM内核是使用的那个时钟源启动的正常情况下ARM内核是由pll1_sw_clk驱动的而* pll1_sw_clk有两个来源pll1_main_clk和tep_clk。* 如果我们要让ARM内核跑到792M的话那必须选择pll1_main_clk作为pll1的时钟源。* 如果我们要修改pll1_main_clk时钟的话就必须先将pll1_sw_clk从pll1_main_clk切换到step_clk,* 当修改完pll1_main_clk以后在将pll1_sw_clk切换回pll1_main_clk。而step_clk的时钟源可以选择* 板子上的24MHz晶振。*/if((((CCM-CCSR) 2) 0x1 ) 0) /* 当前pll1_sw_clk使用的pll1_main_clk*/{ CCM-CCSR ~(1 8); /* 配置step_clk时钟源为24MH OSC */ CCM-CCSR | (1 2); /* 配置pll1_sw_clk时钟源为step_clk */}/* 1.2、设置pll1_main_clk为792MHz* 因为pll1_sw_clk进ARM内核的时候会被二分频* 配置CCM_ANLOG-PLL_ARM寄存器* bit13: 1 使能时钟输出* bit[6:0]: 66, 由公式Fout Fin * div_select / 2.079224*div_select/2.0,* 得出div_select 66 */CCM_ANALOG-PLL_ARM (1 13) | ((66 0) 0X7F); /* 配置pll1_main_clk792MHz */CCM-CCSR ~(1 2); /* 将pll_sw_clk时钟重新切换回pll1_main_clk */CCM-CACRR 0; /* ARM内核时钟为pll1_sw_clk/1792/1792Mhz *//* 2、设置PLL2(SYS PLL)各个PFD */reg CCM_ANALOG-PFD_528;reg ~(0X3F3F3F3F); /* 清除原来的设置 */reg | 3224; /* PLL2_PFD3528*18/32297Mhz */reg | 2416; /* PLL2_PFD2528*18/24396Mhz(DDR使用的时钟最大400Mhz) */reg | 168; /* PLL2_PFD1528*18/16594Mhz */reg | 270; /* PLL2_PFD0528*18/27352Mhz */CCM_ANALOG-PFD_528reg; /* 设置PLL2_PFD0~3 *//* 3、设置PLL3(USB1)各个PFD */reg 0; /* 清零 */reg CCM_ANALOG-PFD_480;reg ~(0X3F3F3F3F); /* 清除原来的设置 */reg | 1924; /* PLL3_PFD3480*18/19454.74Mhz */reg | 1716; /* PLL3_PFD2480*18/17508.24Mhz */reg | 168; /* PLL3_PFD1480*18/16540Mhz */reg | 120; /* PLL3_PFD0480*18/12720Mhz */CCM_ANALOG-PFD_480reg; /* 设置PLL3_PFD0~3 */ /* 4、设置AHB时钟 最小6Mhz 最大132Mhz (boot rom自动设置好了可以不用设置)*/CCM-CBCMR ~(3 18); /* 清除设置*/ CCM-CBCMR | (1 18); /* pre_periph_clkPLL2_PFD2396MHz */CCM-CBCDR ~(1 25); /* periph_clkpre_periph_clk396MHz */while(CCM-CDHIPR (1 5));/* 等待握手完成 *//* 修改AHB_PODF位的时候需要先禁止AHB_CLK_ROOT的输出但是* 我没有找到关闭AHB_CLK_ROOT输出的的寄存器所以就没法设置。* 下面设置AHB_PODF的代码仅供学习参考不能直接拿来使用* 内部boot rom将AHB_PODF设置为了3分频即使我们不设置AHB_PODF* AHB_ROOT_CLK也依旧等于396/3132Mhz。*/ #if 0/* 要先关闭AHB_ROOT_CLK输出否则时钟设置会出错 */CCM-CBCDR ~(7 10); /* CBCDR的AHB_PODF清零 */CCM-CBCDR | 2 10; /* AHB_PODF 3分频AHB_CLK_ROOT132MHz */while(CCM-CDHIPR (1 1));/ * 等待握手完成 */ #endif/* 5、设置IPG_CLK_ROOT最小3Mhz最大66Mhz (boot rom自动设置好了可以不用设置)*/CCM-CBCDR ~(3 8); /* CBCDR的IPG_PODF清零 */CCM-CBCDR | 1 8; /* IPG_PODF 2分频IPG_CLK_ROOT66MHz *//* 6、设置PERCLK_CLK_ROOT时钟 */CCM-CSCMR1 ~(1 6); /* PERCLK_CLK_ROOT时钟源为IPG */CCM-CSCMR1 ~(7 0); /* PERCLK_PODF位清零即1分频 */ }好按照老样子接下来开始详细讲解每行代码的用处以及为什么这样写 unsigned int reg 0;//声明一个无整型变量reg并且赋值为0。 if((((CCM-CCSR) 2) 0x1 ) 0) /* 当前pll1_sw_clk使用的pll1_main_clk*/{ CCM-CCSR ~(1 8); /* 配置step_clk时钟源为24MH OSC */ CCM-CCSR | (1 2); /* 配置pll1_sw_clk时钟源为step_clk */}CCM_ANALOG-PLL_ARM (1 13) | ((66 0) 0X7F); /* 配置pll1_main_clk792MHz */ CCM-CCSR ~(1 2); /* 将pll_sw_clk时钟重新切换回pll1_main_clk */ CCM-CACRR 0; /* ARM内核时钟为pll1_sw_clk/1792/1792Mhz *///这一部分主要是设置ARM内核时钟的那么ARM内核时钟是由什么来决定的呢 由上图可知其内核时钟源来自于PLL1此时PLL1为996MHz然后经过分频操作后最终就会配置到ARM上。 在本例中设置ARM内核时钟为792MHz所以我们肯定要更改PLL1时钟频率那么在修改之前我们需要先将内核时钟源改为其他的时钟源那么我们看一下可修改的时钟源有哪些 ①、pll1_sw_clk 也就是 PLL1 的最终输出频率。 ②、此处是一个选择器选择 pll1_sw_clk 的时钟源由寄存器 CCM_CCSR 的PLL1_SW_CLK_SEL 位决定 pll1_sw_clk 是选择 pll1_main_clk 还是 step_clk。正常情况下应该选择 pll1_main_clk但是如果要对 pll1_main_clk(PLL1)的频率进行调整的话比如我们要设置 PLL11056MHz此时就要先将 pll1_sw_clk 切换到 step_clk 上。等 pll1_main_clk 调整完成以后再切换回来。 ③、此处也是一个选择器选择 step_clk 的时钟源由寄存器 CCM_CCSR 的 STEP_SEL 位来决定 step_clk 是选择 osc_clk 还是 secondary_clk。一般选择 osc_clk也就是 24MHz 的晶振。 if((((CCM-CCSR) 2) 0x1 ) 0) /* 当前pll1_sw_clk使用的pll1_main_clk*/{ CCM-CCSR ~(1 8); /* 配置step_clk时钟源为24MH OSC */ CCM-CCSR | (1 2); /* 配置pll1_sw_clk时钟源为step_clk */}寄存器CCM_CCSR的配置如下所示 由上图可知PLL1_SW_CLK_SEL是第2位。所以要进行右移2位然后变成最低位如果是0则代表是pll1_main_clk如果是1则代表是step_clk。所以如果判断是pll1_main_clk我们则需要更改成step_clk。将step_clk的时钟源为24M的晶振。 CCM_ANALOG-PLL_ARM (1 13) | ((66 0) 0X7F); /* 配置pll1_main_clk792MHz */该寄存器的配置如下 将第13位设置成1代表使能PLL1输出。 并且本例中设置ARM内核时钟为792MHz即PLL1设置为792MHzPLL1 CLK Fin *div_seclec/2.0Fin24MHz所以可以计算div_seclec为66。 CCM-CCSR ~(1 2); /* 将pll_sw_clk时钟重新切换回pll1_main_clk */即将第2位设置成1即可。 CCM-CACRR 0; /* ARM内核时钟为pll1_sw_clk/1792/1792Mhz */由于我们已经将PLL1设置成792MHz那么我们只需要将分频系数设置为1即可。该寄存器配置如下图所示 /* 2、设置PLL2(SYS PLL)各个PFD */ reg CCM_ANALOG-PFD_528; reg ~(0X3F3F3F3F); /* 清除原来的设置 */ reg | 3224; /* PLL2_PFD3528*18/32297Mhz */ reg | 2416; /* PLL2_PFD2528*18/24396Mhz(DDR使用的时钟最大400Mhz) */ reg | 168; /* PLL2_PFD1528*18/16594Mhz */ reg | 270; /* PLL2_PFD0528*18/27352Mhz */ CCM_ANALOG-PFD_528reg; /* 设置PLL2_PFD0~3 */由上图可知我们已经成功配置了PLL1时钟频率那么接下来我们开始配置这PLL2和PLL3其中由上图时钟树可知PLL2有4路PFD时钟PLL3有4路PFD时钟。 我们先设置PLL2的4路PFD时钟。 reg CCM_ANALOG-PFD_528; reg ~(0X3F3F3F3F); /* 清除原来的设置 */由上图可知存器 CCM_ANALOG_PFD_528n 其实分为四组分别对应PFD0~PFD3每组 8 个 bit。 reg | 3224; /* PLL2_PFD3528*18/32297Mhz */ reg | 2416; /* PLL2_PFD2528*18/24396Mhz(DDR使用的时钟最大400Mhz) */ reg | 168; /* PLL2_PFD1528*18/16594Mhz */ reg | 270; /* PLL2_PFD0528*18/27352Mhz */ CCM_ANALOG-PFD_528reg; /* 设置PLL2_PFD0~3 */我们就以 PFD0 为例看一下如何设置 PLL2_PFD0 的频率。PFD0对应的寄存器位如下 PFD0_FRAC: PLL2_PFD0 的分频数PLL2_PFD0 的计算公式为 528*18/PFD0_FRAC此为 可 设 置 的 范 围 为 12~35 。 如 果 PLL2_PFD0 的 频 率 要 设 置 为 352MHz 的 话PFD0_FRAC528*18/35227。 PFD0_STABLE: 此位为只读位可以通过读取此位判断 PLL2_PFD0 是否稳定。 PFD0_CLKGATE: PLL2_PFD0 输出使能位为 1 的时候关闭 PLL2_PFD0 的输出为 0 的时候使能输出。 /* 3、设置PLL3(USB1)各个PFD */ reg 0; /* 清零 */ reg CCM_ANALOG-PFD_480; reg ~(0X3F3F3F3F); /* 清除原来的设置 */ reg | 1924; /* PLL3_PFD3480*18/19454.74Mhz */ reg | 1716; /* PLL3_PFD2480*18/17508.24Mhz */ reg | 168; /* PLL3_PFD1480*18/16540Mhz */ reg | 120; /* PLL3_PFD0480*18/12720Mhz */ CCM_ANALOG-PFD_480reg; /* 设置PLL3_PFD0~3 */ 我们先设置PLL3的4路PFD时钟。 reg 0; /* 清零 */ reg CCM_ANALOG-PFD_480; reg ~(0X3F3F3F3F); /* 清除原来的设置 */reg | 1924; /* PLL3_PFD3480*18/19454.74Mhz */ reg | 1716; /* PLL3_PFD2480*18/17508.24Mhz */ reg | 168; /* PLL3_PFD1480*18/16540Mhz */ reg | 120; /* PLL3_PFD0480*18/12720Mhz */ CCM_ANALOG-PFD_480reg; /* 设置PLL3_PFD0~3 */ 寄存器 CCM_ANALOG_PFD_480n 和 CCM_ANALOG_PFD_528n 的结构是一模一样的只是一个是 PLL2 的一个是 PLL3 的。寄存器位的含义也是一样的只是 频 率 计 算 公 式 不 同 比 如 PLL3_PFDX480*18/PFDX_FRAC(X0~3) 。 如果PLL3_PFD0720MHz的话PFD0_FRAC12 如果 PLL3_PFD1540MHz 的话PFD1_FRAC16; 如果PLL3_PFD2508.2MHz 的话PFD2_FRAC17 如果 PLL3_PFD3454.7MHz的话PFD3_FRAC19。 /* 4、设置AHB时钟 最小6Mhz 最大132Mhz (boot rom自动设置好了可以不用设置)*/ CCM-CBCMR ~(3 18); /* 清除设置*/ CCM-CBCMR | (1 18); /* pre_periph_clkPLL2_PFD2396MHz */ CCM-CBCDR ~(1 25); /* periph_clkpre_periph_clk396MHz */ while(CCM-CDHIPR (1 5));/* 等待握手完成 *//* 5、设置IPG_CLK_ROOT最小3Mhz最大66Mhz (boot rom自动设置好了可以不用设置)*/ CCM-CBCDR ~(3 8); /* CBCDR的IPG_PODF清零 */ CCM-CBCDR | 1 8; /* IPG_PODF 2分频IPG_CLK_ROOT66MHz *//* 6、设置PERCLK_CLK_ROOT时钟 */ CCM-CSCMR1 ~(1 6); /* PERCLK_CLK_ROOT时钟源为IPG */ CCM-CSCMR1 ~(7 0); /* PERCLK_PODF位清零即1分频 */其时钟结构图如下图所示 从图中可以看出 使能所有的时钟部分 void clk_enable(void) {CCM-CCGR0 0XFFFFFFFF;CCM-CCGR1 0XFFFFFFFF;CCM-CCGR2 0XFFFFFFFF;CCM-CCGR3 0XFFFFFFFF;CCM-CCGR4 0XFFFFFFFF;CCM-CCGR5 0XFFFFFFFF;CCM-CCGR6 0XFFFFFFFF; }这里举CCGR0为例。 led初始化部分 led_init(); /* 初始化led */这个部分在之前文章中已经讲过了 看完这篇文章你就彻底懂啦保姆级讲解-----I.MX6U驱动LED灯《使用汇编语言编写》 2023.4.17 看完这篇文章你就彻底懂啦保姆级讲解-----I.MX6U驱动LED灯《使用C语言编写》 2023.4.18 beep初始化部分 void beep_init(void) {/* 1、初始化IO复用复用为GPIO5_IO01 */IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01,0); /* 2、、配置GPIO1_IO03的IO属性 *bit 16:0 HYS关闭*bit [15:14]: 00 默认下拉*bit [13]: 0 kepper功能*bit [12]: 1 pull/keeper使能*bit [11]: 0 关闭开路输出*bit [7:6]: 10 速度100Mhz*bit [5:3]: 110 R0/6驱动能力*bit [0]: 0 低转换率*/IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01,0X10B0);/* 3、初始化GPIO,GPIO5_IO01设置为输出 */GPIO5-GDIR | (1 1); /* 4、设置GPIO5_IO01输出高电平关闭蜂鸣器 */GPIO5-DR | (1 1); }key初始化部分 void key_init(void) { gpio_pin_config_t key_config;/* 1、初始化IO复用, 复用为GPIO1_IO18 */IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0);/* 2、、配置UART1_CTS_B的IO属性 *bit 16:0 HYS关闭*bit [15:14]: 11 默认22K上拉*bit [13]: 1 pull功能*bit [12]: 1 pull/keeper使能*bit [11]: 0 关闭开路输出*bit [7:6]: 10 速度100Mhz*bit [5:3]: 000 关闭输出*bit [0]: 0 低转换率*/IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF080);/* 3、初始化GPIO *///GPIO1-GDIR ~(1 18); /* GPIO1_IO18设置为输入 */ key_config.direction kGPIO_DigitalInput;gpio_init(GPIO1,18, key_config);}按键中断初始化部分 void exit_init(void) {gpio_pin_config_t key_config;/* 1、设置IO复用 */IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0); /* 复用为GPIO1_IO18 */IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF080);/* 2、初始化GPIO为中断模式 */key_config.direction kGPIO_DigitalInput;key_config.interruptMode kGPIO_IntFallingEdge;key_config.outputLogic 1;gpio_init(GPIO1, 18, key_config);GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn); /* 使能GIC中对应的中断 */system_register_irqhandler(GPIO1_Combined_16_31_IRQn, (system_irq_handler_t)gpio1_io18_irqhandler, NULL); /* 注册中断服务函数 */gpio_enableint(GPIO1, 18); /* 使能GPIO1_IO18的中断功能 */ }IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0); /* 复用为GPIO1_IO18 */IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0xF080);key_config.direction kGPIO_DigitalInput; key_config.interruptMode kGPIO_IntFallingEdge; key_config.outputLogic 1; gpio_init(GPIO1, 18, key_config);由上图可知key所连接的接口为UART1_CTS所以需要将UART1_CTS设置复用功能为GPIO功能。并且将其GPIO1_IO18 为下降沿触发中断。 GIC_EnableIRQ(GPIO1_Combined_16_31_IRQn); /* 使能GIC中对应的中断 */调用函数 GIC_EnableIRQ来使能 GPIO_IO18 所对应的中断总开关I.MX6U 中 GPIO1_IO16~IO31 这 16 个 IO 共用 ID99。 system_register_irqhandler(GPIO1_Combined_16_31_IRQn, (system_irq_handler_t)gpio1_io18_irqhandler, NULL); /* 注册中断服务函数 */调用函数 system_register_irqhandler 注册 ID99 所对应的中断处理函数其中GPIO1_Combined_16_31_IRQn为注册的中断号gpio1_io18_irqhandler为注册的中断服务函数当产生这个中断后会自动进入gpio1_io18_irqhandler这个中断服务函数中。 gpio_enableint(GPIO1, 18); /* 使能GPIO1_IO18的中断功能 */通过函数 gpio_enableint 使能 GPIO1_IO18 这个 IO 对应的中断。 按键中断服务函数部分 void gpio1_io18_irqhandler(void) { static unsigned char state 0;/**采用延时消抖中断服务函数中禁止使用延时函数因为中断服务需要*快进快出这里为了演示所以采用了延时函数进行消抖后面我们会讲解*定时器中断消抖法*/delay(10);if(gpio_pinread(GPIO1, 18) 0) /* 按键按下了 */{state !state;beep_switch(state);}gpio_clearintflags(GPIO1, 18); /* 清除中断标志位 */ }调用函数 gpio_clearintflags 来清除 GPIO1_IO18 的中断标志位 while循环部分 while(1) { state !state;led_switch(LED0, state);delay(500);}每隔500msled灯亮灭。 最终编译验证 按下 KEY 就会打开蜂鸣器再次按下就会关闭蜂鸣器。LED0 会不断闪烁周期大约 500ms。 结束语 如果觉得这篇文章还不错的话记得点赞 支持下
http://www.hkea.cn/news/14286755/

相关文章:

  • 网站建设能挣钱个人建什么网站最赚钱吗
  • 服务器 多个网站工业品牌设计公司
  • 建设网站怎样提要求wordpress页面的模板
  • 雨花区区网站建设公司做网站彩票网站
  • 摄影工作室网站设计百度检索入口
  • 开一家做网站公司成本电商图片助手
  • 中国空间站是干什么的百度导航
  • 广州技术支持:网站建设哪些建材网站可以做宣传
  • 太仓做网站邯郸本地网站
  • 伊春信息网手机优化大师官网
  • 简述网站推广方式android开发环境搭建
  • 做网站链接怎么弄什么网站做新产品代理
  • 网站开发工作室策划案时尚网站模板代码
  • 河北网站备案系统网页设计毕业设计理念
  • 广州网站制作方法网页设计是啥意思
  • 酒店类的电影网站模板免费下载怎么查网站流量
  • 昆明网站建设方案报价做ps的网站有哪些功能吗
  • 网站怎么做伪静态页面网站制作的总结与体会
  • 网站运营方案设计顺德营销型网站建设
  • 河北网站开发WordPress四栏主题
  • 企业形象网站建设网络工程师招聘
  • 伯爵手表网站网站建设的地方
  • 杭州做网站费用洛阳软件开发公司有哪些
  • 江苏省建设工程备案网站湖北seo优化诊断
  • wdcp 网站备份网站备案现状
  • 网站优化建设宁夏合肥网站建设-中国互联
  • 网站开发毕业答辩ppt项目建设综述
  • 国外的网页制作网站实物黄金哪个网站做的好
  • 有没有公司做农副产品网站的网站内容建设
  • 东莞做网站推广北京做网站浩森宇特