20201012会议要点总结
遇到问题,要珍惜问题
每遇到一个问题,就放弃一个问题,就永远不会成长,遇到一个问题,解决一个问题,能力就会提升一步。
论文一页纸
每周负责的人需要写出一页论文相关的内容
每件事情都要做到底
每件事情都要做到底,做10件未完成的事情不如做一件完成的事情
研究生要会做也要会写
研究生要有做事的能力,也要学会总结,否则知识就会散掉。
每遇到一个问题,就放弃一个问题,就永远不会成长,遇到一个问题,解决一个问题,能力就会提升一步。
每周负责的人需要写出一页论文相关的内容
每件事情都要做到底,做10件未完成的事情不如做一件完成的事情
研究生要有做事的能力,也要学会总结,否则知识就会散掉。
日期 | 星期 | 时间记录 | 学习内容 | 日合计 |
---|---|---|---|---|
10.5 | 1 | 无 | 无 | 无 |
10.6 | 2 | 无 | 无 | 无 |
10.7 | 3 | 无 | 无 | 无 |
10.8 | 4 | 9:00-21:30 | 比赛 | 12.5 |
10.9 | 5 | 9:00-21:30 | 比赛 | 12.5 |
10.10 | 6 | 9:00-21:30 | 比赛 | 12.5 |
10.11 | 7 | 无 | 无 | 无 |
周合计时间 | ||||
周平均时间 |
出现问题的原因:全局变量只被声明而未被定义
已采取的方法:在使用的地方对全局变量进行定义
结果:已解决
1 | //include.h文件 |
1 | //photo.h文件--使用全局变量的文件 |
gcc 提供了为了满足用户不同程度的的优化需要,提供了近百种优化选项。用来对编译时间,目标文件长度,执行效率这个三维模型进行不同的取舍和平衡。优化的方法不一而足,总体上将有以下几类:
1)精简操作指令;
2)尽量满足cpu的流水操作;
3)通过对程序行为地猜测,重新调整代码的执行顺序;
4)充分使用寄存器;
5)对简单的调用进行展开等等。
gcc提供了从O0-O3以及Os这几种不同的优化级别供大家选择,在这些选项中,包含了大部分有效的编译优化选项,并且可以在这个基础上,对某些选项进行屏蔽或添加,从而大大降低了使用的难度,毕竟,在一定基础上进行取舍,比万事从头开始要好得多。下面着重围绕这几个不同的级别进行简单介绍。
对于大函数,优化编译占用稍微多的时间和相当大的内存。使用本项优化,编译器会尝试减小生成代码的尺寸,以及缩短执行时间,但并不执行需要占用大量编译时间的优化。
打开的优化选项:
1.l -fdefer-pop:延迟栈的弹出时间。当完成一个函数调用,参数并不马上从栈中弹出,而是在多个函数被调用后,一次性弹出。
这一优化选项主要是减少因函数调用后弹出参数所使用的时间,函数调用结束之后,不会立即将参数弹出,后续函数使用栈不多的时候,这个优化并不会影响函数的执行,只是相当于减少了栈的空间,若后续函数所需栈空间不够的时候,系统会把栈内堆积的参数一次性全部释放,这样就大大减少了栈弹出的时间。—提高了函数的执行效率
2.l -fmerge-constants:尝试横跨编译单元合并同样的常量(string constants and floating point constants)
1 | e.g: |
编译器发现str1和str2所用的常量都是”Hello”,那么编译器不会给向内存申请两个地址,只会申请一个地址存放”Hello”,然后两个指针指向的字符串是同一个”Hello”的地址。—减少了目标文件长度。
3.l -fthread-jumps:如果某个跳转分支的目的地存在另一个条件比较,而且该条件比较包含在前一个比较语句之内,那么执行本项优化.根据条件是true或者false,前面那条分支重定向到第二条分支的目的地或者紧跟在第二条分支后面. —提高执行效率
1 | e.g: |
4.l -floop-optimize:执行循环优化,将常量表达式从循环中移除,简化判断循环的条件,并且optionally do strength-reduction,或者将循环打开等。在大型复杂的循环中,这种优化比较显著。
—提高执行效率
*(常量表达式就是表达式里面只有常量的式子,比如1+2是常量表达式,如果定义a为常量1,那么a+2也是常量表达式)*
1 | e.g: |
循环打开后,新程序只需要进行20次迭代,而不是100次。之后,只需要采用20%的跳转和条件分支,并且在多次迭代中表示可能显着减少。循环管理开销。为了产生最佳效益,不应在需要指针运算的展开代码中指定变量。这通常需要“基础加偏移”寻址,而不是索引引用。
5.l -fif-conversion:尝试将条件跳转转换为等价的无分支型式。优化实现方式包括条件移动,min,max,设置标志,以及abs指令,以及一些算术技巧等。
1 | e.g: |
6.l -fif-conversion2基本意义相同。—提高执行效率
7.l -fdelayed-branch:这种技术试图根据指令周期时间重新安排指令。 它还试图把尽可能多的指令移动到条件分支前, 以便最充分的利用处理器的治理缓存。—提高执行效率
在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序。重排序分以下3种类型:
(1)编译器优化的重排序:编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
(2)指令级并行的重排序:现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
(3)内存系统的重排序:由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
1 | e.g: |
8.l -fguess-branch-probability:当没有可用的profiling feedback或__builtin_expect时,编译器采用随机模式猜测分支被执行的可能性,并移动对应汇编代码的位置,这有可能导致不同的编译器会编译出迥然不同的目标代码。
1 | e.g: |
9.l -fcprop-registers:因为在函数中把寄存器分配给变量, 所以编译器执行第二次检查以便减少调度依赖性(两个段要求使用相同的寄存器)并且删除不必要的寄存器复制操作。
通过发送AT指令让EMW3072连接WiFi,WiFi连接成功后,EMW3072芯片会回发”STATION_UP”,收到这个回发信息后,芯片就设定已经连接上WiFi。
1 | //====================================================================== |
连接WiFi成功后,芯片通过发送AT指令让EMW3072连接服务器,连接服务器成功后,EMW3072芯片会回发”SERVER,CONNECTED”
1 | //====================================================================== |
接收返回信息函数是每个AT指令发送后都需要用到的函数,根据发出的命令存储不同的返回信息供芯片判断发送指令成功与否。
1 | //====================================================================== |
芯片通过这个函数发送消息,函数会将你想要发送的消息进行二次组帧以确保信息的稳定性和安全性。
1 | //====================================================================== |
进入AT指令模式: +++
退出AT指令模式,进WIFI的透传模式: AT+CIPSENDRAW\r
重启模块: AT+REBOOT\r
设置串口回显打开: AT+UARTE=ON\r
设置串口回显关闭: AT+UARTE=OFF\r
设置 Station 名称 和 密码: AT+WJAP=Seventeen,jjljjl123789\r
查询当前Station模式的IP地址,子网掩码和网关: AT+WJAPIP?\r
查询当前Station连接状态: AT+WJAPS\r
断开当前Station连接: AT+WJAPQ\r
STATION模式下,启动一个tcp client: AT+CIPSTART=1,tcp_client,192.168.31.244,8888\r
断开id=0的连接: AT+CIPSTOP=0\r
查询id=0的连接状态: AT+CIPSTATUS=0\r
id=0连接,tcp client发来的数据下发至串口: AT+CIPRECV=0,53588\r
1 | void comm_init() |
1 | for(;;) |
1 | Send_Procedure_Branch: |
1 | PostBack_Procedure_Branch: |
开发C语言程序需要经过四个步骤:预编译、编译、链接、运行
预编译
预编译对源码中所有的预处理语句进行处理,例如: #include语句所包含的文件内容替换掉语句本身,所有已定义的宏被展开。根据#ifdef,#if等语句的条件是否成立取舍相应的部分,预处理之后源码中不再包含预处理语句。GCC预处理可以生成.i的文件。
编译
这一阶段,编译器对源码进行词法分析、语法分析、优化等操作,最后生成汇编代码。
汇编
这一阶段使用汇编器对汇编代码进行处理,生成机器语言代码,保存在后缀为.o的目标文件中。当程序有多个代码文件构成时,每个文件都要先完成汇编工作,生成.o目标文件后,才能进入下一步的链接工作。
链接
经过汇编以后的机器代码还不能直接运行。为了使操作系统能够正确加载可执行文件,文件中必须包含固定格式的信息头,还必须与系统提供的启动代码链接起来才能正常运行,这些都是又链接器来完成的。
在STM32L431RC芯片中,链接的工作由链接文件.ld来完成,链接文件的主要功能就是将多个目标文件(.o)和库文件(.a)链接成一个可执行的文件。
链接文件中主要有以下三个部分:链接配置、内存布局定义、段链接定义
链接配置中设定一些符号变量的定义、入口地址、输出格式等
1 | /* Entry Point */ |
ENTRY(Reset_Handler)
—–指定入口地址
_estack = 0x20010000
—–指定RAM的结束地址(起始地址为0x20000000,说明RAM区大小为64K)
_Min_Heap_Size = 0x200
—–指定堆的大小为512B
_Min_Stack_Size = 0x400
—–指定栈的大小为1KB
MCU_SECTORSIZE =2048
—–指定扇区大小
MCU_FLASH_ADDR_START = 0x8000000
—–指定Flash起始地址
GEC_USER_SECTOR_START =0
—–指定用户区起始扇区号
GEC_USER_SECTOR_END =127
—–指定用户区结束扇区号
GEC_USER_RAM_START =0x20000000
—–指定用户RAM开始地址
GEC_USER_RAM_END =0x20010000
—–指定用户RAM结束地址
1 | MEMORY |
MEMORY给出了地址的划分
这里的名字USER_INTVEC,FLASH,USER指的是一段地址,ORIGIN是起始地址,LENGTH是该段地址的长度。仔细观察可以发现,在下一部分SECTIONS中每段结束后会有 >USER_INTVEC,>FLASH,>USER,这个意思是将程序的各个内容放在USER_INTVEC,FLASH,USER所指的地址中。
1 | SECTIONS |
SECTIONS实际上指定了程序的各个内容该如何放置在FLASH或者RAM中。
. = ALIGN(8);
—– .表示当前地址,. = ALIGN(8)表示从当前地址开始后面的存储进行8字节对齐
KEEP(*(.isr_vector))
—– KEEP防止所有.isr_vector段被过滤掉,防止被优化
>USER_INTVEC
—– 将.isr_vector段的内容放置在USER_INTVEC中
一般的程序中包含常见的几个段:
text(存放程序)
rodata(存放被初始化的数据)
data(表示初始化不为0的变量)
bss(表示初始化值为默认的全局变量)
text,rodata放在flash中,data中的初始化值作为rodata放在flash中
变量在ram中占有空间,bss占ram空间
1 | .malloc : |
段可以自定义,如上面写的malloc段,由于编译obj过程中不会生成用户自定义的段,因此在源码中需要指定需要特殊处理的段
结尾的>MALLOC
指上面花括号内的内容都放在第二部分中定义的MALLOC空间中。如果没有AT> FLASH
,那么编译bin文件时地址是连续的