|

我是老温,一名热爱学习的嵌入式工程师5 p4 @2 f: k8 u8 C
关注我,一起变得更加优秀!一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。
* h6 s) r) u: H9 R2 Z$ S& C" W6 p使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。0 W/ g& R5 N5 `7 q% e
iqum1mzn1i364012804319.png
: B7 K2 D+ F; g+ r h% [+ C( ]二、实现原理原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。
$ ?" }. e. Z. j三、代码实现国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread
1 d6 P0 m$ l4 n l7 I头文件接口: m# E3 v% M. ]& b8 E
本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:
6 X/ }$ u* B, z9 G/*
4 ~9 w# }/ B, H 驱动注册
3 A0 A' z- _* E# I+ W*/
% Z8 \ k7 ?% C3 X) S8 ^- }1 ]& z$ rint cola_device_register(cola_device_t *dev);: L7 i, K: p Y
/*
: k/ v( a/ y7 g( q. } 驱动查找
- _* r5 _; P3 m1 o5 y: a# S*/6 U" l8 t/ v7 B; L: n7 ?
cola_device_t *cola_device_find(const char *name);2 H3 j: W( [+ W
/*
8 ^# r, E; Q' v9 B( S' B 驱动读& R& [# p) Q! H: J2 o+ ?& n9 ^! j
*/3 |; `8 l7 V' t {1 i! V: ?, W
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);7 l- m7 |# S7 Q$ S$ _5 M
/*5 q$ P( Z* l9 H4 q6 l
驱动写' u8 W! A p: P1 a" e
*/: o$ p+ _/ v5 E( x/ T5 y0 P
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
( v% B: N# F5 u7 a. j9 F+ y/*8 s8 \- S4 i, U: |4 f
驱动控制) C& N) g# k4 U6 u
*/8 n& r. |5 H$ K6 E+ r! S
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);;头文件cola_device.h:6 i/ U1 Q0 d5 q
#ifndef _COLA_DEVICE_H_" }. A O& X- n6 \- l! D3 r3 G
#define _COLA_DEVICE_H_$ Z# R6 }8 i J; Z
enum LED_state9 q3 b3 |! D. C" G, S% M' k# ~
{& K5 ?# K8 ~ k% T% X
LED_OFF,; d) t' W( y z7 Y$ T6 n
LED_ON,6 K/ E) u8 m* D; n
LED_TOGGLE,+ l1 k1 D5 Q0 B8 U% O# `4 J
};% v6 o$ B. P* d; k" v. h( _
typedef struct cola_device cola_device_t;
/ M; h( }; X3 P: ~struct cola_device_ops- S, s, d6 H p3 Z
{- X8 Q f8 ]. A4 J- \
int(*init)(cola_device_t*dev);
5 r5 j+ ~ a6 G0 y int(*open)(cola_device_t*dev,int oflag);
/ E# d# D# x8 k4 `4 _ int(*close)(cola_device_t*dev);
5 d3 C: q; l4 E! Z; t5 p int(*read)(cola_device_t*dev,int pos,void*buffer,int size);
6 O+ v" M* n( r- c3 N int(*write)(cola_device_t*dev,int pos,constvoid*buffer,int size);
5 _) _# ?, ~9 t+ |2 c4 ] int(*control)(cola_device_t*dev,int cmd,void*args);3 j* o" t: ]9 b# b$ ~2 Q0 J& y+ f
};* a% |/ o% L/ [7 b% e9 T- P2 M) a/ ?
struct cola_device. e8 s- S% O: h. H7 O
{" g( \: r$ K9 h1 f3 `' T9 A9 r
const char* name;
: ?0 A! z3 d9 W struct cola_device_ops *dops;
, f% f+ {3 M4 t% H; X* A( \ struct cola_device *next;& k% C$ ^4 Q% m( ^8 l
};
% k$ K; `/ Y( u ~" f, T/*4 Q: G) X z$ e3 s: e3 ?
驱动注册
f/ \# m# M% ]*/1 c5 v* I& E% X! U" U2 |8 ^
int cola_device_register(cola_device_t *dev);
* p4 ~$ C8 U6 S9 \/ M9 r/*
r0 K, H1 L4 s& W: S/ g6 m 驱动查找0 p; U( W8 Y' U
*/
5 y& Z' F: l" V* Xcola_device_t *cola_device_find(const char *name);1 L( @! |4 B& Y8 I- ^) s- p9 ?
/*
$ S7 N" p4 r; [* v; U 驱动读
, o& J, j5 {3 S* [! P* O*/( r+ v/ i2 `9 @3 s ~0 T4 J- R4 Z
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);
2 S0 X' k o z! ^# q _: K/*
0 E0 X [9 z0 u/ G! k 驱动写+ c7 P( d+ C: [7 o) r& [- ^# e
*/
) {0 t \8 E- R; ^0 {* v, cint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);* ~8 U% x% X) T; S, I. \
/*% M; _3 W4 \" e' ^
驱动控制
0 q3 \7 }# d$ C*/) h1 O$ T- Z+ W- B$ U4 L" H
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);
: H- b" i+ P, Y4 s$ V! ?% O* x#endif 源文件cola_device.c:+ H+ t5 F* y: Y6 m8 Q# @' y& Q4 k- K# B
#include "cola_device.h"# \0 Y# `, ~( D3 D7 j: d, {* [
#include
( C" ?/ D2 g; F- k#include ) k0 v3 f( s8 C& x7 [7 Y
struct cola_device *device_list = NULL;' t0 `4 y; h6 |- y/ _1 k9 q' O
/*
; Y0 b- F2 P; l( C* f 查找任务是否存在
% s' G! i; z6 H*/
7 b/ S8 F' z' n( Vstatic bool cola_device_is_exists( cola_device_t *dev )+ n5 m9 ^! u" r, i2 E
{
9 H; ]! w0 Y! Q cola_device_t* cur = device_list;
8 x" e, Y3 d7 S* a while( cur !=NULL)
; y: y; q" ^; y+ L+ t4 D' P {
. @/ G7 \% V) \8 G6 J- H if(strcmp(cur->name,dev->name)==0)
0 O5 }6 b7 Q( ^/ j; f7 _ {
0 k+ I9 q3 V4 S return true;
! I6 T4 ]/ u1 A+ } B/ | }8 p# p! t6 A) q# B4 @
cur = cur->next;% Z0 M& g1 V o: g$ z! ?
}
4 t6 R3 h5 O& Q& T! r+ p! P3 [ return false;
% s6 ]; j+ j' x" z! ^& q}
; g2 _4 G7 O: Z: w! C0 x+ estatic int device_list_inster(cola_device_t *dev), ?4 N D+ Y* j! M" l
{
6 G& N K! |: f u4 S7 n( r cola_device_t *cur = device_list;
' J" R( J# O+ f4 E& {* O. r if(NULL== device_list)( @9 }0 p4 B( N$ v/ q* P
{
) g! N1 X+ a+ l1 D6 J* t, ?3 ]; m device_list = dev;
7 }& M% S, \" L3 ]7 C" F dev->next = NULL;
, y. D: _$ G% {# V$ }5 N1 O3 i }6 S. C& c9 \% `; O* f8 S7 m- H9 K7 V
else# `8 {5 w0 y. ^; `4 ~8 r. f
{$ p7 E) r/ ^! L3 J. V- |
while(NULL!= cur->next)
1 S7 k; w1 C- Y* g6 H9 m0 [2 l {' |( S. H8 i) K/ `8 K
cur = cur->next;; H' x+ t+ \, X- J+ d6 ?
}
2 s6 ]8 \4 j3 J' b7 V cur->next = dev; N+ G8 l0 P) I$ f) ^/ l$ [
dev->next = NULL; a2 t/ w2 R2 u/ M1 K0 s- Y
}" {) T R! ^5 R! Q) [6 f
return 1;
, S' T O6 y' q; q/ {, e}. R# U ^0 b4 K6 X' S9 h9 L. y
/*
/ L3 O" f O/ G& M2 i+ o1 o 驱动注册
- d1 V( O; q" ?: L1 ^) ?7 ? C8 q*// E6 y |5 e* y, `
int cola_device_register(cola_device_t *dev), C D; Q2 j' D6 n5 J, h" w
{4 D5 U+ H0 z2 H+ u7 U. v
if((NULL== dev)||(cola_device_is_exists(dev)))" B k4 s4 K, N4 L) G
{4 V' i4 H4 a# x
return 0;2 }$ w- |/ ]- G- D" k( O
}" h2 T0 n9 p2 q1 h
if((NULL== dev->name)||(NULL== dev->dops))
8 o' u/ Z% r$ d* c8 l {3 p# w: Z+ g! l- l: B
return 0;7 B# @# |6 s3 X; y. Y) ~$ ~/ J% J
}( l; Q) j0 Z% F5 P& v" c# x+ D; u Y* M
return device_list_inster(dev);
+ ^' d* q& Y7 C! W: C2 r}6 A7 \5 @. T8 Z. b
/*
, x1 I- Q. n$ z+ [4 F3 s 驱动查找: x8 T }5 N9 R" n! L" I/ }' O* ?
*/. y% Y# r' {9 N8 x: v% F" T& i2 _
cola_device_t *cola_device_find(const char *name)# o. h4 y( f# K# l
{- D3 J& ^0 A0 ^) i* U
cola_device_t* cur = device_list;4 c1 u. Y0 v0 t8 o2 x+ [
while( cur !=NULL)6 [! h; d, T i8 ^' K5 }. M4 \; G
{
1 R" M& K9 K5 K5 L8 Q: h0 i; I if(strcmp(cur->name,name)==0); h) _1 {! R( d. D2 r9 ^
{
. @4 t/ F4 i2 t s return cur;1 R! F* _6 B) F. e1 u) j, I
}
% T4 \3 B# t1 `. T; y; w cur = cur->next;& }& x5 p8 ^ C4 G" ^; H( d( ]! R+ l0 N
}
5 ]2 [+ l" P: i1 y2 P' m5 d7 c0 U1 s2 _ return NULL;8 |8 f; g. g' `
}
/ Y5 u( x) }3 D: K2 I) O9 a/*
2 K1 ]% u% e8 d 驱动读
, v- V+ V# i# O' x1 l* K*/
% q( D& @. M$ C4 F5 a( |int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size)! {9 t9 h, f* F) s. ^- `
{0 N" h; m8 {! O. v: G) l
if(dev)
0 u3 h7 h( a o. X0 ? {' B4 u* j# e0 t6 p
if(dev->dops->read)
) i/ D$ D9 ?/ g* |8 F- I {; o) d& u) k- X
return dev->dops->read(dev, pos, buffer, size);8 p0 y2 v A7 x& \5 E* |
}
( v% @+ B& U* i0 z }
7 {" [/ o* l% d* N t return 0;
# _$ @2 `4 u) K5 U4 Q}8 a1 P" ^! U* d/ c/ K; b
/*
- A+ e6 l% C. k+ f 驱动写
) W9 i% j/ A+ V/ ~( ^+ ~. \*/
" w8 D* ^1 N( M4 Z1 Z oint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)
6 k' m& I" h" m6 o' n{
; q0 p0 g, x7 Q, o8 i: ~% u; X0 b' s if(dev)
) |) |" w; _2 K) o: c; S {
/ z( t! P) u4 Y& Q if(dev->dops->write)
2 ?4 h. r! f! u3 `( [1 c; R {
: f! z: L8 k) X" R' }1 ~ return dev->dops->write(dev, pos, buffer, size);/ f8 v. {- m' F, p
}
! u+ X: t4 O" P, H }
* {% c& w% P+ A- l8 X return 0;
! i# d$ ]9 e- Q* ~% A" K} B+ z) F3 {6 J# M2 b
/*
/ d& g# C% {2 |3 U. s 驱动控制
5 G1 Z, W6 t: S; H*/5 J+ p4 b7 Q; u; Y! \7 q
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg)
/ F" k2 B# i+ C{+ Y% C( Z+ [+ _: h- Q+ J/ V
if(dev)
/ B: f# D8 z7 u& f2 l, T {( m: D1 i% y) d# l3 p0 b
if(dev->dops->control); x2 t. K3 ^4 k% _, p
{
7 l I" M, g0 y% x( ~3 E" l6 Q" Q3 x return dev->dops->control(dev, cmd, arg);) S' J7 p7 }% v
}
8 @8 y" }9 C, Y7 \ }
) H4 s: g1 x& S, a return 0;
3 F+ q; b- a" {; @5 Y}硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。# v0 j O9 V/ s( ]. J8 }0 `. s
#include "stm32f0xx.h"6 x% r, r& A+ @: B h" [
#include "led.h"( T; ` A/ q D4 z4 L
#include "cola_device.h"2 {' w; P( ]& T. k" m; M1 t, i
#define PORT_GREEN_LED GPIOC 4 ^3 p r+ e, r
#define PIN_GREENLED GPIO_Pin_13 , _# j! O/ `; n+ k: e2 e/ n
/* LED亮、灭、变化 */1 t5 C1 X% t/ B" D
#define LED_GREEN_OFF (PORT_GREEN_LED->BSRR = PIN_GREENLED)
7 Q! u, E5 U& r& K3 }. {% i M#define LED_GREEN_ON (PORT_GREEN_LED->BRR = PIN_GREENLED). K' @7 f- j" T+ @
#define LED_GREEN_TOGGLE (PORT_GREEN_LED->ODR ^= PIN_GREENLED)1 L4 G: u) z/ q! D" A* Z$ |% r
static cola_device_t led_dev;( u; N) ^7 \, ?( b) f& n3 x( Z
static void led_gpio_init(void)0 _' n: x: E" u |7 L6 K
{0 m! L7 ?3 x) @" J) X
GPIO_InitTypeDef GPIO_InitStructure;. K+ e" \3 g. ~* f8 D2 z
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);: u; o" r" H+ M! H' J
GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;
' x- v, I1 B6 d, X$ @& U- | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+ e) E7 M) {) j: D+ g GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
0 _) A B6 u9 U( H4 H( T GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
2 ]2 e+ b l) \2 R! o! c. I GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
3 w0 I1 H+ R2 Y GPIO_Init(PORT_GREEN_LED,&GPIO_InitStructure);
8 r) k# ]9 s2 K3 G0 j7 b LED_GREEN_OFF;1 I; E5 p6 v2 D) d1 U
}* T3 b3 P7 O! }
. o% |; W; j8 p, K# V
static int led_ctrl(cola_device_t *dev, int cmd, void *args)
6 ~' s0 g8 {# q r8 j- m3 @{% N9 s" l% u3 ]* y* `/ ^
if(LED_TOGGLE == cmd)
" v# U; ~; w+ F6 w [( M2 u; h {
! @; J; e# k9 @+ K: A7 J; _ LED_GREEN_TOGGLE;
- X- ?# n2 N& M9 F }/ W% f/ v3 [' A7 R! H5 M$ J3 q
else: N9 P/ E9 e$ _! C
{9 j% P( c" j. H9 ^! `5 ^+ x
}
8 D/ S- h- R, c0 S8 g- a8 n return 1;% b( T$ C" F( U/ G) L8 X7 K" {- w
}2 Z. v7 {. W" |, S
static struct cola_device_ops ops =5 I3 |2 F& A( d4 j
{# o& t$ x c& p3 P$ o/ c- w
.control = led_ctrl,, n C8 ~0 L5 B1 j
};1 V- i! |! r6 `, l3 Z! Z B9 U
void led_register(void)- i+ c- `, I5 Z3 ~, q+ L! N2 p
{
`4 V2 P8 h3 l+ Y0 A' Q, O) v led_gpio_init();! m+ t, R* Z% @
led_dev.dops =&ops;
. @1 q/ C+ O8 \& b led_dev.name ="led";9 @ y7 E& b( {, T
cola_device_register(&led_dev);
- h4 _% ?9 T+ y( I' R6 `% V0 R}应用层app代码:. W; z& g! z) d
#include & z; y0 P9 S* o+ `, l
#include "app.h"7 I/ n; u' I# T, C
#include "config.h") X. N4 o) }0 e- u$ E0 w
#include "cola_device.h"
1 ` G( ~: Y; E1 |#include "cola_os.h"
. W9 I# H2 o1 Y( Y6 K9 D* _7 T5 nstatic task_t timer_500ms;% T" s7 E3 Q$ g4 J/ F" u
static cola_device_t*app_led_dev;
3 ^5 l; V& Y v) j//led每500ms状态改变一次
* ]/ w+ h3 u7 G) d/ ostatic void timer_500ms_cb(uint32_t event)* C! M5 i4 u' x3 R
{7 T" f0 v0 F; l0 Y) J+ j# u
cola_device_ctrl(app_led_dev,LED_TOGGLE,0);
* D: i$ b3 p7 [3 @! L% I) R}4 g& D* E- U' |4 b' {' h4 ?
void app_init(void)
" M# I; |4 j5 C, @& w! B{! ~$ N/ I% w2 D2 B/ ?0 j2 W
app_led_dev = cola_device_find("led");
+ V' v5 ^5 D. `. M- Y3 c& K assert(app_led_dev);
7 e: u R0 e5 t8 C( ^; U* \ cola_timer_create(&timer_500ms,timer_500ms_cb);+ e6 K' }. k: o" k4 ?
cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);, a- f: \& _4 a# @
}这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。
* l/ a# W1 G( {) D# D4 t$ _3 h/ W四、代码下载链接https://gitee.com/schuck/cola_os q. |- N9 b+ j5 R H
原文链接:https://blog.csdn.net/ziqi5543/article/details/101512722( M- ]( H: O9 M9 S6 Y
-END-& B/ E3 f+ n8 p4 `
往期推荐:点击图片即可跳转阅读
* t2 p) ~0 a4 e+ | . I2 f- S/ K4 L2 X! `. q
" v) Q. w- j3 N& l
- ~$ H* d9 D7 D+ f
% l2 o; D; f" g m5 Q
cn3tnkaahgv64012804419.jpg
+ C( @( m! W7 P5 U
6 q, h, J0 C4 ]0 N 嵌入式 C 语言的自我修养; D. d5 c+ x; }$ Q3 X; P; M
0 E+ a0 t$ E6 [! C
! h0 ?) M. m ~( q* |
. G o, G t4 U* f* O. Y l% @* C
. P/ P7 B$ z* x: r, t% j0 E
gx4vtvp0u0r64012804519.jpg
9 h' }+ G' W3 i0 T& k
+ C, X& W9 _1 P- T F* ]; Y 被 char 类型的变量坑惨了!
2 E( C N# t* G4 {- n
. A( r/ N% B0 X8 I5 Z& d ^ + r* d6 f o" r) w
% o' ^1 u$ c0 M1 d
qjozbkpbfwf64012804619.jpg
) {1 I% S3 q0 D 5 n6 g# i9 R6 ? h( B5 S( |! K# T
嵌入式 C 语言知识点,动态变长数组' A+ J! W4 N9 F- I: B( @- I! q
0 J- A. x) d3 x9 }
0 j9 I7 R4 |% a u ; G" q- u. ^( M! }/ j# k
我是老温,一名热爱学习的嵌入式工程师
3 z, ^2 N: V# X. `% G关注我,一起变得更加优秀! |
|