本帖最后由 黑皮男 于 2017-5-24 19:29 编辑
7 Y5 B' d1 o8 E& E) L- O2 V/ o: W9 S. o6 X
基本情况: 手上已经有了好几块STM32,NUCLEO_F303,NUCLEO_L073,NUCLEO_L476,NUCLEO_F412。感谢社区,收集了这么多板子,满满的幸福感啊。之前也通过串口和NUCLEO进行了交互,但是在后续调试的过程中发现问题很多,经常死机。由于当时码代码水平有限,也就只能那样了,随着逐渐的深入学习码代码,相比之前来说,可以实现更多的功能了,也能更容易的理解各位大咖写的代码了。现在再来发表一片试用的帖子,这次不是使用一块板子,而是两块,L073和L476。所搭建的代码同时支持这两块开发板,实现了串口命令行。先来张效果图: {. J! k( o/ x2 h" h! O
0 M# p0 h* ]. O$ C代码结构:
1 A8 m) j! E2 f1 A( C2 oecode
6 v7 E. G5 E! r& B( r |-common
) J' p k5 F( I$ o8 l3 H, F |-drivers
) [, D! x8 C4 R& I |-library
: c) H1 `4 e4 g/ A |-OS* @ A0 M( q2 \8 m5 Z* g. p2 `! @
|-FreeRTOS
& e, b5 K/ C: b2 J, r- o) e* u7 u |-platform4 B/ h0 o5 d1 }+ b6 s9 W
|-targets
7 R/ X V. o- ~9 I |-TARGET_STM32L0
( V2 {5 W5 u8 X5 j2 E |-BSP
( I2 J/ m* o9 ` |-CMSIS
/ l& b0 r' z/ S) L |-common
+ @' z2 I1 [+ T; t |-NUCLEO_L073; A6 K0 R% q1 n: P8 [. H
|-STM32L0xx_HAL_Driver& r# B- ?& ~8 P! t" n( t
|-TARGET_STM32L4
* D& h: A- V% Y7 b6 w" m# O2 p |-BSP
; K% C' N: Y+ ^1 d/ Q1 T |-CMSIS$ b8 g7 K: ?. D' r2 e( E
|-common1 C$ e1 f" |* a- Y) E% @
|-NUCLEO_L4764 M, e# u7 c0 R
|-STM32L4xx_HAL_Driver
2 A: d- Y. j$ t$ R H& W8 x
$ ^$ s) f; Y0 C |-user
: q; `& _/ F) b9 l; _ 以上列出了主要的代码目录,借鉴了一下mbed,整个target来决定目标板。target目录主要是对不同的目标板进行封装,然后提供统一的接口函数。: b1 V/ E" }! C5 ~
所有平台相关的代码都在platform目录中,目前实现的功能有命令行,pwm,serial,timer,platform_driver。像mbed这样的软件平台提供的接口函数很友好,所以这里也借鉴了一下,例如pwm功能,有period_us,period_ms,period_pulsewidth_us,period_pulsewidth_ms这样的接口,对于使用很方便,虽然都是借鉴,但是这也是一种进步,看的多了,也就慢慢会写了,以后就会慢慢行程自己的习惯。
% f) A" T6 x3 |+ [" e 此外不得不说,前人都趟过不知几遍浑水所总结的经验,真的没有必要自己再从头走一遍,拿来用,这样才能更快的完成新功能,这次所完成的命令行是基于双向量表来完成的,这里借鉴了一下linux平台下的list实现方法,真的是太经典了,自己之前写了一些简单的链表结构,感觉很混乱,还是大咖们写的经典啊。' j8 K( l; J* `/ S0 D
命令行的实现:# F( k+ Z w3 j/ w& u. H
命令行其实就是对一串字符串进行解析,然后根据解析的结果找到对应的函数并执行。这个就是最基本的思路。- Q( \3 k8 ^2 w3 A
实现命令行可以分解成,字符串输入,字符指令和参数解析,命令匹配和执行这几部分。' s$ z* f9 s% s1 C7 c' k
先看一下命令行的结构体,
, P7 ^2 L& N2 i- w* e0 H- M q- struct ecode_cli_dev{ o7 e. C! G; m4 s
- struct list_head cli_entry;//强大的链表功能由此实现
( ~/ Z3 H0 g$ A3 q! L - const char *name;
9 G/ K: W! i5 \) G3 J* z - int rxlen;
2 [) X) C1 S2 P# W+ N/ ? - char rxbuf[CLI_BUF_SIZE];
8 r- Z! K0 c+ Y2 g* f0 v - struct stdioex_device *stdio;//由此获取数据的输入输出句柄& ~5 F/ Z: k2 i3 n
- int flag;
5 v1 C" l3 @- P2 w, Z% S* v/ h - void *private_data;//一些私有数据,尚未用到6 z. G: k4 L% p9 V; f A% I
- };
复制代码 然后是命令的结构体# g% M3 ^/ \" I o2 t. j) n$ ^
- struct cli_command{
/ S2 r" X- ?, Y3 p - const char *name;
* m1 Z, }" ^; u2 Q1 ]2 `1 Z - const cli_command_handle_t handle;
- _ ^4 j: } g - const char *help;0 ?: L2 V3 x) }1 h* }" d& f
- };
8 }% E% r* U& A& L0 V/ t: I- R - 9 V5 H; x, N% H' B9 i
- struct cli_commands_list{
# S5 \8 G% X) A' o - struct list_head entry;//强大的链表功能
& s( Q/ R* P. ^+ {! d1 m - struct cli_command *commands;
$ C7 j3 X2 V, j1 A - };
复制代码 $ S$ l+ D, K0 A3 c0 n! o3 L' Z
( L' y! x) ]3 R ?
接下来看一下命令匹配部分,(又开始贴代码了 ),list_for_each,强大的list由此开始,首先是串口数据接收,接收完一行数据后,解析出指令的命令名称和参数,命令名称传入此函数进行命令匹配,如果命令名匹配成功则进行执行相应的命令。这里的每个链表节点都是指向一个命令数组,每个数组中都是不等数量的命令。
$ f4 c- a" `3 |( c! O/ j* _- struct cli_command * ecode_cli_match_command(const char *name)7 F/ @) m" R: A& y" T
- {
& N* O0 \, M" F, ?( [+ [ - struct list_head *commands;
* [7 P: f$ N2 l* z+ G - struct cli_command *command=NULL;
# Q! X4 q) U; ~8 ]% f# x - 5 K! @! r) j7 X' J
- list_for_each(commands, &cli_commands_head) F* d, C+ a/ z
- {( S% m' J0 f! K, k
- command = ((struct cli_commands_list *)commands)->commands;# T5 A2 |& J8 f
- if(command!=NULL): {1 g9 m& \$ @9 e' L$ G
- {7 r5 U3 w: ]- u( N3 ]* s5 G: g$ X
- while(command->name!=NULL)& \1 j" _2 L, Q$ Y
- {7 z; ~" T a7 w3 [
- if(0==strcmp(command->name, name))
& P1 _7 q. H" O7 c7 { H$ K - {
9 q; q6 }8 F, G7 U k- n( \ - return command;* M& h" N* k) Z9 r8 x/ }
- }
# U: R# N, l) I5 Q8 x - command++;
& Q: i8 x; d0 {) D% E - }- B2 h6 t1 P4 p: E" B1 h7 Y
- g9 K% c5 \) I0 v! w K
- }- u! Y3 `* B ]: n: _( i4 ]: R$ |$ e
- }
A: j& R# F; ? ^$ d - return NULL;
" Z" q( X6 O6 [* X- c - }
复制代码
: i3 ~6 u4 `& a# `, y! N$ R7 u, u$ [3 S) u; ]7 D
完整的代码放到了github上了http://github.com/ArnoYuan/ecode,有点大,就不上附件了,剩下的代码也不一一介绍了。
' f" z3 Z) h- a" v2 P2 z: M; o$ Z+ j: l6 S- h C+ l
非常感谢QianFan (相关gcc+makefile编译的帖子https://www.stmcu.org.cn/module/foru ... 53&highlight=ubuntu,虽然是在ubuntu环境下编译,但是windows也可以搭建出linux的编译环境,需要交叉编译工具gcc,git附带的linux命令行和mingw的make),参考了其相关的帖子,支持了gcc+makefile编译,同时也能够使用printf,只不过nano.specs目前还不能使能,虽然我的makefile写的不怎么样,每次都会重新编译,但还是能用的。, q+ A/ w2 N* R& K0 t0 t
* |9 @) s; _* J
; L8 @# U0 P& R# n9 _0 o: E2 F4 I7 q+ j& h$ M# V! Y# T
' v# e, x% I1 `
|
这个还是有的,只是简单的回显,没做过多处理
其实uboot已经支持stm32了,可以弄一个
可以 考虑一下