|

我是老温,一名热爱学习的嵌入式工程师3 Y6 u1 |$ g5 l' D4 u
关注我,一起变得更加优秀!一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。
: ]8 t3 \+ b; |8 y3 Z使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。
: g$ k# d( J& Z, y7 G/ L# R, v
tl0wljn5hd464020406145.png
E2 | E$ G/ o. w. j1 ?二、实现原理原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。
! q" |% f) B3 [- N三、代码实现国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread
6 e g! I7 g! W+ J. E头文件接口:# [1 n( q9 E a. [' g1 f1 ~
本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:
+ a/ r! G# N$ Q% U" ]8 [) G/*) W; b, a1 j: K9 u
驱动注册
* O7 f' b2 u" f4 l*/0 M1 _, @- j$ u5 d& w
int cola_device_register(cola_device_t *dev);
, ?1 ?& z* Y% G* `9 b/*
% l& p$ p. J5 v* o5 h' k8 ^: |( ` 驱动查找* B/ T3 H8 {6 F% L: s
*/
# |& o1 {. P0 w' D) L6 x0 Jcola_device_t *cola_device_find(const char *name);
5 N3 ^" o& C" m+ h# R" ^+ w, P/*
+ k' |( S3 a8 j 驱动读
) b+ Y/ y7 h; a% z0 @! q*/
4 m9 N" p9 O: ?: j2 \4 Zint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);6 M0 u! G$ ^/ i- b* u4 K) c8 n
/*1 G' I6 F' ?5 k# }* Y# c
驱动写
3 f/ q7 p' E2 m3 g# z x2 [*/
B' ]( G- h f: @2 W, ^int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);" I' c: u$ A0 T( |5 y% i
/*. w( G+ k. x& `- }% r/ R5 a
驱动控制
, |: Q- D T' q7 S8 c*/
9 f: H& V! o% B* @8 |/ H8 Dint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);;头文件cola_device.h:2 s$ J6 y2 o( x! l5 @9 s
#ifndef _COLA_DEVICE_H_& g. k( s4 y; ~+ y' k' Z! g
#define _COLA_DEVICE_H_; E( v" R2 _/ c* i, H' a; j3 u
enum LED_state
: Y9 M) Q5 a) {+ v{
: V/ |: b T) \ LED_OFF,
6 r3 M1 u$ m9 @5 v$ [0 P LED_ON,
" n! T4 \. j0 ?/ A& V4 R& a' @. d LED_TOGGLE," Z5 v" v @" }
};7 y1 B/ p L7 P5 j) p; }0 L. P7 |& K
typedef struct cola_device cola_device_t;- n8 o% x8 P( q
struct cola_device_ops" \( U% r5 F1 T7 J
{: A% a! n4 H ~) }% ?5 S' @" U& N
int(*init)(cola_device_t*dev);
/ x" T% j" h% T! A4 i int(*open)(cola_device_t*dev,int oflag);
( |& x4 [8 n% J" } int(*close)(cola_device_t*dev);
1 R$ ^; V# p! N. F) _8 c int(*read)(cola_device_t*dev,int pos,void*buffer,int size);
- y/ D' C2 X3 g9 k& ]7 I% u int(*write)(cola_device_t*dev,int pos,constvoid*buffer,int size);
7 O; ~8 `. |8 @# q" o& f- ], F int(*control)(cola_device_t*dev,int cmd,void*args);! ?3 Q% p% `+ b1 F( w$ D' E6 Z0 f
};
6 Z# g) }* g1 t1 [- r: Lstruct cola_device
" O; a! W; `4 q2 Z2 f/ ~- Y- W{
% y6 \5 y& ^6 l/ e- c const char* name;
) I1 N6 N6 A H( m3 U- } struct cola_device_ops *dops;
& \9 D v; x( g8 O# ^ struct cola_device *next;! z) ~+ K" _, D# {
};% M: \; j, V: r/ I: R9 v" k
/*, k% K% J& @9 n2 i
驱动注册
2 T9 T& X; L I- F*/* V0 P6 F- P4 d3 R2 `* z
int cola_device_register(cola_device_t *dev);& L2 u5 J9 k& W; B6 ~( K3 d
/*
/ p& X3 F, O9 T# o: V6 o 驱动查找
: v+ A. u, u3 u- W$ _*/2 q. T# }6 @+ t/ }) T
cola_device_t *cola_device_find(const char *name);
% c) v5 d4 T6 }! O/*
, S: D6 \- k' ^! X" W1 _( q 驱动读
3 f" h4 A( c! V3 U# l) ]*/
3 }/ m" E) P" w# t2 Rint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);
' ?$ [1 L0 {3 I4 W; A* m& ]0 {+ ?/*. ?, F0 t$ n( q0 ~5 z( e! m, G
驱动写
5 p( `1 p' p: R7 @5 p9 y*/
- t5 @% N3 G! q+ p+ O+ {" t( eint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
3 y/ L3 H! w: t# o. g$ r/*( t) |7 `" u9 v$ b6 ?+ V. W5 Q
驱动控制
' G( V% [4 ^$ C" _6 V+ t9 A6 a*/9 A' `$ ]/ C e5 c' ~
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);9 p: Z8 Y' K5 u
#endif 源文件cola_device.c:
% i/ c$ }3 Z) A4 S#include "cola_device.h"
& v% F4 m! s6 c, F3 q7 f#include * S$ G) X) _# p5 R5 F$ ]
#include
; f$ `) R! K ^0 \9 bstruct cola_device *device_list = NULL;8 j; X0 j. U- j$ W" L+ Q2 K
/*( @8 O! m; _; M# {
查找任务是否存在
3 r0 U; Z" H8 B/ t% [*/
+ e- i; |1 o! Istatic bool cola_device_is_exists( cola_device_t *dev )
7 v) e7 W% ^# }/ s* J{+ {2 W. |8 A$ m
cola_device_t* cur = device_list;" v# m8 j' q4 C# W; Y
while( cur !=NULL)# E; N6 f) D5 E) S. _3 n2 i! D
{5 t" V/ l0 ~8 a+ t0 ]. }2 C# M
if(strcmp(cur->name,dev->name)==0)
4 H' P6 E* P3 p3 B" H# c2 G l {
0 a% m& a! a7 Q) Y2 y) H5 s5 s return true;7 G) \; N* J; t7 n" g& b& G
}
# N' Z7 z& k6 B# _* S! X6 [) P2 y cur = cur->next;" R' ~8 b: d+ d( S8 q2 C: B
}0 Q+ \5 C3 l: j7 E9 L$ \1 K
return false;, ~/ i* @% S5 ]$ t* r, g& K$ z
}' Y2 `1 _. D$ D
static int device_list_inster(cola_device_t *dev)) U( R+ r6 {# R' c9 B: H A* b% x$ V
{4 v! I8 ?3 T' _ L
cola_device_t *cur = device_list;- ^: }- B# b' D8 o1 f5 u6 {
if(NULL== device_list)
1 j3 G5 b3 k3 g1 U! e; k, Q7 }% c {: C% X4 A2 r7 E- z- K
device_list = dev;
, k, d9 A6 s5 d1 M) @: E8 \! ^( s dev->next = NULL;
7 O& {7 N" {5 j2 f- P7 U5 m! H }
% A' p! D5 l" y2 h. h* l* r0 v else; E# q/ G, o# b/ H- `
{1 {. F8 k# _6 R) Y0 i
while(NULL!= cur->next)6 E0 S# W# G; x# q2 H' c% U
{# @# r/ J+ h* _
cur = cur->next;5 K) g! p8 J5 k8 B& b: D$ q" y p
}
6 {) t% D# R+ c8 \4 i. h cur->next = dev;: t4 @# [% `8 u
dev->next = NULL;/ q( z3 ?$ ?& `( C
}
- s6 }5 V' D( w t6 o$ H return 1;/ d% C5 A. B3 `2 f- X+ p
}
" N1 Z+ h$ Z( e( ]- {% x2 J Q/** u7 Q" s W; P# d6 S, x' G
驱动注册5 t2 S& }: E5 s' H: y# U9 }* P& s
*/
$ I. ? J* K5 @" \2 _" K2 }int cola_device_register(cola_device_t *dev)! B& H6 N2 n( r n3 e( V( g
{& h4 o3 e3 ^% C2 b/ o( Z" T! g
if((NULL== dev)||(cola_device_is_exists(dev)))
# P {% x) P; a2 b5 G8 Q+ ?6 J/ u {4 n# U2 Y4 e# w( y( G1 l0 {
return 0;
7 k! X8 k r( h4 S& X" G }! v1 |9 a$ ?3 w6 o
if((NULL== dev->name)||(NULL== dev->dops))
; ]3 k% ~8 r' V) z' m {
7 q* V7 i, `& x8 I. F- r# e return 0;
; m3 m5 M( i* {7 q9 b }( T! ~. R( {/ I& ]5 m* o, S
return device_list_inster(dev);
% Q$ n4 f" L7 j}
) {' V0 O( v3 g9 B% B) K/*
( ` a* w; E3 m, J 驱动查找
& i6 x/ z2 E3 C! J; f*/& `' a; C+ A1 }( Y% V; [) ^
cola_device_t *cola_device_find(const char *name)) e& ?- m$ G; D' p3 n w
{7 h4 [+ N7 D4 f* q6 U
cola_device_t* cur = device_list;
- U# F8 H8 n1 a% Z; _ while( cur !=NULL)$ j1 }; ]( d r
{
4 S" g2 Q) Z' n$ W! l5 U7 I if(strcmp(cur->name,name)==0)
/ i7 A: y: H! D8 t4 u {! ^- |& D! b, i/ d/ v
return cur;
3 H1 e |) q( b, \/ ]4 d/ y) W, F }
1 o2 R* m) e/ } cur = cur->next;9 c" r1 I5 {# z: o x# [5 B1 c
}
! m+ p7 I( T* Q9 L' z6 l, \ return NULL;
; ~( [ L1 j! X}
; F- n2 b) ^0 i" S2 m3 t! _/*
0 _& d7 f- F3 W$ s 驱动读- ?, T/ s- }1 H, w
*// a& f' j5 p9 H9 I- o) Q. n5 H% m
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size)
4 k. p8 I% W. H: p+ z* w{
0 ]3 X* _1 W( U9 A' H( s; K$ m if(dev)
* g3 o( I( U. Q( c5 | {% L- z- \" Q, T% v' L) p
if(dev->dops->read)
# ` A6 {+ M4 e0 H# s1 C5 f {
$ `4 Z! W5 O0 @5 R4 m return dev->dops->read(dev, pos, buffer, size);
( T* _+ }; F$ L/ R }% |! k' L: P5 z
}
7 J/ [1 k* V( V# B: q return 0; B+ J& h6 T$ L; F& f" C8 y
}
8 X* o/ }& ~' x5 g9 j/*
) Y: @, U) t& S4 f0 V 驱动写, ^3 I$ _! u$ k7 a
*/
2 o8 B$ X" J9 d9 E" p2 q/ \% d1 Kint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)
( A; Y4 z- v% W* \{
2 T# N! F; N! Y8 ]$ |, ~& C if(dev)% b1 X0 Z" T: \6 {" z) L' s' P
{& |9 K5 x5 M, E9 F( j
if(dev->dops->write)
* t2 G6 Q4 H; ?$ b {
& F& S$ u, P, j: U return dev->dops->write(dev, pos, buffer, size);9 k+ K$ V+ Q3 \+ d/ n
}
- }) K! n2 S# {+ x0 ~& i! _6 o }
" b. y9 J/ h' s8 H4 O" O return 0;; G9 G6 }- T. T; k7 X9 u! D
}& {' R, L( u2 E" C0 J% n/ c
/*
4 u. F3 l- V e 驱动控制. b/ N; i8 E$ _( s8 a* x
*/
4 S# n2 T+ ^( u+ kint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg)+ r, d8 R' N/ l
{/ s, u1 B* X, r5 Z6 A8 Y( ]) e
if(dev)4 B; ?6 z. w% L8 | v
{
) k( t* D4 s D* v2 `' a" [: w6 S if(dev->dops->control)- n _$ |" Q' V2 Y' C
{# ~' ^/ l( x1 Y+ d' `+ F
return dev->dops->control(dev, cmd, arg);. {: ^! t" `1 D6 Q2 m5 m
}
' S" |; ` I/ z! I( ]* W# `5 L, i }
~- H1 b% G. E b return 0;5 g: d! U7 w; f" v9 y. N0 S5 v
}硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。
: z4 I8 F, ]* b! H3 N4 W#include "stm32f0xx.h"* q4 i5 m4 s }
#include "led.h"
* F$ H% @- T/ W$ ?( @7 ^3 v) J, R# {#include "cola_device.h"
' `$ p% c% A# f#define PORT_GREEN_LED GPIOC
8 z( y ^4 F8 C& C4 Y: v" v#define PIN_GREENLED GPIO_Pin_13
& |9 n: z6 R) A- u" A# r5 }0 D/* LED亮、灭、变化 */* y( [1 U& D7 |0 u; L
#define LED_GREEN_OFF (PORT_GREEN_LED->BSRR = PIN_GREENLED)
& I/ f" \: ~( j#define LED_GREEN_ON (PORT_GREEN_LED->BRR = PIN_GREENLED)
4 ~, u# O/ n& o$ _( k1 I, r#define LED_GREEN_TOGGLE (PORT_GREEN_LED->ODR ^= PIN_GREENLED)8 R& L2 ~3 N! F! v& J1 l
static cola_device_t led_dev;3 e ?2 n1 b6 ?: b4 Q
static void led_gpio_init(void)
9 d B0 ~0 |* [; J& O$ W9 v{: z8 ]+ V% F8 O
GPIO_InitTypeDef GPIO_InitStructure;+ z# o1 a7 I+ l5 D
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);$ p0 D6 X, F# `
GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;
- A6 G A0 _) v L( s GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
4 R$ [9 o- w" H: Y3 ] GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;# u+ w+ g' p! m" b6 D; A
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
1 c# `/ x+ h9 Z3 p6 C GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;7 h' H8 D! G8 f+ [. E
GPIO_Init(PORT_GREEN_LED,&GPIO_InitStructure);$ R8 S3 ]+ C+ F. S9 F7 o5 M: v/ c
LED_GREEN_OFF;8 l' h, ~: ~" I: y7 N @1 ]0 ^
}, r& G9 k; o5 @' X! s
! t( I" W- N; x. S( k$ R1 O$ ^
static int led_ctrl(cola_device_t *dev, int cmd, void *args)+ _2 z: Q% k2 R6 S7 i3 ^
{ s( S( _7 L5 _8 b8 F$ f0 G( k$ \/ Q9 k
if(LED_TOGGLE == cmd)) L$ |4 [, v6 V( m9 [
{5 E6 [6 ]& l- a$ O: w8 D
LED_GREEN_TOGGLE;* e' Q C6 n! Z" u G
}, j9 z Y. v1 z3 d9 }' @- _
else
: F2 s1 Q" `& g' k' B+ | {2 F! B$ t3 H! S- V3 O n
}
: X6 d# M# |4 f3 j2 v return 1;3 a/ r t! i1 d/ M' b) v
}
! g, o. V. |4 n% ?0 ystatic struct cola_device_ops ops =
( Q/ p3 H/ I9 `! q{9 ~/ V2 Y0 }# g7 V; Y( l
.control = led_ctrl,
8 r* Y! n, Z( @5 k( D};' s8 Y8 Y% R9 v8 K
void led_register(void)/ C( G# d9 L0 F/ |/ O g) Q
{" T& ^/ w3 ?3 g8 o/ {/ O2 a- B
led_gpio_init();
: W/ `8 T! B. I/ r2 ? led_dev.dops =&ops;7 P/ R1 R3 D" U* w8 J9 {. P) G
led_dev.name ="led";+ U6 v* B; @. i: P0 j) b
cola_device_register(&led_dev);% P: }; V4 V1 Q' e4 M: Q& V
}应用层app代码:
7 X* h1 ]4 u* W2 E9 X#include
" e: y/ _0 T6 b* r& g#include "app.h"
% W9 ?' s$ |2 ~6 y: e1 G5 Z8 V4 K# c& G#include "config.h"4 o4 q3 R, n- f+ V* O7 w' Q8 E
#include "cola_device.h"1 W9 k" v# ]8 c! b% M* b z3 G/ P
#include "cola_os.h"
4 d0 G( E% f) B1 c5 \& ustatic task_t timer_500ms;
2 j. h( o0 f; \$ J7 X" O1 A/ b2 Astatic cola_device_t*app_led_dev;
: W* C, N2 W+ X//led每500ms状态改变一次) T8 N( }+ @5 B
static void timer_500ms_cb(uint32_t event)
1 c3 J c8 u) W; u4 A. i{" a2 b$ l% F. K3 `0 k
cola_device_ctrl(app_led_dev,LED_TOGGLE,0);: o2 _+ L3 H% D* u; J; L1 c. n
}
, J# @$ y0 w5 t/ vvoid app_init(void)
1 L! V. L3 D2 o; X# D3 i{
7 c" g& d* _2 m# h; ` {3 E5 S' v app_led_dev = cola_device_find("led");- M# R* E& n' g5 u
assert(app_led_dev);
- |/ s6 R6 C& [% e/ a) ^: U cola_timer_create(&timer_500ms,timer_500ms_cb);
1 g) a9 ~/ K s cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);
2 z9 J/ G8 {" B}这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。9 l& X; c5 u! @
四、代码下载链接https://gitee.com/schuck/cola_os/ Y1 z4 |7 I5 x7 h1 J( m
原文链接:https://blog.csdn.net/ziqi5543/article/details/101512722$ n. @6 O0 b2 K1 K
-END-* R) \' M, T! o7 |
往期推荐:点击图片即可跳转阅读8 @0 D% ]; s0 g6 L: v( o
0 B% G3 i! J/ c+ U; I
: d# P( r/ C5 |0 p- i. G- m
1 ^' ^7 K# |2 H" H & V: M; n" D" a
y0jnszoy0hn64020406245.jpg
% S' d H9 {* L4 ^/ x6 g 4 N X* v# A: j7 l
嵌入式 C 语言的自我修养; h+ [2 T6 n' K+ [5 M6 r
! E) D! b1 [7 s, q% D 4 p( M' G! ^# O: ?
2 e5 D) C$ g8 L6 K
4 A7 |' N; B* [! w: n1 v6 Q+ _
43r33df43ip64020406345.jpg
; d2 m: `( h! g% S- _0 L( m: X1 V 5 H% l: E/ E, n c" V
被 char 类型的变量坑惨了!- U& \- y2 O( T
/ ] u/ T" ~' E
* f `: k$ G3 o! u2 [0 [; @, u
) g$ p' Q# f* ]4 @9 }! j
vcbyugpp1n064020406445.jpg
% I9 }% d6 |" H
1 M0 h3 g7 ^2 ~5 R/ g
嵌入式 C 语言知识点,动态变长数组' j5 o! v9 b1 A# i( S* ]
# U- L, p# C1 W8 s" l) M
2 {$ m K! B, y% r" H' A
9 P3 K! v. R ^3 ~ 我是老温,一名热爱学习的嵌入式工程师
" V7 H8 \0 E( h f; w关注我,一起变得更加优秀! |
|