|

我是老温,一名热爱学习的嵌入式工程师 v% S/ s; [: \
关注我,一起变得更加优秀!一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。
% h( K6 P8 F8 ^# O! c* l& |使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。 K- R) z4 _2 u% d* F0 F/ p
kgq5x1duezb6402851105.png
: N- V8 C4 U" b- ~% {1 y# P5 M) j二、实现原理原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。1 @. k' w: n8 g, N
三、代码实现国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread% M. C! i4 x9 _1 L
头文件接口:1 J, X: K0 P# B* r1 F9 F
本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:
$ ^0 t* a: l) _& w: ~* V' ]/*: x7 T0 j: W: W' A' Q9 f4 P: E
驱动注册
; [& }" h% L0 u, t; z: L- w4 G*/; c8 b9 C& Q3 x! l$ V9 S! I# h
int cola_device_register(cola_device_t *dev);3 U1 o% s! ]0 d; E
/*
3 I1 I r, g- f, u 驱动查找
- t5 D3 w4 X2 S6 V*/1 _2 r* V' g2 n
cola_device_t *cola_device_find(const char *name);
' g/ E0 r) G @5 ^! v8 R9 L/*/ W# U y4 @; x* _. Y4 j" M7 `/ C
驱动读- y" u! v* j( `- V
*/
) ^" [0 G) v1 I8 \6 G! ]int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);7 P2 d8 F5 f( }, w5 q
/*% k( L) B# D7 Q7 R4 l6 H
驱动写( o0 l v- }( V
*/
, W9 L" F4 x. k( o# |& V6 Nint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);8 u- O7 U! o$ ^, {/ G( `
/*( W' Q. M/ M. `5 D$ q! N% ?
驱动控制& ?) {9 p1 B- ]5 g0 Q3 i2 P
*/4 ` `9 y9 ?- e# J; [
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);;头文件cola_device.h:
7 G7 I' a) M* U#ifndef _COLA_DEVICE_H_
" j0 O$ O9 x' `$ R6 m#define _COLA_DEVICE_H_' q8 w5 }! V+ P q3 z
enum LED_state0 U3 n4 g0 `8 y
{
; i$ f: @* c% A# N2 b+ n7 F) \ LED_OFF,9 L5 k6 _) ?: V/ ~, Y3 w U
LED_ON,
, E/ _8 r1 X: c5 H LED_TOGGLE,
& [) e+ X2 E- _7 w# r% v9 ]6 w3 u( U};
1 r! ~: [0 }: z& Ctypedef struct cola_device cola_device_t;9 G* u/ X& D5 P) V* G2 I6 c
struct cola_device_ops
5 L0 [ k3 r' n: `: P, C5 A4 k6 ^{
! b% j1 _# s9 B) n' v' s int(*init)(cola_device_t*dev);
/ u# B* x! S& g; X9 K; ]) V& Q" X int(*open)(cola_device_t*dev,int oflag);+ [: R }* v& X
int(*close)(cola_device_t*dev);' H, {: \0 x2 F/ s# F9 d( m3 K" h
int(*read)(cola_device_t*dev,int pos,void*buffer,int size);
: R, u% f1 u* o$ T int(*write)(cola_device_t*dev,int pos,constvoid*buffer,int size);
, Q$ X' `: e- g3 b: _7 d int(*control)(cola_device_t*dev,int cmd,void*args);; Z$ |# y" I: t" o9 c+ Q( D3 n K$ A
};" y) k1 g5 `9 ]
struct cola_device& E5 j! e! l+ D$ c/ q+ I) h
{
1 H! P( _! T2 M. |0 B const char* name;$ g% ~. A) [) ~3 u
struct cola_device_ops *dops;
6 ^9 I, c8 A4 Y5 N6 u5 ?& i3 q struct cola_device *next;
5 o2 r: O8 g4 A4 k) f7 L};3 x/ Z: \" Z% C2 z0 |
/** }* Y2 i+ P6 v
驱动注册0 Z+ Q- y W" Y
*/7 m- t/ `0 P" z/ Z4 b# v# `
int cola_device_register(cola_device_t *dev);
2 q# z% V" N( @& {4 L0 H/*
3 S( c4 k) h3 b. h( B5 W0 T& b, S5 | 驱动查找
4 R8 n. _4 N/ F4 ~2 _*/
9 _% V* T- q4 y9 ?8 |9 Ncola_device_t *cola_device_find(const char *name);- e# P8 X5 U5 s5 T
/*
% ]# d; R" w* B2 Z. R 驱动读, M7 {. r6 Z8 ^( e r
*/' B0 J) H7 s8 u! g6 G
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);
/ L3 j Z3 G8 \5 J# _2 s/*$ k, ]7 t0 ^2 P5 w$ H: |: U d
驱动写' w7 j2 D; A1 _* r& T
*/
# z+ k \ p3 e2 K% E$ U# Mint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
& `5 b; o( S% O n" C: V. _/* q* o: l* a4 B9 F
驱动控制
7 `5 F, V7 `# e5 H; L% r4 [! [*/
0 e2 q$ E9 J$ Z* lint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);7 P" I8 |; ]0 Z- l# E ^
#endif 源文件cola_device.c:
! \6 a$ V( [1 d#include "cola_device.h"
% K2 c2 V9 g. }#include
! X* S% @9 {& {0 Y% w3 y#include
0 s! C: x0 e7 m+ astruct cola_device *device_list = NULL;
3 \6 U0 _7 O9 F3 l; k1 h/*6 ]2 a4 S* c5 s
查找任务是否存在
X, ^8 ?! R& l( K. G" Z*/( a' e8 Y) [6 H4 s! t
static bool cola_device_is_exists( cola_device_t *dev )
3 }, x2 F: E3 \$ U. D0 [{
) t* o: `9 b* l d! l& X cola_device_t* cur = device_list;4 e2 X& f* W9 W1 T
while( cur !=NULL)- T% q( C6 x% {6 }- I% u# l
{3 H( B1 }3 q& }' P. _! R
if(strcmp(cur->name,dev->name)==0)
- b, B2 n( b U( e$ w {4 t9 |8 l6 Q; p( Q" A) w
return true;
; o4 I+ ^& [7 s ` }% _) [2 m0 D. m/ m1 S
cur = cur->next;; d4 x% I) P# K9 h$ O9 o/ Q
}
% @. s1 i F7 ?+ T3 s+ t return false;
# P8 M3 U0 ~$ Z9 J}
9 J% ]! n6 X: I2 m3 n0 X1 s& astatic int device_list_inster(cola_device_t *dev)6 K1 b9 T1 i1 l: k3 k' R
{
( @' t s! J* ?$ H) G cola_device_t *cur = device_list;$ g9 E5 _ ~9 Q- W9 B l2 X/ x; D
if(NULL== device_list), O, ]+ M8 _7 Y4 v, l% b6 [# ?
{. z2 a5 F/ k. a8 d- w8 Z+ }5 U
device_list = dev;
' o! t& l3 L9 z* M. N F dev->next = NULL;
/ K8 O2 I1 C9 l8 X$ K( b }: I/ h1 Y. r# v+ p. ?
else4 z7 ]* _ Y' m# ^1 U2 z
{( }" }& |: |9 S% p, [) T
while(NULL!= cur->next)
! K- f8 n. w/ }8 j" N {8 u# s: p: v5 ?* n6 T
cur = cur->next;
" z2 {9 F! W& o/ W/ {* g' V }1 G: ?9 N( P' ?& b5 n
cur->next = dev;
7 m; e$ [, P A* H dev->next = NULL;
' u: l( g4 W8 n }: P9 B8 h' Y- d
return 1;" a, s$ y$ e2 Q' Z
}' t5 }% c/ y* A7 ?1 p+ {
/*: \' J% j8 a* S; y& x
驱动注册" p( y3 L8 v9 l; \! P, c
*/
' H0 l, q4 ?& q3 [; N# lint cola_device_register(cola_device_t *dev), S3 t( x) j% f4 \3 w
{
6 S1 A( ?9 m3 b+ ~5 u6 v) { if((NULL== dev)||(cola_device_is_exists(dev)))
( g4 O" K3 Q, N- {) i {1 X1 W3 S' l/ m" q
return 0;! W8 p. Q9 {9 P
}4 M. L. r/ J% w3 C9 r2 j( z$ u
if((NULL== dev->name)||(NULL== dev->dops))0 F. o% v" \# X1 b/ P
{5 m2 v M( F8 l2 s2 v6 K; w' |
return 0;
" P" o% f: A- @: A) W A }+ k" T# b/ L7 d) [. U! H `
return device_list_inster(dev);9 M# t( v! D9 p% n" S& n
}: u K. z/ l7 c, M+ {7 c
/*
% |/ \) R: y/ @/ a1 m+ O$ B7 G7 ] 驱动查找. y2 T8 a$ ~1 L6 e0 r3 I ?
*/
2 j: g7 C* G$ L& acola_device_t *cola_device_find(const char *name)
: P" r, I" d0 L7 S3 `: J0 H; w{
( { V5 ]! K( h9 w cola_device_t* cur = device_list;7 {9 _) S4 H! _# p' }8 _9 Y' ]
while( cur !=NULL)0 T5 F s1 w( G4 R' [: P7 s
{ g% J' M- D! N: ?: Z) M( v6 S+ d
if(strcmp(cur->name,name)==0)
! K- H# H( j2 S9 T) R N' ] {- s7 q! s2 n, I( n( e
return cur;1 F) F% w* H/ O4 Q" V/ F
}+ a' m# ~3 j" }" e) j/ S
cur = cur->next;0 o+ {* l' G! ]: n; I/ b9 |# }
}
/ {! ?8 J8 O# ]# m return NULL;
7 O" `) |- k- ?/ i3 J q: J4 o}# g+ X, k8 d, _
/** u; P1 [! ]1 Y& k1 [% q9 x
驱动读6 h& u5 j4 v9 ^% _0 U- y7 L
*/
/ a l4 H1 G7 l$ r4 dint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size)7 i+ d1 N# p" @
{- \( R. i+ m& k& T5 p; }. \
if(dev)
7 n* i3 n# P/ A; ~7 U7 U# a {
7 n* l% I9 O2 u4 S5 \2 C if(dev->dops->read)
7 [/ }7 Y7 o8 G9 o* N' { {& P( a. j. }9 y \; i+ ]
return dev->dops->read(dev, pos, buffer, size);
! K% ?0 N: Y4 ?; c% `3 q9 V; g+ F% ~ }
, v" X. z- Y$ }0 A% m }
$ I" v9 z: j P6 l' r return 0;
, ~+ L4 C) p% G( g' J5 D}
" H+ L$ w/ y! [5 L/*
4 F) N, G* E3 ]( b# b 驱动写
- j* b0 A" I0 _0 ~% C5 P*/, J3 P+ [8 \0 f' L, r. M* L4 N
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)* B0 s; U* u* z- x1 G
{2 m" i2 A e( R/ m
if(dev), J: E* q7 |" A# L1 C6 q' p
{
& f0 v" X7 W4 e' K3 w5 P2 i0 x if(dev->dops->write)3 a* n8 {. ~8 N+ M
{0 r7 ]1 p! ^. ^$ b: U
return dev->dops->write(dev, pos, buffer, size);0 O5 V/ [$ q) H2 {
}. G, j% t& o) M/ h) k* r; r
}
8 J- U( J1 D5 G9 U0 ~- ` return 0;) n! z4 ~) W9 S0 A) A
}
: f: ?+ v9 E% v" Y% ?4 Y9 T( |/*5 q$ P# N, t! E% z9 G6 P
驱动控制, t4 ]( `; a' }, c
*/
6 W" @. d5 M# w& Hint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg)
, |7 W6 {; |6 b% C" p. {9 z. H{" _& R6 P9 j% v, P* j8 i% R8 F
if(dev)
) k& `% Q4 Y1 ?0 T; M% `: L {* z5 C5 P) C7 @4 D j
if(dev->dops->control)6 e# I) E- x' s0 D0 v) k
{
6 W8 A1 {( X( g: L4 v6 S6 i$ r return dev->dops->control(dev, cmd, arg);# {* O! _4 O* a/ x$ B4 J
}
* t2 U8 |; F& \* e }
8 d$ Q9 ~. g- f3 r3 X return 0;3 t6 Z& t6 B8 b' u( h7 [
}硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。
$ K* x7 Q+ W2 q g; H* L- W#include "stm32f0xx.h"3 l; h8 X+ {& P) X% o% ~+ `
#include "led.h"" G2 O4 ~4 Z' X+ j6 C h8 o
#include "cola_device.h"
$ B' V9 J6 h+ R0 m6 K9 K) Y#define PORT_GREEN_LED GPIOC
0 W" |4 F8 k! T# L0 z#define PIN_GREENLED GPIO_Pin_13 ( R# b2 f2 l! P }" ]! K1 F: F& h/ B
/* LED亮、灭、变化 */( _# z) ]0 t8 o; M: r/ Y: L! d
#define LED_GREEN_OFF (PORT_GREEN_LED->BSRR = PIN_GREENLED)* W. u/ J- Z! x1 T4 ]# p) L* c- @
#define LED_GREEN_ON (PORT_GREEN_LED->BRR = PIN_GREENLED); V7 s! f9 V6 V/ W' `& @
#define LED_GREEN_TOGGLE (PORT_GREEN_LED->ODR ^= PIN_GREENLED)
1 D) z2 @" J8 dstatic cola_device_t led_dev;
" ]/ }9 j8 ~* q: }% P6 ustatic void led_gpio_init(void)8 X, [0 A% o/ q p% ], F
{0 d8 |( s0 k/ ^) m
GPIO_InitTypeDef GPIO_InitStructure;3 }1 t$ l, u$ X, [8 |
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);+ x1 k% z. R: Q0 ?% H' r1 y
GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;
$ E9 G/ D* v# B) V- i& y* j GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
; |. Q7 Q9 d. T' w GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
2 R' x3 ]% W5 I- }0 R GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
) {4 W/ b6 s5 @9 u! \4 v GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;$ k) o c; @+ _) u( B; X
GPIO_Init(PORT_GREEN_LED,&GPIO_InitStructure);
) r# E" U* h9 m$ |2 c3 ? LED_GREEN_OFF;
' L2 i# q7 y& g( k}; R6 |+ R* V5 _/ u/ `+ n
4 E, D! N4 }% C1 g, x
static int led_ctrl(cola_device_t *dev, int cmd, void *args)8 {& W4 j' o. m% x' t
{
+ W4 n7 M' ?) E3 v: i8 e if(LED_TOGGLE == cmd)
& h. I' X. X0 W: [6 {4 _. j {
& r( b7 o" h" q9 M8 _) m LED_GREEN_TOGGLE;
3 W( R2 F7 C9 M" j" {, V } R4 h6 ~# i2 C U/ A
else
& _ Q0 L/ [8 }( |9 J" z+ u; x {! j) d; k" ?* D4 @- R. q4 X2 b
}
e. i$ G. u2 j# B9 o/ t$ T return 1;- }% L* G: ?1 Z; z! d
}
. o$ ~9 d* ~0 e# R) \static struct cola_device_ops ops =+ {6 ]; H) x+ ]) j& J4 D
{2 {5 l) r7 {: X( \: `& E. V3 `
.control = led_ctrl,& |) f9 d' Q! v( m7 v
};. P. i" o, e$ _# X' r- M
void led_register(void)
- v" O4 ~) P) O) `* D. @{4 M- k3 F5 R6 I0 E6 @3 b/ M
led_gpio_init();
1 |$ o$ |) }: s/ g" Z# | led_dev.dops =&ops;! J1 N$ c/ v# Z; B5 B
led_dev.name ="led";9 j9 @/ \* D/ ^: ~7 }7 l: h
cola_device_register(&led_dev);+ \# |1 H1 f; o+ d' ^- g6 M
}应用层app代码:) N; i. a* ~$ D5 ]$ z5 J
#include
# ?* [ w( Y9 t9 K- ~#include "app.h"
& x5 n3 e6 H& Z# g% K: k8 F#include "config.h"1 w: g' `/ `1 M+ e* M
#include "cola_device.h"
7 ~% C9 m" v% e3 ~$ T @2 q- Y1 v#include "cola_os.h"
. Y2 F5 L- W4 u" [& ustatic task_t timer_500ms;
; p3 D8 b+ C5 g8 k: g. {7 Istatic cola_device_t*app_led_dev;
; @/ O+ ]( C/ i$ X) V" d//led每500ms状态改变一次
1 f! {* J" [8 M# \- \1 Estatic void timer_500ms_cb(uint32_t event)1 s2 V) ^; o8 z9 K
{1 A" }1 N0 o% [# u9 V
cola_device_ctrl(app_led_dev,LED_TOGGLE,0); ^# c# c2 p4 m
}
' P$ f9 H2 k* q: G4 u& ^$ Lvoid app_init(void)+ _' F2 H+ u2 `
{
" }; z$ V, q# j# T% k6 H0 J$ a app_led_dev = cola_device_find("led");+ O6 ` i. T9 z* K2 G% C3 n
assert(app_led_dev);
, O% v- a( G( q# R; u cola_timer_create(&timer_500ms,timer_500ms_cb);
& f9 E: ]$ e l cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);6 U3 N# V$ k" Q$ V8 t* F# p
}这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。. { a7 L9 k( @ L) u0 j1 [8 W
四、代码下载链接https://gitee.com/schuck/cola_os
* C3 g- s4 t! w& a) J# G# e9 z原文链接:https://blog.csdn.net/ziqi5543/article/details/1015127221 R/ r" Y3 z' `) W) x
-END-' F! h7 ^7 d" L% c, Y
往期推荐:点击图片即可跳转阅读
* w3 a: q; c. f: e& Y) X/ K
W8 K, N- V$ w- f3 K* U* v2 _ ; _, g+ z% J. i) C
+ N) o! h, N: N5 N $ z' d2 H! K o1 @ D7 f0 ]6 S
b0beaurbwco6402851205.jpg
( M6 Y6 ]: Y! M8 X/ }8 B; J
# u' ?8 g7 G. \9 o" m$ e/ e 嵌入式 C 语言的自我修养
: i# W" W3 O+ V4 R# M
( d) |6 u- H( Q8 C& [, d+ l" h 6 D. [8 P6 f$ \4 a$ e. K
; z. F$ a3 K; V, `6 h/ x, _* B
+ T& j5 s& P5 T2 E6 @( |" } A
yh50034yjyz6402851305.jpg
5 e( {! M4 ?/ I" U* r
- S1 W* k1 s7 O! L9 `$ W/ w8 M1 n
被 char 类型的变量坑惨了!2 W* h* | O- A( o" Z% S- P& |
; e6 Q7 g: G: l* o3 W
. p! n! q3 h4 F4 f2 f6 N+ ^
5 k' w4 _# q* @. u
wjvt2xsxnar6402851405.jpg
8 _5 L) |# p+ }
1 M' a5 d& l7 C 嵌入式 C 语言知识点,动态变长数组
9 a# M( n& e, R
/ i( y% a; x- L3 Y+ |
! t/ Y c! i x1 R0 R6 j# M / U' Q+ {6 f6 O4 b1 Y
我是老温,一名热爱学习的嵌入式工程师
5 h- L+ W9 N, m( x" Z6 m关注我,一起变得更加优秀! |
|