|

我是老温,一名热爱学习的嵌入式工程师
% `. Z: A; \+ g关注我,一起变得更加优秀!一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。
& z; m) w1 Q" z6 ?8 f ^8 ?使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。* u6 J3 r$ u% z; K5 Y' ?2 `
fklzywkcs2a64033372513.png
* x; l) l ^1 i% A7 t
二、实现原理原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。
% a$ o, Q7 z- H5 L三、代码实现国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread$ F' O+ _9 F, P7 X9 N5 J9 J0 t5 H$ x
头文件接口:
# P1 `' X) j3 n1 G+ p9 V8 e本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:7 e2 _" A3 }* s' \( V% Q# c
/*! o$ K* T; w. ?( t, V
驱动注册3 w3 |6 r$ M) E7 B3 R* N4 \
*/+ V; D( B! j6 m7 O4 y1 z f
int cola_device_register(cola_device_t *dev);
7 q; F9 w0 k- V4 w; ^" U* M! y4 O/*
, j8 b$ R) R4 ]5 @$ Z G0 s# e! Z 驱动查找
_2 V/ G, C# v* I2 d7 q6 `*/* i5 \) T7 R, x9 o7 @* l
cola_device_t *cola_device_find(const char *name);5 O4 v8 `6 D0 @9 S" W
/*
4 d+ F' o5 D( f5 M/ o6 n& M5 { 驱动读
4 O" m' O9 t" {5 q g*/
4 e6 S% T) a* i9 z7 qint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);. _+ g- F2 E: A7 v* D! t. m1 m
/*
3 L; ]" r3 E" C) e 驱动写
+ a! d2 a1 ?2 f" ]/ a" j*/
$ k, ^4 X' D) {1 T/ O! Z+ k5 b( r8 _int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);2 V# B" D" Z: U
/*1 Y6 S. D @8 s8 {' H2 f
驱动控制# x [: L4 Q, o" |# ^
*/4 ~ E' M8 B! ^5 z2 P0 M
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);;头文件cola_device.h:
" b% Y) u5 H: ]9 b# {, o: Z4 \#ifndef _COLA_DEVICE_H_8 K U5 n4 _1 R, }
#define _COLA_DEVICE_H_( l4 m! l" |0 ?% z9 K
enum LED_state
$ |- E7 D! ?! |" F{
6 O6 j) F( N1 M7 q6 D6 I LED_OFF,* @8 K% K8 N3 B7 l
LED_ON,1 A& C1 W, n, X2 {4 k: H8 Y2 X, c
LED_TOGGLE,
9 d# V: M/ l# |- R* z+ E};
* C: _* e$ U' }typedef struct cola_device cola_device_t; f& G2 p, I6 H5 i W# ?; j
struct cola_device_ops- f9 V4 s4 I+ P! j) \
{) {" Z) }" I, L7 H% s$ t5 G5 p
int(*init)(cola_device_t*dev);
( I' y) M" l$ E% _ W& Q) U int(*open)(cola_device_t*dev,int oflag);! r' Y* f9 v" S& U
int(*close)(cola_device_t*dev);
6 V2 f7 S. Y7 F int(*read)(cola_device_t*dev,int pos,void*buffer,int size);
{5 @! f4 c- ?9 _* \* P. C! H+ C" x0 ? int(*write)(cola_device_t*dev,int pos,constvoid*buffer,int size);/ q0 }2 E2 M L( b: [& h9 X
int(*control)(cola_device_t*dev,int cmd,void*args);
* Z" w I5 w& u3 f};8 @9 a2 C9 W5 ?8 [* P
struct cola_device. i* c5 O& o; o* F2 M( D1 J* y
{6 D) W$ O; I6 _' L
const char* name;5 u7 `- k! N# c
struct cola_device_ops *dops;' q+ d' R; m c' o1 ~6 b9 W7 C' `
struct cola_device *next;' p) w& c, N% j* ~
};& Z+ X5 b# W1 y. s: X
/*
5 l2 |8 u7 D# z" w- T% m, a 驱动注册
* w W8 L: n' R3 S*/2 q2 U0 n/ r; l8 ]; ~
int cola_device_register(cola_device_t *dev);/ Q4 ~* ^4 r/ E5 l) R0 A U5 F
/*
, i* E8 y P5 |2 S. w% }1 W3 z 驱动查找
# T. ~5 E4 @; A$ V) e*/" o1 {) c. c" _
cola_device_t *cola_device_find(const char *name);' Q; R8 a( t0 N' @. U5 g4 T
/** @7 d% {5 L6 ]6 q
驱动读 \3 J$ G4 G+ d" W! x
*/
# e7 J: M4 V/ b1 Dint cola_device_read(cola_device_t *dev, int pos, void *buffer, int size);
& J, L* l9 Z5 y9 n( n8 j" F( _7 W5 r/*+ Q& q' q c" u2 W$ F
驱动写
8 E/ a1 T# m* s& ?' A, G*/
1 P5 q& ^2 _1 v. F( o1 n/ l" \. Wint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
w, i7 H) H' _+ I/*
" V/ D5 f, F# W4 k 驱动控制
P) W4 X2 ^* w( I*/
( q9 ?: }, }' F# Y' n6 qint cola_device_ctrl(cola_device_t *dev, int cmd, void *arg);
! F1 T6 p5 z. i0 n: p, c6 B#endif 源文件cola_device.c:% Q5 B* K, W( x" `1 G6 V: O
#include "cola_device.h") f) x( Q* q# d$ j% C4 @6 M
#include
: m7 D& Z6 P: D) C#include . C0 O/ x) I; S
struct cola_device *device_list = NULL;/ _0 H7 T7 [- A
/*/ G& k) I9 V! I9 i
查找任务是否存在) G G H0 ^- Z# h$ r' m
*/
9 ]+ t6 e/ i2 e6 \* |, kstatic bool cola_device_is_exists( cola_device_t *dev ): d. z# P9 L) G: l; _0 y
{
C& w: B ^9 C6 [ E cola_device_t* cur = device_list;
% [* M. y8 `' X* W while( cur !=NULL): Q' p* N, X. G5 ^
{5 @( |4 Q/ n I% f
if(strcmp(cur->name,dev->name)==0)
, F, b9 \0 H4 k+ |; v {# X* A$ F" r8 Y" o2 `0 ]
return true;
0 x0 O. F: |( {- g }' `5 ^1 n/ S6 ]5 h9 b% D r
cur = cur->next;. C+ U8 J9 K" v/ S: z
}' A- p! k& C- x- k" z$ C- d5 I3 Z- f9 K
return false;$ F* J, |& @$ B8 a/ s& h# _$ S
}
7 E5 P) U4 G4 L8 Hstatic int device_list_inster(cola_device_t *dev)
+ l9 e# ~( J: x9 m' p{
" C( _# c/ G* f% F. Z cola_device_t *cur = device_list;
- i% l! j/ o& m" `) Q! w: |8 o if(NULL== device_list)- c" |0 `* [- E/ ]; m4 y$ X
{# H( m& V+ d2 b$ q" x
device_list = dev;! A4 V0 Y& w8 a9 p" [6 _. y
dev->next = NULL;* l, V6 g2 ]; F4 w* F
}( J; P( n7 F. ^$ y/ A/ u
else
0 J5 i+ N' N3 w# r8 q, } { _8 D9 |+ J7 \2 L' Z x" P8 _
while(NULL!= cur->next)3 R( Q5 y; ?, z
{+ F1 j9 x* Y6 ~5 I4 Y
cur = cur->next;
8 h; M/ i; ^6 i; H* K# k8 |7 d: ` }
7 L+ l) D) m1 Y6 Y/ w1 v cur->next = dev;# v( L4 E! }7 ]7 {" W
dev->next = NULL;$ V9 T! b* [! D, x
}
0 ^1 r; V2 {7 V7 g0 e return 1;6 F: w3 F B0 O9 r) y. m3 ]
}2 ~$ m. ~# o% g" i3 K; h9 b) B6 p
/*
4 B* I% p6 Z( s! o! b: o. W 驱动注册
6 ^/ b1 r& I s5 c*/+ N R0 B+ Z7 |1 M& ~
int cola_device_register(cola_device_t *dev)
) n; A4 c- M7 R* ?# v3 Q0 ~: v6 M{
( H) [* @4 V/ _2 f; K if((NULL== dev)||(cola_device_is_exists(dev)))
; }" t$ j3 a* a: d {+ ~; R) j" {' L' Y7 c0 b
return 0;
! ~: t6 `- m5 h( T }* Q- z# a; \/ u2 j' F
if((NULL== dev->name)||(NULL== dev->dops))
- O$ c5 A) E6 L! D0 p {
! p% [% @8 K% c& n6 P return 0;
/ J* _- v3 R# ^# H }# w f. ` m6 v1 {0 {% L5 A
return device_list_inster(dev);
9 M4 S$ b- [+ n. L3 F}+ ~- F% A1 D6 j0 E
/*
$ a& Z0 e+ d- K; f2 _# e 驱动查找
8 N5 U5 |' v+ Y' P* O) o*/
1 H; U# H% i, c& [ D4 Icola_device_t *cola_device_find(const char *name)$ ^( c) Q% d5 L
{
' [% B8 R w- } cola_device_t* cur = device_list;8 z4 L! b: {' V
while( cur !=NULL)
: p" A! B7 r( v5 k. S4 w5 J {
- K" W9 G! Q& s6 M if(strcmp(cur->name,name)==0)
) ?2 V) F n( p6 }$ | {
' `. p. Q5 l# t+ U- H1 i$ e9 x+ c; E return cur;6 V- `" p3 d7 o* g9 c5 M, N
}
- x; `5 x- L2 b; @% v+ I5 | cur = cur->next;
: C6 m1 G) q/ z% E: S# g; J4 @ }
& m' ]0 ?( k( P/ H8 D* C* I" X return NULL;1 L3 r( i+ e5 j
}
0 i1 R% K0 }; s( t7 Y/*2 D3 P1 R, c. H, b, T
驱动读: ]: x# p4 }+ r, I) o* b$ \. u3 Q& T
*/
- W/ k7 A; I6 b( ]int cola_device_read(cola_device_t *dev, int pos, void *buffer, int size)! i; u; j8 H( A8 Q% |2 \: N
{
+ J# R p! g5 Y6 C3 l) X4 o if(dev)
- S) g: y) {: s s# }& y6 L- Z% X {8 z, v& G5 D' ?( m L5 i: E
if(dev->dops->read)2 P( Y1 h$ ^* N
{/ I5 R" h2 P, H2 L
return dev->dops->read(dev, pos, buffer, size);8 M& q. @( h$ Z1 }
}
$ I1 f& N+ u2 V; D- x5 A }
1 E" T+ _" i' j return 0;
- `3 d6 e- |* i}
( m# v9 F7 b, M2 N. o' q/*
; Y t( Z* o4 m4 f) _ 驱动写* I. F) Y D+ C. s+ U- t$ s7 A
*/
. t) |2 X: _; b. t# d' R7 J! z: G4 Nint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)
% c$ r# A% M5 Y! f n" ~{- `' X3 C" k: y* D% t2 d8 X
if(dev)$ d* z" x( \- n2 J
{# c: t6 J0 u) C1 s. F0 l% G+ H
if(dev->dops->write)+ I1 V7 \; m6 @
{
) \# A+ t/ B+ v( b3 m; q return dev->dops->write(dev, pos, buffer, size);
4 ^% M5 i( p: v( \) i+ k }
: S9 a( i# Q' D. n" r4 [+ b0 h }) P/ w, H( |% Z- H
return 0;- m d3 F6 B/ H
}
# G8 c, m) h7 u/*
& \) v% `" N2 ?2 I! ? 驱动控制8 f2 R/ r4 x0 d, K6 a# O4 I
*/) Y4 v& S( k0 }- ^
int cola_device_ctrl(cola_device_t *dev, int cmd, void *arg)! Q! r, T4 V3 A, y$ N
{' o% f' H. W/ S A/ o$ E6 x! k
if(dev)9 H' y# P8 _! p$ A
{( d/ G7 @2 v# ~
if(dev->dops->control)
! A1 B" } m, U& b2 l" ^ {8 a; W4 j: i* I
return dev->dops->control(dev, cmd, arg);
0 H$ U6 }( o$ {5 Q7 @( L9 H }
. |, i" D, R( ]! {& M$ I }
7 x9 ~/ W) a. W" c return 0;$ Z/ x% o" v% D# K* d
}硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。 P* ]! z2 y) |6 E- n' V. P
#include "stm32f0xx.h"% b0 b4 ?- j" E6 u
#include "led.h"5 X: [' l- ` U& B S+ p9 A. d
#include "cola_device.h"
1 W. S: r8 o' n% R2 h H! C0 G#define PORT_GREEN_LED GPIOC % H2 U! |1 b: J; { A$ K- W
#define PIN_GREENLED GPIO_Pin_13
$ s3 V- S2 W9 O% o6 Z4 _( n v4 z. A/* LED亮、灭、变化 */, A' N0 q% f4 k
#define LED_GREEN_OFF (PORT_GREEN_LED->BSRR = PIN_GREENLED)
' {, j- g- M( Z9 `#define LED_GREEN_ON (PORT_GREEN_LED->BRR = PIN_GREENLED)5 N) G! n: g" I) Y
#define LED_GREEN_TOGGLE (PORT_GREEN_LED->ODR ^= PIN_GREENLED): p( j1 R1 c/ e) g9 O! v
static cola_device_t led_dev;. L8 |% T/ ~1 q2 W, W. a. h
static void led_gpio_init(void)& O2 R9 T; J6 i2 W0 ]+ w
{
. j+ x* P; s4 U" a# ^6 e6 i GPIO_InitTypeDef GPIO_InitStructure;8 G2 p7 p/ ^( Q
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
2 f2 `7 I6 U4 ^( C# J GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;9 d3 M6 k6 w- w3 T0 ]; o$ J
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;1 C+ r) a0 y6 ^1 R1 _; l
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
& Z+ z. B) i6 h; b7 x5 n GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;; d/ k6 n, P$ @& }" R+ B/ v
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;/ N! c6 y7 L+ B7 i& j- t# Z8 q6 H
GPIO_Init(PORT_GREEN_LED,&GPIO_InitStructure);: v3 }& R$ o9 z+ T$ ?) x
LED_GREEN_OFF;& W3 P# y: D1 q
}
6 O% x" i6 ^6 E( K/ F5 L* v* j1 }' G. w5 F' C$ v; b6 c: J7 Y e6 q, u) b
static int led_ctrl(cola_device_t *dev, int cmd, void *args)
) J3 ?9 c$ Q" O# D# e3 [4 l. K{0 q, K6 ~3 B' Z& `
if(LED_TOGGLE == cmd) O1 P5 j/ b$ D, i2 R6 ~* s
{
/ m( E4 }, P, m( o- G3 X LED_GREEN_TOGGLE;( p; z+ N" e& `( N' R( g
}
W5 [) M4 F. z1 w else
9 w5 @# o4 B- f) I2 g {- Q' V8 _4 _, O x; E
}" H: V- S6 b' u; }
return 1;8 _: Z5 J* F3 U- @# A6 z
}% C! O8 k% L5 s) _+ a
static struct cola_device_ops ops =2 l) {& }7 q" n' a' s/ q! }% W
{
, y1 C7 s. X6 N' c' ]7 t, ^ .control = led_ctrl,
& L/ d* V$ {9 B' f k6 w$ q f; ^};
" Y2 l# `& E% j P+ J6 @void led_register(void)2 G: [2 u3 L! `; `$ s- g/ x( h% M0 J) [
{) v3 m, O+ a8 W" _' n+ W) m# O
led_gpio_init();% S0 L2 d+ D0 l4 p3 r
led_dev.dops =&ops;( J' A: g+ }. b
led_dev.name ="led";
) L3 B; b' {: I+ g cola_device_register(&led_dev);
) n# J5 p, Y3 r' _}应用层app代码:. i7 Z1 b4 a* F
#include 5 x+ \ ~1 t2 G% _
#include "app.h"
6 k' o8 D% U, `1 }$ \; q7 S1 b1 e" B2 z#include "config.h"' x5 p- R7 w+ F3 k2 G, f5 W
#include "cola_device.h": O3 M! A8 Y0 v+ I: p
#include "cola_os.h"
! f! c0 \7 b0 B' {/ i+ K& {static task_t timer_500ms;
, s+ B" W& G6 Gstatic cola_device_t*app_led_dev;6 o s1 @2 D" }2 ~+ q* O
//led每500ms状态改变一次4 [9 d3 z$ t2 R' C+ _/ e, Y
static void timer_500ms_cb(uint32_t event)) U; B( a' ^" O4 z. v, L7 |' f6 A
{
2 ^3 ]8 V( Q0 w" G cola_device_ctrl(app_led_dev,LED_TOGGLE,0);
% x6 M2 W2 A8 }; Y; N; l# q}- r; }5 ?, K+ z
void app_init(void)
0 V) m# c6 |3 F' p4 A d{
8 x) I/ U- y9 G# ~2 y( F, S7 ? app_led_dev = cola_device_find("led"); G& x+ p$ g: i8 @* s
assert(app_led_dev);
+ i: I$ c% {' ] cola_timer_create(&timer_500ms,timer_500ms_cb);
7 \' f/ f1 J+ y cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);
: c9 j( e; Z9 o+ C}这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。
9 Q" f' c c. Y. G, M四、代码下载链接https://gitee.com/schuck/cola_os
s3 k7 \; A c0 _原文链接:https://blog.csdn.net/ziqi5543/article/details/101512722
1 g8 t! D9 i% u3 Y e. f-END-: V7 J9 N. V. R
往期推荐:点击图片即可跳转阅读
6 F% @" l( N9 E9 D ( s0 Y- W7 k# Q# P7 ^, y3 t. W& J( d
# p2 x% f9 T9 o$ N, M) y
H d, P$ n2 g& }/ s% d/ m" N
# B5 o0 _; Z1 `( [- _
fjadnxnkhyg64033372613.jpg
, n7 Z5 N% W! ]9 O7 v
4 S$ R' y) ~: S) p! ~ 嵌入式 C 语言的自我修养' U7 t% s0 \( R) `9 @
+ k! j, g! X% M, B n/ k
2 u$ y& j- A7 r! {5 B/ Y % t7 T$ W8 p0 {; m+ F' W
* y, Y% S: y7 r# x4 H \& }: S4 h
4z4yvomwdol64033372713.jpg
: W# v2 T# D3 `0 U9 W6 @ y! T : ^$ H+ ` K$ ^7 f8 J/ d
被 char 类型的变量坑惨了!/ f% G V9 z; E B6 R* ?2 V1 u
& V; m3 q9 h& |$ J# r
7 S2 S9 N0 p, b: h & N, _8 Q1 w9 y2 `
eic1o4k04ps64033372813.jpg
" _& \& Z+ q0 }1 l
' x/ x1 B% r) W2 {& y+ w& `
嵌入式 C 语言知识点,动态变长数组
# Q Z$ n; R; i: f . h) Y8 \2 e3 a9 J- R8 z0 w
5 _" g6 S" G, L; Q9 {2 q- ^4 C* s
b- a$ [ h' y
我是老温,一名热爱学习的嵌入式工程师9 e! u5 K) j- z6 Y) Y: p
关注我,一起变得更加优秀! |
|