干活中用到了深度解算板,写了相应的驱动程序,放出来。
这个模块本身的协议比较简单,所以模块的驱动也很小巧。
驱动被设计为拥有指令器和接收机两个部分,完全被动方式运行,与具体的平台解耦,只支持串口通讯。
深度传感器器解算板。⽤于读回深度传感器器的测量信息,转为串口输出。
深度解算板⽀持接入ROVMAKER的深度传感器线序,适⽤于MS5837型号深度传感器。确认线序后将传感器接入解算板的任一1.25mm防反接座,目前只支持同时接入一个MS5837深度传感器,连接解算板到外部主控制器。
解算板和传感器需在水面上电。上电后解算板会测量出环境空气的压力值标为深度输出的零点。上电后⽆传感器故障,解算板即开始输出深度温度信息。
解算板输出字符串格式: T=XX.XXD=XX.XX\r\n
浮点数温度输出 T 单位:摄⽒度(°C)
浮点数深度输出 D 单位:米(m)
例: T=25.27D=1.21 温度为25.27°C深度为1.21m
解算板可通过串口发送字符串配置解算板参数。
/*
*******************************************************************************************
*
* M10 DRIVER MODULE
* M10驱动模块
*
* File : M10Driver.h
* By : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2020/04/29
* version: V1.0
* History: 2020/04/29 V1.0 the prototype
* Note : The M10 driver is divided into two part, i.e. cmder and recver. The cmder is for
* sending the M10 command. The recver is for resolving data from the M10.
* lack "!!\r\n" command in this version intentionally, so that the receiver can
* only take care of the common data in form of "T=XX.XXD=XX.XX\r\n".
********************************************************************************************
*/
#ifndef M10DRIVER_H
#define M10DRIVER_H
/*
******************************************************************************************
* INCLUDE
******************************************************************************************
*/
#include
/*
******************************************************************************************
* DEBUG CONFIGURATION
******************************************************************************************
*/
// to enable debug messages in this module
// #define M10_DEBUG
/*
******************************************************************************************
* TYPE DEFINE
******************************************************************************************
*/
typedef struct M10STRUCT_DATA{
float temp; // °C
float depth; // m
} M10Data;
typedef void (* M10FUNC_DATA)(M10Data data);
typedef enum {
M10LED_OFF = 0,
M10LED_ON = 1,
M10LED_TWINKLE = 2,
}M10LEDScheme;
/*
************************************************************************************
* INTERFACES
************************************************************************************
*/
void M10Cmder_Init(void (* outChannel)(uint8_t *buf, uint16_t len));
void M10Cmder_Destroy(void);
void M10Cmder_setLiquidDensity(uint16_t value);
void M10Cmder_setLEDScheme(M10LEDScheme s);
void M10Cmder_setBaudRate(uint32_t value);
void M10Cmder_setDepthOffset(float value);
void M10Cmder_setTempOffset(float value);
void M10Cmder_ClearOffset(void);
void M10Cmder_ResetBoard(void);
void M10Cmder_FactoryReset(void);
void M10Recver_Init(M10FUNC_DATA onRecvData);
// Call it to modify the call-back function.
void M10Recver_RegisterCallback(M10FUNC_DATA onRecvData);
void M10Recver_CleanupBuffer(void);
// Feed the receiver every byte received so that receiver can notify user
// the resolved data for each frame.
void M10Recver_Feed(uint8_t nextByte);
void M10Recver_Destroy(void);
#endif // of M10DRIVER_H
/*
*******************************************************************************************
*
* M10 RECEIVER MODULE
* M10驱动模块 - 接收机
*
* File : M10Recver.c
* By : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2020/04/27
* version: V1.0
* History: 2020/04/27 V1.0 the prototype
* Note : The receiver has simple format check for data, which only checks for whether they
* are right characters. A more strict format check may be implemented in the further.
********************************************************************************************
*/
/*
*********************************************************************************************
* INCLUDES
*********************************************************************************************
*/
#include
#include
#include "M10Driver.h"
#include "RxMac.h"
#ifndef M10_DEBUG
#undef _DEBUG
#endif
#include "DebugMsg.h"
/*
*********************************************************************************************
* LOCAL FUNCTION
*********************************************************************************************
*/
#define ARRAYSIZE(arr) (sizeof(arr)/ sizeof(arr[0]))
static void _onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
RxFlag HorU,RxFlag Ender);
/*
*********************************************************************************************
* LOCAL VARIABLE
*********************************************************************************************
*/
static const char * _str_M10Recver = "M10Recver";
static M10FUNC_DATA _onRecvData;
static const uint8_t _flag_header[] = {(uint8_t)'T', (uint8_t)'='};
static const uint8_t _flag_ender[] = {(uint8_t)'\r', (uint8_t)'\n'};
static const RXFLAG_STRUCT _flags[] = {
{_flag_header, 2, RXFLAG_OPTION_STRONG_HEADER},
{_flag_ender , 2, RXFLAG_OPTION_STRONG_ENDER }
};
static RxMac _mac;
static uint8_t _macBuf[23];
/*
*********************************************************************************************
* INTERFACE IMPLEMENTATION
*********************************************************************************************
*/
void M10Recver_Init(M10FUNC_DATA onRecvData){
_onRecvData = onRecvData;
_mac = RxMac_Create(_flags, ARRAYSIZE(_flags), _macBuf, sizeof(_macBuf) - 1,
NULL, NULL, _onFlushed);
if(_mac == NULL)
for(;;)
;
}
void M10Recver_Destroy(){
_onRecvData = NULL;
RxMac_Destroy(_mac);
}
void M10Recver_RegisterCallback(M10FUNC_DATA onRecvData){
_onRecvData = onRecvData;
}
void M10Recver_CleanupBuffer(void){
RxMac_ResetState(_mac);
}
void M10Recver_Feed(uint8_t nextByte){
RxMac_FeedData(_mac, nextByte);
}
/*
*********************************************************************************************
* LOCAL FUNCTION IMPLEMENTATION
*********************************************************************************************
*/
static int _FloatFormatRight(const char *beg, const char *end){
const char *p;
if(end - beg <= 0)
return 0;
for(p = beg; end - p > 0; p++)
if(!isdigit(*p) && *p != '-' && *p != '.')
return 0;
return 1;
}
static void _onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
RxFlag HorU,RxFlag Ender){
const char *pD;
M10Data data;
if(_onRecvData == NULL || !state.headerFound || !state.enderFound)
return;
buf[len] = '\0';
pD = (const char *)&buf[2];
while(pD[0] != '\r' && !(pD[0] == 'D' && pD[1] == '='))
++pD;
if(pD[0] != 'D' || !_FloatFormatRight((const char *)&buf[2], pD) ||
!_FloatFormatRight((const char *)&pD[2], (const char *)buf + len - 2)){
_dbg_printf2("%s: got corrupt frame-%s", _str_M10Recver, (const char *)buf);
return;
}
data.temp = (float)atof((const char *)&buf[2]);
data.depth = (float)atof((const char *)&pD[2]);
_dbg_printf3("%s: got data-temp(%.2f),depth(%.2f)\r\n", _str_M10Recver, data.temp, data.depth);
_onRecvData(data);
}
/*
*******************************************************************************************
*
* M10 COMMANDER MODULE
* M10驱动模块 - 指令器
*
* File : M10Cmder.c
* By : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date: 2020/04/29
* version: V1.0
* History: 2020/04/29 V1.0 the prototype
* Note :
********************************************************************************************
*/
/*
*********************************************************************************************
* INCLUDES
*********************************************************************************************
*/
#include
#include "M10Driver.h"
/*
*********************************************************************************************
* LOCAL FUNCTION DECLARATION
*********************************************************************************************
*/
static void _sendCmd(char cmdByte, const char *paramStr);
/*
*********************************************************************************************
* LOCAL VARIABLE
*********************************************************************************************
*/
static void (* _out)(uint8_t *buf, uint16_t len) = NULL;
/*
*********************************************************************************************
* INTERFACE IMPLEMENTATION
*********************************************************************************************
*/
void M10Cmder_Init(void (* outChannel)(uint8_t *buf, uint16_t len)){
_out = outChannel;
}
void M10Cmder_Destroy(){
_out = NULL;
}
void M10Cmder_setLiquidDensity(uint16_t value){
char buf[8];
(void)sprintf(buf, "%u", value);
_sendCmd('F', buf);
}
void M10Cmder_setLEDScheme(M10LEDScheme s){
char buf[8];
if(s > M10LED_TWINKLE)
return;
(void)sprintf(buf, "%u", s);
_sendCmd('L', buf);
}
void M10Cmder_setBaudRate(uint32_t value){
char buf[14];
(void)sprintf(buf, "%lu", (unsigned long)value);
_sendCmd('B', buf);
}
void M10Cmder_setDepthOffset(float value){
char buf[14];
// Note: may overflow here, consider snprintf
(void)sprintf(buf, "%.2f", value);
_sendCmd('D', buf);
}
void M10Cmder_setTempOffset(float value){
char buf[14];
// Note: may overflow here
(void)sprintf(buf, "%.2f", value);
_sendCmd('T', buf);
}
void M10Cmder_ClearOffset(void){
_sendCmd('C', NULL);
}
void M10Cmder_ResetBoard(void){
_sendCmd('R', NULL);
}
void M10Cmder_FactoryReset(void){
_sendCmd('r', NULL);
}
/*
*********************************************************************************************
* LOCAL FUNCTION IMPLEMENTATION
*********************************************************************************************
*/
static void _sendCmd(char cmdByte, const char *paramStr){
int len;
static uint8_t buf[20];
if(_out == NULL)
return;
if(paramStr == NULL)
paramStr = "";
len = sprintf((char *)buf, "!%c%s\r\n", cmdByte, paramStr);
_out(buf, len);
}
接收器的实现依赖于我写的通用接收机:
通用接收状态机模块
至于DebugMsg.h则是我自己使用的调试信息的模块:
#ifndef _DEBUG_MSG_H
#define _DEBUG_MSG_H
#include
#ifdef _DEBUG
#define _dbg_printf0(format) ((void)printf(format))
#define _dbg_printf1(format,p1) ((void)printf(format,p1))
#define _dbg_printf2(format,p1,p2) ((void)printf(format,p1,p2))
#define _dbg_printf3(format,p1,p2,p3) ((void)printf(format,p1,p2,p3))
#define _dbg_printf4(format,p1,p2,p3,p4) ((void)printf(format,p1,p2,p3,p4))
#define _dbg_printf5(format,p1,p2,p3,p4,p5) ((void)printf(format,p1,p2,p3,p4,p5))
#define _dbg_printf6(format,p1,p2,p3,p4,p5,p6) ((void)printf(format,p1,p2,p3,p4,p5,p6))
#define _dbg_printf7(format,p1,p2,p3,p4,p5,p6,p7) \
((void)printf(format,p1,p2,p3,p4,p5,p6,p7))
#define _dbg_printf8(format,p1,p2,p3,p4,p5,p6,p7,p8) \
((void)printf(format,p1,p2,p3,p4,p5,p6,p7,p8))
#define _dbg_printf9(format,p1,p2,p3,p4,p5,p6,p7,p8,p9) \
((void)printf(format,p1,p2,p3,p4,p5,p6,p7,p8,p9))
#else
#define _dbg_printf0(format)
#define _dbg_printf1(format,p1)
#define _dbg_printf2(format,p1,p2)
#define _dbg_printf3(format,p1,p2,p3)
#define _dbg_printf4(format,p1,p2,p3,p4)
#define _dbg_printf5(format,p1,p2,p3,p4,p5)
#define _dbg_printf6(format,p1,p2,p3,p4,p5,p6)
#define _dbg_printf7(format,p1,p2,p3,p4,p5,p6,p7)
#define _dbg_printf8(format,p1,p2,p3,p4,p5,p6,p7,p8)
#define _dbg_printf9(format,p1,p2,p3,p4,p5,p6,p7,p8,p9)
#endif
int dummyprintf(const char *format, ...);
#endif
这样在项目中同时宏定义 _DEBUG 和 M10_DEBUG 时才会打印调试信息。不需要的话删除相关语句就好。
想要了解相关技巧的话详见:
C语言宏配置的各种奇淫技巧
使用此模块基本分几步:
以下代码示例了在上电后不断读取数据并进行解析(假设使用标准输入输出上的串口和深度解算板通信):
#include "M10Driver.h"
#include
#include
……
// 收到数据的回调函数
static void onDataResolved(M10Data data);
// 发送信道
static void sendChannel(uint8_t *buf, uint16_t len);
void main(){
uint8_t b;
……
M10Recver_Init(onDataResolved);
M10Cmder_Init(sendChannel);
// 如果需要的话发送对应指令
// M10Cmder_ResetBoard();
for(;;){
// 不断得到下一个字节并喂给接收机
// 接收机会通过回调函数实时传递解析出来的值
b = (uint8_t)getchar();
M10Recver_Feed(b);
}
}
static void onDataResolved(M10Data data){
// data中就是实时解析到的数据,具体怎么使用是你的事
}
static void sendChannel(uint8_t *buf, uint16_t len){
// 往标准输出输出这个字节
while(len-- > 0)
putchar((char)*buf++);
}
2020/06/06 放出V1.0