. Y( z- o2 o) [& t# p led.h里面用到的位操作是在sys.h头文件中定义了。 t4 @/ b9 a# O( P: w
7 y! T! [' c8 `8 \/ a. m ' ~. w, v- W: w. i6 @; F, x) m" q 这个初始化代码看起来非常简洁,首先使能用到的IO口时钟,然后初始化相应的IO口。在初始化函数中一眼就能看出两个LED分别是PA2和PD8口。代码理解起来非常容易。 + m r: z# P1 |3 A4 ?% Q, n) b0 e( y/ D- ~& j
接下来看某火的代码' r/ D3 B! K, t" u" u
头文件 bsp_led.h 2 z2 ]$ }3 L$ X( h4 g; h+ O$ Z- T s4 X. ~+ H# v! A! |& W
$ M3 V* l; B9 h. O) E
% ^: ^' f' `3 @1 m ] C文件 bsp_led.c * n# a- u j, K0 l5 L, u- H2 T Q7 K
! S3 f, {- }0 l5 i/ _3 Q
/ h/ k9 X7 F% X$ l" B 首先从文件名字就能发现区别,上面的是led.h,下面的是bsp_led.h。前面加了一个bsp,这个bsp是什么意思呢?BSP即Board Support Package,板级支持包。也就是这个文件是和当前硬件系统有关的。然后在看头文件中的内容,发现在头文件中,把LED用到的IO口和具体引脚重新定义了一个名字。然后在C文件中初始化LED口的时候,用的都是新的名字。初始化的流程也是先使能用到的IO口的时钟,在初始化用到的相关IO口。但是从初始化代码中很难看出,当前使用的LED口是哪个端口。代码看起来感觉就比较费劲。 O+ ^9 {$ G3 y, q9 v+ G
, {$ G, o5 v$ L& v+ E) a: ? 为什么一个简单的LED功能,风格却相差这么大呢?这两种风格你自己的代码更接近于哪一种呢?从我自身来说,刚开始的时候比较喜欢上面的那种风格,简单明了,代码写起来很容易。但是随着写代码的时间增加,逐渐开始喜欢下面的这种风格。代码也由上面的风格逐渐转换为下面这种风格了,下面就分别讨论一下这两种风格的差异。. Q3 |) u/ |3 s4 l( A
5 @: }+ `# h& ]" t6 d
刚开始写代码的时候,第一种风格比较适合,写起来比较简单,容易理解,代码出现问题时查找起来也更加方便快速。但是随着项目的增加和需求的各种变化,就会发现,第一种代码修改起来比较麻烦,比如LED口发生了变化,那么头文件和和初始化函数都需要修改,变动一次要修改好几个地方,修改的时候容易漏掉有些地方,导致调试起来各种问题不断,增加了调试的难度。这时就想,能不能值修改一个地方,就能把LED口用到的地方都修改过来。此时就需要用到第二种代码的方式了。在头文件中将LED用到的端口和时钟都抽象出来,重新定义一个名字。在初始化代码的时候,初始化的只是是LED口,至于这个LED具体对应到哪个口,直接在头文件中定义就行。这时候初始化代码就不需要修改了。 ) R0 ] j3 p$ V- u 2 z( G" ?% r3 b8 X6 s( {3 ~% u 简单的理解就是,第一种方法写起来简单,针对的是具体的IO口,但是一旦项目发生了改动,修改和移植起来比较麻烦。第二种方法写起来复杂,但是是一个抽象的方法,它的初始化函数和具体的IO口没有关系。当项目发生变动或者移植起来更方便。 , o6 k j6 ~- e* Y) m ; ^7 x" K V# m$ [3 K+ m 这两种方法各有优缺点,可以根据自己的实际情况选择不同的方法,也可以将这两种方法结合起来。比如我感觉第一种方法的位带操作比较简单,将所有的位操作统一定义在一个文件中,使用起来比较方便。第二种方法的位带操作都卸载头文件中,写起来比较麻烦,也比较复杂。但是第二种方法把LED口使用的IO口和引脚抽象出来比较好。那么就可以将第一种的位带操作和第二种的端口抽象同时用在自己的项目上。8 e* y5 U/ p- F4 j1 B