电子产业一站式赋能平台

PCB联盟网

搜索
查看: 183|回复: 0
收起左侧

如何实现嵌入式软硬件分层处理接口?

[复制链接]

572

主题

572

帖子

4361

积分

四级会员

Rank: 4

积分
4361
发表于 2024-8-12 17:50:00 | 显示全部楼层 |阅读模式
我是老温,一名热爱学习的嵌入式工程师+ I% Y2 }0 h# ]9 B4 R
关注我,一起变得更加优秀!一、前言以STM32为例,打开网络上下载的例程或者是购买开发板自带的例程,都会发现应用层中会有stm32f10x.h或者stm32f10x_gpio.h,这些文件严格来时属于硬件层的,如果软件层出现这些文件会显得很乱。
$ E, \* f( _" r# w: m3 [使用过Linux的童鞋们肯定知道linux系统无法直接操作硬件层,打开linux或者rt_thread代码会发现代码中都会有device的源文件,没错,这就是驱动层。
: i: V, ?1 o4 s/ v# u! G

ub3zndohhcv6401503748.png

ub3zndohhcv6401503748.png

7 h) M8 V9 \0 ]: i二、实现原理原理就是将硬件操作的接口全都放到驱动链表上,在驱动层实现device的open、read、write等操作。当然这样做也有弊端,就是驱动find的时候需要遍历一遍驱动链表,这样会增加代码运行时间。: o  |- \3 [7 V7 v( ~5 f
三、代码实现国际惯例,写代码先写头文件。rt_thread中使用的是双向链表,为了简单在这我只用单向链表。有兴趣的可以自行研究rt_thread
( }" L, i  J# |  m头文件接口:7 Y% Y9 n0 ]1 m) [3 f
本次只实现如下接口,device_open 和device_close等剩下的接口可以自行研究。这样就可以在应用层中只调用如下接口可实现:
' s4 ?0 c, s/ Q3 l% d0 U, q. E0 c/*2 D9 a2 X1 P/ W  E
    驱动注册, k: `/ ~$ l* {9 H# [
*/5 v- p0 u# p9 e2 l, s7 W
int cola_device_register(cola_device_t *dev);
2 v" L, D) ~. D! ?3 P/*
# A% k3 v; T5 ?. e4 d    驱动查找; P! w7 G5 W  a0 W7 f) A" H
*/2 C  e, a/ t! ^
cola_device_t *cola_device_find(const char *name);/ l/ k8 z; H3 _: V3 F
/*
- A2 I3 X# }/ x+ X+ S    驱动读' E2 k& a- z( d5 V0 b8 K
*/
. h& v2 k9 D* ?( t" `  Iint cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size);
5 K. W( c" e( k: h/*
8 q6 L; z/ t8 R    驱动写
0 P" Q5 @& _8 E3 y& v*/
6 O& m5 Q' q( R6 {6 x  xint cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
8 O* |- S) i5 k. Z% q/ Y% }/*
6 f+ w! r6 h7 _" k7 r) |8 t    驱动控制8 Y5 w$ j. k# w% f$ k
*/7 Y6 @) Y* }& r" d& r! v
int cola_device_ctrl(cola_device_t *dev,  int cmd, void *arg);;头文件cola_device.h:) s: R9 P( E0 w. K& R
#ifndef _COLA_DEVICE_H_
4 R! w1 d0 |! B3 A$ |5 D#define _COLA_DEVICE_H_% W- j1 P& o0 _8 n1 D
enum LED_state
6 o9 v( ^2 {; h$ `- S! m" H{
, O  v. i9 l9 ?1 {3 n4 q9 C& U& y    LED_OFF,  K2 w5 d" P, R* w
    LED_ON,: n, A! x" }7 g
    LED_TOGGLE,
: d1 H" K$ y: u' c};
2 l7 d8 `7 M- Btypedef struct cola_device  cola_device_t;" A, M: S  @9 H/ w: L, D
struct cola_device_ops4 Y1 @9 s/ S$ T
{8 ~0 i6 S) E: Q* k' c' b2 j
    int(*init)(cola_device_t*dev);0 T. u" p. Z1 N. ?1 k
    int(*open)(cola_device_t*dev,int oflag);7 d7 A% [+ i5 p3 _9 q' r! B
    int(*close)(cola_device_t*dev);
" C+ ]8 k7 L* B% t  N/ i4 Z. _    int(*read)(cola_device_t*dev,int pos,void*buffer,int size);& v6 E; }4 A3 `+ X" J) _( O( Y
    int(*write)(cola_device_t*dev,int pos,constvoid*buffer,int size);
8 [1 B& ?4 q) z  F7 v    int(*control)(cola_device_t*dev,int cmd,void*args);
1 P: p. ]) D' {: d$ L3 S};/ D1 z' S- V/ M5 I  M5 E; O% f9 L
struct cola_device
: T* R9 \: I! j{& g- j5 k- ?6 @2 E% y- p
    const char* name;' z* z- [, R5 q  U7 n  s# U
    struct cola_device_ops *dops;
! m+ y/ q& U1 ^0 ~3 ]    struct cola_device *next;
% L% Y1 o! I+ `* S2 y8 }! A# p};8 I: g/ ^" h1 F0 ], ^8 P& H
/*
  y8 Z4 \, E- I. |1 X) V    驱动注册$ c) m0 w* @0 _7 m% U1 @1 e
*/
) U# z2 m8 M# |. |; `+ K) lint cola_device_register(cola_device_t *dev);- P; X4 r6 V, X  M% a  k
/*' m2 x) e: U8 S" O- I5 d2 {
    驱动查找
7 u: N, x4 c6 k*/
( I# c1 I2 V: x% \: F& mcola_device_t *cola_device_find(const char *name);
: u. t0 Q8 Y- f+ d/*6 C9 a8 H* v4 O1 b& F
    驱动读$ J1 p2 P( c0 L+ V( h
*/& k. b" A4 s# B# o0 T2 ]* ^
int cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size);* J# z. g4 G' k8 V; S& q) v
/*
* I  ?5 M* X$ b* o3 B$ H; M3 n    驱动写
1 H5 Q: y( Y9 ~+ g4 u1 R*/
( n, k% Y. g, U6 t; ~int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size);
+ F! T9 X$ ]2 K& |, ~+ o' k/*' n4 @! @1 L$ y( V
    驱动控制
0 J+ L6 F+ _8 _- ]*/
" ?. N  [# j* S, d- ?; @+ dint cola_device_ctrl(cola_device_t *dev,  int cmd, void *arg);+ d3 {2 t2 O% s: c* S, w/ h* k1 {
#endif 源文件cola_device.c:+ R9 g! ^0 I; D; U; ]
#include "cola_device.h"6 U% P) J! V* l1 M; y5 Y1 Z+ I9 x
#include
6 _( U. R1 m. Q) e7 l# s- A#include
( A; u# G; J# a1 z( e9 c* rstruct cola_device *device_list = NULL;, i% h0 k  m3 d5 c! p  F7 S3 K2 P0 _
/*) W) L: y2 m+ `) L0 M8 w# I
    查找任务是否存在2 \! X  {# H. h
*/
! ~. s+ C  M3 k8 Hstatic bool cola_device_is_exists( cola_device_t *dev )1 ?) B4 S" q0 k9 w  X
{6 a" Y* a) {5 q
    cola_device_t* cur = device_list;
: d. Z% @4 ^; @( l3 O# |& D    while( cur !=NULL)
8 B7 }" r7 R. E1 ^1 M6 k) O4 j    {: z) g- ~& U" K- U9 d, ]
        if(strcmp(cur->name,dev->name)==0)( K# B, T" M# Q% E4 v3 d- K, W+ {. e
        {! t* w/ ~3 u# P& t  B+ N6 N
            return true;
0 r* T; A7 n. ^3 P        }* ~4 @  S# y9 M. H6 R7 b2 ?) C# Y
        cur = cur->next;
  x; c; f: O3 H    }" R7 o* p4 u: d" f" d* D# g
    return false;
3 |/ `/ D/ V" q4 `8 z}
* q; d" ]# ^- m8 X7 [% Tstatic int device_list_inster(cola_device_t *dev)
9 s: a8 t3 [0 ?" w- Y  D, \{
6 g5 H1 t8 ~! Y9 S$ l2 a$ K" L; ]5 K    cola_device_t *cur = device_list;! f' v4 f8 p% S) {1 w1 ~0 P. l1 s
    if(NULL== device_list)
& a8 n. @) g  g* U    {' y/ L# T( V* v( n/ B; @
        device_list = dev;$ b7 s" f2 y6 f* c9 M
        dev->next   = NULL;, _" ^+ ~1 V% \6 [
    }
; e* B2 `7 n8 e+ G+ u; u2 @    else
& m* S. i* d: w9 A, m    {5 d( o3 q' f* E6 T3 x
        while(NULL!= cur->next)
- ^+ ^; z+ V0 b2 s2 K7 R        {
! g, ^/ \! ]0 ]% `- K& T            cur = cur->next;
' ~, q$ l- X0 O/ {& G4 p: A        }
3 }; [/ c1 J' s4 o        cur->next = dev;
( r- u8 S6 l6 L6 ]# C        dev->next = NULL;
7 `* W: e1 U4 j# ~    }
. I7 B$ b' j+ w    return 1;
" j7 o) J0 f3 p0 ~}& Z( }. ]( C* e6 Q7 X
/*1 G5 V) [8 B) `
    驱动注册  L: G/ j; z9 K, ~
*/. V; T% B8 y* }" T5 w0 g
int cola_device_register(cola_device_t *dev)9 f2 C* C  F+ |5 ?( w- X
{: w1 t1 `9 }+ G; W
    if((NULL== dev)||(cola_device_is_exists(dev)))" H7 _2 A% o6 D
    {. L4 {$ R# {# I
        return 0;
& I( w; Q3 w4 I6 I) {0 I    }( x; ^! Y5 ~! y; F0 X, g9 J
    if((NULL== dev->name)||(NULL== dev->dops))# W' _0 i  @1 I& k3 [* v
    {. U$ P7 E4 o3 `4 J9 \! D
        return 0;7 m2 h* r9 r' l& `2 B6 a! \; {
    }, y$ @  A0 i% d) z9 X! U- a
    return device_list_inster(dev);$ @' H) G; W- Z# f3 A
}
+ i* ]; s. e/ q* ~# J$ E/*
1 X& G) @, G7 U; t" b: [4 l* E5 @* I    驱动查找3 j  M) I$ m' E; Q: F/ \/ O
*/, [7 R: d- [  g2 _$ e- D: u; d) ~
cola_device_t *cola_device_find(const char *name)
  I% U" E4 K5 b3 d- C{/ @/ C; `6 E) q
    cola_device_t* cur = device_list;; a0 O) A2 p. Q) N. e# Y
    while( cur !=NULL)4 B, W% K7 j) d5 I/ Y" J+ v
    {5 |7 c; T- ^+ ]8 Z
        if(strcmp(cur->name,name)==0)+ G% L7 Q; ]4 E
        {
( P" B) i+ H& x8 ?6 H+ p9 C- Z            return cur;. P  x" S) G% I
        }
) s) z) Q1 t; [" C+ b        cur = cur->next;
, ^+ ~* o. K- g9 q7 x0 ?6 G    }! d$ Z# W8 h+ P+ b/ S
    return NULL;) s# L" x) @6 b2 S8 G4 i
}+ p& q; ^1 w2 a9 y4 h. {
/*8 k9 S' I* Y0 D
    驱动读
7 W6 w6 P/ f8 [*/0 W/ t5 u) H1 L3 `
int cola_device_read(cola_device_t *dev,  int pos, void *buffer, int size)
" u" O4 W, X( Q: w) R  j0 p{& Z: p5 h, i2 \- J+ P. H, a
    if(dev)1 ?7 ?2 M0 ?& Z5 L
    {$ }- `. Q3 K9 P9 s- s+ T
        if(dev->dops->read)
/ s* b. L- M4 G        {9 U5 h# @- j, @* n7 z$ B9 E; ]
            return dev->dops->read(dev, pos, buffer, size);
5 B/ [0 ?& Y  s        }
; O' t. x! d& R    }- o) Y2 l( J7 F
    return 0;
9 L5 o2 u+ A2 v}
, j( `/ S  c: @( V/*: R6 j( a' B2 K$ \6 W
    驱动写
4 j4 {8 f9 s/ G% }*/
5 f# N5 T1 n; F; X: m2 U- l+ V7 [int cola_device_write(cola_device_t *dev, int pos, const void *buffer, int size)* s! }" O0 J6 g: Z2 n8 _
{
+ m% Y$ h1 g, [    if(dev)+ i: Q) t2 j4 F# l0 y0 ^
    {: c- F/ I' V, h$ u9 d" m+ N! m4 u
        if(dev->dops->write), {& d& ~& n! a$ P* Z
        {
# |# w% |, p% p            return dev->dops->write(dev, pos, buffer, size);
0 _# N; K$ }) u: Q; ]        }
0 {" m& |9 x* X    }5 T+ h1 H- \, X* w; h9 [; y5 R
    return 0;
9 o4 v: G6 s9 S% D7 T1 E}
4 L5 t  O- N8 B+ K( g( T% r/*
( t3 u4 x- Q4 x0 {2 y$ |1 v3 H    驱动控制
$ x+ D/ O2 w5 G" W5 o*/4 {( B2 J5 @4 L6 G4 x- m: N
int cola_device_ctrl(cola_device_t *dev,  int cmd, void *arg)# B, @9 a' x% V# @
{
: _, J" u7 V) ^    if(dev)
& R2 u8 a/ ^- b    {
% t4 }% [) A$ z9 L9 A        if(dev->dops->control)5 R$ h1 g7 v" b, Z8 V
        {
& M( x5 {% n+ L4 u3 b& o# d            return dev->dops->control(dev, cmd, arg);
2 w7 M, z' [( P; C1 H% R        }1 a; F( v+ p: w) l- P5 C% W
    }( G" i9 j: z& W5 c9 u! r
    return 0;
8 @9 B! T+ s1 }' s' ~}硬件注册方式:以LED为例,初始化接口void led_register(void),需要在初始化中调用。
) m6 y2 T3 w+ P/ @7 F#include "stm32f0xx.h"1 f) W$ r7 b! J; s- U; r
#include "led.h": i& V9 B8 ~' n6 H2 `
#include "cola_device.h"7 P1 D; o1 Z  E8 t( p6 m; K  e$ B
#define PORT_GREEN_LED                 GPIOC                   + P- [4 k$ E* B% [7 U( r3 }
#define PIN_GREENLED                   GPIO_Pin_13              ! S3 S7 q, U/ g
/* LED亮、灭、变化 */( Y/ k; s% o6 \* l5 _' L9 R8 `& X
#define LED_GREEN_OFF                  (PORT_GREEN_LED->BSRR = PIN_GREENLED). I+ J8 f) p2 e; b# |! [; C
#define LED_GREEN_ON                   (PORT_GREEN_LED->BRR  = PIN_GREENLED)
' D* d- ^. m+ k  i1 u3 H) _) X#define LED_GREEN_TOGGLE               (PORT_GREEN_LED->ODR ^= PIN_GREENLED)! X* F% T; k! q, T6 z
static cola_device_t led_dev;
, }. ?% ^* l& E# Qstatic void led_gpio_init(void)$ n$ A5 ^5 ]! ^" N* c
{
: N$ l$ o' X8 e$ [: M    GPIO_InitTypeDef GPIO_InitStructure;
3 H; N, U  S2 c* X2 E- n    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
6 \2 w1 M: E' |  I3 I    GPIO_InitStructure.GPIO_Pin = PIN_GREENLED;$ W3 w  ]0 k( L6 |6 n8 `
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;2 `6 Y2 [. Q9 ~8 I& ]" b5 n
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;; D2 j7 o* x, a6 l: \2 `
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
" U8 E0 l$ Z5 d8 u9 w6 U( b" r( `" y    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;* E5 u0 u+ A% B2 ?% R" ^! q
    GPIO_Init(PORT_GREEN_LED,&GPIO_InitStructure);9 N: v+ V* k: _: e) i
    LED_GREEN_OFF;7 |9 I$ a+ `, }  n2 b
}
6 U# J( C1 b0 x7 f. ]3 F( Q8 |% N  ~; A* x1 w
static int led_ctrl(cola_device_t *dev, int cmd, void *args)& U7 b" D; q" \* K- s- y! c
{. I3 ]; \) Z3 r; q# ?- ^
    if(LED_TOGGLE == cmd)8 m! b+ r' \- T/ h4 t$ u* b
    {( j. A" E2 A9 a
        LED_GREEN_TOGGLE;& i, A% y! c5 O$ s/ m
    }
" X* }' {" R( R3 }1 `7 m    else' a  Q$ a& [" d* t  w+ y4 p/ q
    {
% b% Z6 j$ ]/ v4 y. Q    }1 i8 f5 U7 F% y& f8 t
    return 1;& k- j4 G+ w. s; [! p% C
}
  k! b, B( e& K8 y, Y5 J2 o8 pstatic struct cola_device_ops ops =
0 s4 E6 t- r8 Y- N' r2 I7 ^{
' a8 H7 c) X; r .control = led_ctrl,
5 `* a% j) m# y( Y3 g};
, h! F( I& e7 J/ hvoid led_register(void)$ O1 [1 c3 T3 [& J& h/ O
{1 W; d7 i0 D4 I; X4 i
    led_gpio_init();
1 W; E% Y' f0 B( Z+ \" e    led_dev.dops =&ops;  \/ @5 U4 d/ A$ M
    led_dev.name ="led";5 m2 P. N" O, Q5 o
    cola_device_register(&led_dev);6 ^8 Z6 J; t6 a% X% z+ T1 @, U
}应用层app代码:
, p' r& ?5 B+ }% G# E% A* d#include ( Q4 O( l9 @( I- e1 z6 m
#include "app.h"0 N! U# g" q" G. a& q" k
#include "config.h"+ K- o0 \" r5 X, J8 l" K8 r' W' m/ U
#include "cola_device.h", [9 S! v/ u' u. x! P; P' q
#include "cola_os.h"
& Q( m  `! G7 _# w( p# ^static task_t timer_500ms;/ ?& x7 d$ i5 K9 q2 ?
static cola_device_t*app_led_dev;
6 R/ R/ y& Z4 m6 T8 f//led每500ms状态改变一次
$ f' v4 A4 _" R* W4 A3 g  xstatic void timer_500ms_cb(uint32_t event)  d8 B/ w/ `  B3 h. O+ a& i3 j
{
! }, ^$ N4 ~) O% i, u    cola_device_ctrl(app_led_dev,LED_TOGGLE,0);- p: j2 W# w# a- `/ U/ J8 A
}2 f! w0 b$ e$ A5 c0 r" y
void app_init(void)
. ]7 Z: t) O+ m! h+ g{
& h6 R# w0 k6 u1 y% r    app_led_dev = cola_device_find("led");: z4 d  y6 F  P
    assert(app_led_dev);2 |/ p" j3 w" h% {8 T! K  n$ K
    cola_timer_create(&timer_500ms,timer_500ms_cb);) z' d+ a! j" J9 r: {+ o" e4 V
    cola_timer_start(&timer_500ms,TIMER_ALWAYS,500);
" }: [* E- }$ L# Y5 C}这样app.c文件中就不需要调用led.h头文件了,rtt就是这样实现的。
5 s5 R' I3 W8 f; q0 S& |四、代码下载链接https://gitee.com/schuck/cola_os
% M& x9 a7 y3 s
原文链接:https://blog.csdn.net/ziqi5543/article/details/101512722/ ^1 }/ ]; `& i7 ^
-END-
4 p, n/ p/ T5 X! e往期推荐:点击图片即可跳转阅读
- u! U; Z: c1 t( i/ _                                                        - ]3 U$ F* Q8 o/ O" X
                                                               
) \% ~# ?# L! [% g                                                                        3 V2 B. P/ j0 |6 a- F0 m" ]
                                                                               
  C* o* M& b9 D) ?0 i3 z

khwhke5bjre6401503848.jpg

khwhke5bjre6401503848.jpg

0 q# T" O3 A& p; O                                                                               
1 c5 ?, a9 }( y. e7 a/ b" N                                                                                        嵌入式 C 语言的自我修养7 K0 N- r) F) Y9 S
                                                        2 a1 X1 u2 D! o. E, n. w
                                                                5 x- w' A: n9 o9 y% U/ }# b) k4 U  _
                                                                       
6 M* h! h1 x' L1 Z2 e                                                                                6 {4 P8 b" j: Z3 P

tcrizskjblx6401503948.jpg

tcrizskjblx6401503948.jpg

, X; ~/ P0 t! J5 i( o2 d                                                                                1 |5 s- w  D7 C1 `+ c
                                                                                        被 char 类型的变量坑惨了!
' Q9 Q8 ?. _1 X. z                                                                - V# f5 A8 |$ z) K5 s8 ?2 u
                                                                       
" X9 r$ Q8 g- u                                                                                * G, m! W8 O9 i% x* U$ C2 T

uq1yseaaos36401504048.jpg

uq1yseaaos36401504048.jpg

+ m6 C" j1 r; o* Y: q. i1 R1 z( S% j                                                                               
- X3 i/ a3 q; A& y$ q5 J  ]                                                                                        嵌入式 C 语言知识点,动态变长数组
+ x+ y. Y5 f1 f3 m                                                                                . R5 M9 g3 A& h) N5 X4 p
                                                                       
' i. o/ E- r; q: n$ y                                                               
/ j' `$ i. \! M# u0 A) A+ S                                                        我是老温,一名热爱学习的嵌入式工程师5 z4 P5 ^0 E1 W2 a
关注我,一起变得更加优秀!
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


联系客服 关注微信 下载APP 返回顶部 返回列表