在嵌入式开发中如何提高自己的代码水平 1 _$ y' p; `9 \+ G# C - V, G Q$ c" F5 i: C8 ` 在开始学习嵌入式系统或者单片机系统的时候,大多数人的学习方法都是自己找视频教程或书本自己学,有的人也许会掏钱报个培训班什么的跟着老师学。$ \; C2 y# E$ }# {
2 `( D( Q% g* v% y* v
当自己慢慢的可以独立写代码的时候,就会觉得已经学会了。特别是自己能独立完成一些简单的项目之后感觉自己可以出师了。慢慢的随着各种项目的锻炼,写代码的能力也会慢慢提高。写到最后就会发现,其实好多项目都是不同的代码重新组合,一个功能写好之后,在每个项目中都可以用。比如写好了一个串口功能之后,那个项目用到了串口,直接将以前写好的代码拷贝过去就完了,最后开发项目就变成了一个拼积木的过程。- G$ {/ w5 r8 x$ f6 z9 ^7 d- S
$ h9 K& C1 b0 {8 g/ V
这时候基本写代码好像就失去了最开始学习的激情,写代码就变成了一个体力活了,基本也不用动脑了,都是复制粘贴了。写代码的能力好像也很难在突破了,感觉到了瓶颈。这时候就很难找到视频或者书籍或者老师教自己如何突破这个瓶颈。此时如果想要自己的代码水平更进一步,要怎么做呢,下面我就将自己的经验分享一下。( \2 y, f, i. f) q* f% Z: N
; K/ ^! D+ q" D+ }( Q) V! V8 h" e$ s5 f
在自己写完一个功能之后,如果想知道自己写的怎么样,最好的办法就是找一个别人写的同样功能的代码去比较。看看自己写的和别人写的有什么区别。找代码的时候,不能网上随便找一个,因为你不知道你找到的代码是初学者写的还是高手写的。容易被误导,这时就要找大家比较认可的,代码风格比较好的去比较。我一般找到都是某原子和某火的代码。下面就通过一个简单的LED代码来分析比较一下。" D) H9 v* @6 Z7 ?, Q
* P9 @4 {5 E5 s) A
首先看某原子的代码6 v- I7 v% s% v
2 U5 P N; Q; i1 r8 e4 O# l. N- S
这是 led.h 的代码' b: w6 ? S( R. t2 F1 t% |$ r
" ~7 j" f+ Y8 `3 `5 j ' G9 o% J/ a" R 这是 led.c 的代码$ _ V' l- U6 J2 _. U* Z
; g I% M8 z4 ]: z0 x
# t. H3 ]) C# Y8 R led.h里面用到的位操作是在sys.h头文件中定义了。 ' B2 L7 A3 r2 D1 b! K* [" A* j8 f2 g5 D' C
/ A0 N5 y3 H& r 这个初始化代码看起来非常简洁,首先使能用到的IO口时钟,然后初始化相应的IO口。在初始化函数中一眼就能看出两个LED分别是PA2和PD8口。代码理解起来非常容易。 8 `$ W ]# s: y* L & w' l- c: ^) m' o 接下来看某火的代码3 P F, z6 t- a# V3 I L1 G, S
头文件 bsp_led.h " f# ~5 E3 \; K0 {3 ?' m6 l, B) B1 u$ S2 X& }* T3 `3 h
1 K& E6 y3 d; o: z* b L! s8 g Z; a$ b7 y
C文件 bsp_led.c 7 x$ Y- y1 ?% k5 U+ F( P. k& b I" g8 t J3 T7 r# h. g
: [% K! I0 P+ a: A) n f, ^ A
3 | Z7 X" n3 O% E- u/ [ H
首先从文件名字就能发现区别,上面的是led.h,下面的是bsp_led.h。前面加了一个bsp,这个bsp是什么意思呢?BSP即Board Support Package,板级支持包。也就是这个文件是和当前硬件系统有关的。然后在看头文件中的内容,发现在头文件中,把LED用到的IO口和具体引脚重新定义了一个名字。然后在C文件中初始化LED口的时候,用的都是新的名字。初始化的流程也是先使能用到的IO口的时钟,在初始化用到的相关IO口。但是从初始化代码中很难看出,当前使用的LED口是哪个端口。代码看起来感觉就比较费劲。 n/ s% d9 f/ v: h . W/ @ ^/ _" V* W 为什么一个简单的LED功能,风格却相差这么大呢?这两种风格你自己的代码更接近于哪一种呢?从我自身来说,刚开始的时候比较喜欢上面的那种风格,简单明了,代码写起来很容易。但是随着写代码的时间增加,逐渐开始喜欢下面的这种风格。代码也由上面的风格逐渐转换为下面这种风格了,下面就分别讨论一下这两种风格的差异。2 ?3 S0 u. W+ j& b/ h& s9 L: x
; c2 T$ z6 I2 F: w9 I; Z 刚开始写代码的时候,第一种风格比较适合,写起来比较简单,容易理解,代码出现问题时查找起来也更加方便快速。但是随着项目的增加和需求的各种变化,就会发现,第一种代码修改起来比较麻烦,比如LED口发生了变化,那么头文件和和初始化函数都需要修改,变动一次要修改好几个地方,修改的时候容易漏掉有些地方,导致调试起来各种问题不断,增加了调试的难度。这时就想,能不能值修改一个地方,就能把LED口用到的地方都修改过来。此时就需要用到第二种代码的方式了。在头文件中将LED用到的端口和时钟都抽象出来,重新定义一个名字。在初始化代码的时候,初始化的只是是LED口,至于这个LED具体对应到哪个口,直接在头文件中定义就行。这时候初始化代码就不需要修改了。 8 f9 r# z; I0 p& O t; n$ y 6 }4 r9 @9 ~$ @+ H/ J7 } 简单的理解就是,第一种方法写起来简单,针对的是具体的IO口,但是一旦项目发生了改动,修改和移植起来比较麻烦。第二种方法写起来复杂,但是是一个抽象的方法,它的初始化函数和具体的IO口没有关系。当项目发生变动或者移植起来更方便。 0 u6 T$ e4 O0 {5 B$ S# d6 W 3 g) @* u% T k. k 这两种方法各有优缺点,可以根据自己的实际情况选择不同的方法,也可以将这两种方法结合起来。比如我感觉第一种方法的位带操作比较简单,将所有的位操作统一定义在一个文件中,使用起来比较方便。第二种方法的位带操作都卸载头文件中,写起来比较麻烦,也比较复杂。但是第二种方法把LED口使用的IO口和引脚抽象出来比较好。那么就可以将第一种的位带操作和第二种的端口抽象同时用在自己的项目上。( b* m+ _ ]' Y# |8 V
( w9 l% {. G1 G7 K
这样通过对别人代码的分析,然后结合自己的代码,对比不同代码的优缺点,然后再修改自己的代码。不断的模仿别人优秀的地方,自己的代码也就写的越来越好了。如果感觉自己的技术比较好了,那么就可以去看库函数的源码,或者操作系统的源码,看看官方的源码是如何将不同类型不同型号的单片机抽象为统一的函数。如果哪天你看到别人的代码之后,一眼就能看出代码的优缺点时,那么就说明你的水平已经很高了,已经突破了自己的瓶颈了。 * P" @- M1 U+ y8 M5 Z, S' h. p- Z( Q———————————————— , R p n, _4 Q! E# T版权声明:本文为CSDN博主「嵌入式@hxydj」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 & k3 F1 p9 J* h9 v# m原文链接:https://blog.csdn.net/qq_20222919/article/details/126748702 / \/ V+ M$ ]( |# D. b. v( k+ O& U7 y
; W& j0 G7 [+ Y2 n1 C/ Y