|

我是老温,一名热爱学习的嵌入式工程师! q1 T* w N' ]2 c( g
关注我,一起变得更加优秀!一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。
! u9 _: g, O1 m0 ?使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。
( h' g/ i! }6 R! n8 E8 c, Q* X
z1mhjlnzuzp64016688011.png
& O S# }7 X& j1 A1 O二、实现原理原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。! g# P. i6 S- ]1 |" W% \2 V
三、代码实现国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread" n& H: n/ g& @& g( A
头文件接口:% o$ |6 {0 X7 Z5 a7 w$ Z
本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:
* S. _+ c7 `. |" z2 P9 c' `! {/*
! O; M4 f8 h4 j( K" c7 q4 s 驱动注册% H! T5 i6 z8 `
*/
7 ~, W t, C: _! V8 ]& {3 Q" yint cola_device_register(cola_device_t *dev);& h0 U6 H: h2 K- ^
/*1 N( v( O/ ^ W9 x
驱动查找! P( g/ X# l( o3 M. c
*/
L! p8 F6 l3 ?- f' y+ p* `cola_device_t *cola_device_find(const char *name);; q! e4 g' s. V p1 f' c
/*
. i; Y- S4 P, _) ~$ c! [ 驱动读2 Q4 @; J$ ]& G
*/% v9 s' f9 `' L/ T, I; d k4 F
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);% t" n( U J. w: m
/*
) T/ y0 a' B M 驱动写 ^7 p3 R9 u) C3 g6 x
*/2 B9 F' s/ I0 i
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
& h' \/ m3 D7 f- x8 C/*" C# z9 y+ A I3 _( F
驱动控制
. p3 U0 ?5 [3 s9 T! i F8 l" \3 v2 S*/
( L$ P) X9 e- ?int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);;头文件cola_device.h:; `0 k" t. r* b7 P& N
#ifndef _COLA_DEVICE_H_
7 b. _1 k( e% O: |2 l% i5 N#define _COLA_DEVICE_H_
: H* r- u: T$ k' {1 m; ^( u7 l$ xenum LED_state. Y" x% J4 Z1 e- t6 U* \5 y
{
Z8 V% d+ q. `! P LED_OFF,$ |7 R9 A, T, C/ R! ]" }
LED_ON,0 B) |, ~/ q7 D$ U2 E6 j
LED_TOGGLE,/ f9 C. m- K& ]4 b4 n4 W
};* ?: y; h" {! j& \
typedef struct cola_device cola_device_t;: T X: E5 C$ Q3 ~
struct cola_device_ops4 ^ m7 `& X4 ^( s6 N+ Z0 l4 @: b
{
! k4 e' x, N: l1 Z b4 H$ C int(*init)(cola_device_t*dev);+ R' H9 I, y3 ~0 d. C; ^# }. _9 Y1 Q
int(*open)(cola_device_t*dev,int oflag);
* Z, s7 ]5 T* I1 A( H int(*close)(cola_device_t*dev);' `1 F% T, `0 B! j% C& ]6 @& M5 B
int(*read)(cola_device_t*dev,int pos,void*buffer,int size);
z# `3 i# j7 y5 d4 w4 | n int(*write)(cola_device_t*dev,int pos,constvoid*buffer,int size);
6 y. y! Q: v- l0 I int(*control)(cola_device_t*dev,int cmd,void*args);
; g5 P# F* l' \+ n' F! a T};2 K. Z, ]% [( m
struct cola_device7 W1 [- x7 h1 V8 s. R0 @: t/ d
{. m: c2 e9 p9 J* D) K
const char* name;
; G( n% h! x0 q% x struct cola_device_ops *dops;
* S' d1 J& Z6 I/ ~) v1 U struct cola_device *next; h0 k5 }" M% f8 q
};4 }8 s5 d) v' `6 Z) d4 o# V* y
/*
! V2 X4 Z1 _9 m5 I" B+ w& o- S 驱动注册
- z; w- u( A g" L" r% I0 n8 F$ V, x*/' S; P9 L: I4 M& K$ g5 N. B6 J" N
int cola_device_register(cola_device_t *dev);
$ A9 B4 A& D0 a& g1 o/*
- L/ Q6 n6 i) [+ G) t5 \; n 驱动查找
' D1 P E, R: T& g# @- F# F*// H: F* l" }% b8 C
cola_device_t *cola_device_find(const char *name);
6 s3 I* `6 z% ?8 W/*% p- I, u' x" m, p" H
驱动读- ~# V6 X/ G! t
*/
. O1 A1 r7 l7 h/ ]6 j. Wint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);, [6 H4 V; q: [- B* ~3 H
/* c2 i5 h6 Z4 V6 Q. ]
驱动写
( T4 g, }& F- w6 M4 g1 _*/
$ q( m& Z) u- U \% Gint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);- o# D( ^" b, v
/*
5 [ h- s: t& h, f* ], `: a0 b 驱动控制/ D9 q( C6 ^5 A% {; U8 `
*/
9 w4 x9 v9 ?8 Y' H7 wint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);
# H8 B9 l7 p) t! p+ ]#endif 源文件cola_device.c:# V" k' @6 ~4 B# p$ q
#include "cola_device.h"9 M; O2 h4 l [5 \0 _
#include
/ H8 x% w0 {/ Y4 `2 h#include
% h& Q/ g: ?# y( e7 }struct cola_device *device_list = NULL;
5 l: C0 `% K" ?5 h( z$ f3 i/*1 c! m) z; u# ~
查找任务是否存在
( U: @/ E* p$ c5 E6 ~*/
8 L% W" F% w. W$ h1 g& \static bool cola_device_is_exists( cola_device_t *dev )7 }+ \0 Y4 Z& b
{& V% R9 k9 U9 f* z$ ?/ [5 }
cola_device_t* cur = device_list;2 a' t \4 q1 e) @: L( d4 M% Y
while( cur !=NULL)
, z# o) y- ?4 x: e9 V0 ? {
+ \, s2 B1 g3 J& o) m. q: j if(strcmp(cur->name,dev->name)==0)
" l$ Q% e4 z: G# T3 _, H {8 u- ]' U+ F$ L2 P# N5 R8 y# v+ l, `
return true;1 y M+ y" M6 O% w& b! c7 f
}, p& P) M% B+ c8 d+ R
cur = cur->next;$ E% h9 |: D5 R. W( G" {
}" O1 E4 i+ h# b8 w' {# m; x9 r/ k
return false;
7 j N' g+ [( [# J}! Z. p1 G- @1 L' d
static int device_list_inster(cola_device_t *dev)8 d9 j! p8 |" F
{1 }5 N( _! \4 P6 U! \
cola_device_t *cur = device_list;
5 t! Z/ D/ X3 ~3 M% e( B# o if(NULL== device_list)& u# p( P( l; c" D, w8 f/ V0 F
{
7 T3 d: i' l/ `8 i/ h device_list = dev;
: [8 S Q, O$ | dev->next = NULL;0 q6 @/ ?. f7 z5 a* p+ Z/ x
}
' a$ ~+ N* R& @9 X9 v% P else
6 l5 ^) `' V1 Z1 F1 ^6 H {+ U w& R' z1 \! p1 [- [5 e% k
while(NULL!= cur->next)
' k* H/ e5 c2 [! W/ S: X {/ H7 Y2 s3 I% ?( R3 o
cur = cur->next;
$ c. Y2 e6 C& @5 O$ C# C7 b3 R }0 U* y& e# f* B# W6 x$ F
cur->next = dev;/ g# W) x9 H- e& \% Y& M* L% V
dev->next = NULL;( T6 R: w" s7 ?$ z" o( _0 s
}
+ E- G: w! G0 [ return 1;, s: _/ u' L, C$ E) j6 M2 [5 n
}
' R9 r) z$ u; y T8 t/*
7 I2 Z; q" I) |- v 驱动注册- m; U+ V0 _2 o) Z" p0 @3 H" r& C
*/# d. |( G! M a3 V& A: |
int cola_device_register(cola_device_t *dev)
. {' p' H0 y- P1 v7 q/ P{5 _2 t1 ~4 R: G6 L2 j) n
if((NULL== dev)||(cola_device_is_exists(dev)))
# k+ F5 n$ E% L. w, O {2 y2 i' a4 {" H$ u
return 0;# N! v y: T, ^! A& e
}
) r& T: U# ^6 [ if((NULL== dev->name)||(NULL== dev->dops))# h3 ~# Q" v) H
{6 m( _6 q/ O0 _( d' O& w! C
return 0;& ~9 X7 J- p& |5 p" O' ?
}: i2 a( R6 M: X) L. r
return device_list_inster(dev);
" O3 F" z! k4 ]3 w! X, o}
7 Y" \ X7 I# u/ b8 z& a/*3 O2 [& b. K- Y' n; w" G% i% B) i
驱动查找' n* g8 v5 W8 Z- r, f
*/
7 H6 m5 W- H6 M k% {! dcola_device_t *cola_device_find(const char *name)
t/ t( R" j! N* T, t{# G7 i) F7 B& E L7 W
cola_device_t* cur = device_list;' w. ~8 l+ T4 N `4 B$ l( r: s
while( cur !=NULL)
M7 i! V m# L& t9 @* r {
! ]! b. m7 D8 T: ` F% J if(strcmp(cur->name,name)==0)
- ~% \/ W" t. U& L f! [9 j; @4 ~ {
9 q7 N7 H* A+ v: B2 S5 t' W return cur;# |* Q" ^) x/ ?6 ~% }
}
5 O* p- Z! L, l8 A _/ ^ cur = cur->next;
: B' d Q* S2 x* V- { }! c& @6 q! ^9 J7 z
return NULL;
0 Z, O$ _8 `! M}5 \$ q7 [! m+ j6 o3 r! a7 u5 g- U! l
/*
3 r( k4 L/ q. N" e- ~+ h 驱动读
: y$ j- { w& y J$ {: m*/+ Y# g8 t1 _8 V! j/ Q/ Z
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size)
) g* ]" o# A! p" N' |# Y{+ n1 k* B) l6 y; N+ j; l
if(dev)7 ]. a/ f& A B, r/ Z
{
* G: c# ]! C5 o, P5 X if(dev->dops->read)
: |! ~" p* {/ r: p {
! k( N& i0 R9 z1 X8 J return dev->dops->read(dev, pos, buffer, size);3 J0 X: f/ D- H+ `# f" C" W2 L3 g
}1 F, p* A5 d. s$ n
}
# L- ]2 r, ~! [3 i0 V' c4 @0 l1 O return 0;9 T3 R) r- v3 M$ p$ r5 ^- N; s
}& I8 |- m- H/ U6 I- R$ V* Y ]
/*+ ]. A/ y- h- T7 h4 |
驱动写
' f* T) N' U6 {# t& a5 X*/
$ h0 g& ^0 g" E: U( ^int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size): _! k3 ^3 J( W% Y, g
{) o3 r9 [6 T- {
if(dev)
3 v2 [7 a! i0 ~. x4 _' Q% {( H& m! H0 O$ i {
( w; i" D( b0 @- m& i; w- _ if(dev->dops->write)
! }* `& O& y y {
y7 f1 a5 Z0 i0 |! | return dev->dops->write(dev, pos, buffer, size);
+ y+ c; ` D) H }9 p- L6 q! Y% E' k
}' n8 O6 s( \7 q4 P: U
return 0;! p2 u) x" Z, C& R' K' Y( ]
}
3 m/ r9 t: z3 G( n& n5 t. P+ P4 m7 Z/*
3 v- U% P! a1 O5 ]7 r' d 驱动控制
- v0 X6 z! G; n& O5 L*/8 y$ @ M: N, O7 L+ q
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg)0 m2 @6 Y1 n7 `9 ?! l; M8 W
{
) l2 q0 l: z: P3 ~9 l if(dev) S; B6 U. M2 d
{
0 z7 m; @0 L g if(dev->dops->control)& \2 s1 `) m& t% ~+ O6 u h
{+ Y% f% Y# M2 v
return dev->dops->control(dev, cmd, arg);
# E. O/ {0 D2 g% b7 [ }5 {( u: i. }- \; f8 @0 @- S
}+ f# ^8 `8 u5 l
return 0;& O4 ~- D9 ]! x+ [3 Y' L- S5 C# W
}硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。
! s; b h4 K) }* y, k: J) I7 s#include "stm32f0xx.h"8 v+ o+ x2 v w3 I- ]
#include "led.h": u/ ?, g7 k" U' F* k/ Y
#include "cola_device.h"
% e5 @1 V! Z4 B* U1 o) q#define PORT_GREEN_LED GPIOC ( U! @5 @/ M9 c, P* [' v$ C- X% u2 `
#define PIN_GREENLED GPIO_Pin_13
% e" k$ R" U( e9 i, ~5 Q/ w3 l/* LED亮、灭、变化 */% K) ?* U n$ J' D, i1 F7 N/ G
#define LED_GREEN_OFF (PORT_GREEN_LED->BSRR = PIN_GREENLED)8 W x& p! l! t, z
#define LED_GREEN_ON (PORT_GREEN_LED->BRR = PIN_GREENLED)5 z" a, ` f' X, u" W! G+ t; ~
#define LED_GREEN_TOGGLE (PORT_GREEN_LED->ODR ^= PIN_GREENLED)
! o3 ~ w- P: n- |: |! gstatic cola_device_t led_dev;% ?, _# L& n0 p$ c( T& ]
static void led_gpio_init(void)
, r+ |: O0 i b1 u{
6 g+ P q& P2 f* Z' A GPIO_InitTypeDef GPIO_InitStructure;
' D, |# d/ s3 J. a" K RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
2 ^* v/ x% s+ l+ w& c3 B GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;
2 V! c. p$ m3 V1 L4 h& Z9 g/ I GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
% \0 s# h. @4 A- L$ T" Q7 K GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;- ? z3 U7 l2 Z6 L7 o
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;2 W. a# w9 [* }- \) r0 I
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
: O$ t! w8 c' [6 O, B( e GPIO_Init(PORT_GREEN_LED,&GPIO_InitStructure);
3 ?8 c2 ?1 u5 R0 S0 y LED_GREEN_OFF;8 @1 T9 H, ?& j. S
}4 x5 Q0 S) r& X$ e$ H
A6 C; [ g. \6 z# Bstatic int led_ctrl(cola_device_t *dev, int cmd, void *args)
3 d* I3 j8 T& O' A+ d{8 p! M: c: Q b5 ~% A2 g
if(LED_TOGGLE == cmd)
2 Y8 y: ^+ o) W$ B6 A" \9 O. T; B {8 _: g5 _1 {$ C) G# h
LED_GREEN_TOGGLE;# C, ^6 A; V% U2 ? ~
}7 m; `+ l5 b7 p# f
else
0 C- b( w! \& r) E/ W2 r$ C! u {
! Y. u( f- `: G } R# X, ]$ r( i. d, B X
return 1;
8 u: H$ I8 D# K* A. D1 y# X7 P& g}
) A: Q! _3 M* R( B1 X+ p$ Istatic struct cola_device_ops ops =
2 ~7 S3 ]- y4 \ m# e/ H{. l% Q1 ?- f( ?. @ V' s- s; r
.control = led_ctrl,7 V4 W0 n x% A5 L' u& [
};
& W3 d, b* y! S+ \) I/ K% x' G# Avoid led_register(void)
5 m9 Q; S& ?# Q3 C+ k |4 F{- d9 A/ {1 Z1 O: q- [
led_gpio_init();
2 M5 B1 ~% ?2 g, x' H. L led_dev.dops =&ops;' C+ q9 Q4 T, O3 q9 c3 X2 W
led_dev.name ="led";
9 L" r+ |! Z/ _) R8 a+ A s7 N cola_device_register(&led_dev);% I) N8 v6 b. A- c: }3 q: v, H
}应用层app代码:5 G6 D% U" z' F7 @9 f z8 a) Y) i
#include
, a" W j8 b* c0 o5 n, d5 k* u9 ]#include "app.h"5 ^* G `" j5 u
#include "config.h"
Z3 Z" e0 ^) J+ @3 Y#include "cola_device.h", g# E* |* F _# u+ l" j9 w
#include "cola_os.h"
3 ^% U+ {* U. \8 X& v) _1 Pstatic task_t timer_500ms;
) j& W/ G8 ~) ]9 k1 Istatic cola_device_t*app_led_dev;
1 c! s' `2 y1 }, P# ]/ e9 I1 P//led每500ms状态改变一次! N) A! k4 J" E$ V/ \
static void timer_500ms_cb(uint32_t event)
7 a9 p6 O, i. j) u{( v4 v' I8 |4 j3 F
cola_device_ctrl(app_led_dev,LED_TOGGLE,0);
- y5 v- `" {* @3 y6 D _% `3 v( V; o G}
, y1 J/ E) `$ p; |1 o3 Q1 e& nvoid app_init(void)
9 [& N0 v' K8 W9 U4 F{
: d9 L3 c6 {. R' z* x+ U3 k app_led_dev = cola_device_find("led");
; `3 g* q7 j2 c8 X5 R+ f assert(app_led_dev);. q. }% B% h8 Z+ Q5 O
cola_timer_create(&timer_500ms,timer_500ms_cb);
+ H7 E X# z2 i) J% ^; z- A, a cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);
! O& e8 b; ]$ _9 V9 {}这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。' z& {2 R3 Y" O- i
四、代码下载链接https://gitee.com/schuck/cola_os: S6 _6 w0 Q5 r0 i' G4 T" d
原文链接:https://blog.csdn.net/ziqi5543/article/details/101512722; l, l- P* Z5 F9 A
-END-
7 t. s2 G0 G, z+ j1 Q往期推荐:点击图片即可跳转阅读
) h( E! X, A/ p1 }* J
* o& q& I0 s7 ^7 V" u 6 C8 S9 q# g1 J6 c3 S6 E" d
4 ]6 I9 [3 p( ` _
8 y9 c) z/ m7 X7 j9 ^
tpmooidoc3b64016688111.jpg
+ x1 U! C2 i7 W/ {, N1 u( @% k. A; _5 ^4 h
' j$ I1 Z* H1 }) }2 c 嵌入式 C 语言的自我修养
. A2 U! x& O, _7 J' x( ~ . D- o! W+ S2 c3 _5 K8 a7 f
2 k' |" ]* I" z: [# c
6 m) d8 J! V0 C* k9 N! |
& X; m0 z+ N1 I+ O) z
hlim1ktnzbg64016688211.jpg
: i6 s! e2 v% V: [9 v
3 l. E+ [6 K7 x- P3 W# r 被 char 类型的变量坑惨了! L0 q8 ^& m; B6 _1 x1 M$ B: K
1 A. r: m z# Y5 S& V* }* y
0 U& g O: @& ?; ~- x ' u H7 k" j7 p# }! ^! a. z4 W
3lxaqgtm2wq64016688311.jpg
# ?! G) {8 `* k7 h. X
- Z6 Q9 \1 H4 I
嵌入式 C 语言知识点,动态变长数组
* D0 H3 j0 v! j- v2 F: B: G ! d& T5 }+ K; e
9 S a2 s/ A/ o* i% _# q
8 ]8 m* J9 S0 H5 a+ H! { 我是老温,一名热爱学习的嵌入式工程师
$ v8 T# A6 L, X. O% R( p. h# w关注我,一起变得更加优秀! |
|