|
我是老温,一名热爱学习的嵌入式工程师4 n' o7 \0 `6 v; k \4 T5 k: z5 F
关注我,一起变得更加优秀!一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。
, e. _+ Z% [$ w, t# C- V使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。
6 ^9 B# G$ ]6 n/ i
sis112cs4gh64026495427.png
" ^% W0 o4 r/ w/ I. L; p二、实现原理原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。
2 l, W" d+ [" z: A( M1 G! L三、代码实现国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread
2 W( t4 C8 M: [, c8 w3 Y' e头文件接口:1 u& |' h( B; h( t
本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:
f* I" B7 m5 Q0 j/*/ M; H8 o4 X9 f5 w* I- k
驱动注册
% K& ?9 `0 @4 F' C*/( ?0 J7 F2 F# `/ T9 w9 F
int cola_device_register(cola_device_t *dev);7 l4 C3 }, D, K4 H# o
/*
0 Q" s- R3 c" A 驱动查找0 ]( ]3 g" i, I5 @) c$ H: B
*/9 ^3 W7 }4 A H2 D7 U" W
cola_device_t *cola_device_find(const char *name);7 D; U0 c q5 y
/*
% S0 p. {! c3 N# \, v8 M 驱动读, Z) g( z* j! G) b! H
*/
E& }% t- p, ~+ W1 nint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);3 B7 K: v c) Z/ I' f0 h$ q
/*
4 H- E: _# |) f3 S$ h$ o1 j 驱动写. c6 T& B. B. S2 y% {
*/
) G5 q0 h N3 d# e( xint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);4 g" _; [+ S% F! P( R
/*( L; A7 O: ^, E b2 H T- ]' g
驱动控制$ X% ~3 s+ }0 _3 |0 ?3 \
*/
! x5 k7 k+ K- `# Uint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);;头文件cola_device.h:
, Y5 R. T5 L2 {$ U* q& W9 X0 G#ifndef _COLA_DEVICE_H_' a. {9 M" t& N
#define _COLA_DEVICE_H_
8 t2 C h) _5 ` kenum LED_state2 t* _4 A5 T, [; v. N8 V" G6 k
{2 t: H& N5 {0 G6 ~. I/ x0 [+ B
LED_OFF,
4 C4 S3 k' D9 Z- Y6 y1 Q* C& X LED_ON,
" v4 c' q1 l% T/ ` LED_TOGGLE,& S/ J) K' S/ i5 W4 M! c+ P j
};/ a1 G& W4 }$ a& `) b- i0 z
typedef struct cola_device cola_device_t;
" i+ q/ g" p) S- a& g) G6 wstruct cola_device_ops, l/ {! y8 y, L8 W
{
' x2 j a4 e- s, D3 @0 u8 H int(*init)(cola_device_t*dev);
7 B5 d: v X' H7 y& v; ? int(*open)(cola_device_t*dev,int oflag);* T# E" T0 x/ C4 R$ b
int(*close)(cola_device_t*dev);
Z. y/ }! j& m# `! i9 p int(*read)(cola_device_t*dev,int pos,void*buffer,int size);
) J* [: A- x0 d. t4 J int(*write)(cola_device_t*dev,int pos,constvoid*buffer,int size);
& N% V0 v- d: A; A2 P int(*control)(cola_device_t*dev,int cmd,void*args);* ?- @4 u/ M: |
};( P: ?* K& k. Y1 r0 l6 A Q1 y
struct cola_device
/ g0 u8 v3 e0 [, i/ k8 \{0 V! j$ k' C! i7 Q7 r
const char* name;+ a1 Y. X8 a9 z8 C7 U* u
struct cola_device_ops *dops;4 [5 i' x7 ]. Z8 U; p- ]- Y- B' ]# N1 G7 i
struct cola_device *next; t4 U# r R+ k9 U" n- D0 n
};
( W; F; e2 u# r$ t/* L/ g$ z' H: Q/ ^
驱动注册
: i0 h1 Q; L% |*/
- }; t" @- G7 o& K: |int cola_device_register(cola_device_t *dev);) a7 W9 r8 T4 u8 d
/*, }. ~' u2 u; y1 m
驱动查找9 [& Y+ ~+ _" U& Y Q( c. I2 W
*/ U. t& |1 L& d+ C! T
cola_device_t *cola_device_find(const char *name);
* r( I. A' ^% Y. L ]6 \2 b1 n/*
* Q" t; q8 ~: e' `8 M 驱动读
8 e& e0 V, E% r' e5 J& }*/
0 J3 K5 Y& N3 a- p" |6 X+ e4 Cint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);
; x% ?2 I4 x, j7 A8 T$ v( x1 d/*
" k6 |0 p8 B4 j1 g7 F; [' b2 q 驱动写6 H; H" _6 R0 Q2 Q* T
*/2 F. b' x6 Y/ W) e1 q. ~5 N! ^# v3 Y
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
* s2 n1 N- D/ ^& Y+ o/*% F6 M' c y3 E1 D7 |( n8 M
驱动控制
/ c3 Z2 W/ C; v! x9 s) j( W. u& g*/
) r$ I9 y) s4 _0 n; o+ S e7 Sint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);; U J, L {/ x
#endif 源文件cola_device.c:
! P; b2 S% ?3 o) ^3 V$ l#include "cola_device.h"2 j/ N8 }4 y8 N% t* o$ i, r) A
#include
) ?( |9 ^ l1 X4 b9 ?5 b* n#include 6 _$ }6 n8 t4 |' P8 r3 _
struct cola_device *device_list = NULL;" a5 {( g* D' x# H" E
/** q; a8 t0 \' x1 Z/ `+ O; @) O
查找任务是否存在
! p$ {' a, R( ^- S*/1 k2 J$ C W8 R: _
static bool cola_device_is_exists( cola_device_t *dev ) z$ @6 Q/ ?2 c" ]
{. }) b5 x5 {( D7 j- o7 }
cola_device_t* cur = device_list;
0 F* ^; Z5 g- | while( cur !=NULL)
' F" a1 n7 |, j$ C: ? {7 k9 N' s1 d2 N) s. n, K! d
if(strcmp(cur->name,dev->name)==0)8 J2 k- G: c; {+ A4 P
{
9 I% L4 z* [) @2 u, i* |- H6 `- G return true;2 d6 K7 t; S( i/ M
}
- O# c: m; l+ j7 s; a cur = cur->next;
* Q7 L$ |% P& B }
J$ Z9 e# ]) E F$ ?- |+ Y return false;
% d% A( D) w W3 U' s n}! w1 Q# C k, E; l: W
static int device_list_inster(cola_device_t *dev)
" i, r# f1 |# O# l$ B{) f/ T( D' }6 ]+ }
cola_device_t *cur = device_list;) \8 c$ H: _$ x; n( j" n. z
if(NULL== device_list)
) D, ~ r4 p- {0 ?. ^9 Y2 ^ {
& ]+ u# |+ d$ f7 u; @ device_list = dev;
1 c9 ? r" B& g& h3 r0 o) H( k dev->next = NULL;
0 U3 g5 k. a# _9 z- H }
/ l! e9 `4 k& D" p else( f' K' o! q+ P
{
$ z) \) S) J3 R. w while(NULL!= cur->next), x$ j3 y* x/ e+ [, a
{
7 w1 S* R# J' F cur = cur->next;4 _# o" @% J. P1 z3 h$ B
}& k% I5 l( Z" V9 M, M- r
cur->next = dev;
6 \7 K6 h' c8 o) Z dev->next = NULL;: F+ e3 a: K4 w9 C9 m2 l
}
) F7 p* W1 }( `3 T' p4 G0 s return 1;
- g4 u/ p; D' k! C8 l}
, o7 K" F/ d, C& R; M/*! R3 X; z) O" J+ Q1 p* B! @' l/ i
驱动注册 A1 C* d2 j( |: b, s& O* P& W
*/
8 {( T* ]; a! Qint cola_device_register(cola_device_t *dev)
' @7 ?0 I4 ~, ^{ w; ~4 n, N! Y! n
if((NULL== dev)||(cola_device_is_exists(dev)))7 e3 Q" x; w: F% X
{4 _& x+ V7 s/ [5 p% m: ?2 O# }
return 0;& z& n2 K6 _; s3 c2 z3 Y
}
. T9 }' j4 j: u* ^ if((NULL== dev->name)||(NULL== dev->dops))% p- m: c) f; x! v6 } b6 B
{
! Y6 D7 [; T% v: Q& y0 h return 0;* V: j7 a4 l9 z* q+ P( F- {
}& M3 p1 N, i; w, ^1 N2 C
return device_list_inster(dev);
- B" x- ^/ J5 C6 y5 o}
8 F! Y% S$ W# X$ A' c! S1 q/*
7 G( r! f8 \. D3 d 驱动查找/ y. D+ L: N$ B% @2 b0 V
*/
, R: h, s! `( U$ ^cola_device_t *cola_device_find(const char *name)# }9 V) {: v5 U
{
; n3 i+ Y- g$ m" ^; d cola_device_t* cur = device_list;/ ~7 z( t1 I+ A F4 F; [$ J. @
while( cur !=NULL)
* ~/ T; U) n( ]* L$ w( f8 v* j {
" ^ M; }6 {! `' c$ E+ G if(strcmp(cur->name,name)==0)
, u& c4 `) [7 z+ V) V! [ {* S; h5 L/ I* G' J
return cur;! @# r) x* Z7 S" T+ V
}
, D1 s* V$ H5 D1 A+ g# ~ cur = cur->next;. m5 s2 Q) Q5 t" ^0 \9 y L$ N
}) ]; @3 _- W. U+ S ?/ n( y) h$ B
return NULL;1 }2 d+ {$ a$ ]: J: A+ O o
}3 T; `9 z. Q. m$ j
/*8 C, A/ W+ u' \8 o2 c8 e2 r
驱动读- ~' J; N* D1 p, Z/ @; H+ B( g# c0 ^
*/
" s; V! o' f' O8 P1 mint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size)# \$ {, X/ V# Y7 v! f
{3 c7 |# W. S; M% H' h, y6 Y+ Q$ P
if(dev)& ?) `6 q- m; _* S G
{7 w# d- @$ t7 I. c1 g. H7 `
if(dev->dops->read)
" o: ? ^8 L7 p+ R& }! V. y2 j {
; o+ Z# C3 E' } return dev->dops->read(dev, pos, buffer, size);
1 s3 h# U% K/ q$ n$ v }
& [% M8 L- O" R) [ }
- @. F) s6 i! m0 R! w) A return 0;
, ^; A, }2 U8 F0 k} P M7 y" u+ X. V
/*# R8 ~" @: ?+ H9 @- e
驱动写
# l; v( \: _- x) u5 G8 L*/
' K6 D; g- n8 s, f3 p0 h5 Mint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)
' f0 q) c, i2 @8 s$ b3 E3 [* y{
) ?1 w e( T1 _4 ?! K( P& Y! ^ if(dev)
% w+ a% x& j8 H {
' W9 i. `( J1 y) r if(dev->dops->write)# ^1 G" H. m( l8 R$ Z
{
2 `. c2 D6 m" ?9 }& Z, G return dev->dops->write(dev, pos, buffer, size);
' k s: B6 R+ U4 j4 ? }
& r( |. [$ Y9 A4 T5 a: y2 Q v }
8 G3 X! [( P7 b8 A, E8 c return 0;; m* [: h( b- e' w) D5 ^! D
}, g* s+ g! ]" R v
/*3 [& r% A% Z0 i! y, G
驱动控制
% t4 D% N ~/ J# U9 E+ b*/. D5 ^3 I: t6 ]% G' D# F$ j
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg)
5 [; x# B: {4 w7 E& c6 T: X- w{7 _0 x6 @* X% a* Q, J+ o( @
if(dev)
( }. x' p9 Z7 g: `4 |$ N3 _0 { q {
, F$ q* K* t& } if(dev->dops->control)" O! x; V6 O' n$ O; |
{( N7 a' s$ H$ |) h) _4 A1 T
return dev->dops->control(dev, cmd, arg);1 r9 l7 [5 U' v) U( t8 o" O) O
}
4 {3 x; M( A. C5 L1 R$ M }6 J7 F* D1 [5 `# [0 ]/ V
return 0;- H3 U/ o. b( B. [5 @3 v& Z
}硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。
$ F w& ]! ?5 i% w+ B Q; F, l' g#include "stm32f0xx.h"" t: v. v& J) J; s
#include "led.h" O% O( [! D) F4 e& Y/ ^, R% k
#include "cola_device.h"
3 m& k# W; d' T6 @! g9 {% @- t#define PORT_GREEN_LED GPIOC
2 Y: h8 t: V6 a, M* z; C#define PIN_GREENLED GPIO_Pin_13 ( W7 }4 [2 }, @
/* LED亮、灭、变化 */! o: |1 Z6 Y! C6 h
#define LED_GREEN_OFF (PORT_GREEN_LED->BSRR = PIN_GREENLED)
# ?9 p r9 H# {7 Y0 K7 k#define LED_GREEN_ON (PORT_GREEN_LED->BRR = PIN_GREENLED)
. X8 o8 M9 C. g; N' Y#define LED_GREEN_TOGGLE (PORT_GREEN_LED->ODR ^= PIN_GREENLED)
4 D: Z! m) f* H0 B+ g( Istatic cola_device_t led_dev;+ ~! o8 X3 U" h1 u9 \
static void led_gpio_init(void)
' h2 V2 R2 y8 {6 y; ~8 `+ O{
/ M8 v' r, M( ?) v1 _ GPIO_InitTypeDef GPIO_InitStructure;
) d* Q1 B2 T- Y. `) S' l RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
3 a0 I' O% C) B7 w8 a/ v: | GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;# U0 K( Z# B( H$ L7 e) I( |
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;4 p* f \' a6 L* b5 |
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;8 n# d" l* K4 Y5 ]* K7 u& n
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
0 H( N0 |' i. O& e5 F$ @$ D8 J GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;$ n; N1 k+ g0 y
GPIO_Init(PORT_GREEN_LED,&GPIO_InitStructure);
* I3 l: H0 D0 [; c4 g" { LED_GREEN_OFF;
+ P' v0 _: A6 t( N' O6 s$ B}
( Z! g- z8 C# j! z2 v% `$ R3 y1 Z; N6 X; t- E
static int led_ctrl(cola_device_t *dev, int cmd, void *args)
/ Q! u9 Z! Z& @7 O! q0 R{& B$ H' t' w- U. i
if(LED_TOGGLE == cmd)& Y0 w; e& X1 l, H
{, d D" L1 }$ _9 W) r L) s. }2 l
LED_GREEN_TOGGLE;# r1 m( S0 s/ N' q( D6 g" I
}
$ n6 e6 V5 c/ X% Z @ else8 X" k5 X6 Y; Q8 f1 [% L! L: }7 ~
{
2 t" U, x7 s O' D, D' R }
1 C1 m. O3 G! s4 j, \5 d! x return 1;
1 N- j9 O1 q1 D2 P}
0 t% d8 v' U) Y: S- R" Y% x0 xstatic struct cola_device_ops ops =
" i$ N, r7 N, V9 H& _' J/ l e{3 L2 R' M. ^# C$ k$ h8 T `0 [
.control = led_ctrl,
" w6 K+ F' t$ {};
( k5 @! G; L& D$ @, s! d$ fvoid led_register(void)8 n" T' g9 Q1 ]
{' N" `0 l1 Y, g& K
led_gpio_init();2 m& w2 Y( `& O0 V+ w6 I$ I
led_dev.dops =&ops;
, k9 Z; b- \6 l: }0 u8 v6 { led_dev.name ="led";
6 k) M, ], m$ o/ h# N9 ]" p cola_device_register(&led_dev);) w/ y0 `8 F! t1 I1 p
}应用层app代码:
8 P2 n; W& ~3 x' ?( i#include
1 W' R" p: `- ?#include "app.h"
/ D( @; C% X0 t#include "config.h"
, ^9 \# b8 V: J; ~; m5 ]: U#include "cola_device.h"! O9 n% k# K, I0 @
#include "cola_os.h"
y% t7 j/ L ~% e7 I) S5 estatic task_t timer_500ms;
9 H q4 _' @" p9 @6 B/ e' c+ ]static cola_device_t*app_led_dev;
) U( G3 X4 l* _# }! n( q//led每500ms状态改变一次8 `# H# s8 S& [. w( C6 X. ]
static void timer_500ms_cb(uint32_t event)) [) b' r3 z7 o! Y
{. A- T2 N' Q+ d5 f' Q0 ?. l
cola_device_ctrl(app_led_dev,LED_TOGGLE,0);
- {3 Y4 ~6 k# @+ e3 N* Q}! C' M8 q/ g3 x
void app_init(void)
4 c8 A9 a& d9 [5 v4 U{
- F% a! s. Q/ N5 H7 p( O( I) j app_led_dev = cola_device_find("led");$ c9 z4 }% p# P! H& K. U; x a
assert(app_led_dev);0 n5 f$ G! I3 }$ J# a
cola_timer_create(&timer_500ms,timer_500ms_cb);/ ], e' @% A) i" m
cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);
3 V6 i) U( B$ d8 ~3 P}这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。. E7 n: x0 k2 _9 i7 o" k7 U
四、代码下载链接https://gitee.com/schuck/cola_os! O R0 _9 p1 o D4 C
原文链接:https://blog.csdn.net/ziqi5543/article/details/101512722. y7 V( k3 h0 N5 ~7 o4 D
-END-
A5 Z& c. X8 H/ K# w1 s往期推荐:点击图片即可跳转阅读
3 `4 ]& @. R% \) I" s / C. a# z/ \8 [5 R
" f6 }9 p& f! }. A! Z7 ^7 h5 W5 q, U( a
' l2 _' B! K: L5 S0 Y1 k
$ j B% L! i: @( r6 d! E8 e9 a
qffajmyjrru64026495527.jpg
9 @0 Z/ e2 R& U+ `. A6 G
2 N+ c' ` @& p7 f4 H' i/ N# C 嵌入式 C 语言的自我修养( u. R" c. B5 i E0 G. M( t/ x
# J9 v0 W; J# l- C. _; [4 X" r
2 B/ E, | P+ U% u% f " A# J0 d! U7 ^8 [( y& R0 N3 l! P2 I7 _( q
5 Z y% F& x$ n! _- h# S
dfe224e5wga64026495627.jpg
6 m/ T, t, {0 C7 T2 U # N Q6 v' r3 y4 _
被 char 类型的变量坑惨了!
2 o, u/ K/ y/ C5 C6 W1 E) L2 L / {: Y1 J3 j3 E* u5 H; {
: l" R8 Y5 Y) t- O/ p6 ` * a$ r, s$ Y' K* A4 {, E& T
b3qpejpoxth64026495727.jpg
2 D3 ^ j+ R! r. v8 P1 k4 X8 v
% u$ w+ W4 K0 f 嵌入式 C 语言知识点,动态变长数组
, {. m- G ]1 a; x8 I
7 |5 S0 @$ u9 \" ? ; L, @0 i0 d/ o `: ?- L" W/ C
$ C1 V2 B4 _8 r8 }7 b8 a- J
我是老温,一名热爱学习的嵌入式工程师
2 d$ _+ Z( U2 Q6 b; b关注我,一起变得更加优秀! |
|