|

我是老温,一名热爱学习的嵌入式工程师* i L- f$ J2 B
关注我,一起变得更加优秀!一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。% W* m% n, d3 l+ Z8 }& _! A
使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。
7 l. `( P |' u1 _: U
4pm3zqnxh0k6406080032.png
[; @) d& {$ x6 ?0 W+ [二、实现原理原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。4 O4 r$ {4 p9 C
三、代码实现国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread" J* O% T2 ^; ^" ^
头文件接口:
' X5 L6 F1 z' l( B7 F: C1 z( }" W本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:; p5 r- B/ k, ?+ v& V% b" ?
/*7 D" o7 N# |' G4 x+ g7 ^/ D
驱动注册
% A4 p$ U6 p. {- [*/
( a! x6 A% _7 T. i9 y* r- [int cola_device_register(cola_device_t *dev);
1 t% r: J) O6 q+ ~5 j/*
: }6 m |5 w3 F4 e6 A! y5 D9 G 驱动查找6 l0 @1 l+ x. j+ q/ O
*/
- ?% K0 V; i! C1 t$ O, I @cola_device_t *cola_device_find(const char *name);
; r/ ~% t0 N1 O: S+ e7 |* {! H/*
8 z5 V. N0 `; `! s/ D8 a 驱动读
; [) W* N( z/ n! Q5 p9 s% A*/
8 e9 y1 \( w% _) |int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);# i$ R6 ]+ C/ T" s5 ^' t
/*
8 T! l0 f( v$ X' {0 j 驱动写
( M6 v& [* X- F2 l d*/+ H0 D: k8 p6 e( @; s2 O
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
5 F2 e$ q) t6 p1 j5 k/*5 U, q: O# Z9 G$ x
驱动控制, j, A9 R* B2 f6 E) m
*/
: j7 y) K# x; ?2 k" f) qint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);;头文件cola_device.h:
0 ~" l7 i5 K4 ]6 q9 ~#ifndef _COLA_DEVICE_H_
# A- k, `4 T- E' Y. _2 K; _#define _COLA_DEVICE_H_6 G2 `6 G8 C9 f/ k/ E% R" R- c4 ~
enum LED_state& c, v' k2 ~" L
{
* b' x7 ^ [& s1 r" x LED_OFF,9 P% v2 j6 S A* o5 O' ]. ^7 ?
LED_ON,0 O6 ^& Z! I: m" G1 _
LED_TOGGLE,
]& n0 y$ t# J; n};
! J: c5 D( l# l+ ], rtypedef struct cola_device cola_device_t;
# R: Y' U! B0 }* O# Hstruct cola_device_ops
: f5 N" E* L; c3 ?{. `, w+ R( d" V! C
int(*init)(cola_device_t*dev);7 b, Q. w, e& p+ U+ r# t0 K' J7 O& `
int(*open)(cola_device_t*dev,int oflag);
; p+ c' m# h& e0 w) Z6 @ int(*close)(cola_device_t*dev);
+ f+ k8 K6 J* w- F# O0 J2 u2 R int(*read)(cola_device_t*dev,int pos,void*buffer,int size);% A% e1 }! D* w9 ]1 H9 M) }9 S4 V- I* u
int(*write)(cola_device_t*dev,int pos,constvoid*buffer,int size);. _! Y" Z' z+ C# U
int(*control)(cola_device_t*dev,int cmd,void*args);
( R% ?# T o# [/ E! p};
+ u5 x1 X& ?0 H- p1 Ustruct cola_device/ i* x" l O) ]1 r) U
{; S% x' H z. f
const char* name;
/ l7 z/ m+ w( [" N) ] struct cola_device_ops *dops;& Y* s7 |" @ K, V) N/ H2 A
struct cola_device *next;- @6 Q* X3 e C. M
};
" U6 {! l$ V9 \1 o/ D4 P" I/*
1 \. D0 A$ x) r; v. a. j 驱动注册( {- w# \& j# v7 _3 j# Y/ |
*/
% H* E9 q% f M4 tint cola_device_register(cola_device_t *dev);
4 K: L' m. d0 g7 x; A1 Z/*2 X1 c0 `: i3 _0 X
驱动查找0 r! Q0 ^( ~' |7 H5 O8 O
*/
; ]$ A9 e2 ~' h+ Z% S$ Icola_device_t *cola_device_find(const char *name);
1 s4 G1 w; r6 P/*
o7 q9 ^9 a0 v( ~5 d( d% E 驱动读
+ D3 i+ H! ~' l0 R9 t! G*/+ ]0 i8 v0 L% w4 q9 R. A
int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);5 f+ \( Q; \# N
/*
+ A4 _0 u; z" {0 D# O 驱动写7 q+ z% V6 w6 ]9 [5 b7 @) @: i
*/5 @# x: s7 i$ j* D. C& U3 N
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);0 @4 S9 W+ N# T( u9 u; ^9 v7 K
/*( {( ~4 y, W! y
驱动控制
. L$ }+ H& y7 z. c* T*/
! ?$ ^' Q0 O& C9 [int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);
- e+ w6 G3 Y6 ]9 t$ Z#endif 源文件cola_device.c:
) s' c! z9 C b0 { E' n#include "cola_device.h". i* ?8 |! e: b8 p2 M/ o
#include 0 O1 H5 k$ m1 J! L1 ^
#include
8 S5 A9 q9 W* V. Fstruct cola_device *device_list = NULL;* r! m9 y% L- m$ z/ @1 \
/*
# B \4 t( i5 _" [ 查找任务是否存在: j: [- B- v: ` z( J
*/
5 O1 g9 m, t8 I3 s3 B1 kstatic bool cola_device_is_exists( cola_device_t *dev ), s9 Q; V, e6 @/ B& k+ Y$ M2 A9 p
{
2 m1 E& m5 ~' E2 [" o N! b cola_device_t* cur = device_list;
. g- D8 M: G7 D- J5 ~) | while( cur !=NULL)7 q6 I9 z- X7 o
{8 c( ]# ~* @! l* _. H/ |$ N
if(strcmp(cur->name,dev->name)==0)( t& n) Y) O8 S; b
{( ^2 `0 a ?( u, r( {# [
return true;6 i% H7 r& |2 ]
}" L$ @% M" x4 Q9 b S! U
cur = cur->next;
- _% J0 v& g! ~4 _+ F }% q& |3 E& a( g/ u! ]( F
return false;! d7 c8 K1 t3 I2 P: L2 M
}; D+ Q( J+ T. o4 e6 G9 P) u3 b
static int device_list_inster(cola_device_t *dev)! Y$ R( m2 X6 \1 K# `
{- c! w3 k7 X; O: z2 J9 G! |
cola_device_t *cur = device_list;8 ^+ n) L1 F8 z' x" ?! G
if(NULL== device_list)5 }# ]* F& i R& t g# ]( X7 z
{
( l* P, R6 }* K device_list = dev;5 ?3 E2 E6 v& k- o; R8 w
dev->next = NULL;% q- V+ f7 }0 Q! m- f0 G( ]
}$ F7 k# }- F2 v
else
* ^6 x. I+ e! | {
2 m p2 u V$ F0 ~2 V3 N' b6 P while(NULL!= cur->next)
' t& y ?# m' M6 y2 {" c {
3 x5 \( f& v d* m' I; J5 z cur = cur->next;; [' B; @0 k1 U) L
}2 O' A5 J! G7 U! W( a; c+ q% o/ o
cur->next = dev;
1 @+ e' q6 b6 m! ?& V dev->next = NULL;
5 I- S# E) ^; R8 b& a" o1 g }7 P- f, J/ ^; B+ y! y3 ?0 |- e$ B5 S
return 1;
A% H/ m' C- e2 {7 P1 ^}
5 E1 o( x8 |, Z/*
! P1 r+ j: _( q 驱动注册7 O' v) {2 _ c5 a j
*/) ~: i5 v( O' ?% i; r
int cola_device_register(cola_device_t *dev), {* ~# N& w% I
{- F8 B4 @" B# D, f
if((NULL== dev)||(cola_device_is_exists(dev)))
0 \) D: w, g! [- t# { {
( c7 P7 E8 H, F, [3 O& z' ^ T7 w return 0;; ~; N; d! U7 W8 ?/ r
}
. A0 p \* `& J5 L9 ~- `2 ~ if((NULL== dev->name)||(NULL== dev->dops))
/ P& N4 g, q8 f% D* {9 I {
$ Z& \# z& z; w) P* C return 0;
; E7 G, `9 C: W5 ^; n7 U }
$ j. n* h6 ?5 h) r& D# J1 R" l return device_list_inster(dev);* Q0 L5 x( S( m; ^& M
}4 w- N: b! K8 _+ U2 H/ \$ e% a
/*
; p) k0 u% d5 e7 S- @( S 驱动查找; p; M# T0 W4 J$ C9 b
*/) m6 ~3 C/ I1 D3 D
cola_device_t *cola_device_find(const char *name); N r! q, z9 a& t' q' f
{% V! w, |( G( i
cola_device_t* cur = device_list;
' C! S2 q0 r! j3 B- P while( cur !=NULL)7 z7 U% c! M5 E
{" w" x" M [1 n, f# Z; y
if(strcmp(cur->name,name)==0)
+ o, [/ N6 }# K2 N+ u {
5 I. h6 w+ p- C8 L return cur;4 B8 D6 F% ]: x
}
2 d4 h6 o* M& M m" d7 ~- Y' u- K3 u cur = cur->next;5 O" a% T3 r n, i; J" J4 x1 t/ G
}
* Z4 Q. y( e7 K; J9 U, m; { return NULL;
% u+ `4 Q! {: f0 B}1 n* W! @% t7 [% q
/*
9 [/ q7 n9 Q! U 驱动读4 L8 c% l- ?! o& q: l( S5 U% I
*/
! N _. _) [5 v. t7 T3 }. w; hint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size)
5 r) W: J$ X& F `2 x{
- K, ?# {+ T* `& E/ a3 `3 X if(dev)! v, o0 ?5 B. A6 R( i$ v' {
{0 [+ p. T. b3 K# p3 z% }( c0 ~
if(dev->dops->read)( N/ ], K! h3 N7 C6 t
{
$ n3 A2 W. z* {/ c/ T5 @ return dev->dops->read(dev, pos, buffer, size);
. X* h+ m- C9 u* y( t8 h7 L. }+ Y }6 y" Q* w" n% h' X
}
7 o6 B1 s1 X$ _# C( ]8 v return 0;
1 @& {8 P' ^1 L8 S; ~& L5 a0 N0 B}# x4 I3 i6 i' U4 a0 C) J3 Y
/*
3 N- F0 U1 t& ?3 r" {' d 驱动写
5 U4 ]1 D8 }* q6 T- S*/5 R/ q. M9 z. Z
int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)) b [, z/ q5 c$ j
{
% y- D$ \8 U8 |7 F" [+ o if(dev)
9 D/ M7 U/ }- j* R. X: c {
3 ^9 L: m3 Q% p$ a" Q/ C if(dev->dops->write)9 l9 ~8 {2 C {! q, Q
{9 f4 o1 [9 e* m/ k5 X0 H7 D& }
return dev->dops->write(dev, pos, buffer, size);4 Y, b9 J$ o. i5 l9 H* o
}; @4 x! J6 G! o+ j
}
6 G3 P; u9 J4 e return 0;2 ^2 g Q6 c+ f& d# U3 M- ]
}
4 z7 q y# a, s+ b' o1 L* l' D/*
# U% g3 L# }) \' y2 w! R7 s 驱动控制7 |( r/ j8 A" |6 h: X6 w# @/ w
*/! U* W' y, g: d( d; M0 m1 k2 Z
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg)
) _5 u, G0 R3 ~& y6 O" Q7 ]. i$ c{# V5 w, t5 \/ B% d2 s7 }5 k8 [
if(dev)
* l8 C' N" U; n: H) [3 R {: L; I; a/ ^* P# i: W5 A: [' |
if(dev->dops->control)7 E- H# X& r. `* j& u2 N
{
7 v- m6 w3 g" ] return dev->dops->control(dev, cmd, arg);5 J0 F5 W( J& b$ W% j
}# `# L0 N& ~+ E
}1 J9 U+ M( S+ Y
return 0;& W. ^+ h5 Z. }' \. y2 V7 ^( x3 F5 J
}硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。5 b, F1 l1 e% V% ]& l$ _5 v
#include "stm32f0xx.h"3 P: f6 w; y8 o- _
#include "led.h". c+ G$ r# f. f& h. l9 b
#include "cola_device.h"
+ D4 o2 ~: n+ e0 M! G* L# b% e( k#define PORT_GREEN_LED GPIOC
5 _( x8 }/ A5 c4 V% O#define PIN_GREENLED GPIO_Pin_13
* z! S d. M$ B# D; z; c6 K8 W/* LED亮、灭、变化 */
/ E" V" A' i E0 l |; t8 R* j#define LED_GREEN_OFF (PORT_GREEN_LED->BSRR = PIN_GREENLED)
F+ C; ^9 @0 s' C#define LED_GREEN_ON (PORT_GREEN_LED->BRR = PIN_GREENLED). o8 p$ r* E, h/ V$ m
#define LED_GREEN_TOGGLE (PORT_GREEN_LED->ODR ^= PIN_GREENLED)
2 s- F9 i4 k. {8 X6 ~static cola_device_t led_dev;
: M: _) f6 ]/ Z1 y/ g. M% Vstatic void led_gpio_init(void). d ?4 t* V. }1 K* x; `) ]
{, @2 C( v& Q& [
GPIO_InitTypeDef GPIO_InitStructure;1 n% A, [* T4 d" Z7 P; l
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); K% F2 x+ _- K# R
GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;
: U1 G2 F1 F) h* x9 D3 f GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
" B: g2 ]& ~. f4 E: i GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
' {+ |; x7 ^( M GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
5 W- n2 h' X% K5 ?; p GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
0 n# _/ ^, N/ ^3 e" }( x GPIO_Init(PORT_GREEN_LED,&GPIO_InitStructure);0 I$ ^" v" ?; p
LED_GREEN_OFF;$ c: q' ^ h4 E$ \5 i1 L( h, Z
}9 K, I8 B' w% P4 l
, T" \1 |' v' Z( F: Sstatic int led_ctrl(cola_device_t *dev, int cmd, void *args)
9 M, U" P! \3 l( K) h; G; U; W{
8 ]+ Z: m4 E& h% k' A if(LED_TOGGLE == cmd)
+ y2 \* R' |+ U" Z+ | {9 z% |9 J- D3 M% P' N- T" m
LED_GREEN_TOGGLE;
* u$ X- L) \% |3 x- ] }
% N5 L) p2 {" F X# k3 o3 G/ } else, H. Y, H$ C. z! h/ ~9 y
{
% P+ s# e7 k6 p# ~& ` }+ ]. `6 r. \4 I% k3 ^) E) s
return 1; ] P& l; J! ]9 L4 T( L2 u
}4 M! |: H4 H; |/ B7 E, p8 n. g! M1 l, c
static struct cola_device_ops ops =
; c3 v9 z$ z/ O$ E: B{
- A6 [; G. q7 G* f8 M+ v .control = led_ctrl,1 R8 {. v: t, x) q
};( [7 `* ^* e' a% @+ V+ i( C( r
void led_register(void)0 d$ o1 E/ v# ~6 u+ O2 c- ]0 |1 P
{
5 z7 @7 r/ h9 \& k& ]+ K# T led_gpio_init();
8 r) p5 A& S/ h7 {& D led_dev.dops =&ops;
$ f3 y& I" X ~7 a# S4 p8 m led_dev.name ="led";
, h: a8 p( v) a% b cola_device_register(&led_dev);& S+ o/ s( h- o- g0 a/ o# `
}应用层app代码:
0 k5 b/ r' u8 V1 A#include
; q4 `* |+ C6 b H6 p/ m+ w#include "app.h"
8 e& k6 e# j- P3 U/ }; `#include "config.h"
/ ^6 ]6 O: h4 T) ]9 a' B7 z% f0 x#include "cola_device.h"( j* g; B4 y9 b6 C
#include "cola_os.h"6 P5 ]$ d8 j8 c( ?6 l
static task_t timer_500ms;' Q* X9 w- R1 A5 D
static cola_device_t*app_led_dev;
1 _/ j2 j! L; G/ r3 R//led每500ms状态改变一次; D' H: D( M7 K1 y7 ]1 L6 d
static void timer_500ms_cb(uint32_t event)
+ @6 @2 l1 p0 e8 B{. v" G6 ^2 S3 A. j0 Y6 w0 u
cola_device_ctrl(app_led_dev,LED_TOGGLE,0);
9 |8 O9 h3 m0 R9 l+ [8 P; m' [$ i}6 A& @" i f4 H+ W2 X
void app_init(void)
# [# X0 i$ f; ]7 h; g! Q! l{
* ]" V) ^. k4 F' o. \; s app_led_dev = cola_device_find("led");+ _4 U! H% w5 t; n" n
assert(app_led_dev);
: T4 R) H$ e$ I cola_timer_create(&timer_500ms,timer_500ms_cb);/ @3 D! ~/ ^- k0 c1 j
cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);" v6 m- o1 }$ Q- ?1 E" U# M% Y
}这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。
1 l9 k. b" c R+ N四、代码下载链接https://gitee.com/schuck/cola_os. C1 H( |+ v; i5 n; `( S
原文链接:https://blog.csdn.net/ziqi5543/article/details/101512722
* d( j0 ~: x0 \% ?/ O( f-END-
5 F, Z9 A' m; W3 k+ r; }往期推荐:点击图片即可跳转阅读' h% v0 g( H" u- d$ K
; K0 M6 U+ T9 s2 ]% x# ~$ k
" K/ x/ G( s& w8 n
6 t4 `) f; `" r' U+ L
! j) n `* h. F2 | `1 K
mahdxwf5ccg6406080132.jpg
% D7 y+ x; D+ M: y
7 l8 P _1 e6 j* Y: x
嵌入式 C 语言的自我修养
W9 y# P% M4 \: k% n0 o' s
) b! j& y& \: n7 }& z. U 5 D! z7 ~$ y2 @; d
. f: f0 K5 D( W3 u: s
4 z. Y" P' @9 n' T2 g3 v
wcjwldqw0tb6406080232.jpg
- |6 V5 F$ a" l* X
! T2 v8 U- _8 n4 O: o9 f8 z' D* T 被 char 类型的变量坑惨了!/ p# {3 N* L, W9 N$ o: n
( z, ]9 M2 z1 M1 B- \
8 V4 I& l! d- }1 V$ W4 E
. x0 [) Z4 j5 L3 ~, a
hdpnidmviml6406080332.jpg
& N5 X* Q% L" z5 F1 p' J5 O $ o- H2 j4 M6 L3 G. I- L
嵌入式 C 语言知识点,动态变长数组
$ s' K' z. P* G. d$ i ?8 X" C
; }! d e4 F, P6 ?$ t! a
4 I. X) k, X0 F5 j9 l: q! y" N ' r: y' I# T1 @* [
我是老温,一名热爱学习的嵌入式工程师
9 ^. v* z9 s: J1 e; L: l! D8 f关注我,一起变得更加优秀! |
|