Linux设备驱动思想在STM32编程中的应用

2023-05-16

这几天看了一下Linux设备驱动,发现这套思想其实也可以用在普通的单片机编程上。这种思想较好的分割了驱动层和应用层的任务,方便分层开发。

以前,我们开发STM32驱动的时候,会给设备写一套函数来控制它。假设现在有一块单片机开发板,外接设备UART和LCD。

我们会这样写函数

--------UART驱动------

void UART_Init();

int UART_Send(const char *str,int size);

int UART_Rec(char *rec_buffer);

...

--------LCD驱动-------

void LCD_Init();

void LCD_DrawPoint(int x0,int y0);

void LCD_DrawPicture(picure* mypicture);

...

然后我们拿这些函数进行应用开发。

这样做并不是不可以,但不同的设备,其函数名、形参都不一致。这导致做纯应用层开发的人,无法快速理解和使用设备。要么他需要经常去咨询驱动层的工程师,要么干脆应用和驱动全由一个人负责。

当引用Linux驱动设备的思想之后,这个问题可以得到解决。这种思想大概就是,不管驱动层实际控制的是什么设备,应用层只需要使用open,read,write,close这样的函数就能操作设备。这些函数原型都是广为人知的C语言文件操作函数。

首先定义一个结构体,名为Device,它包含了设备名等一些必要信息,和对设备的四个操作:open,read,write,close。这些操作由函数指针实现。

typedef struct device
{
    /* data */
    char  device_name[10];
    int (*open)(const char * pathname, int flags);
    int (*read)(int fd, void * buf, int count);
    int (*write)(int fd, void * buf, int count);
    int (*close)(int fd);

}device;

这个device就可以实例化为各种具体的设备。比如一个UART,我可以定义device uart;然后设置uart的device_name为"uart"。

然后定义uart_open函数,在里面进行UART的初始化。

int uart_open(const char * pathname, int flags)

{

 /*

UART引脚初始化;

UART时钟初始化;

UART波特率设置....

*/

}

同理,定义uart_read,uart_write,uart_close。uart_read的功能可为从UART判断标志位并接收数据,uart_write的功能可为UART发送数据。uart_close可以为关闭UART时钟。

 

定义好了之后,把uart的函数指针赋予初始值就行。

device uart =
{
    "uart",
    uart_open,
    uart_read,
    uart_write,
    uart_close

};

 

这样,一个活生生的设备就体现出来了。现在最重要的是uart这个结构体变量。只要拿到了这个变量,就可以控制UART。因为这里面有UART的基本信息和操作它需要用到的函数。

我们还可以定义device lcd,把它也进行赋值,操作过程和uart一致。

系统中有很多设备uart,lcd,led,button....都可以像这样定义device xxx。为了方便管理,做一个数组(或者链表等其他线性表),把所有的device变量组织在一起,取名设备管理表。

typedef struct device_list
{
    device *Device_List[DEVICE_LIST_NUM];
    int Device_List_index;
}device_list;

device_list global_device_list ;

把设备加入这张设备管理表的操作,就叫设备注册。
void Device_register(device* mydevice)
{
    int index = global_device_list.Device_List_index;

    global_device_list.Device_List[index++] = mydevice;
    global_device_list.Device_List_index = index;

}

所有的设备都注册好之后,以后需要使用哪个设备xxx,可以凭设备名device_name在这张表中搜索,最后返回搜索结果。

int Device_find(const char* device_name)
{
    int i = 0;
    int index = global_device_list.Device_List_index;
    for(i=0;i<index;i++)
    {
         
        if(strcmp(global_device_list.Device_List[i]->device_name,device_name)==0)
        {
            return i;
        }
    }

    return DEVICE_LIST_NUM;

}

 

拿到了搜索结果,意味着拿到了device xxx这个结构体变量,就可以通过它的结构体成员open,read,write,close来控制设备了。岂不是很方便?要注意的是,read,write的函数形参里面有void *类型;这意味着你其实可以传入任何类型的数据指针,而不仅仅是传统意义上的字符串。这很有用,因为不同的设备需要进行交互的信息可能不一样,单纯字符串想要较好的表示这些信息有难度。

int Device_open(const char * pathname, int flags)
{   
    device* dev;
    int fd = Device_find(pathname);
    dev = global_device_list.Device_List[fd];

    (* dev).open(  pathname,  flags);

    return fd;
}

int Device_read(int fd, void * buf, int count)
{
    device* dev;
    dev = global_device_list.Device_List[fd];
    return (*dev).read( fd,   buf,   count);

}

int Device_write(int fd, void * buf, int count)
{
    device* dev;
    dev = global_device_list.Device_List[fd];
    return (*dev).write( fd,   buf,   count);

}
int Device_close(int fd )
{
    device* dev;
    dev = global_device_list.Device_List[fd];
    return (*dev).close( fd );

}

使用举例:

void main()
{
    int fd = 0;
 
    /*先注册*/

    Device_register(&uart);
    Device_register(&lcd);
  

    /*后使用*/
    fd = Device_open("uart",0);
 
    Device_read(fd,NULL,0);
    Device_write(fd,"*****i am uart***\n",12);
    Device_close(fd);
    printf("fd = %d \n",fd);

    fd = Device_open("lcd",0);
    Device_read(fd,NULL,0);
    Device_write(fd,"*****i am lcd****\n",12);
    Device_close(fd);
    printf("fd = %d \n",fd);


     

}

这样做之后,应用层开发人员无须在各种不同的驱动API中焦头烂额。他只需要知道两点:

1.设备名。"uart","lcd","led"...

2.read和write的数据格式。

这就够了。open,read,write,close这些都是市民皆知的函数。无论什么设备,接口都能保持一致。相当完美的分离了应用层和驱动层的开发。由于不上文件系统,所以原有的open,read,write,close以Device_open,Device_read,Device_write,Device_close替代。

当然,其实文件操作的函数也不光有这四个,还有seek等等。感兴趣可以加入到device结构体里面。但要注意,定义的函数指针越多,应用开发的负担越重。在够用的情况下,尽量少定义一些没用的成员是明智之举。

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux设备驱动思想在STM32编程中的应用 的相关文章

  • PX4-mavros之Roslaunch使用 及流程介绍

    首先在Ros工程目录src下 xff0c 创建新的功能包 使用命令 catkin create pkg px4 launch 注意此处不需要添加任何依赖了 然后建立一个launch文件夹 xff0c 如下图所示 2 改写launch文件即可
  • 聊一聊那些应该了解的大佬(飞控,人工智能方向)

    写在前面的话 xff1a 以下内容与图片大多来自于网络 xff0c 如有侵权 xff0c 请告知我进行修改 部分评论仅为个人观点 xff0c 无人机方面大牛很多 xff0c 无法一一评说 xff0c 在此随意发挥 也欢迎各位看官补充完善 R
  • ArduPilot+mavros+gazebo+QGC联合仿真初体验

    首先给出最终效果图 xff1a 实现内容与PX4官网代码功能类似 xff0c 四旋翼飞机自动起飞至2 5m高度 xff0c 悬停一定时间 xff0c 然后自主降落 记录如下几个需要注意的地方 xff1a 一共使用到三个文件夹 xff0c 其
  • ArduPilot姿态控制方法解析---(倾转分离)

    先给出一些预备知识 xff1a 欧拉角 xff1a 即所谓的Roll Pitch Yaw 而事实上 xff0c 根据其定义 xff0c 欧拉角的具有不同的表示 存在先绕哪个轴 xff0c 后绕哪个轴转的差别 xff08 将旋转分解成绕三个轴
  • C中main函数解析

    参考链接 main函数不同写法 以下为main函数的6种不同写法 xff1a span class token function main span span class token punctuation span span class
  • ArduPilot姿态环控制-----传感器初始化

    参考链接 xff1a https blog csdn net lixiaoweimashixiao article details 80540295 首先我们假定从void AP Vehicle setup 开始 xff0c 这里是飞控所有
  • ArduPilot飞行前检查——PreArm解析

    ArduPilot飞行前检查 主要包括两个部分 1 初始化中遥控器输入检查 xff1b 2 1Hz解锁前检查 附 xff1a 显示地面站信息 参考文章 xff1a Ardupilot Pre Arm安全检查程序分析 1 初始化中遥控器输入检
  • ROS_PX4_gazebo学习记录

    在官方程序上 xff08 PX4 wiki上为offboard起飞到2m高度 xff09 进行更改 xff0c 实现首先起飞到固定点 xff08 x 61 1 y 61 2 z 61 5 然后按照给定角度飞行 补充 xff1a 最终实现效果
  • Rospy初次使用记录-定点飞行

    由于接触到pytorch xff0c 所以用python完成与ROS的通信 xff0c 下面例子为从程序中摘出来的一部分 xff0c 用到了ROS消息的订阅与发布 xff0c 服务的通信 xff0c 可以作为参考使用 xff1a span
  • 四旋翼飞行器数学模型

    最近接触到四旋翼无人机的位置控制方法 xff0c 就又了解了一下四旋翼飞机的数学模型 xff0c 现总结如下 xff1a 位置环 xff08 均定义在惯性坐标系下 xff09 P
  • 基于ROS与optitrack的四旋翼飞机开发流程

    本文将一些注意点记录下来 xff0c 适合于开发调试 xff1a 目前只是分段调试通了 xff0c 带后续联合开发的时候在来补充还有没有什么注意点 xff08 过程也算麻烦 xff0c 也算不麻烦 xff09 xff1b xff32 xff
  • ROS_调试(三) 打印输出

    ROS INFO 采用类似C语言的形式 ROS DEBUG ROS DEBUG STREAM 采用类似C 43 43 语言的形式打印 ROS DEBUG STREAM NAMED ROS DEBUG STREAM THROTTLE NAME
  • px4调试bug--添加mavlink_log_info信息

    写在前面的话 有一阵子没有看px4的代码了 由于项目和论文的需要 又要接触这个 其中又遇到一些新的问题 找到了一些新的解决方法 故在此记录一下 总是在几种飞控代码之间跳来跳去 没有认真研究一个 有点遗憾 PX4的代码调试还没有找到什么好的方
  • APM,PX4之开源协议

    APM代码设计的是GPLv3协议 xff0c PX4代码采用的是BSD协议 从上图可以看出 xff0c ardupilot的代码是允许别人修改 xff0c 但是修改之后必须开源且采用相同的许可证书 而PX4代码则是允许别人修改 xff0c
  • C语言实现mavlink库与px4通信仿真

    参照网址 http mavlink io en mavgen c 首先从github上下载对应的C uart interface example 对应的github仓库网址为https github com mavlink c uart i
  • RK3308--8声道改成双声道+录音增益

    改为双声道 修改dts文件 相关路径 xff1a Y hxy RK3308 sdk 1 5 kernel arch arm64 boot dts rockchipY hxy RK3308 sdk 1 5 kernel Documentati
  • Flightmare install 安装指南

    flightmare 是ETH推出的一个用于gazebo仿真 xff0c 强化学习训练的平台 xff0c 并在github上公开了其源代码 本文主要记录在配置环境过程中出现的问题 github网址链接 https github com uz
  • matlab发送mavlink消息

    主要介绍了通过matlab脚本实现UDP发送mavlink消息 xff0c 为后面matlab计算 xff0c 与Optitrack联合调试 xff0c 控制无人机做准备 示例演示效果链接为 matlab通过UDP协议发送mavlink消息
  • apm-ros-optitrack初步尝试

    本文记录采用ArduPilot固件 xff0c 室内optitrack环境下飞行实现中遇到的一些问题 在apm mavros仿真中 xff0c 总是出现mavros state 显示 not connected 在实际的操作中 xff0c
  • APM代码调试知识点汇总

    由于项目的需要 xff0c 对ardupilot的源码进行二次开发 本文记录在二次开发中遇到的问题以及注意事项 xff1a CUAV V5 实测 apm 串口 xff0c 对于姿态数据的发送和接收在200Hz的时候 xff0c 是没有问题的

随机推荐

  • ardupilot之mavlink消息--从飞控发出--单向

    飞控采用mavlink消息进行数据的传输 普遍说法是 xff0c 现有的mavlink消息几乎已经涵盖了所有你的能想象到的内容 xff0c 完全可以覆盖多处需求 无奈科研总是要定义一些新鲜玩意 xff0c 所以总是有无法完全满足需求 xff
  • ardupilot之mavlink消息--飞控接收--单向

    由于项目需要 xff0c 完成一个测试demo 本次从dronekit中发送mavlink消息给飞控 xff0c 飞控接收发来的wp信息 xff0c 然后进行修改供程序使用 首先祭出测试视频 dronekit arudpilot test
  • ArduPilot 添加自定义调节参数

    实际变成操作中 xff0c 需要对ardupilot代码进行修改并添加对应的调试参数 xff0c 这样 xff0c 可以通过地面站很方便的进行修改参数 目前修改代码在parameter h中的G2类 xff0c 表示为全局的参数列表 参数类
  • Python_mavros_manual_contoller

    利用python完成mavros与PX4的通信工程 xff0c 同时也完成了对应的PX4中对应消息代码的调试查看 span class token keyword from span future span class token keyw
  • PX4 混控部分分析

    PX4的混控部分大体思路和ardupilot是一致的 更多的PX4采用的是脚本读取的形式完成其中的读取 转换以及最后的应用 首先从机型选择后 对应为toml文件 如下图所示 采用对应的px generate mixers py来自动生成对应
  • PX4 Position_Control RC_Remoter引入

    PX4飞控位置环控制中如何引入遥控器的控制量 本文基于PX4 1 12版本 相比于之前的版本 多引入了Flight Task这么一个模块 省流总结 遥控器的值通过 flight tasks update gt velocity setpoi
  • AS--Location specified by ndk.dir...

    问题 span class token operator span span class token class name What span went wrong span class token operator span span c
  • ros中的message filters时间同步--> 用于image和imu的结合

    转载自 xff1a https blog csdn net He3he3he article details 109643391 xff11 xff0e message filters介绍 message filters用于对齐多种传感信息
  • autoware.ai docker配置

    配置环境 xff1a Ubuntu18 04 显卡驱动 510 85 02 cuda 11 1 用了我一整天的时间 xff0c 累死了 先按照此博文操作 博文里的这一步骤我没有用 sudo apt key fingerprint 0EBFC
  • 使用libcurl发送HTTP请求的一个简单示例代码

    代码简单解释 设置header 首先要声明header的结构体变量 xff0c 然后设置对应header值 xff0c 最后将其设置到curl结构体中 span class hljs comment 声明 span CURL curl sp
  • make -C和M=的作用

    当make的目标为all时 xff0c C KDIR 指明跳转到源码目录下读取那里的Makefile xff1b M 61 PWD 表明然后返回到当前目录继续读入 执行当前的Makefile
  • docker参数详解

    1 xff1a docker参数详解 docker useage of docker D 默认false 允许调试模式 debugmode H 默认是unix var run docker sock tcp host port 来绑定 或者
  • 【星伦商学院】中小企业经济复苏公益座谈会圆满结束

    中小企业经济复苏公益座谈会 为帮助中小微企业破解难题 渡过难关 xff0c 全面推进复工复产 xff0c 6月30日 xff0c 中小企业座谈会 xff08 以下简称会议 xff09 在中国 浙江诸暨市召开 力求创新举措破解制约中小微企业用
  • 从旋转矩阵到欧拉角

    摄影测量中 xff0c R转角系统一般是以y轴为主轴 xff0c 但是在很多代码中 xff0c 发现R的定义很多 xff0c 据自己需求 工业标准中一般采用Z X Y转角系统 xff0c 先绕x旋转 xff0c 再绕y 最后是Z 即如下所示
  • Git只clone指定的分支

    默认的clone会下载远程仓库的所有分支 有时候为了避免创建多个git仓库 xff0c 想将一些资源在一个git仓库下统一管理 xff0c 这时候就会出现 xff1a git远程仓库分支很多 xff0c 但是各个分支没有多大关联 xff0c
  • Ubuntu系统无法update的解决方法

    今天安装Ubuntu系统的时候 xff0c 出现了一些状况 xff0c 首先说个自己犯的幼稚错误 首先我制作好了启动盘 xff0c 并且按着步骤安装完系统 进入系统 xff0c 我自认为输入了密码 xff0c 进入了我的账号 xff08 其
  • 什么是嵌入式AI开发?人工智能芯片指什么?STM32、树莓派、Jetson TX2、华为昇腾部署神经网络区别在哪?

    嵌入式芯片 xff1a https zhuanlan zhihu com p 449570075 芯片公司代表 xff1a https www jiqizhixin com articles 2020 01 31 9 相较于CPU GPU等
  • RK3308--固件编译

    快捷路径 相关路径 xff1a cd work hxy RK3308 sdk 1 5 添加依赖包 若编译遇到报错 xff0c 可以视报错信息 xff0c 安装对应的软件包 当时下面一大段依赖包直接添加时 xff0c 不能实现 可能是因为中间
  • ChatGPT会如何影响我们的工作生活和人力资源需求

    ChatGPT xff0c 这几天体验了一下 xff0c 确实是非常震撼 一方面是因为它的回答确实相当好 xff0c 自带一点框架逻辑 xff0c 有上下文理解能力 xff0c 可以追问 xff0c 有情商 虽然很多时候都是一些正确的废话
  • Linux设备驱动思想在STM32编程中的应用

    这几天看了一下Linux设备驱动 xff0c 发现这套思想其实也可以用在普通的单片机编程上 这种思想较好的分割了驱动层和应用层的任务 xff0c 方便分层开发 以前 xff0c 我们开发STM32驱动的时候 xff0c 会给设备写一套函数来