[嵌入式開發模塊]JY61姿態角度傳感器 驅動模塊

前言

幹活中用到了JY61姿態角度傳感器,寫了相應的驅動程序,放出來。

驅動被設計爲擁有指令器和接收機兩個部分,完全被動方式運行,與具體的平臺解耦,只支持串口通訊。

JY61簡介

概述

JY61姿態角度傳感器 六軸模塊

  • 採用高精度的陀螺加速度計MPU6050,通過處理器讀取MPU6050的測量數據然後通過串口輸出,免去了用戶自己去開發MPU6050複雜的IIC協議,同時精心的PCB佈局和工藝保證了MPU6050收到外接的干擾最小,測量的精度最高。
  • 模塊內部自帶電壓穩定電路,可以兼容3.3V/5V的嵌入式系統,連接方便。
  • 採用先進的數字濾波技術,能有效降低測量噪聲,提高測量精度。
  • 模塊保留了MPU6050的IIC接口,以滿足用戶訪問底層測量數據(加速度、角速度)的需求。
  • 模塊內部集成了姿態解算器,配合動態卡爾曼濾波算法,能夠在動態環境下準確輸出模塊的當前姿態,姿態測量精度0.05度,穩定性極高。

通信協議

(1)串口通信參數

  • 電平:TTL
  • 波特率:9600/115200 bps
  • 停止位:1
  • 校驗位0

(2)數據包
模塊發送至上位機每幀數據分爲3個數據包,分別爲加速度包、角速度包和角度包,3個數據包順序輸出。波特率115200時每隔10ms輸出一幀數據。

加速度包:

角速度包:

角度包:


(3)控制指令


以上都是從數據手冊上覆制黏貼下來的,很複雜吧。

但是沒事!驅動程序已經都幫你搞定了!

驅動文件

JY61Driver.h

/*
*******************************************************************************************
*
*                                    JY61 DRIVER MODULE
*                                       JY61驅動模塊
*
* File : JY61Driver.h
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date : 2020/05/03
* version: V1.0
* History: 2020/05/03 V1.0 the prototype
* Note   : The JY61 driver is divided into two part, i.e. cmder and recver. The cmder is for
*          sending the JY61 command. The recver is for resolving data from the JY61.
********************************************************************************************
*/

#ifndef JY61DRIVER_H
#define JY61DRIVER_H

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

#include <stdint.h>

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

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

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

typedef enum {
  JY61DT_Acc,  // Acceleration
  JY61DT_AgV,  // Angular Velocity
  JY61DT_Ang,  // Angle
} JY61DataType;

typedef struct JY61STRUCT_DATA{
  JY61DataType t;
  // m/s^2  when t = Acc
  // °/s   when t = AgV
  // °     when t = Ang
  float x;
  float y;
  float z;
  float temp;  // ℃
} JY61Data;

typedef void (* JY61FUNC_DATA)(const JY61Data * data);

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

void JY61Cmder_Init(void (* outChannel)(uint8_t *buf, uint16_t len));
void JY61Cmder_Destroy(void);
void JY61Cmder_InitializeAngle(void);
void JY61Cmder_CalibrateAccelerometer(void);
void JY61Cmder_SleepOrWakeup(void);
void JY61Cmder_SerialOutput(void);
void JY61Cmder_IICOutput(void);
void JY61Cmder_BaudRate115200(void);
void JY61Cmder_BaudRate9600(void);
void JY61Cmder_HorizontalInstall(void);
void JY61Cmder_VerticalInstall(void);


void JY61Recver_Init(JY61FUNC_DATA onRecvData);
// Call it to modify the call-back function.
void JY61Recver_RegisterCallback(JY61FUNC_DATA onRecvData);
void JY61Recver_CleanupBuffer(void);
// Feed the receiver every byte received so that receiver can notify user
// the resolved data for each frame.
void JY61Recver_Feed(uint8_t nextByte);
void JY61Recver_Destroy(void);

#endif  // of JY61DRIVER_H

JY61Recver.c

/*
*******************************************************************************************
*
*                                   JY61 RECEIVER MODULE
*                                   JY61驅動模塊 - 接收機
*
* File : JY61Recver.c
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date : 2020/05/03
* version: V1.0
* History: 2020/05/03 V1.0 the prototype
* Note   : 
********************************************************************************************
*/

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

#include <string.h>
#include <ctype.h>
#include "JY61Driver.h"
#include "RxMac.h"

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

#define JY61DF_LEN 11  // length of JY61 data frame

/*
*********************************************************************************************
*                                      TYPE DEFINITION
*********************************************************************************************
*/

typedef struct JY61FRAME_STRUCT{
  uint8_t headByte;  // 0x55
  uint8_t cmdByte;
  uint8_t xL;
  uint8_t xH;
  uint8_t yL;
  uint8_t yH;
  uint8_t zL;
  uint8_t zH;
  uint8_t TL;
  uint8_t TH;
  uint8_t Sum;
} JY61Frame;

typedef struct JY61RS_STRUCT{
  int16_t x;
  int16_t y;
  int16_t z;
  int16_t temp;
} JY61ResolvedInt;

/*
*********************************************************************************************
*                                       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_JY61Recver = "JY61Recver";

static JY61FUNC_DATA _onRecvData;
static const uint8_t _flag_headerAcc[] = {(uint8_t)0x55, (uint8_t)0x51};
static const uint8_t _flag_headerAgV[] = {(uint8_t)0x55, (uint8_t)0x52};
static const uint8_t _flag_headerAng[] = {(uint8_t)0x55, (uint8_t)0x53};
static const RXFLAG_STRUCT _flags[] = {
  {_flag_headerAcc, sizeof(_flag_headerAcc), RXFLAG_OPTION_HEADER},
  {_flag_headerAgV, sizeof(_flag_headerAgV), RXFLAG_OPTION_HEADER},
  {_flag_headerAng, sizeof(_flag_headerAng), RXFLAG_OPTION_HEADER}
};
static RxMac _mac;
static uint8_t _macBuf[JY61DF_LEN];

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

void JY61Recver_Init(JY61FUNC_DATA onRecvData){
  _onRecvData = onRecvData;
  _mac = RxMac_Create(_flags, ARRAYSIZE(_flags), _macBuf, sizeof(_macBuf),
                       NULL, NULL, _onFlushed);
  if(_mac == NULL)
    for(;;)
      ;
}

void JY61Recver_Destroy(){
  _onRecvData = NULL;
  RxMac_Destroy(_mac);
}

void JY61Recver_RegisterCallback(JY61FUNC_DATA onRecvData){
  _onRecvData = onRecvData;
}

void JY61Recver_CleanupBuffer(void){
  RxMac_ResetState(_mac);
}

void JY61Recver_Feed(uint8_t nextByte){
  RxMac_FeedData(_mac, nextByte);
}

/*
*********************************************************************************************
*                               LOCAL FUNCTION IMPLEMENTATION
*********************************************************************************************
*/

static int _frameSumRight(const uint8_t * frame){
  uint8_t sum = 0;
  int i;
  for(i = 0; i < 10; i++)
    sum += frame[i];
  return sum == frame[10];
}

static void _frameResolve(JY61ResolvedInt *rst, const JY61Frame *frame){
  rst->x = (((int16_t)frame->xH) << 8) | frame->xL;
  rst->y = (((int16_t)frame->yH) << 8) | frame->yL;
  rst->z = (((int16_t)frame->zH) << 8) | frame->zL;
  rst->temp = (((int16_t)frame->TH) << 8) | frame->TL;
}

static void _onFlushed(RxMac sender,RxMacPtr buf,uint16_t len,RxState state,
                       RxFlag HorU,RxFlag Ender){
  JY61Data data;
  JY61ResolvedInt rData;
  if(_onRecvData == NULL || !state.headerFound)
    return;
  if(!_frameSumRight((const uint8_t *)buf))
    return;

  _frameResolve(&rData, (const JY61Frame *)buf);

  data.x = rData.x / 32768.0f;
  data.y = rData.y / 32768.0f;
  data.z = rData.z / 32768.0f;
  switch (buf[1]){
  case 0x51:
    data.t = JY61DT_Acc;
    data.x *= 16;
    data.y *= 16;
    data.z *= 16;
    break;
  case 0x52:
    data.t = JY61DT_AgV;
    data.x *= 2000;
    data.y *= 2000;
    data.z *= 2000;
    break;
  case 0x53:
    data.t = JY61DT_Ang;
    data.x *= 180;
    data.y *= 180;
    data.z *= 180;
    break;
  default:
    // will never hit here
    return;
  }
  data.temp = (float)rData.temp / 340.0f + 36.53f;
  _onRecvData(&data);
}

JY61Cmder.c

/*
*******************************************************************************************
*
*                                    JY61 COMMANDER MODULE
*                                    JY61驅動模塊 - 指令器
*
* File : JY61Cmder.c
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date : 2020/05/03
* version: V1.0
* History: 2020/05/03 V1.0 the prototype
* Note   : 
********************************************************************************************
*/

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

#include <stdio.h>
#include "JY61Driver.h"

/*
*********************************************************************************************
*                                       LOCAL VARIABLE
*********************************************************************************************
*/
static void (* _out)(uint8_t *buf, uint16_t len) = NULL;

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

#define JY61CMDBYTE_INITANGLE      0x52
#define JY61CMDBYTE_CALIACCMETER   0x67
#define JY61CMDBYTE_SLEEPORWAKE    0x60
#define JY61CMDBYTE_OUTPUTSERIAL   0x61
#define JY61CMDBYTE_OUTPUTIIC      0x62
#define JY61CMDBYTE_BAUDRATE115200 0x63
#define JY61CMDBYTE_BAUDRATE9600   0x64
#define JY61CMDBYTE_HORINSTALL     0x65
#define JY61CMDBYTE_VERINSTALL     0x66

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

void JY61Cmder_Init(void (* outChannel)(uint8_t *buf, uint16_t len)){
  _out = outChannel;
}

void JY61Cmder_Destroy(){
  _out = NULL;
}

static void _sendCmd(uint8_t cmdByte){
  static uint8_t frame[3] = {0xFF, 0xAA};
  if(_out == NULL)
    return;
  frame[2] = cmdByte;
  _out(frame, sizeof(frame));
}

void JY61Cmder_InitializeAngle(){
  _sendCmd(JY61CMDBYTE_INITANGLE);
}

void JY61Cmder_CalibrateAccelerometer(void){
  _sendCmd(JY61CMDBYTE_CALIACCMETER);
}

void JY61Cmder_SleepOrWakeup(void){
  _sendCmd(JY61CMDBYTE_SLEEPORWAKE);
}

void JY61Cmder_SerialOutput(void){
  _sendCmd(JY61CMDBYTE_OUTPUTSERIAL);
}

void JY61Cmder_IICOutput(void){
  _sendCmd(JY61CMDBYTE_OUTPUTIIC);
}

void JY61Cmder_BaudRate115200(void){
  _sendCmd(JY61CMDBYTE_BAUDRATE115200);
}

void JY61Cmder_BaudRate9600(void){
  _sendCmd(JY61CMDBYTE_BAUDRATE9600);
}

void JY61Cmder_HorizontalInstall(void){
  _sendCmd(JY61CMDBYTE_HORINSTALL);
}

void JY61Cmder_VerticalInstall(void){
  _sendCmd(JY61CMDBYTE_VERINSTALL);
}

依賴

接收器的實現依賴於我寫的通用接收機:
通用接收狀態機模塊

使用示例

使用此模塊基本分幾步:

  1. 初始化模塊
  2. 如需要發送指令則實現並註冊信道給指令器;註冊回調函數給接收器,這樣接收器在發現完整的數據幀時就會通過回調函數進行通知。
  3. 不斷接收數據,並喂(Feed)給接收器;如需要發指令,隨時調用指令器的接口。

以下代碼示例了在上電後發送校準指令,然後進入自動模式,之後不斷讀取數據並進行解析(假設使用標準輸入輸出上的串口和JY61通信):


#include "JY61Driver.h"
#include <stdio.h>
#include <stdint.h>
……
// 收到數據的回調函數
static void onDataResolved(const JY61Data * data);
// 發送信道
static void sendChannel(uint8_t *buf, uint16_t len);

void main(){
  uint8_t b;
  ……
  JY61Recver_Init(onDataResolved);
  JY61Cmder_Init(sendChannel);
  
  // 可以發送各種命令,比如
  // JY61Cmder_HorizontalInstall();
  
  for(;;){
    // 不斷得到下一個字節並餵給接收機
    // 接收機會通過回調函數實時傳遞解析出來的值
    b = (uint8_t)getchar();
    JY61Recver_Feed(b);
  }
}

static void onDataResolved(const JY61Data * data){
  // 這裏會得到實時解析到的各個包的數據
  switch(data->t){
    case JY61DT_Acc:
      // 加速度包的處理
    break;
    case JY61DT_AgV:
      // 角速度包的處理
    break;
    case JY61DT_Ang:
      // 角度包的處理
    break;
    default:
      // 不應該會到這
    break;
  }
}

static void sendChannel(uint8_t *buf, uint16_t len){
  // 往標準輸出輸出這個字節
  while(len-- > 0)
    putchar((char)*buf++);
}

更新歷史

2020/06/07 放出V1.0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章