|
我是老温,一名热爱学习的嵌入式工程师
5 D; K+ A8 _) N8 T关注我,一起变得更加优秀!一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。
. s* {' z3 [2 s% I* p使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。
- J9 W7 z& p- D* f0 A. Q' q
nifqreso5dr6407358407.png
' R( q, w: V- f$ Y* j9 z二、实现原理原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。! O0 b. ]- h. C2 h m W# i, K
三、代码实现国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread3 i. G6 t$ o7 s4 Y, U
头文件接口:8 @& Z0 c- n: w3 o# l
本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:) |! R0 D/ K( K4 `3 D w, @6 g, f
/*& H* r( S( f0 _9 m6 L; i
驱动注册0 {: {) r/ k- H
*/
1 k' V$ j3 H0 e' [* e& C& w0 sint cola_device_register(cola_device_t *dev);+ j; V3 Z/ c* U4 v: |7 I
/*
" \: c8 a4 E5 r( C+ J' m0 e: H 驱动查找& S' s, `2 i: z5 }$ K$ U
*/! O/ h. p1 I g1 A9 L: c0 ^- t
cola_device_t *cola_device_find(const char *name);
1 \/ S1 e4 k2 g: u8 p1 G/*
6 X0 y; R _' o1 D 驱动读( W$ {; e: k6 b" p6 ^
*/
: [' G9 _- Q0 O% R6 x" u1 m& @# qint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);" [& K5 s3 l) G$ c
/*2 `! I/ H$ A. M* Y& Q3 _
驱动写( N, b% n, z) I
*/- q- ?% o9 T3 N" b! [
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
# E7 x" W/ y& @3 @! T/*
" F$ F1 A! x8 w) Y% u0 e$ a9 n, @ 驱动控制
4 y# S8 Q/ B: b( L$ b1 a*/1 Q ^* ?* I1 k/ i
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);;头文件cola_device.h:
& V& O" A9 r& }* [6 \% ~! u/ S#ifndef _COLA_DEVICE_H_
! W) |4 x8 U9 _. c& ]1 H/ ~#define _COLA_DEVICE_H_ G3 e1 z0 d9 n6 ?2 M
enum LED_state0 C2 G' P0 g4 W. k& c' I
{& \* k8 k3 E3 u* p8 Y6 F
LED_OFF,
. h: m. A% C& I& m. F' E LED_ON,. q5 Q. Y o! I) ^. P& R
LED_TOGGLE,
( _, w1 c9 d8 I5 E};
' o t7 K! g4 ]6 Vtypedef struct cola_device cola_device_t;, ~& ?, C6 [- n
struct cola_device_ops8 j( W/ p/ a. n! H' u. W& W
{* P7 W- h- [; b% X
int(*init)(cola_device_t*dev);- |. t: O7 X6 w% n$ X
int(*open)(cola_device_t*dev,int oflag);
; e. T4 G8 @% i int(*close)(cola_device_t*dev);
9 G6 X6 s- c, N, o- a: U int(*read)(cola_device_t*dev,int pos,void*buffer,int size);& N/ D5 i% e8 R
int(*write)(cola_device_t*dev,int pos,constvoid*buffer,int size);6 h0 A$ H+ C. T
int(*control)(cola_device_t*dev,int cmd,void*args);
9 o* Y# j: P3 U- }3 M+ K; Y};
4 M% C" w9 q, C* z2 r% j" Rstruct cola_device& h) _& E4 G0 B& K. u5 j" Y
{. w' A4 H) u5 O! v; `
const char* name;4 \9 d9 m! n* [% |
struct cola_device_ops *dops;. ]% B7 W. Z4 |% f
struct cola_device *next;
/ q$ f( H5 d- r; V7 h};
1 |5 B- T4 w+ M4 P/*# q. Z1 X7 P4 I) f* W$ }
驱动注册# y. c* x7 k4 j7 d) F k/ p
*/+ L% p. m% v) ]0 v- f
int cola_device_register(cola_device_t *dev);
n, _/ Q- e, ~9 E ]; r9 Q. n$ b/*0 E% m0 i" Z2 t$ {/ x
驱动查找
5 c' v1 g6 s! G*/7 G% ?5 x4 B: O! N+ l+ H/ F8 y
cola_device_t *cola_device_find(const char *name);
; N7 G$ Y7 A* e, `6 v5 b: r0 S5 \/*- H5 A3 O$ i V% P5 M6 Z) f H
驱动读
9 ]8 V. r" |' Y4 a: l*/: u9 Z; J- ^3 e
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);
, E7 W$ f3 V+ b/*0 k( o# M& G$ E0 }) t t
驱动写5 I& e& ~& {/ t5 Y9 q+ D
*/
. O3 E8 e N C; g- H# `& N" jint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
& L9 O; a0 z8 S3 Y/*
, c- c6 S% D9 a& `, B 驱动控制8 }6 [4 K& f( B5 E3 X9 h& o
*/
* [& H' l8 |3 u7 h$ E3 J& D4 T! Sint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);. ]1 U1 w2 F$ N" v+ l
#endif 源文件cola_device.c:
9 k, f8 t- R" [4 k#include "cola_device.h"
0 E* Q9 I* ]" [& N#include # f3 b, {2 N+ A$ {' L
#include ! P6 P4 o7 y/ d1 H
struct cola_device *device_list = NULL;
7 |/ d/ F9 }( O/*% N' O6 I; v; i" s6 V ]
查找任务是否存在
7 t& Y; |4 ^# v! m7 _*/8 T; J2 x b- D% L
static bool cola_device_is_exists( cola_device_t *dev )% @9 Q# R$ D& R0 E) P( L
{
% f5 g, Y1 M7 v' N, K cola_device_t* cur = device_list;
7 X# d& m# D* m9 [9 O9 D$ A7 z while( cur !=NULL)
1 E G. |1 @* O' I {0 a+ E v2 d+ q6 U
if(strcmp(cur->name,dev->name)==0)
. Z9 b0 ~) g! Z( \& e9 }0 o {
; ^" [# P# {( Z7 l7 l return true;# l3 ?7 c( j$ W4 c# U! ^
}+ z) L0 t+ Z$ N, j+ p
cur = cur->next;
& |. |$ J$ j9 k" _( [( d2 c8 y2 T+ m }3 x8 a0 X/ |# F9 R6 K
return false;
6 j. ~7 r2 h: ~, |) ^3 S}+ Y( N9 r8 W R- f5 |3 D4 f
static int device_list_inster(cola_device_t *dev) ~; c V( W3 x3 v# Y
{: }. f0 O* I- ^% _
cola_device_t *cur = device_list;
* j# w1 E8 E. x+ A; w/ [ if(NULL== device_list)& P; t. T1 Z* s0 d
{
1 h! y3 L ^3 Q& H& z* `# ^: S device_list = dev;' b& L% J* \6 z7 P8 E+ S4 S0 T! m7 t
dev->next = NULL; w* a- L; L: N* Z1 M! }4 j z0 x
}4 n/ @; ?9 |7 S6 {& t% F/ O, N
else
( e& s+ [& ?9 e3 R7 E% J6 K {2 m% _6 n, |" j6 T/ C& ]
while(NULL!= cur->next)
' k# t1 c8 m$ P6 _! }. y2 q {
# q* z% G1 g1 r% z2 M2 C7 M cur = cur->next;* D* T# o) b% h5 W
}3 x2 T: m, G9 u* f" o
cur->next = dev;$ P& {; P9 Y$ S$ ]0 A" |- {7 [! I' g
dev->next = NULL;
! d, l1 O( S2 r: _# T4 \) f6 X, e }
& \4 n/ w: t" G6 x, {- k return 1;
; U+ Y# F- [. o+ n, g}' y" F& {7 V. h
/*8 Y( o0 k0 d. b4 }
驱动注册
* ^' A- h& b6 s2 i- g*/
: B* ~' ?7 b$ O; aint cola_device_register(cola_device_t *dev)
# q6 g9 f* z. Y$ Z{% ^& o6 ?. f9 ~; w8 l8 \# Z# Y$ o% C3 W
if((NULL== dev)||(cola_device_is_exists(dev)))1 F: g! i# r8 p/ L
{: o$ M) z! D5 t/ n+ g
return 0;+ e' f$ j- r. u- @9 |
}
2 P$ j8 i$ x; E! ~ if((NULL== dev->name)||(NULL== dev->dops)): @5 r, k1 L L0 O! a$ ?
{# g. v+ }) t8 B' X5 M
return 0;
. y& Q' z, a0 V' M E) @: V7 m2 u- f# c }
3 a+ g% m4 [2 J* p! G3 | return device_list_inster(dev);7 C$ D1 }; ] _8 K
}
# `/ V8 a/ U% `4 A7 E2 g/*
" @$ A. ?4 f8 o! l$ ~! k% U3 ~ 驱动查找8 j; f" Y$ }. j9 y; [- s6 x7 D# C
*/7 H4 I; V6 F# Z" g! N' c
cola_device_t *cola_device_find(const char *name)+ i0 r! F4 c `, O0 d! H
{
! t/ ^! J+ a% H' f5 M cola_device_t* cur = device_list;: \+ c' }; {# ~# j
while( cur !=NULL)/ \( g: C( b! @- ]
{" ~$ ~ N" k0 r8 A% |
if(strcmp(cur->name,name)==0)
& x$ A2 v" J% G& d6 n& @ {3 T9 t5 I6 I4 {- h( r/ X
return cur;7 j9 `) X* F- _! w$ F
}# ]9 m l2 Z2 C! b1 X, F
cur = cur->next;1 |, T( N# ~% z) e8 }- E
}0 Z6 e3 q8 s2 F; B/ {( l
return NULL;
5 K* ^5 e% B1 i! |' f+ I3 B}
, e3 y, P- z W; k/*# Z% R+ r* D3 b
驱动读
; |1 t. U6 `8 B/ H- {) a. R. b*/6 v% X3 V# Q) A
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size)4 \$ o) J4 i; k- F- r/ q* s0 u. e _9 A7 m
{ ^7 ~/ M/ t2 p3 z9 y2 L( G+ ?
if(dev)" ~6 w6 c" z, S- u+ r" [* K
{
# `) Y/ P& f/ C( k8 t; e- S if(dev->dops->read)
' U, o6 Z- x6 N! X; X {
+ v9 Q8 n' k/ K9 r$ k return dev->dops->read(dev, pos, buffer, size);
* z- U5 t" U: c7 g0 | }* U7 M$ p; W! v) Q5 e6 ]6 u
}6 f1 ]; u+ q/ X) {1 k
return 0;& B- ^" K0 S6 k) C- o+ ~
}1 i' k7 t* }& W) y
/*
: J9 x0 `1 O1 p 驱动写
8 N1 n& a* v) Q: V6 I*/
7 n0 x( ~9 ]0 d8 i( b% qint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)6 x) o* x+ |1 S3 o8 ?( |9 x
{$ e4 _# u% V! X) g* Y& ]
if(dev)5 L3 e# ?6 D5 |0 K
{2 X6 |0 @$ t+ h# M
if(dev->dops->write)
# o& R9 T4 Z5 j4 j3 H7 Q {2 }) P4 Q- N3 M. ~" o5 y( K
return dev->dops->write(dev, pos, buffer, size);, T( | z/ Y4 @; E' D5 O! x5 O
}
9 x+ P& }5 }$ t* d% Y! Q }
# A! S0 T; l# [' j1 ? return 0;1 u9 g+ j) E5 v' m5 G O. u' l3 J
}8 m0 J& ^6 ^0 @; R4 L; b
/*
6 o) I, v) W9 s/ v8 f 驱动控制7 ?* z- P# t2 d6 O8 Z3 Z5 f I* B
*/
% i* t# z( G' V3 @' ?9 f& eint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg)
- n9 t$ Y3 u7 G4 |3 \5 o{' ~+ F8 |8 @( D' p9 n# Y/ o& R% s
if(dev)8 t8 O2 E! [+ c5 x/ F
{0 K% K# A; v/ i4 d* A
if(dev->dops->control)
$ r% x, ~- N$ H2 R$ q3 w {6 F: F) \ ^, ^8 P, n# N
return dev->dops->control(dev, cmd, arg);' I6 F) _- h8 |0 d N& g& Q
}0 a+ y$ `. Y* g, P9 y0 u
}
2 t& F1 t& A/ H return 0;
: A# t7 K6 G) O}硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。
! }+ I6 e, I" b K8 j# D#include "stm32f0xx.h") N `+ E7 {! f3 c2 X6 `" ~) R3 s
#include "led.h"" O5 N6 Q, e) v! L
#include "cola_device.h"
; X& Q' ~% u3 N- W# P8 e#define PORT_GREEN_LED GPIOC ( a. P' I- n' Y
#define PIN_GREENLED GPIO_Pin_13 2 {7 r, i }: e M' G4 y
/* LED亮、灭、变化 */- S. ?0 u% Q; d2 E+ F
#define LED_GREEN_OFF (PORT_GREEN_LED->BSRR = PIN_GREENLED)+ ^! j0 d |' Z3 x
#define LED_GREEN_ON (PORT_GREEN_LED->BRR = PIN_GREENLED)
2 \' T. n; k8 m# I5 {- _#define LED_GREEN_TOGGLE (PORT_GREEN_LED->ODR ^= PIN_GREENLED)
' _+ D: A7 T; G, v, Bstatic cola_device_t led_dev;7 Q+ F1 I; _/ Y" q; E
static void led_gpio_init(void)
5 K8 c! u0 I# q; j0 K+ n{1 X4 b4 F. L$ J" t$ H
GPIO_InitTypeDef GPIO_InitStructure;- i" ^2 h/ F( c- q$ T
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
$ f' \ [& Q( M GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;
9 `7 C$ l1 |, |! h2 @# I% n$ m GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; h; f4 K4 n& h/ u' Z, a b
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ R& L1 D0 m0 X1 Q GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;) ? r" c' D, E7 z. r5 }
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
- I8 ]1 o5 y7 d( ~6 k; } GPIO_Init(PORT_GREEN_LED,&GPIO_InitStructure);# D! y5 H# r1 u. v, H% o
LED_GREEN_OFF;6 B( p9 u/ x S9 A7 q0 j
}7 N" D' @* [9 j
( T' `$ j- i7 m1 r z5 t$ Pstatic int led_ctrl(cola_device_t *dev, int cmd, void *args)$ x; H2 k2 P, e4 Y+ c& n% k/ g$ \
{
9 N) Y9 y4 X0 m. q8 H9 r- ^ if(LED_TOGGLE == cmd)
4 i2 e$ ~. F. V% x8 \+ A* \# S {. f; r* M, x; i% t1 U& ~6 `& x
LED_GREEN_TOGGLE;9 y4 |) _- n% _# |9 C; _: n
}
9 t5 F( }4 ]7 U0 Q& I else$ D1 V6 C9 w2 _1 `1 ]
{
8 S' V R/ c- x# S9 {, d }
. B+ U% b5 j9 x return 1;
5 J. U" C2 u2 Y4 W7 I}
" b) G7 k, ?! Q A2 Vstatic struct cola_device_ops ops =, c _5 F, Q/ a% E
{
& i( @2 P5 u% l, M0 m .control = led_ctrl,* D% h+ o0 R" N) I+ m, b
};5 v- e+ n# R$ n4 t+ i2 o6 t( a( \
void led_register(void)
. x# z2 }0 w0 D5 n{, z- m4 B' }; c: V1 e
led_gpio_init();& X: z% y2 _! ]: i( S1 k7 J, n9 E
led_dev.dops =&ops;. n) P) B" k6 I
led_dev.name ="led";- S, W% F. p4 `$ u3 b
cola_device_register(&led_dev);5 U3 z) ]$ N q }' _9 e
}应用层app代码:2 \8 a$ S" m6 z) P
#include
) @$ e+ K F, h#include "app.h"9 s9 _; s4 s* W! u+ w
#include "config.h"
" H& s$ J5 _4 `4 Y" ^) d& i#include "cola_device.h"
" e' Z6 R7 ?- Q7 e, K#include "cola_os.h"
# v$ U9 H$ X$ I1 w w" Sstatic task_t timer_500ms;
* c0 m( f' f" N! L8 k2 R5 Ystatic cola_device_t*app_led_dev;
/ c4 [* d1 \! z% E* a6 e//led每500ms状态改变一次
4 Q: t4 z) G2 ?: K. Wstatic void timer_500ms_cb(uint32_t event)
' Q# U- r/ Q$ W( c1 |3 N" y0 e{' v: a" X) Y& a# [
cola_device_ctrl(app_led_dev,LED_TOGGLE,0);0 ?; v' T+ L0 c
}) R" R# s: {2 `" L7 V, n: w
void app_init(void)9 ^. v5 I2 C: i1 }( I% Q
{
. E9 ^" X% c" b app_led_dev = cola_device_find("led");
5 y% e/ l7 W- v assert(app_led_dev);
6 s4 m0 @8 c, B6 q( i0 r1 T cola_timer_create(&timer_500ms,timer_500ms_cb);
/ B1 |" b- J+ M9 p+ g1 g8 T5 S" y R cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);8 m2 p* e% w$ u1 {# X. O; n ?
}这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。
; S6 Q8 F9 m2 ~3 e9 C! Y四、代码下载链接https://gitee.com/schuck/cola_os
9 H9 b9 U) }9 M- `' W# W原文链接:https://blog.csdn.net/ziqi5543/article/details/101512722
- a" J7 T9 i3 D-END-
; O/ T. a9 X0 I. r往期推荐:点击图片即可跳转阅读
5 X6 n: r4 k n; L% o7 h/ o1 U, z , ^6 w: v; q# f- ?& Y$ p
4 i6 V' q( [$ k) t$ o
! M: u* N- X, F5 ^' q' ? ' z$ P& @" |1 G8 s/ d2 w) z
4zkn4lei2pc6407358507.jpg
# s5 @, H) A7 _' G , x% \3 }5 w1 i% {
嵌入式 C 语言的自我修养2 i% h x5 t" m3 P9 y6 I- _
' Z2 @$ M+ @. d, w w7 x$ l
w1 B& x' f+ S 8 `7 w0 o! B7 r1 @$ w! i$ t9 D
+ R7 t/ e$ u2 O3 E' y4 X
j2sbzyfxtr36407358607.jpg
4 t9 g1 _9 \3 g/ m6 y$ I8 d
* @& U- d6 l% F 被 char 类型的变量坑惨了!
# c7 g+ P M0 t/ R) s 7 _3 _" r9 f+ X2 [+ u
$ Z2 N: a! G* B. b9 Q+ ~% U
; n) [! D7 ]4 @) U+ [
wvryonpjgkp6407358707.jpg
! F& d' |$ ^' L4 ~1 S: h0 B# U
2 p: s( {, I. x2 T' j1 a
嵌入式 C 语言知识点,动态变长数组. ?% V+ I$ I) t5 f9 {7 a9 J
$ `3 \. k5 S. }0 p/ d $ b7 q2 c. K" |
5 P" v; W/ T0 [6 c0 S5 U/ B! u& \
我是老温,一名热爱学习的嵌入式工程师* a& I4 S. W: S9 Q" w
关注我,一起变得更加优秀! |
|