利用与硬件无关的方法简化嵌入式系统设计:驱动程序实现
摘要
本文探讨如何在项目中实现与硬件无关的驱动程序。即插即用的设计理念能够显著降低嵌入式软件或固件设计的复杂性,无论设计者的经验水平如何,都能从中受益。如果您想了解驱动程序的基本函数和嵌入式系统的软件架构,请参见文章“利用与硬件无关的方法简化嵌入式系统设计:基本知识”。
简介
在嵌入式系统设计中,设计人员通常要编写驱动程序和固件的代码,确保所选传感器能够实现其所需的基本功能。这一过程往往耗时且繁琐。为解决这一难题,可以通过结合硬件、软件和固件的方式,采用即插即用的设计思路,从而简化传感器的 选择和系统集成。与硬件无关的驱动程序不仅能够让传感器集成变得更加高效,还可以作为一种通用解决方案,便于在未来的设计中重复使用。本文将以惯性测量单元(IMU)传感器为例,说明如何实现与硬件无关的驱动程序,不过,这种方法同样适用于其他类型的传感器和器件。驱动程序采用C语言编写,并在一款通用微控制器上进行了测试。
驱动程序实现
附录中包含提及的所有图片和代码,可供读者查阅。
- adis16500_rd_error_flag
附录中的图10展示了该函数的实现。该函数读取ADIS16500_REG_DIAG_STAT寄存器中包含的错误标志,如果未发生错误,所有位都为0。可能的错误有10个,因此,该函数会返回一个ADIS16500_ERROR_FLAGS结构,其中包含10个布尔字段,每个字段代表一个错误。该函数只读取ADIS16500_REG_DIAG_STAT寄存器,并使用特定错误掩码检查该寄存器的各个位,发现逻辑1时,该结构的相应字段就会设置为true。
- adis16500_rd_temp
这是一个温度读取函数,其实现方法与加速度和陀螺仪相同(详情请见本系列第一篇文章)。读取的值用°C为单位表示。其二进制值包含在16位寄存器ADIS16500_REG_TEMP_OUT中。之后,数据将经过二进制转二进制补码的转换。得到的二进制补码值将乘以温度比例因子(单位为°C/LSB),最终得出以°C为单位的数值,并记录在作为输入传递的指针中。该函数实现可参见附录中的图9。
- adis16500_get_ts_usec
该函数用于获取IMU的时间戳,单位为μ s。其实现方法与adis16500_rd_temp函数完全相同。具体可参见附录中的图9。
- adis16500_rd_data_cntr
该程序读取已输出的数据数量。实际上,只需读取名为 ADIS16500_REG_DATA_CNTR的寄存器即可实现。当该寄存器达到最大值 时,将从0重新开始。该函数的实现方式可参见附录中的图9。
- adis16500_wr_acc_calib
该函数用于执行自定义偏移校准。设计人员通过调用该函数,可将偏移值添加到从输出数据寄存器读取的值中,从而将x、y、z校准值添加到x、y、z加速度数据中。该函数的输入是指向ADIS16500_XL_OUT类型结构的指针,该结构包含x、y和z浮点类型字段。该函数的目标是从浮点值转换为二进制补码值,再从二进制补码值转换为二进制值。所有步骤可参见 附录中的图11。接下来,需要将二进制值写入偏置寄存器,例如,对于x轴,需要写入两个寄存器: ADIS16500_REG_X_ACCEL_BIAS_L(低16位)和 ADIS16500_REG_X_ACCEL_BIAS_H(高16位)。y轴和z轴也是如此,各自有相应的偏置寄存器。为了检查该程序是否正确执行,放置IMU传感器时,确保z轴垂直指向天空。在这种情况下,x轴和y轴的加速度值接近0,z轴的加速度值接近–9.81 m/s2(–g)。调用校准函数并传递一个校准结构,其中x、y和z字段均等于–9.81 m/s 2,校准后的读取结果为x = –9.81;y = –9.81;z = 0,即表明校准偏移函数正常工作。
- adis16500_wr_gyro_calib
这是与陀螺仪有关的偏移校准函数,其实现方法与加速度校准函数完全相同。区别在于,陀螺仪的校准需要按照数据手册中的说明,使用对应的陀螺仪偏移寄存器来完成。
本文着重介绍IMU传感器驱动程序,但其软件/固件结构可用于任何类型的传感器。因此,要实现对所有传感器的通用支持,只需根据传感器与微控制器之间的通信协议(如 SPI、 I2C、UART 等)进行调整。传感器的初始化方式仍然有效,因为初始化阶段记录了通过通信协议进行收发的函数。
如何在项目中引入和使用驱动程序
除了关于传感器和微控制器单元(MCU)间硬件连接的基本说明外,本文还提供了相关指南,从软件和固件的角度介绍如何引入驱动程序。
传感器驱动程序没有通用的组织结构。图1所示为建议的文件夹结构。 userlib文件夹中包含所有传感器驱动程序。在本示例中,只有IMU传感器驱动程序,但如果项目包含更多传感器,组织方式基本相同。userlib中有两个文件夹,分别是include和src。include文件夹包含驱动程序的头文件,即本例中的adis16500.h,而src中包含源文件,即adis16500.c。userlib中还有一个指定include指令的makefile,如图2所示。
![]() |
图1. 项目文件夹结构。
![]() |
图2. userlib makefile。
图3所示为主makefile。它位于应用层,靠近main.c。该makefile包含user.mk ,如图3中红色下划线所示(代码第115行)。
图3. 主makefile。
借助makefile (.mk),设计人员可以在应用层(比如在 main.c内) 引入驱动程序的接口,并且可以调用传感器驱动程序的所有公 共函数。这样,应用层和传感器驱动层之间就会建立起链接。 在应用层可以得知传感器的驱动程序接口( (adis16500.h))。因此, 在应用层,将通过上文讨论的初始化程序建立传感器驱动层 和外设驱动层之间的链接。在IMU传感器的具体用例中,发送 器、接收器SPI函数和系统延迟函数将在 main.c文件中定义,如 附录中的图2所示。这三个函数完全遵循驱动程序头文件中的原型,即附录中图3顶部所示的原型。这三个函数内部是外设驱动层提供的函数,如spiSelectspiSend、 spiReceive、spiUnselect和chThdSleepMicroseconds 。因此,SPI接收器、发送器和系统延迟函数代表外设驱动层和传感器驱动层之间的链接,这些函数将分配到初始化结构中,如附录中的图2所示。以上就是在项目中引入驱动程序的整个过程。
如果要从传感器获取输出,设计人员可以使用adis16500_rd_acc和 adis16500_rd_gyro部分介绍的函数。传感器读取并没有完全通用的方法,图4仅提供一个示例。
图4. 传感器输出读取示例。
在此示例中,main.c中有一个无限循环,始终检查名为__adis16500_data_ready的布尔静态变量。该变量与回调函数相关,当DR引脚变为高电平时,它将切换到TRUE,这意味着已有新数据可用。在这种情况下,主函数将调用adis16500_rd_acc和adis16500_rd_gyro 函数。通过全速运行IMU传感器,设计人员将能够以2 kHz的输出数据速率(ODR)获取数据。
结论
本文介绍了驱动程序功能,以及如何通过与硬件无关的方法简化传感器集成。与硬件无关的驱动程序可以作为一种通用解决方案,在未来的设计中重复使用。
关于作者
关联至此文章
产品
产品分类
{{modalTitle}}
{{modalDescription}}
{{dropdownTitle}}
- {{defaultSelectedText}} {{#each projectNames}}
- {{name}} {{/each}} {{#if newProjectText}}
-
{{newProjectText}}
{{/if}}
{{newProjectTitle}}
{{projectNameErrorText}}