第一个程序深度解析(STM32F407)
一.编程知识-进制10进制里每一位的权重从右往左数个十百千万也就是10^0, 10^1, 10^2,10^3……16进制里每一位的权重从右往左数分别是16^0, 16^1, 16^2, 16^3, 16^4, ……8进制里每一位的权重从右往左数分别是8^0, 8^1, 8^2, 8^3, 8^4, ……进制输出printf输入scanf十进制%d或%i%d八进制%o输出无前缀%o输入时可带可不带0十六进制%x小写字母或%X大写%x输入时可带可不带0x二进制标准C没有原生占位符需自定义函数或使用itoa()无二.编程知识-字节序1.大小字节序大小端假设int a 0x1234567816进制数中每位数值占据4 bit在内存中是以8个bit作为1byte。因此0x12345678中每两位作为1byte, 其中0x78是低byte0x12是高byte。在内存中的存储方式有两种判断大小字节序的方法指针强转类型2.位操作1.逻辑左移int a 0x123; int b a2; // b0x48C2.逻辑右移int a 0x123; int b a2; // b0x483.取反unsigned int a 0x123; unsigned int b ~a; // b的每一位都是a对应位的取反4.位与unsigned int a 0x123; unsigned int b 0x456; unsigned int c a b; // c等于a位与b即a,b的每一位进行与操作 1 1 1 1 0 0 0 1 0 0 0 05.位或unsigned int a 0x123; unsigned int b 0x456; unsigned int c a | b; // c等于a位或b即a,b的每一位进行或操作 1 | 1 1 1 | 0 1 0 | 1 1 0 | 0 06.置位重要置位公式 x | 1nunsigned int a 0x123; unsigned int b a | (17) | (18); // 设置a的bit7, bit8, 赋给b7.清位重要清位公式 x ~1nunsigned int a 0x123; unsigned int b a ~((17) | (18)); // 清除a的bit7, bit8, 赋给b8.把某几位设置位某值比如要把bit7设置为1把bit8清除为0这可以分两步操作先设置bit7再清除bit8。 还有一种情况bit[8:7] val, 不知道val的取值是多少怎么办 先清除bit8、bit7再或上val代码如下unsigned int a 0x123; unsigned int b a ~(37); /* 清除bit7, bit8 */ b b | (val 7); /* 设置bit7, bit8为val */三、汇编知识-汇编、反汇编、机器码1.程序处理4个步骤步骤输入输出核心动作常见报错类型1. 预处理.c.i宏替换、头文件展开、删注释无不检查语法2. 编译.i.s语法分析、生成汇编代码语法错误Syntax Error3. 汇编.s.o/.obj生成二进制机器码目标文件极少数低级错误4. 链接.o 库.exe/a.out合并目标文件、解析外部地址未定义引用Undefined reference2.反汇编文件格式推荐写法 (命令)说明.bin文件fromelf.exe --bin -o $LL.bin #L$LL.bin意思是在输出文件.axf的目录下生成一个同名的.bin文件。fromelf.exe --bin -o .\Objects\你的工程名.bin .\Objects\你的工程名.axf这种是直接写明路径和文件名。需要你把Objects和你的工程名换成自己工程对应的实际目录和名字。.dis文件fromelf.exe --text -a -c -o $LL.dis #L--text -a -c是输出反汇编信息的标准参数组合。fromelf.exe --text -a -c -o .\Objects\你的工程名.dis .\Objects\你的工程名.axf同样可以替换为你的实际路径和文件名。生成 .bin 文件二进制固件在 Run #1 的输入框中添加以下命令fromelf --bin -o $LL.bin $LL.axf生成 .dis 文件反汇编文件在 Run #2 的输入框中添加以下命令fromelf --text -a -c --output$LL.dis $LL.axf3.汇编深入分析1.汇编怎么调用C函数直接调用2.寄存器的作用3.栈的作用假设A函数把变量val放在了R4寄存器里。如果这时候调用B函数而B函数也要用R4就会把A函数的值覆盖掉。为了解决这个问题B函数在开头会先把R4原来的值临时存到栈里压栈等B函数执行完了在返回前再从栈里把值取回来放回R4出栈。这样A函数回来后R4里的val还是原来的值一切正常。4.解析汇编四.汇编点灯PRESERVE8 THUMB ; Vector Table Mapped to Address 0 at Reset AREA RESET, DATA, READONLY EXPORT __Vectors __Vectors DCD 0 DCD Reset_Handler ; Reset Handler AREA |.text|, CODE, READONLY ; Reset handler Reset_Handler PROC EXPORT Reset_Handler [WEAK] ; IMPORT main ; LDR SP, 0x20000000 0x20000 ; BL main ; /* 使能GPIOF */ LDR R0, (0x40023800 0x30) LDR R1, [R0] ORR R1, R1, #(15) STR R1, [R0] ; /* 设置GPIOF9为输出引脚 */ LDR R0, (0x40021400 0x00) LDR R1, [R0] ORR R1, R1, #(118) STR R1, [R0] ; /* 设置GPIOF9为推挽输出 */ LDR R0, (0x40021400 0x04) LDR R1, [R0] BIC R1, R1, #(19) STR R1, [R0] ; /* 设置GPIOF9为低速输出 */ LDR R0, (0x40021400 0x08) LDR R1, [R0] BIC R1, R1, #(318) STR R1, [R0] LDR R2, (0x40021400 0x18) Loop ; /* 设置GPIOF9输出1 */ LDR R1, [R2] ORR R1, R7, #(19) STR R1, [R2] LDR R0, 100000 BL delay ; /* 设置GPIOF9输出0 */ LDR R1, [R2] ORR R1, R8, #(125) STR R1, [R2] LDR R0, 100000 BL delay B Loop ENDP delay SUBS R0, R0, #1 BNE delay MOV PC, LR END