[嵌入式开发模块]GY25倾斜角度传感器 驱动模块

前言

干活中用到了GY25传感器模块,写了相应的驱动程序,放出来。

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

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

GY25简介

概述

GY-25 是一款低成本倾斜度模块。工作电压3-5v 功耗小,体积小。其工作原理,是通过陀螺仪与加速度传感器经过数据融合算法最后得到直接的角度数据。此倾斜度模块以串口TTL 电平全双工方式与上位机进行通信。该产品精度高,稳定性高。能够在任意位置得到准确的角度,输出的波特率有9600bps 与115200bps有连续输出与询问输出两种方式,可适应不同的工作环境。与所有的单片机及电脑连接。

通信协议

(1)串口通信参数(默认波特率值115200 bps,)

波特率:9600 bps 校验位:N 数据位:8 停止位:1
波特率:115200 bps 校验位:N 数据位:8 停止位:1
注意:波特率选择可通过PCB 上焊接点选择。

(2)模块输出格式,每帧包含8 个字节(十六进制):

①.Byte0: 0xAA 帧头标志
②.Byte1: 0x00~0xFF 航向角高8 位
③.Byte2: 0x00~0xFF 航向角低8 位
④.Byte3: 0x00~0xFF 俯仰角高8 位
⑤.Byte4: 0x00~0xFF 俯仰角低8 位
⑥.Byte5: 0x00~0xFF 横滚角高8 位
⑦.Byte6: 0x00~0xFF 横滚角低8 位
⑧.Byte7: 0x55 帧结束标志

计算方法: 角度= 高8 位<<8|低8 位(结果为实际角度乘以100)
例:一帧数据 <0xAA-0x00-0x64-0x03-0XE8-0x27-0x10-0x55>
表示:航向角=1.00 度
俯仰角=10.00 度
横滚角=100.00 度

(3)命令字节,由外部控制器发送至模块(十六进制)

①.0xA5+0x51: 查询模式,直接返回角度值,需每次读取都发送
②.0xA5+0x52: 自动模式,直接返回角度值,只需要初始化时发一次
③.0xA5+0x53: 自动模式,ASCII 码输出,便于直接电脑串口助手查看
④.0xA5+0x54: 校正模式,校正俯仰横滚角0 度,需要保持水平时候发送
⑤.0xA5+0x55: 校正模式,校正航向0 度,航向任意角度清零

驱动文件

GY25Driver.h

/*
*******************************************************************************************
*
*                                    GY25 DRIVER MODULE
*                                       GY25驱动模块
*
* File : GY25Driver.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 GY25 driver is divided into two part, i.e. cmder and recver. The cmder is for
*          sending the GY25 command. The recver is for resolving data from the GY25.
********************************************************************************************
*/

#ifndef   GY25DRIVER_H
#define   GY25DRIVER_H

/*
******************************************************************************************
*                                          INCLUDE
******************************************************************************************
*/

#include <stdint.h>

/*
******************************************************************************************
*                                    DEBUG CONFIGURATION
******************************************************************************************
*/

// to enable debug messages in this module
// #define GY25_DEBUG  

/*
******************************************************************************************
*                                         CONSTANT
******************************************************************************************
*/

// Frame Header byte of data frame
#define GY25DF_HEADER  0xAA
// Frame Ender byte of data frame
#define GY25DF_ENDER   0x55
// length (in byte) of data frame
#define GY25DF_LENGTH  8

// Frame Header byte of command frame
#define GY25CF_HEADER          0xA5
// Query mode
#define GY25CMD_QUERY          0x51
// Automatic mode
#define GY25CMD_AUTO           0x52
// Automatic mode(ASCII)
#define GY25CMD_AUTO_ASCII     0x53
// Calibrate pitch and roll angle
#define GY25CMD_CALI_PITCHROLL 0x54
// Calibrate course angle
#define GY25CMD_CALI_COURSE    0x55

/*
******************************************************************************************
*                                        TYPE DEFINE
******************************************************************************************
*/

typedef struct GY25STRUCT_DATA{
  int16_t angleCourse;  // = 'real angle' * 100
  int16_t anglePitch ;  // = 'real angle' * 100
  int16_t angleRoll  ;  // = 'real angle' * 100
} GY25Data;

typedef void (* GY25FUNC_DATA)(GY25Data data);

/*
******************************************************************************************
*                                        INTERFACES
******************************************************************************************
*/

void GY25Cmder_Init(void (* outChannel)(uint8_t b));
void GY25Cmder_Query(void);
void GY25Cmder_EnterModeAuto(void);
void GY25Cmder_EnterModeAuto_ASCII(void);
void GY25Cmder_CalibratePitchRoll(void);
void GY25Cmder_CalibrateCourse(void);
void GY25Cmder_Destroy(void);


void GY25Recver_Init(GY25FUNC_DATA onRecvData);
// Call it to modify the call-back function.
void GY25Recver_RegisterCallback(GY25FUNC_DATA onRecvData);
void GY25Recver_CleanupBuffer(void);
// Feed the receiver every byte received so that receiver can notify user
// the resolved data for each frame.
void GY25Recver_Feed(uint8_t nextByte);
void GY25Recver_Destroy(void);

#endif  // of GY25DRIVER_H

GY25Recver.c

/*
*******************************************************************************************
*
*                                    GY25 RECEIVER MODULE
*                                    GY25驱动模块 - 接收机
*
* File : GY25Recver.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   : only for hex format
********************************************************************************************
*/

/*
*********************************************************************************************
*                                       INCLUDES
*********************************************************************************************
*/

#include "GY25Driver.h"
#include "BufferExternalArray.h"

#ifndef GY25_DEBUG
#undef _DEBUG
#endif

#include "DebugMsg.h"
/*
*********************************************************************************************
*                                       LOCAL FUNCTION
*********************************************************************************************
*/

#define ARRAYSIZE(arr)  (sizeof(arr)/ sizeof(arr[0]))
#define _bufGet(index) BufferUINT8Indexed_get((BufferUINT8Indexed)_buf, index)

/*
*********************************************************************************************
*                                       LOCAL VARIABLE
*********************************************************************************************
*/

static const char * _str_GY25Recver = "GY25Recver";

static GY25FUNC_DATA _onRecvData;

static uint8_t _frameBuf[GY25DF_LENGTH];
static BufferUINT8Array _buf;

/*
*********************************************************************************************
*                                 INTERFACE IMPLEMENTATION
*********************************************************************************************
*/

void GY25Recver_Init(GY25FUNC_DATA onRecvData){
  _onRecvData = onRecvData;
  _buf = BufferUINT8ExternalArray_Create(_frameBuf, GY25DF_LENGTH);
  if(_buf == NULL)
    for(;;)
      ;  // fatal error
}

void GY25Recver_RegisterCallback(GY25FUNC_DATA onRecvData){
  _onRecvData = onRecvData;
}

void GY25Recver_CleanupBuffer(void){
  Buffer_Cleanup((Buffer)_buf);
}

void GY25Recver_Feed(uint8_t nextByte){
  GY25Data data;
  if(Buffer_isFull(_buf))
    BufferUINT8_FrontOut((BufferUINT8)_buf);
  BufferUINT8_BackIn((BufferUINT8)_buf, nextByte);
  // if we haven't received GY25DF_LENGTH bytes.
  if(!Buffer_isFull(_buf) || 
  // or it's not a frame.
    _bufGet(0) != GY25DF_HEADER || _bufGet(GY25DF_LENGTH - 1) != GY25DF_ENDER){
    _dbg_printf1("%s: got corrupt frame.\r\n", _str_GY25Recver);
    return;  // then bye.
  }
  // if found a data frame.
  data.angleCourse = (_bufGet(1) << 8) | _bufGet(2);
  data.anglePitch  = (_bufGet(3) << 8) | _bufGet(4);
  data.angleRoll   = (_bufGet(5) << 8) | _bufGet(6);
  _dbg_printf4("%s: got data-Course(%i),Pitch(%i),Roll(%i)\r\n", _str_GY25Recver, data.angleCourse, 
    data.anglePitch, data.angleRoll);
  if(_onRecvData)
    _onRecvData(data);
  Buffer_Cleanup((Buffer)_buf);
}

void GY25Recver_Destroy(){
  _onRecvData = NULL;
  Buffer_Destroy(_buf);
  _buf = NULL;
}

GY25Cmder.c

/*
*******************************************************************************************
*
*                                    GY25 COMMANDER MODULE
*                                    GY25驱动模块 - 指令器
*
* File : GY25Cmder.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 "GY25Driver.h"

/*
*********************************************************************************************
*                                  LOCAL FUNCTION DECLARATION
*********************************************************************************************
*/

static void _sendCmd(uint8_t cmdByte);

/*
*********************************************************************************************
*                                       LOCAL VARIABLE
*********************************************************************************************
*/
static void (* _out)(uint8_t b) = NULL;

/*
*********************************************************************************************
*                                 INTERFACE IMPLEMENTATION
*********************************************************************************************
*/

void GY25Cmder_Init(void (* outChannel)(uint8_t b)){
  _out = outChannel;
}

void GY25Cmder_Destroy(){
  _out = NULL;
}


void GY25Cmder_Query(void){
  _sendCmd(GY25CMD_QUERY);
}

void GY25Cmder_EnterModeAuto(void){
  _sendCmd(GY25CMD_AUTO);
}

void GY25Cmder_EnterModeAuto_ASCII(void){
  _sendCmd(GY25CMD_AUTO_ASCII);
}

void GY25Cmder_CalibratePitchRoll(void){
  _sendCmd(GY25CMD_CALI_PITCHROLL);
}

void GY25Cmder_CalibrateCourse(void){
  _sendCmd(GY25CMD_CALI_COURSE);
}
/*
*********************************************************************************************
*                                 LOCAL FUNCTION IMPLEMENTATION
*********************************************************************************************
*/
static void _sendCmd(uint8_t cmdByte){
  if(_out == NULL)
    return;
  _out(GY25CF_HEADER);
  _out(cmdByte);
}

依赖

接收器的实现依赖于我实现的环形缓冲区:
环形缓冲区/循环队列C语言面向对象实现(二)Buffer类源码

至于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

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

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

使用示例

使用此模块基本分几步:

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

以下代码示例了在上电后发送校准指令,然后进入自动模式,之后不断读取数据并进行解析(假设使用标准输入输出上的串口和GY25通信):


#include "GY25Driver.h"
#include <stdio.h>
#include <stdint.h>
……
// 收到数据的回调函数
static void onDataResolved(GY25Data data);
// 发送信道
static void sendChannel(uint8_t b);

void main(){
  uint8_t b;
  ……
  GY25Recver_Init(onDataResolved);
  GY25Cmder_Init(sendChannel);
  
  // 延迟一小段时间
  (void)MyOS_DlyHMSM(0, 0, 0, 100);
  // 校准角度
  GY25Cmder_CalibratePitchRoll();
  // 延迟一小段时间
  (void)MyOS_DlyHMSM(0, 0, 0, 200);
  // 进入自动模式
  GY25Cmder_EnterModeAuto();
  for(;;){
    // 不断得到下一个字节并喂给接收机
    // 接收机会通过回调函数实时传递解析出来的值
    b = (uint8_t)getchar();
    GY25Recver_Feed(b);
  }
}

static void onDataResolved(GY25Data data){
  // data中就是实时解析到的数据,具体怎么使用是你的事
  // 注意里头的整型值是 真实角度 * 100 后的值
}

static void sendChannel(uint8_t b){
  // 往标准输出输出这个字节
  putchar((char)b);
}

注意:GY25可以选择用ASCII格式输出,但此模块不支持也并不打算支持解析ASCII格式的数据帧。

更新历史

2020/06/06 放出V1.0

  • 10
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
引用\[1\]: GY-25A模块是一种倾角传感器模块,可以通过串口输出角度数据。引用\[2\]: K_A14_012是一种基于STM32单片机驱动GY-25倾斜角度模块的方案,可以实现串口和OLED双显示。引用\[3\]: ADIS16203是一款完整的倾斜角测量系统,采用了ADI公司的iSensor™集成技术,可以通过SPI接口访问倾斜角数据。基于这些引用内容,STM32可以通过串口或SPI接口与倾斜角度传感器进行通信和获取数据。具体的实现方取决于所选的传感器模块和STM32的型号。 #### 引用[.reference_title] - *1* [STM32获取GY-25A倾角传感器串口输出数据](https://blog.csdn.net/hwytree/article/details/122622720)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [K_A14_012基于STM32等单片机驱动GY-25倾斜角度模块 串口与OLED0.96双显示](https://blog.csdn.net/lfmnlxx79691557/article/details/129209387)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [ADIS16203角度传感器的stm32驱动实现要点](https://blog.csdn.net/MENGHUANBEIKE/article/details/80380774)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值