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

建设垂直网站需要哪些流程图搬家公司价目表

建设垂直网站需要哪些流程图,搬家公司价目表,大山子网站建设,wordpress+简书模板#x1f431;作者#xff1a;一只大喵咪1201 #x1f431;专栏#xff1a;《理解ARM架构》 #x1f525;格言#xff1a;你只管努力#xff0c;剩下的交给时间#xff01; 目录 #x1f3c0;直接操作寄存器点亮LED灯#x1f3c0;地址空间#x1f3c0;ARM内部的寄存… 作者一只大喵咪1201 专栏《理解ARM架构》 格言你只管努力剩下的交给时间 目录 直接操作寄存器点亮LED灯地址空间ARM内部的寄存器汇编指令⚽内存访问指令四种栈 ⚽数据处理指令⚽跳转指令⚽伪指令 汇编和反汇编C与汇编⚽Flash上的内容 纯汇编点灯总结 直接操作寄存器点亮LED灯 在学习C语言的时候我们会写个Hello World程序来入门当我们写ARM程序也该有一个简单的程序引领我们入门这个程序就是点亮LED。 查看原理图确定控制LED的引脚 如上图是四种常见的LED驱动电路 方式1使用引脚输出3.3V点亮LED输出0V熄灭LED。 方式2使用引脚拉低到0V点亮LED输出3.3V熄灭LED。 有的芯片为了省电等原因其引脚驱动能力不足这时可以使用三极管驱动。 方式3使用引脚输出1.2V点亮LED输出0V熄灭LED。 方式4使用引脚输出0V点亮LED输出1.2V熄灭LED。 但是对于我们写程序来说不用关心输出的是3.3V还是1.2V只需要知道引脚输出的是高电平还是低电平简称输出1或0。 逻辑1–高电平逻辑0–低电平 芯片操作引脚 如上图本喵的STM32F103ZET6开发板上控制引脚输出0点亮LED灯这里仅控制Red的LED灯操作的引脚是PB0。 使能GPIOB组引脚 从芯片手册上查找相关寄存器 如上图是RCC_APB2ENR寄存器用来控制不同组GPIO的使能将该寄存器的bit3设置为1就使能了GPIOB。 那我们怎么找到这个寄存器呢 如上图是不同寄存器所在的地址范围。Reset and clock control RCC是用来使能外设时钟的它的基地址是0x40021000。 又因为RCC_APB2ENR寄存器的偏移地址是0x18所以该寄存器的绝对地址就是0x40021000 0x18。 设置GPIOB0为输出模式 如上图再从这张表中找到GPIOB的基地址是0x40010C00。 如上图所示是GPIOx_CRL寄存器x是引脚编号本喵这里使用的是PB0所以x就是0需要配置MODE0和CNF0。该寄存器的偏移量是0x00所以该寄存器的绝对地址就是0x40010C00 0x00 。 MODE0的两个比特位配置为11表示输出并且输出速度设置最大此时电平变化最快。 CNF0的两个比特位是配置输出模式的这里仅是点灯使用默认值即可。 设置引脚电平 如上图是GPIOx_ODR寄存器用来控制引脚的输出电平根据偏移地址得到它的绝对地址是0x40010C00 0x0C。 由于是PB0所以控制它的bit0ODR0即可该位是1输出1该为是0输出0。 要实现bit0 1或者bit0 0不能直接GPIOx_ODR 1这样虽然能让bit0为1但是该寄存器的其他位被置0了。 操作寄存器的某一位时不能影响其他位。 置一GPIOx_ODR | (10)。 置0GPIOx_ODR ~(10)。 这样的方式就仅在操作bit0其他位并不影响。 如上图所示GPIOx_BSRR寄存器它的绝对地址是0x40010C00 0x10对于PB0只需要操作BS0位和BR0位。 BS0写1输出1BR0写1输出0这些位写0没有任何影响此时就可以仅操作这一个寄存器即可效率较高。 编程 如上图所示启动文件中的汇编代码蓝色框中的是语法规定必须有的暂时不用管它。 板子一上电以后会去向量表__Vectors处开始执行代码执行到DCD Reset_Handler后会开始调用我们自己写的函数mymain在调用之前需要设置一下栈顶SP然后BL跳转到我们自己写的函数中去执行。 如上图本喵自己实现的mymain.c函数中先创建一个32位的指针变量pReg用来访问寄存器。 让指针指向RCC_APB2ENR寄存器的地址0x40021000 0x18将该寄存器的bit3置一使能GPIOB。让指针指向GPIOx_CRL寄存器的地址0x40010C00 0x00将该寄存器的bit0置一设置PB0为输出模式。让指针指向ODR寄存器的地址0x40010C00 0x0C将该寄存器的bit0设置为1让PB0输出1然后延时再将bit0设置为0然后再延时如此反复。 然后编译工程并将程序烧录到开发板中可以看到板子上红色的LED灯在闪烁本喵这里就不贴图了。 地址空间 ARM架构 在上面点灯的过程中本喵在访问寄存器的时候完全就是在使用C语言的指针来访问内存地址为什么这样做就可以访问到寄存器呢 如上图示意图所示在ARM架构的CPU中内存RAM各种片内外设如UARTUSB控制器等都是统一编址的它们的地址是连续的从add1到add6。 CPU在访问不同的地址时会将地址先发给内存控制器memeory controller由内存控制器去访问地址读取数据。 所以在CPU眼里这些外设以及内存的访问方法都是一样的。 x86架构 如上图所示是x86架构CPU访问内存和外设的示意图这里的内存和IO空间中的外设就不是统一编址的而是分隔开的。 内存的地址范围是0~4GBIO空间的范围是0~64k这两个空间在0~64K的地址范围是重复的CPU通过不同指令来访问不同的空间。 当CPU要访问内存空间的时候就使用MOV指令当CPU要访问IO空间的时候就使用IN指令。 精简指令集计算机 ARM芯片属于精简指令集计算机(RISCReduced Instruction Set Computing)它所用的指令比较简单有如下特点 ① 对内存只有读、写指令 ② 对于数据的运算是在CPU内部实现 ③ 使用RISC指令的CPU复杂度小一点易于设计 如上图所示的乘法运算a a * bRISC中要使用4条汇编指令 ① 读内存a ② 读内存b ③ 计算a*b ④ 把结果写入内存 复杂指令集计算机 x86属于复杂指令集计算机(CISCComplex Instruction Set Computing) 它所用的指令比较复杂比如某些复杂的指令它是通过“微程序”来实现的。 比如执行乘法指令时实际上会去执行一个“微程序”在“微程序”里 一样是去执行这4不操作 ① 读内存a ② 读内存b ③ 计算a*b ④ 把结果写入内存 但是对于程序员来说他看不到“微程序”他好像用一条指令就搞定了这一切 这里提到x86架构以及CISC仅仅是为了和ARM架构以及RISC作一个对比我们使用的是ARM架构以及RISC。 ARM内部的寄存器 ARM架构中对于数据的运算是在CPU内部实现的在内部用什么来保存上面乘法运算中的ab以及a * b的结果呢 cortex-M3/M4中寄存器示意图 如上图所示是CPU中寄存器示意图。 CPU内部都有R0、R1、……、R15寄存器它们可以用来“暂存”数据。 对于R13、R14、R15还另有用途 R13别名SP(Stack Pointer)栈指针。R14别名LR(Link Register)用来保存返回地址。R15别名PC(Program Counter)程序计数器表示当前指令地址写入新值即可跳转。 其中R13就是汇编指令里使用的SP但是它有两个寄存器一般情况下使用的是SP_main寄存器运行RTOS的时候任务使用的是SP_process寄存器。 在编程的时候直接使用SP根据不同情况会自动调用相应的栈寄存器。 如上图所示在程序执行的过程中PC寄存器会按照顺序读取指令并去执行。 这16个寄存器之外还有一个xPSR寄存器用来保存程序状态保存上一条指令的执行结果比如比较结果。还有一些控制作用比如屏蔽中断、使能中断。 对于cortex-M3/M4来说xPSR实际上对应3个寄存器 ① APSRApplication PSR应用PSR ② IPSRInterrupt PSR中断PSR ③ EPSRExectution PSR执行PSR 这3个寄存器的含义如上图所示其实就是3个寄存器使用32位中的不同比特位所以就用一个程序状态寄存器xPSR来表示了3个寄存器。 如上图所示就是组后和的真实寄存器。 如上图所示是xPSR寄存器中不同位所表示的意义。 这3个寄存器可以单独访问使用下面汇编指令 MRS R0, APSR 读APSRMRS R0, IPSR 读IPSRMSR APSR, R0 写APSR 这3个寄存器也可以一次性访问 MRS R0, PSR 读组合程序状态MSR PSR, R0 写组合程序状态 汇编指令 一开始ARM公司发布两类指令集 ① ARM指令集这是32位的每条指令占据32位高效但是太占空间。 ② Thumb指令集这是16位的每条指令占据16位节省空间。 要节省空间时用Thumb指令要效率时用ARM指令。 一个CPU既可以运行Thumb指令也能运行ARM指令。通过程序状态寄存器中有一位名为“T”它等于1时表示当前运行的是Thumb指令。 现在有一种情况函数A是使用Thumb指令写的函数B是使用ARM指令写的可以往PC寄存器里写入函数A或B的地址就可以调用A或B。 但是怎么让CPU在执行A函数是进入Thumb状态在执行B函数时进入ARM状态 调用函数A时让PC寄存器的BIT0等于1即PC函数A地址(10)调用函数B时让PC寄存器的BIT0等于0:即PC函数B地址 根据函数地址的bit0位来判断这是用Thumb指令写的还是用ARM指令写的。 这样做非常的麻烦所以后来又引入了Thumb2指令集它支持16位指令、32位指令混合编程。 有那么多指令集ARM、Thumb、Thumb2难道都要记住它们的指令吗当然不会ARM公司推出了UAL(Unified Assembly Language)统一汇编语言你不需要去区分这些指令集。 在程序前面用CODE32/CODE16/THUMB表示指令集ARM/Thumb/Thumb2 我们在使用中不需要记住多少汇编指令没必要写很复杂的汇编程序因为在设置栈后就用C语言来写函数了。 常用的汇编指令只有几类内存访问、数据处理、跳转、其他指令。 以“数据处理”指令为例UAL汇编格式为 Operation表示各类汇编指令比如ADD、MOVcond表示conditon即该指令执行的条件条件符合就执行不符合就不执行该选项可写可不写条件有 如上图这些条件都和程序状态寄存器xPSR中的值有关使用条件的指令之前一定得有改变xPSR寄存器的指令。 {S}表示该指令执行后会去修改程序状态寄存器也是可写可不写。 Rd为目的寄存器用来存储运算的结果Rn、Operand2是两个源操作数 下面本喵用一款神器VisUAL来讲解一下常用汇编指令的用法这是一款ARM汇编模拟器。 ⚽内存访问指令 LDRLoad Register 如上图所示是该指令的用法作用就是从内存中读取数据到寄存器中其中{type}表示读取数据的类型如B就是无符号的一个字节数据该选项可写可不写。 STRStore Register 如上图所示就是该指令的用法作用就是将数据从寄存器中写入到内存中。 如上图所示汇编代码在执行的过程中在右侧的红色框中可以看到寄存器中值的变化在下侧的框中可以看到内存中的值。根据回调代码中的注释很容易看懂意思。 MOV是一个最基本的汇编指令表示数据的移动从源操作数移动到目的操作数如上面中的MOV R0, #0x20000中将0x20000移动到寄存器R0中。 !表示R0R08就是运算完以后要改变R0寄存器中的值。 LSL是一个数据左移指令就相当于C语言中的操作符如上面的STR R2, [R0, R1, LSL #4]表示将R1中的值左移4位然后加到R0上最后将R2寄存器中的值存放到R0中值所代表的地址处。 LDMLoad Multiple Register 如上图所示是LDM的用法作用是从多个地址处将数据读取到多个寄存器中。 addr_mode: IA - Increment After, 每次传输后才增加Rn的值(默认,可省) IB - Increment Before, 每次传输前就增加Rn的值(ARM指令才能用) DA – Decrement After, 每次传输后才减小Rn的值(ARM指令才能用) DB – Decrement Before, 每次传输前就减小Rn的值 ! : 表示修改后的Rn值会写入Rn寄存器, 如果没有!, 指令执行完后Rn恢复/保持原值 ^ : 会影响CPSR, 在讲异常时再细讲 这里的Rn表示地址如LDMIA R0, {R1-R3}表示将R0,R04,R08地址处的数据读取到R1,R2,R3寄存器中。 STMStore Multiple Register 如上图所示是STM的用法作用是将多个寄存器中的值写到多个地址处。这里Rn也表示地址。选项和LDM的用法一样。 如上图所示是将寄存器中R1R2R3中的123放入到R0中的起始地址0x20000处时使用的四种addr_mode方式。 上面是汇编代码下面是执行完毕后内存中的值这个过程中高地址放编号高的寄存器中值。 四种栈 根据栈指针指向可分为满(Full)/空(Empty) 满SP指向最后一个入栈的数据需要先修改SP再入栈。 空SP指向下一个空位置先入栈再修改SP。 根据压栈时SP的增长方向可分为增/减 增(Ascending)SP变大。 减(Descending)SP变小。 组合后就有4种栈满增、满减空增空减。 常用的的栈为“满减” 入栈时用STMDB也可以用STMFD作用一样表示入栈之前先减小SP。出栈时用LDMIA也可以用LDMFD作用一样表示出栈之后再增加SP。 如上图代码所示使用STMFD将数字123入栈此时R13也就是SP寄存器的值是0x1FFF4因为从0x2000开始减了12个字节此时内存中的值也符合。 然后将R1,R2,R3寄存器中的值清0然后再使用LDMFD将栈中的12放入到寄存器中。 ⚽数据处理指令 加法指令 ADD R1, R2, R3 ; R1 R2 R3 ADD R1, R2, #0x12 ; R1 R2 0x12减法指令 SUB R1, R2, R3 ; R1 R2 - R3SUB R1, R2, #0x12 ; R1 R2 - 0x12进行减法运算的时候发生借位时会改变程序状态寄存器xPSR中的N位。 位操作 AND R1, R2, #(14) ; 位与R1 R2 (14) AND R1, R2, R3 ; 位与R1 R2 R3 BIC R1, R2, #(14) ; 清除某位R1 R2 ~(14) BIC R1, R2, R3 ; 清除某位R1 R2 ~R3 ORR R1, R2, R3 ;位或R1 R2 | R3VisUAL里不支持(14)这样的写法写成0x10。 比较 CMP R0, R1 ; 比较R0-R1的结果 CMP R0, #0x12 ; 比较R0-0x12的结果 TST R0, R1 ; 测试 R0 R1的结果 TST R0, #(14) ; 测试 R0 (14)的结果比较的本质就是在做减法用第一个操作数减去第二个操作数比较的结果会改变程序状态寄存器xPSR中的N位和Z位。 ⚽跳转指令 void A() {int a 10;B(a);printf(“ok”); }C程序中函数A调用函数B的实质是跳转去执行函数B的代码函数B执行完后还要回到函数A继续执行后面的代码。 对应的汇编指令就是跳转指令 BBranch跳转BLBranch with Link跳转前先把返回地址保持在LR寄存器中BXBranch and eXchange根据跳转地址的BIT0切换为ARM或Thumb状态(0ARM状态1Thumb状态)。BLXBranch with Link and eXchange跳转前先把返回地址保持在LR寄存器中根据跳转地址的BIT0切换为ARM或Thumb状态(0ARM状态1Thumb状态)。 由于使用的是Thumb2指令集所以只使用B和BL两条跳转指令。 如上图跳转时可以加条件{cond}{.W}不用写。 如上图使用B跳转指令跳转到延时函数Delay中然后让R0减1再使用BNE来判断跳转到哪里当R0不为0时在BNE和SUBS之间执行。 SUBS在SUB减法指令的基础上增加了S表示执行完后会影响程序状态寄存器xPSR的值。 在运行过程中xPSR中的Z位始终为0表示R0的值不为0。BNE是在跳转指令B的基础上增加了条件NE代表的条件就是xPSR中的Z为0。 此时符合BNE条件所以跳转到loop继续执行从而实现延时。但是这个延时函数执行完毕后无法获得返回地址因为B跳转指令不会保存返回地址到LR寄存器中。 如上图所示使用BL跳转指令在跳转之前会将返回地址存入到LR寄存器中如上图所示LR中的值是0x04由于当前地址是第一行返回地址就是下一条指令的地址也就是第2行又因为BL指令是32位指令所以增加4。 当延时结束以后将LR中的返回地址直接赋值给PC寄存器程序从第2行开始执行。 ⚽伪指令 这样一条指令MOV R0, #VAL意图是把VAL这个值存入R0寄存器那么VAL可以是任意值吗不可以 直接给寄存器赋值的数必须是立即数。 假设VAL可以是任意数MOV R0, #VAL本身是16位或32位哪来的空间保存任意数值的VAL所以VAL必须符合立即数的规定 如上图是立即数必须符合的规则但是由我们去判断一个数是否是立即数会比较麻烦并且我就想把任意数值赋值给R0这时就可以使用伪指令。 LDR伪指令 LDR R0, VAL“伪指令”就是假的、不存在的指令。编译器会把“伪指令”替换成真实的指令比如 LDR R0, 0x12 中0x12是立即数那么替换为MOV R0, #0x12。 LDR R0, 0x12345678中0x12345678不是立即数那么替换为LDR R0, [PC, #offset]使用LDR读内存指令读出值offset是链接程序时确定的。 编译器在程序某个地方保存有这个非立即数的值需要赋值的时候就来这个地府读取。 注意LDR作为“伪指令”时指令中有一个“”否则它就是真实的LDR(load regisgter)指令了。 ADR伪指令 ADR R0, Loop比如ADR R0, Loop要将标号Loop的地址读取到R0中它是伪指令会被转换成真实的指令ADD R0,PC,#VALVAL在连接的时候确定。 如上图之前的延时程序可以使用伪指令ADR直接将返回地址赋值给LR寄存器将函数Delay的地址直接赋值给PC寄存器去执行延时函数。 汇编和反汇编 我们的第1个LED程序涉及2个文件start.s、main.c它们的处理过程如下 如上图所示是程序编译的步骤最后面的红色框是反汇编就是将生成的可执行二进制文件变成汇编代码。 汇编汇编文件转换为目标文件(里面是机器码)。反汇编可执行文件(目标文件里面是机器码)转换为汇编文件。 KEIL中反汇编 fromelf --bin --outputled.bin Objects\led.axf fromelf --text -a -c --outputled.dis Objects\led.axf在KEIL的User选项中如下图添加这两项 然后重新编译即可得到二进制文件led.bin(以后用到)、反汇编文件led.dis。 如上图只截取led.dis中前面一小段第一列是地址第二列是机器码第三列是汇编代码。 如上图所示是Thumb/Thumb2指令集中LDR指令的机器码生成规则和前面反汇编文件中LDR对应的机器码做对比可以发现完全可以对的上。 C与汇编 汇编代码中调用C函数时使用BL mymain那如果我想给mymain函数传参呢在前面编译过程中可以看到.c源文件也会被编译成汇编文件然后所有汇编文件再进行汇编生成目标文件然后再进行连接。 此时start.s中调用main.s中的mymain函数这两个文件都是汇编文件汇编调用汇编传参就容易实现了。在ARM中使用寄存器来传参 如上图r0-r3用于调用者和被调用者之间传参数。 r4-r11用来保存局部变量函数可能使用它们所以在函数的入口保存它们在函数的出口恢复它们。 r12-r15是特殊用途的寄存器。 int delay(unsigned int d) {while (d--);return 0; }int mymain() {delay(1000000);return 0; }上面的C代码转换成汇编后调用delay时如下 LDR R0, 1000000 /* 给delay函数传参数保存在r0里 */ BL delay CMP R0, #0 /* 返回值保存在r0中 */可以看到在调用delay之前直接将1000000赋给寄存器R0然后使用BL调用delay此时就通过R0进行了传参。 函数调用结束后delay函数的返回值也保存在寄存器R0中。 ⚽Flash上的内容 如上图是我们生成的反汇编文件其中机器码是烧写到Flash上的汇编码只是为了方便我们阅读。 每条指令会对应一个地址如上图中的0x08000000这个地址在Flash中是真实存在的Flash中的地址也是按照上图中指令的地址这样分布的。 烧到Flash上 地址Flash内容0x08000000000000000x08000004080000090x08000008f8dfd0040x0800000cf000f80c0x08000010200100000x08000014bf00b5010x080000181e419800………… 如上表所示烧到Flash上的内容只有机器码它自动放在与每条指令相对应的地址上。 启动流程 上电后 设置栈CPU会从0x08000000读取值用来设置SP(我们的程序里在调用mymain之前设置了SP)跳转CPU从0x08000004得到地址值根据它的BIT0切换为ARM状态或Thumb状态然后跳转 对于cortex M3/M4它只支持Thumb状态所以0x08000004上的值bit0必定是10x08000004上的值 Reset_Handler 1 从Reset_Handler继续执行使用BL调用我们的mymain函数开始执行C代码。 纯汇编点灯 如上图所示汇编代码上电后程序会执行Reset_Handler处开始执行汇编代码步骤和C语言的一样。 将RCC_APB2ENR寄存器的绝对地址赋值给R0然后将bit3置为1使能GPIOB。将GPIOx_CRL寄存器的绝对地址赋值给R0然后将bit0置位1设置PB0为输出模式。将GPIOx_ODR寄存器的绝对地址赋值给R2然后控制它的bit0位来控制引脚输出0和1。 将bit0设置成1LED灯点亮然后延时将bit0设置成0熄灭LED灯然后延时再使用B指令跳转回Loop处循环点亮 在调用延时函数delay时使用的是BL指令在延时函数中使用BNE判断R0中的值是否为0延时结束后将LR中的返回地址赋值给PC寄存器。 调用延时函数delay时通过寄存器R0传参。 将程序编译并烧录到开发板中可以看到LED灯在闪烁本喵这里也不贴图了。 总结 这篇文章中要对ARM架构有一个框架性的认识知道CPU是怎么访问内存的还有要记住这几条常用的汇编指令其他复杂的指令遇到时自行百度查阅即可。 要明白调用函数是如何传参的以及板子上电后程序的执行流程包括Flash中存放的是什么。
http://www.zqtcl.cn/news/489909/

相关文章:

  • 网站建设改版升级wordpress 艺术家
  • 百度怎么网站排名python做网站的开发
  • 淘宝 网站建设教程视频北京华夏建设有限公司网站
  • 网站公司的利润中国域名后缀
  • 梁山网站建设电话多语言网站建设
  • 网站建设的摘要做直播网站赚钱吗
  • 网站建设明细报价表模板永久免费云服务器无需注册
  • 扁平化网站设计方案大学生做的美食网站
  • wordpress前台打开速度20秒湖南正规竞价优化公司
  • 深度网营销型网站建设wordpress keywords
  • 企业官网快速建站框架物流网站源代码
  • 网站图片设置隐私保护怎么下载搭建购物网站
  • 网站运营和推广可以做mv 的视频网站
  • 成都网站建设冠辰成都关键词优化技术
  • 用什么框架做网站快哪个网站可以自己做名片
  • 免费网站建设ppt模板下载网站设计与程序专业
  • o2o网站设计方案高端定制网站开发设计建站流程
  • 杭州建设公司网站石家庄做网站比较好的公司
  • 英文网站支付怎么做产品做推广都有那些网站
  • 自己做的网站怎么加入微信支付综合性门户网站列举
  • 哪个网站 可以做快递单录入网站怎么做抽奖
  • 网站设计培训班网站域名费用怎么做分录
  • 济南做网站哪里好惠州附近公司做网站建设多少钱
  • 使用oss做静态网站网站广告牌制作教程
  • 外贸看的英文网站公众号模板编辑器
  • 做网站的数据库的步骤阅读网站模板下载
  • 建设网站要钱吗个人养老金制度是什么意思
  • 做h5的网站页面设计软文素材网站
  • 黄冈网站推广软件费用是多少手机网站弹出层插件有哪些
  • wordpress文章链接怎么改怎么优化关键词排名优化