|

我是老温,一名热爱学习的嵌入式工程师
; z4 F) o, B8 H3 {关注我,一起变得更加优秀!一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。
" A, _% \5 o6 |4 f/ g使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。
+ P) b" y+ M* y- k% R' }$ R% q
letrobls00s64019561532.png
. G, N& s4 x# `8 q f5 l
二、实现原理原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。9 d# e! b; t0 W0 B6 n
三、代码实现国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread
; G9 n+ E+ B' i4 A; v头文件接口:
- ~% z% x" h* @. B本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:/ u+ H' d+ b: a
/*9 L, n! I, J# ^% R+ W; N5 ^
驱动注册
: {7 g- S8 ^. a7 B. m V*/3 t! L# [, m" k, w" ^$ T
int cola_device_register(cola_device_t *dev);5 k8 N; ?, I% K! `* y$ j7 J
/*
& |# a1 P/ V7 _7 e0 V3 T9 u 驱动查找$ Q% f2 h8 @+ b+ n ]
*/
! G$ l, E' L H6 Y9 zcola_device_t *cola_device_find(const char *name);
7 d0 V) J9 j0 r* V/ I/*
1 I7 E6 S+ } L* @1 Q3 V ~* w 驱动读8 `' l/ K3 s! N4 m' Y
*/9 _; A; n" f; g
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);
" ^ `: I: E+ p3 [/ m8 g$ R$ M/*/ ]+ \( n3 A3 p' t; G
驱动写
+ ~* f; b( f4 _! M9 P*/; v. R/ A3 H4 c& x, Y
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
8 i% y# X. t1 y ~3 d1 H1 L: u/* s4 q( i0 Q! Y0 O
驱动控制# S7 A, W( {% i7 ~. t7 K3 T! j
*/$ R9 n$ a6 n8 F
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);;头文件cola_device.h:7 e' t9 E. `5 F4 @9 G( D
#ifndef _COLA_DEVICE_H_
+ Q4 I, U: z& l3 [: r#define _COLA_DEVICE_H_
4 X* s$ O! R O" Nenum LED_state
9 p+ \) D) n0 |( v9 c% D) c0 u q{
& f$ j. {! ~* G LED_OFF,
; a% A/ D) O9 O f' u LED_ON,& Z- a& @ w+ W" Y0 @
LED_TOGGLE,4 J, w, X/ j9 M$ W
};: t" D' H$ S# P% Y5 o2 k
typedef struct cola_device cola_device_t;) q! m$ U" M8 X9 b5 |" \- A$ @2 a- L
struct cola_device_ops
- k2 R( `! l% u2 M{& _3 o: @( U, v q
int(*init)(cola_device_t*dev);% a' M& J$ \3 v' d0 `0 n! @
int(*open)(cola_device_t*dev,int oflag);% E& d/ E1 T% ^) q
int(*close)(cola_device_t*dev);
( T5 O6 ^( T/ ~. B/ H: L- w int(*read)(cola_device_t*dev,int pos,void*buffer,int size);
* Z4 |; ^$ s, \! I" E int(*write)(cola_device_t*dev,int pos,constvoid*buffer,int size);
0 q( F- g/ h) \7 U' k' d int(*control)(cola_device_t*dev,int cmd,void*args);% y( I4 } v/ B4 a$ ^
};
; M8 v: I* h! t" \! Kstruct cola_device
8 P, r6 V2 V' R, c{
2 E( F; z6 ~$ J) ?$ a const char* name;+ M1 Q+ ~2 i0 x. {" ?. t g9 l2 {
struct cola_device_ops *dops;/ f6 A8 S5 d* e
struct cola_device *next;5 u1 g9 \7 X' v9 A1 b$ L; o, O
};
1 _) H/ p" w7 x% X' o/*
c, Q) Q4 y8 t9 f; B/ f 驱动注册
4 G4 L4 u0 v/ R6 ?# i1 \ S5 \( u*/
7 ?' X& `# R. nint cola_device_register(cola_device_t *dev);+ D8 X' n/ h A/ B- q/ e& Y
/*+ M" t3 l! `+ v1 V. L+ ]
驱动查找
: p+ K0 e8 e1 l3 B1 [5 i5 q*/
& K" j+ y0 [8 o) Z; E) M9 a. [; f. [cola_device_t *cola_device_find(const char *name);
$ S$ C2 l1 Y% i3 o! l* M: }' }$ L/*
: Y2 x4 o9 i U% o' M% o 驱动读
/ s8 Z, ^, d: K" m# |*/
) x/ d; p/ X8 k7 f, z- Eint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);
^% Z# v! x; D& O/ X/*
1 B4 ^/ J% b8 O) {7 n4 T8 ]7 ?: ^# N( P$ \ 驱动写
/ T4 B E) K( s*/
2 g' A: ^3 N4 Q Lint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
# I4 |/ l2 I+ W E/*
+ a* `( y0 t3 N+ G" ?! N( g 驱动控制
) f+ ^* G3 m1 r1 B( Y; ~*/
# ^4 z) O: C3 D: }( H& qint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);
/ p- m0 d8 M' C: a#endif 源文件cola_device.c:
k! Q* \0 v1 v) [( [, _#include "cola_device.h"
3 n# \5 C7 N' b2 o) `#include 9 ~ o v9 p3 T. d: o8 S+ G8 E% [7 q
#include
1 P% h$ n; g$ z# R1 E- vstruct cola_device *device_list = NULL;; [/ x: \6 w( t# ^; n+ Q
/*- G" U+ H. }/ a9 @0 m
查找任务是否存在
' Z" ~) K% u8 i6 c+ H( E$ J# U( ~*/6 o4 z: }1 U' y' L6 U
static bool cola_device_is_exists( cola_device_t *dev )* T% K' Z5 E- E, {
{
2 i1 w. `! h% W cola_device_t* cur = device_list;
8 k/ [: o3 ]* _+ ]9 D, T) q while( cur !=NULL)' h1 D: [4 P. r
{
- N- S3 \. R9 K0 Z g& c, P if(strcmp(cur->name,dev->name)==0)
e+ p/ u @$ R0 P* V. n: t, A; I {
% U8 Z. s' w! q4 q; I5 L' D& X6 U return true;& y; i7 E* a! W0 u
}
% C3 ^/ u" h# i6 A cur = cur->next;0 H! C P! m7 ~) f% R9 y1 \' v
}
2 F! P+ P$ v% R" | return false; A9 [! A' i: [; U4 A: {! R
}) P, r7 |7 K6 ~) q+ |
static int device_list_inster(cola_device_t *dev)
8 a9 s5 A1 {; U4 c9 t; s{; f1 {- L1 \( W- c
cola_device_t *cur = device_list;7 g+ x K9 i" d
if(NULL== device_list)5 ?. D0 u) N N/ u
{
! f W6 } L" s8 ~, K2 `8 q device_list = dev;4 I. Q; H2 K' G' ~7 s3 r0 n9 R! Y
dev->next = NULL;+ H K( i% G; D: k: N6 P8 m, L
}
5 V7 D! n' a( T2 L# k else
& V2 G j S$ n0 i- |* | {1 Z/ U; w- `: Z. ]2 }
while(NULL!= cur->next)/ A2 h6 @( ], d1 D7 B
{3 k: c0 Q; m/ S: }& c
cur = cur->next;
5 w6 z# G1 h# n+ E' v* l2 M }8 Y" m- A5 ~ ] u# b* x9 }
cur->next = dev;: G1 f- n! E K: }
dev->next = NULL;2 M1 E3 c! h# _- d& ?
}, e# x* y7 b* O; m/ v
return 1;8 s4 u/ O& h* Q$ R# J9 o8 L
}
/ |* p( W* {2 H- U- H e0 M" k/*
0 q' O3 |2 N/ T: \ 驱动注册5 o: @) n+ S! e; m
*/9 ]% a/ A/ k6 M! n. t4 O# J% H
int cola_device_register(cola_device_t *dev)3 L/ {: i: D# C, i' }2 O( l6 T4 A
{: l6 B5 w$ P P+ Y) j* b1 ^& _
if((NULL== dev)||(cola_device_is_exists(dev))); i8 x+ |( x' K6 K7 L- T
{
0 b7 g) o1 y8 t! o5 m* E. S return 0;
( C" A9 V% J: r0 s+ y }2 D& |- Q' G' X' o; S T8 _& Z
if((NULL== dev->name)||(NULL== dev->dops))
/ e) o: B+ A3 s0 ]- J2 a {
! c" W, u# A/ T$ A" U+ r5 e# ^6 D- a return 0;
. W- Z" \3 ~3 A) ]2 G! m }
+ r4 w8 `; v/ ^" p( K- _0 W return device_list_inster(dev);
' `# g8 R3 E: j1 d! J* Y}$ { i/ w3 A, q& @$ e/ L8 T2 C
/*
- u f9 t- |. a# r4 E" x 驱动查找
% `! u/ n, x$ t5 A L$ h1 _*/; |$ T! g+ `8 l
cola_device_t *cola_device_find(const char *name), ^3 n7 r1 X( A6 ~' n, G
{; q" w% n; P' c$ R9 h# Q
cola_device_t* cur = device_list;
j) h1 y4 U1 o: h7 u M$ E while( cur !=NULL)
5 @3 |; m2 l1 h8 h {
8 _ k8 D2 X% l. _2 [ if(strcmp(cur->name,name)==0)& j/ T2 M! J( D) H9 ^: ]( W
{
* N$ T" [; ^, P0 n: l return cur;0 g0 I- K- d, \- ^2 D% ]
}
, r p- b# @7 Q9 Y0 k cur = cur->next;
`# [9 M9 S+ q V& e V \4 ?$ |8 F } r* z0 F$ F% b* c
return NULL;
6 J7 u8 N! M0 r+ @* X/ W5 M7 q$ X: y3 [. \}% ~! W$ G5 u w: Z/ I5 ]
/*( S: r# ^8 d& H& |
驱动读
" c4 ], `; @4 E/ ^; S( h* S*/
9 L& B7 K; W" [) a4 a$ @9 Wint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size)' k- x; m7 J2 K! v: A
{4 s1 h) ]( I3 Q! x' U" P
if(dev)
& z. o/ l$ }+ u& V' ] A {% ?1 l$ e9 W8 y0 z
if(dev->dops->read)
1 _9 Q. u. W% u0 B$ O {
9 i' _5 [! Z5 F! \ return dev->dops->read(dev, pos, buffer, size);' o9 Q7 O# X. S% u0 V; }% X d: _& g
}
+ c3 T1 t) U2 P& j/ G. J: b }
2 B8 a: R$ X# Z5 S+ ]7 S7 ]8 H- h return 0;1 ? T* n( m. j# ]! R: ]
}$ R0 o/ f2 {! s$ G9 p) ~( W _4 @3 }
/* y9 o+ t% R9 S+ k: `0 A$ x
驱动写
9 g( A- p9 S2 e* O7 m% t( [*/
4 [9 _% H3 M- Y6 M6 r* L ]5 Pint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)
7 h0 v2 `' y! `/ K. B" p{1 F6 {: T1 v1 `9 ~+ c( P7 b
if(dev)
4 C" s4 A0 t" N* z2 } {/ ]) {0 I: ?% {
if(dev->dops->write)
" b; l D' y; q! U. e& E { q$ C6 i4 r3 U
return dev->dops->write(dev, pos, buffer, size);
" R9 h6 C. A2 G9 k' m }
. g/ K# b1 d* @3 S- B1 s; y }
4 _( _8 s+ t0 D+ m return 0;2 ?$ o) B, ]- y# r. M7 U/ O5 E
}
# h. r% {7 n2 T) t/*
' s, S2 Z* s; X+ B! V! L. k% U 驱动控制
$ @% Z3 e* n* M8 e*/2 X/ Z/ ^ p% B; @' O0 W0 L
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg)7 F; d; I4 p( C% u" y
{ Z9 s1 U, |6 h9 ?) E9 G' u
if(dev)8 R/ K+ l4 m: o. H: [1 ?" O
{$ U6 c P& \# M
if(dev->dops->control)
. A* e k4 `& H, I! \- ^! W {- K& |1 y( ?0 [6 J+ m7 i$ v
return dev->dops->control(dev, cmd, arg);
/ B1 ?" K7 ?, }; C }- j% r5 ]" h/ m2 K' @0 T5 Q
}! ?1 ~$ s% }1 d6 ?! U( W
return 0;
0 _) }0 S J3 f$ C; E}硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。
: N. X0 W) U1 w8 @6 a#include "stm32f0xx.h"3 ~2 Y( K6 ]5 d/ h; t
#include "led.h"7 k! H5 @3 G) O: ]% a9 P
#include "cola_device.h"
8 E7 Z# G, L% V5 N+ ~#define PORT_GREEN_LED GPIOC 9 k" k, o9 a/ {! V v
#define PIN_GREENLED GPIO_Pin_13 ( J$ j/ x, Z. T. \
/* LED亮、灭、变化 */
3 l1 F3 F S5 [0 {; i& m! Q#define LED_GREEN_OFF (PORT_GREEN_LED->BSRR = PIN_GREENLED)
" _9 G, B0 Q! _$ O( l2 i#define LED_GREEN_ON (PORT_GREEN_LED->BRR = PIN_GREENLED)
: S* j6 j# n0 Z M- [* a2 [! i#define LED_GREEN_TOGGLE (PORT_GREEN_LED->ODR ^= PIN_GREENLED)
$ r1 Z0 x6 b' O5 w; T4 |6 pstatic cola_device_t led_dev;" B* q4 p0 }+ f9 g) d, U
static void led_gpio_init(void)8 |, O2 c5 b1 \, g& ^2 j
{
' V) \$ v; [3 @8 t+ P: _ GPIO_InitTypeDef GPIO_InitStructure;
- |7 e( k' q( l5 p# y RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
, ~3 u1 O# q$ [; b GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;
. c! l! s0 N: E, G GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
- c7 {2 x+ |) G! A/ b. V$ K GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; h; l7 g, X8 c( k2 j. x* S$ r8 o
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
/ h! K. l9 D9 v4 N0 g; A$ H: `# B) B GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;' P6 Z# B# Y- N. {- \
GPIO_Init(PORT_GREEN_LED,&GPIO_InitStructure);
2 {" Y- p; q6 V8 T LED_GREEN_OFF;8 a. W' [9 x+ g' f, R' X, `
}0 D/ g8 r7 d! K. @( f6 _
/ G; u; q* F0 ?6 f3 K' R- [5 Q# Q
static int led_ctrl(cola_device_t *dev, int cmd, void *args)! a) a3 |5 b! d+ X" P
{ t1 G) O! E6 `5 m! ^% f% F, g+ j
if(LED_TOGGLE == cmd)
% `) P9 t8 ^) i# D R3 s6 g' {$ P7 h {
, X) }: l( ]5 ?1 G" v8 P LED_GREEN_TOGGLE;
6 ^% N4 P# a% B( D( S: O! R& G6 ` }& ]" @) T/ @1 W6 [% f V# ?4 {+ l
else
' [; v- y+ p% g {
- f& l/ Q# T+ B* Q) g% K }
' T2 ~+ }' V1 ?; L* t1 m return 1;
9 V7 M, }0 K8 H& e! x3 {& L}
- I" z& T# q C/ @9 E* ustatic struct cola_device_ops ops =
h8 A# Q8 J( t{9 F Y1 k4 d$ i, \% v
.control = led_ctrl,
1 T6 C4 K* a9 | ~};
1 y" `# c6 a- ~6 d7 S: x" evoid led_register(void)
9 c. |% h$ k$ T% r{
( n, {" m( \9 `5 `* ^3 D1 i7 E) ~ led_gpio_init();
% f! v! X( V- o, J; _) `# a, x led_dev.dops =&ops;0 A+ x3 v S& ~% U) b) n
led_dev.name ="led";
4 C; z" s/ t4 O( C cola_device_register(&led_dev); z: z5 H5 y5 L/ J! S
}应用层app代码:
* i2 |9 \6 C6 |% R% ~1 N9 ^: Z#include 8 ~) l9 \. B" w7 W9 ]0 u9 k
#include "app.h"
0 e, U! T$ t0 E% k! }#include "config.h"! B s- h. d R( p7 I( P
#include "cola_device.h": M) g7 l! b, M6 y( f* v
#include "cola_os.h"
) @' `, c% l D Q3 bstatic task_t timer_500ms;. N- E: Z) z: l1 n$ X& c5 `# @2 |
static cola_device_t*app_led_dev;
- g) m, E! i3 A/ g7 U4 b7 o7 |7 z//led每500ms状态改变一次' Y. [/ z- u) q( J
static void timer_500ms_cb(uint32_t event)
2 c4 `5 M, k- k7 V: I" A5 t1 Y! [{$ i. L: v) I2 G- j9 A4 Z
cola_device_ctrl(app_led_dev,LED_TOGGLE,0);2 Y/ Y2 B$ X, W% M, o1 F: j
}* G; @) @2 Q4 x5 k8 O
void app_init(void)
% @3 ^1 y" l* }{8 l2 |* @6 Q$ L0 Z
app_led_dev = cola_device_find("led");
( V3 p, h' t7 _3 ] assert(app_led_dev); c: R# q* R4 i F' W
cola_timer_create(&timer_500ms,timer_500ms_cb);7 B$ u+ r9 \' p; C
cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);
. h% Z% U9 A9 ?8 N, f- p}这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。4 D4 }$ n1 Q( L" L( ~1 h
四、代码下载链接https://gitee.com/schuck/cola_os9 _7 ~9 d" }% A) `! y1 n
原文链接:https://blog.csdn.net/ziqi5543/article/details/101512722
1 m3 A5 h4 ~6 H; ~& ]-END-, M8 D* T" S) W% V6 H: f1 K
往期推荐:点击图片即可跳转阅读3 l/ H% D2 a# B
# _: c) e1 d: C2 O* ~6 |
# \! @3 \' u0 B7 f. U$ C0 K 3 b( L; ?) T3 [1 [# ]
6 m; e& ^; _* o6 ~, ]. A
doqlo0cma3e64019561632.jpg
+ S6 n; k& O- ?5 j4 J * J# U8 _% r( P' q: U( T6 N9 @
嵌入式 C 语言的自我修养( @0 k5 D4 a3 i6 i& O1 h
5 }# B' ^2 [/ V0 H) S
7 }# {* \* r/ ? 9 v. X, ]0 C- F( `
1 e0 z- c4 E* I0 V
z24nisnagj164019561732.jpg
, S9 Z5 U3 M& O9 O; P
) _6 c8 T) Z) d" A" U
被 char 类型的变量坑惨了!
; q. ^# Y5 N' P' k9 E3 B/ n: { 6 \! _( D7 c, f6 \; F" X
# Y$ P( ~* ?4 W; W
/ z5 C' T% D! `% O7 k
mwber4x0eku64019561832.jpg
$ ]* ~2 H; u- J( U' G$ g
: _6 m+ m: i9 m; H$ \" B, C 嵌入式 C 语言知识点,动态变长数组+ T% ?, u( U8 r
0 E2 U' O0 m7 w" v
0 E9 q% I- W% [! l6 b: `5 @7 F5 t + l2 x' j1 z9 L$ v1 Z
我是老温,一名热爱学习的嵌入式工程师& E# d T1 d+ |& k! A+ s' P
关注我,一起变得更加优秀! |
|