|

我是老温,一名热爱学习的嵌入式工程师/ w; B5 K1 c. Z3 o% l+ X9 Q
关注我,一起变得更加优秀!一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。( B' M+ S8 }& V8 F- q0 I( B5 N
使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。4 H0 ^. _ \/ u; F! u4 M7 G; ?4 \
qh42vev2gc06406501902.png
* K3 P( V/ v4 P) b4 x9 W: l二、实现原理原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。1 F1 ]9 H+ b, q
三、代码实现国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread
3 z/ R# g3 M3 p7 h! a头文件接口:. n5 l2 `: h3 n& |0 {$ _
本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:9 c0 v# b; h3 l5 `. }1 V9 j8 a
/*" D) {5 s1 R) T: R/ Y) L
驱动注册
1 H5 S8 F+ d. q# Y*/
7 W! }3 F" ^2 ]int cola_device_register(cola_device_t *dev);5 I' C3 P* O# q; f; C ]
/*6 @( v& T) T/ \( Y$ i1 Y) n7 `7 J
驱动查找
7 j& V* B. c2 a( ^*/
9 Z P7 U: E/ u3 D0 K6 \! D. l# R* B+ ocola_device_t *cola_device_find(const char *name);
) ^6 e$ T; K! y. C( ~+ v6 a4 ^/*3 A$ R) y! L9 L7 ~
驱动读' ?# X7 \( V4 n# M' q' g; Q
*/
, V% {+ T) y5 n6 Rint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);4 Z3 N8 C$ W: w) S5 D7 W x( I
/*
7 P @( ]4 [7 ^+ W9 T/ ?* O 驱动写
( d9 m, o" Z: ?$ _) V. G6 q' |: D*/
, m' v- a9 q+ H# c: Lint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);, `, H% y! ]$ W3 b& U
/*
8 r* _! {4 X& _* `1 i( n; r 驱动控制: h. X3 F5 p! U& b: M4 t! R9 W
*/# }: y+ l3 t: R5 y$ F
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);;头文件cola_device.h:/ G7 n2 f: N: W1 [4 _
#ifndef _COLA_DEVICE_H_: ^- o' Q6 |+ s9 K! }* T) G6 i
#define _COLA_DEVICE_H_
! `/ `: O6 z3 ?( X5 lenum LED_state
! o6 X H8 i& |- \% w; \{
! H! c7 Y s% i/ J7 _ LED_OFF,
/ k+ _3 ?% c5 N8 B LED_ON,! }8 E& K! D' G7 K |4 I
LED_TOGGLE,8 k% U/ S3 z, s. z8 v
};
* P0 Y) n! b2 [' dtypedef struct cola_device cola_device_t;7 ] a% p/ z7 o$ U: n
struct cola_device_ops
1 T: Y& o4 A O J/ k7 R{
2 X: X( c g2 g/ w; H int(*init)(cola_device_t*dev);
, J8 o- E. I* M5 D5 ~% {7 G+ T int(*open)(cola_device_t*dev,int oflag);
' }, ?8 ]1 R4 V. u2 e( y int(*close)(cola_device_t*dev);" ^9 t$ z: D+ _" f& C( l: D: c
int(*read)(cola_device_t*dev,int pos,void*buffer,int size);7 D) ]+ }/ F& ^5 Q5 N3 P+ T# {
int(*write)(cola_device_t*dev,int pos,constvoid*buffer,int size);
% U1 y' o" \- y int(*control)(cola_device_t*dev,int cmd,void*args);! H/ t" q+ v) `8 R9 g( F
};' A( T* l" z; a5 F* q
struct cola_device4 s8 W& P/ J7 ~9 a+ `* Y4 W
{
1 x& ?1 F8 h1 J& O6 [ const char* name;6 i7 L) j' B8 F( _# V, F9 |
struct cola_device_ops *dops;, f* E% K: k2 [. y, _0 m
struct cola_device *next;
6 j9 m* I& t2 l. H. T/ E};
& r4 N7 X: }* x! p; a; `- a% x/*
$ J; s1 \$ t$ T# o4 r" I3 [/ b 驱动注册* H0 \- N) B, z, B" I5 }
*/7 ^3 ~6 S# J1 }2 i
int cola_device_register(cola_device_t *dev);
3 V% H& d6 } }% e. e) q; u/*9 R! c7 k- W% z. J" M8 g. m' |
驱动查找
7 j1 S7 V7 N% Y) p3 B*/
3 ?! G& e1 p. Rcola_device_t *cola_device_find(const char *name);
" B/ ~ H; K) H5 d5 a2 S: r; `3 F/*
- O( W: I" l+ I `& ] 驱动读
. J8 Q8 B3 e4 B, Z*/" ]% A2 [5 ^6 _, w: v" Y
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);3 m1 y3 a- f! `) `9 N
/*7 n8 o0 w8 n# U& \
驱动写. d* v1 ]" D+ r+ S& b. J/ z& B
*/
0 l1 b# N& ~6 [: Vint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);1 A7 l* e. R/ l; S9 @ |
/*3 H! G3 `, v$ P4 ]) W3 K
驱动控制! @4 b7 L9 b( {$ B
*/
& M! Z( b; \, _: _5 Dint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);4 g7 ~( A* o/ ] P0 X
#endif 源文件cola_device.c:
9 [7 S0 M1 d" ]#include "cola_device.h"1 H2 H( U' ~1 ^- P, i
#include
: {9 t* b* B/ T4 j2 W#include ) F) f- W% T2 J' i2 _7 \: t
struct cola_device *device_list = NULL;" n- R2 \4 o3 o3 J5 }; G
/*
; g9 l4 V- M# M8 Z& l" y8 f 查找任务是否存在, F9 N" j7 h, L& F/ J) `2 Y6 W
*/
8 ?0 K2 }; x0 G1 W* `static bool cola_device_is_exists( cola_device_t *dev )
" g( B/ z6 E x{ V3 G6 {. B% S* x9 j# w3 B
cola_device_t* cur = device_list;. P0 E9 V8 [' [! ~
while( cur !=NULL)+ G4 q. e( L. S; v. ^. ~
{( \2 e6 w( W' ]5 L& Z1 n; X( k
if(strcmp(cur->name,dev->name)==0)2 k/ R$ D% t0 P8 U
{
; s) C7 ~* {4 Y! B! u) B return true;
5 q; D9 } K, U( D" h- r( [- k }
- C6 e5 |9 T& p! p1 _1 g" v8 Q cur = cur->next;
- e% O" {$ c5 d }- W9 v, a- m" M5 o, \8 n( C5 e
return false;
3 c4 n( z7 @' X5 d1 d8 `* h' d- g}% i( C7 q0 } l9 r1 Z7 Y+ a+ j
static int device_list_inster(cola_device_t *dev)+ a6 L# {3 y: F0 g8 r
{1 C$ ~7 s& p+ ^& ^0 g6 s( v' w( N
cola_device_t *cur = device_list;
" s" s. M( C4 c7 _# i# d# K- t if(NULL== device_list)# X) e8 U2 d- N7 h; Z( d
{
8 }% v; g7 [& b; n0 m device_list = dev;0 `. H+ g* h5 C0 m/ n6 G& m3 j! T/ O! Z$ ?5 E
dev->next = NULL;
" X0 q" t. W- |. P8 o }' g* {; U; T( I' g
else$ ?! z% ]* z9 b, J
{
. p, m2 p: x8 \- m while(NULL!= cur->next)
6 _4 l( s* d+ s: C7 P6 ~( I {% f, r5 ^3 E8 Y; B- {2 _7 {0 C
cur = cur->next;
" H/ i# L9 P& B- Z. L4 t% F; q }
' K( g6 k7 n9 D1 G! @/ j# s* V cur->next = dev;- V: a% J `4 \, I
dev->next = NULL;/ r) R& F. h+ _0 F% g" p: S
}
( Y" p: U1 Z' r; v7 B, }, T return 1;# A3 g6 h7 b& E1 X# u
}& L9 g. f. P/ j Q9 j
/*
& E- c* D1 ~9 p n) _, P 驱动注册" o) c/ X7 Z2 l9 j- q
*/8 [1 a5 [ D2 S0 P0 G
int cola_device_register(cola_device_t *dev)
4 p. [1 D: _, \* J$ _2 p{
6 `2 ], S8 }' d G5 n4 y% ^4 i if((NULL== dev)||(cola_device_is_exists(dev)))
3 g- v9 J: m+ a6 r {/ U9 u0 i/ b$ ~" s" ]0 s4 f
return 0;
. o9 O$ A4 l& X- D9 w }
) J5 J: _) U& Z2 d if((NULL== dev->name)||(NULL== dev->dops))
& e# g" g1 T9 I+ j, |( R {
$ R* O" t3 b) r- ]$ f- A return 0;
; m1 W1 q" H& P }
. X9 n' g- B3 A- |: U3 a return device_list_inster(dev);
0 R" j! `- P$ f2 E$ V; V& }}% V/ H( g2 P V/ H7 v$ y) |
/*
" e5 a- R Q1 F: g' s& G 驱动查找7 p7 @& `- |5 W1 J
*/. X5 a+ t+ r; N. z7 T2 l. S/ y' G
cola_device_t *cola_device_find(const char *name)
+ q/ T9 @! r% x0 a K1 Z{
5 e* W$ @5 x. d5 r1 k& N7 m cola_device_t* cur = device_list;
% [5 W s* r( A2 M" h while( cur !=NULL)* R" s; Y! e) J) X& ]
{
7 m+ [! ` s J5 v' k) h if(strcmp(cur->name,name)==0): E+ m7 i0 r* O5 L' D9 N$ ]$ A4 H( [
{
2 a7 ^" n2 h: K9 | return cur;
* | ?% m2 t/ N }& ?: S6 }& w( t6 |
cur = cur->next;
5 i; @, ?- Y {: g* Y }& \; o1 I X- K) S6 [4 i
return NULL;
f% ]) j. V7 t+ M- y7 c}% e" c" Y& o2 K4 _' s& N
/*- E/ C0 O9 c+ P1 |
驱动读& W ^! m, M( @
*/; [6 T! I# L7 u2 i: g4 C
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size)
! h5 r5 y! R/ h{
: m4 b. ^. [6 f; N. [. y if(dev)8 x$ s o& }0 K- x4 a0 n, }
{9 w% ]/ t1 A# Z% ^/ H7 A4 U2 a
if(dev->dops->read)
' z P) ~$ T0 m) K1 v2 E {* U- a6 s* Q) y; T1 S
return dev->dops->read(dev, pos, buffer, size);4 i* E5 F1 y8 ^8 g1 S% F
} w; w$ Y9 Z) H( _- U/ x
}
. O* t) A4 _' O; q1 B* \) ]) Y return 0;8 E7 U/ K- b; \& d$ S
}
0 N: M2 Q- v. q0 [& H c4 `/*, r8 `3 s9 N! K' @# i" o. z
驱动写
! E' V: d) X2 Z9 y0 k- x3 B7 Q*/; K$ I$ \- T' Y* ]4 V* k$ h# a' [
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)
& _- r& v( F3 ], m! q) }' y{
- m$ }* w8 x3 p4 m- G, |# t3 e if(dev)- o# o% \) N. h9 r# f% g7 r- Q
{
+ A+ c. D+ }# \2 N if(dev->dops->write)* [, {0 _6 K1 ~ _/ G% H# _
{* \- t' ?. a" X4 l
return dev->dops->write(dev, pos, buffer, size);0 V4 E# S8 F+ { m
}- ?7 f2 U4 O6 H* }. m" } Q
}
6 a) Z0 A: u" v2 c7 } return 0;
0 z0 a: o: a- `}3 F4 o3 m% y7 ?7 v q3 Y; `1 N8 H
/*
- W& D9 k5 ?' O! x- Y% v( p0 l 驱动控制( _2 C2 C8 w) A, J) ~
*/9 q0 ?# p- T! l
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg)5 C" t0 D) |6 r3 r+ q% J u6 e
{3 D5 l j3 _& z# }) Y
if(dev)* [$ }0 s2 K) H8 X4 k9 p) V
{
2 F+ F# J' t0 ^6 r if(dev->dops->control)
' H: y! V j/ b+ Z; s. N4 R0 p {
3 K& u p8 D, t! Q2 B7 l return dev->dops->control(dev, cmd, arg);/ U, ?' q/ I( J6 O+ R" v
}" q) W" g6 R" M" e6 G; Y5 w9 v$ x# G
}8 i, Z5 {; {) R2 u' l
return 0;
0 o; @ W! g& r! _& d}硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。
# s1 H+ I M( G- `/ Z#include "stm32f0xx.h"
% \$ U. u7 R% K$ U#include "led.h"
5 Q% U( ~7 p8 j& D#include "cola_device.h"* ~$ S/ {0 Z1 z
#define PORT_GREEN_LED GPIOC
2 G' D# H1 R4 E& ]1 L& k#define PIN_GREENLED GPIO_Pin_13 5 m& ~' f, z0 A; W! M m3 T
/* LED亮、灭、变化 */! r- v/ G E- t. \' z
#define LED_GREEN_OFF (PORT_GREEN_LED->BSRR = PIN_GREENLED)
" g5 R: }: n$ t& J3 y#define LED_GREEN_ON (PORT_GREEN_LED->BRR = PIN_GREENLED)0 S6 V6 ~1 j$ B' d0 a
#define LED_GREEN_TOGGLE (PORT_GREEN_LED->ODR ^= PIN_GREENLED)
% U1 T5 G5 A, L2 x( G8 R6 Istatic cola_device_t led_dev;1 h- ^* A% M+ s: I9 J) q
static void led_gpio_init(void); y$ L% t! [9 J+ y3 H
{
+ w5 V( }- K& K" I' c5 |/ [+ z1 X+ L GPIO_InitTypeDef GPIO_InitStructure;3 B; ^$ v1 D5 y8 B. L1 w' J
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);6 G$ v) c5 A g
GPIO_InitStructure.GPIO_Pin = PIN_GREENLED; m; n) R; p+ H; c% G4 n7 |3 \
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;2 K& [9 o$ C, Z0 v$ o0 z9 F
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
' w7 `" d: h+ _ GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;4 _+ B9 n9 @7 r+ s6 O
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;; S3 y) s2 A3 d/ ~% A
GPIO_Init(PORT_GREEN_LED,&GPIO_InitStructure);6 _1 O$ K4 P' k0 f
LED_GREEN_OFF;; z$ I" G& x& u0 R' d& b0 X9 a: x3 u
}
6 G4 s# t9 t0 K# Q/ r; v' s" I$ i
( t, w s& i, {. o3 v# _) v+ }static int led_ctrl(cola_device_t *dev, int cmd, void *args)
% Y3 ]9 j; x7 Z# Q# j" I% \( x{( O, Y2 ^% h2 H( K
if(LED_TOGGLE == cmd)2 E! ?* q, s/ i4 g, J: a7 c
{
$ a$ t- M% F) H$ P( c+ T! b, d# b LED_GREEN_TOGGLE;
6 w5 t; g8 Y! w n& b, K0 v% R }9 }* `0 W/ y* R0 i3 |* e( Y
else
7 o, U6 m4 X; g3 n2 D- b+ v; z {
1 z6 a' D4 O3 j3 h }, k5 j3 I1 H4 a5 S" j7 J
return 1;* H- L% E6 c& l$ P% L1 }
}
! E$ i, e: M1 s. astatic struct cola_device_ops ops =
( y! c/ }0 o0 J8 z{+ v% g6 ~( j7 S2 s
.control = led_ctrl,
: t- Z C) ] ?( y4 ~; ?+ S6 N};
# p# Q' U+ y" Y: L( svoid led_register(void)
- m! J$ B {! R7 b{
5 X6 E A8 g" Z led_gpio_init();
U5 X0 i* g& [: K led_dev.dops =&ops;
* \5 u3 W C3 j led_dev.name ="led";
6 }9 B, f6 T, F4 k* f cola_device_register(&led_dev);5 V5 y/ Q6 e" K" ^' ~
}应用层app代码:9 t& b ?, |- m
#include % ~ \9 `7 \" [* s
#include "app.h"/ B) c8 Y5 ^7 ?1 Z7 x( a+ Q
#include "config.h"1 }+ M# s j' a1 @
#include "cola_device.h"
% g+ c$ ]& @5 I" V/ r9 p1 b* `#include "cola_os.h": n1 y- Z( c) \- I* n, a* \4 l
static task_t timer_500ms;
f7 |+ s) Y& F& @, r; w T& xstatic cola_device_t*app_led_dev;% T0 G( F6 p# G2 `
//led每500ms状态改变一次! u% D7 o; v) L8 K4 C( n; d2 i
static void timer_500ms_cb(uint32_t event)/ E4 ]! W! c& Z
{5 O1 j, N* e( A
cola_device_ctrl(app_led_dev,LED_TOGGLE,0);- q ?! M1 u. W# s
}
; ?5 y# F8 ], O& X" P7 [void app_init(void)
z$ ?4 N" E3 `. b2 r5 i{
, e: O2 z# ?2 Y s" B) ^ app_led_dev = cola_device_find("led");4 g, Y# H, t5 r) f4 L
assert(app_led_dev);
* z) K' l3 d2 S4 j) r! G cola_timer_create(&timer_500ms,timer_500ms_cb);
; g) m* u* n* ]; e2 [* I: h cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);! D ]$ W9 B5 ~; H( {& b
}这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。
. }: \6 e7 r+ Q+ w, B, ^" H4 I四、代码下载链接https://gitee.com/schuck/cola_os
, }# f( ]* l( c6 e原文链接:https://blog.csdn.net/ziqi5543/article/details/101512722
3 c+ S1 M9 z3 p- k4 M' G-END-
4 a- e# C7 M$ C往期推荐:点击图片即可跳转阅读
2 @$ k. Y; g9 m w 3 \" ?6 p5 h% p" O2 d0 k3 U) f( \
% G/ s! F$ Q% J. E, j. p
9 y# H) o; s! F
4 M# S' x& Z$ D
r223danyx3b6406502002.jpg
9 j6 x. t) I' V+ ^( Z+ p9 ?
. |( w m* Z1 V/ Q" L/ e 嵌入式 C 语言的自我修养2 m- _, h( m; S$ V* }2 G! |5 @: f
1 a( z$ L( `% d7 i5 U. k+ Y9 ]
/ b) X) p" Y0 l: c
; d* g; V( ~ _) Q ; |. J) a& ^! u! Z" F
bbvmupsac0y6406502102.jpg
" l5 K/ m) X' l+ s6 b, r8 f" {9 j* b
9 v9 D" B( ^* f9 h$ B 被 char 类型的变量坑惨了!$ y" l$ l/ |3 \* m9 Y
% U- @6 F% T% N9 V* k - Z' ]: z$ R5 Z: h6 n- G1 I0 X
5 w1 L$ ]. P( ]: b/ p' v5 H. W
jyqadzx1lhc6406502202.jpg
* A8 ?7 Q! s# ?0 L3 x# _" V
/ K3 B' s0 Q' N; x" X 嵌入式 C 语言知识点,动态变长数组
4 m" m( r% d& g" A( u1 j
& ~. J7 r; r. ~; R( [7 M3 w- i
7 f. |0 H; v3 `! a& @% d# E& }4 h 0 n- Y2 c$ p$ t% T7 G: z
我是老温,一名热爱学习的嵌入式工程师/ e8 q) e+ p+ n+ W2 F9 L
关注我,一起变得更加优秀! |
|