[嵌入式开发模块]深度传感器解算板(MS5837转串口板) 驱动模块

前言

干活中用到了深度解算板,写了相应的驱动程序,放出来。

这个模块本身的协议比较简单,所以模块的驱动也很小巧。

驱动被设计为拥有指令器和接收机两个部分,完全被动方式运行,与具体的平台解耦,只支持串口通讯。

深度传感器解算板V1.0简介

概述

深度传感器器解算板。⽤于读回深度传感器器的测量信息,转为串口输出。

深度解算板⽀持接入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

控制指令

解算板可通过串口发送字符串配置解算板参数。

  • !Fxxxx\r\n :
    xxxx为设置的液体密度 设置液体密度:设置所测⽔水的密度。单位:kg/m3。
    通常淡水中密度设置为997(kg/m3),海水密度(1029kg/m3)。 解算板默认设置为997kg/m3。
  • !Lx\r\n:
    x为LED运⾏状态 运⾏指示灯状态:可设置为关闭/常亮/闪烁。 默认为闪烁
    0 LED关闭;1 LED常亮;2 LED闪烁。
    例: !L0\r\n 关闭运⾏指示灯
    !L1\r\n 常亮运⾏指示灯
    !L2\r\n 闪烁运⾏指示灯
  • !Bxxxx\r\n :
    xxxx为设置的波特率 串口波特率设置:默认波特率为115200bps,可通过发送指令修改波特率。通常不需要修改此参数。
    例:!B9600\r\n 修改波特率为9600bps。 当串口1波特率配置发⽣错误时,可通过预留串口2发送该指令配置串口1波特率。
  • !Dxx.xx\r\n :
    xx.xx 为浮点数offset 深度输出offset调整预留指令:浮点数,在当前深度输出的数值上加上offset值。 例:
    当前输出深度-0.55,offset设置0.55,加上offset后深度输出为 -0.55+offset=0.00。 当前输出深度0.1,offset设置-0.1,加上offset后深度输出为0.00
  • !Txx.xx\r\n :
    xx.xx 为浮点数offset 温度输出offset调整预留指令:浮点数,在当前温度输出的数值上加上offset值。 例:
    当前输出温度25.00,offset设置1,加上offset后深度输出为 25.00+offset=26.00。 当前输出深度25.00,offset设置-1,加上offset后深度输出为24.00
  • !!\r\n :
    暂停传感器器输出,串口输出所有参数。再次发送停⽌参数输出,继续传感器输出。串口输出参数格式如下:
  • !R\r\n :
    复位解算板。
  • !r\r\n :
    恢复所有初始化设置。
  • !C\r\n :
    清除所有offset设置 参数配置后传感器器解算板会保存当前设置,重新上电后配置数据仍然有效。
  • !!\r\n:
    暂停传感器器输出,串串⼝口输出所有参数。再次发送停⽌止参数输出,继续传感器器输出。
  • !R\r\n:
    复位解算板。
  • !r\r\n:
    恢复所有初始化设置。
  • !F1029\r\n:
    设置液体密度参数。
  • !L2\r\n:
    设置运⾏状态指示灯状态。
  • !B9600\r\n:
    设置输出串口波特率。
  • !D0.200\r\n:
    深度offset调整预留指令。
  • !T0.200\r\n:
    温度offset调整预留指令。
  • !C\r\n:
    清除所有offset设置 。

驱动文件

M10Driver.h

/*
*******************************************************************************************
*
*                                    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 <stdint.h>

/*
******************************************************************************************
*                                    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

M10Recver.c

/*
*******************************************************************************************
*
*                                    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 <stdlib.h>
#include <ctype.h>
#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);
}

M10Cmder.c

/*
*******************************************************************************************
*
*                                    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 <stdio.h>
#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 <stdio.h>
#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

这样在项目中同时宏定义 _DEBUGM10_DEBUG 时才会打印调试信息。不需要的话删除相关语句就好。

想要了解相关技巧的话详见:
C语言宏配置的各种奇淫技巧

使用示例

使用此模块基本分几步:

  1. 初始化模块
  2. 如需要发送指令则实现并注册信道给指令器;注册回调函数给接收器,这样接收器在发现完整的数据帧时就会通过回调函数进行通知。
  3. 不断接收数据,并喂(Feed)给接收器;如需要发指令,随时调用指令器的接口。

以下代码示例了在上电后不断读取数据并进行解析(假设使用标准输入输出上的串口和深度解算板通信):


#include "M10Driver.h"
#include <stdio.h>
#include <stdint.h>
……
// 收到数据的回调函数
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

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值