bmm150.ino 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /*
  2. *******************************************************************************
  3. * Copyright (c) 2022 by M5Stack
  4. * Equipped with M5Core sample source code
  5. * 配套 M5Core 示例源代码
  6. * Visit for more information: https://docs.m5stack.com/en/core/gray
  7. * 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/gray
  8. *
  9. * Describe: bmm150--Magnetometer 三轴磁力计
  10. * Date: 2021/7/21
  11. *******************************************************************************
  12. */
  13. #include <Arduino.h>
  14. #include "M5Stack.h"
  15. #include "M5_BMM150.h"
  16. #include "M5_BMM150_DEFS.h"
  17. #include "Preferences.h"
  18. #include "math.h"
  19. Preferences prefs;
  20. struct bmm150_dev dev;
  21. bmm150_mag_data mag_offset; // Compensation magnetometer float data storage
  22. // 储存补偿磁强计浮子数据
  23. bmm150_mag_data mag_max;
  24. bmm150_mag_data mag_min;
  25. TFT_eSprite img = TFT_eSprite(&M5.Lcd);
  26. int8_t i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *read_data,
  27. uint16_t len) {
  28. if (M5.I2C.readBytes(
  29. dev_id, reg_addr, len,
  30. read_data)) { // Check whether the device ID, address, data exist.
  31. return BMM150_OK; //判断器件的Id、地址、数据是否存在
  32. } else {
  33. return BMM150_E_DEV_NOT_FOUND;
  34. }
  35. }
  36. int8_t i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *read_data,
  37. uint16_t len) {
  38. if (M5.I2C.writeBytes(dev_id, reg_addr, read_data,
  39. len)) { // Writes data of length len to the specified
  40. // device address.
  41. return BMM150_OK; //向指定器件地址写入长度为len的数据
  42. } else {
  43. return BMM150_E_DEV_NOT_FOUND;
  44. }
  45. }
  46. int8_t bmm150_initialization() {
  47. int8_t rslt = BMM150_OK;
  48. dev.dev_id = 0x10; // Device address setting. 设备地址设置
  49. dev.intf = BMM150_I2C_INTF; // SPI or I2C interface setup. SPI或I2C接口设置
  50. dev.read = i2c_read; // Read the bus pointer. 读总线指针
  51. dev.write = i2c_write; // Write the bus pointer. 写总线指针
  52. dev.delay_ms = delay;
  53. // Set the maximum range range
  54. //设置最大范围区间
  55. mag_max.x = -2000;
  56. mag_max.y = -2000;
  57. mag_max.z = -2000;
  58. // Set the minimum range
  59. //设置最小范围区间
  60. mag_min.x = 2000;
  61. mag_min.y = 2000;
  62. mag_min.z = 2000;
  63. rslt = bmm150_init(&dev); // Memory chip ID. 存储芯片ID
  64. dev.settings.pwr_mode = BMM150_NORMAL_MODE;
  65. rslt |= bmm150_set_op_mode(
  66. &dev); // Set the sensor power mode. 设置传感器电源工作模式
  67. dev.settings.preset_mode = BMM150_PRESETMODE_ENHANCED;
  68. rslt |= bmm150_set_presetmode(
  69. &dev); // Set the preset mode of . 设置传感器的预置模式
  70. return rslt;
  71. }
  72. void bmm150_offset_save() { // Store the data. 存储bmm150的数据
  73. prefs.begin("bmm150", false);
  74. prefs.putBytes("offset", (uint8_t *)&mag_offset, sizeof(bmm150_mag_data));
  75. prefs.end();
  76. }
  77. void bmm150_offset_load() { // load the data. 加载bmm150的数据
  78. if (prefs.begin("bmm150", true)) {
  79. prefs.getBytes("offset", (uint8_t *)&mag_offset,
  80. sizeof(bmm150_mag_data));
  81. prefs.end();
  82. Serial.println("bmm150 load offset finish....");
  83. } else {
  84. Serial.println("bmm150 load offset failed....");
  85. }
  86. }
  87. void setup() {
  88. M5.begin(true, false, true,
  89. false); // Init M5Core(Initialize LCD, serial port). 初始化
  90. // M5Core(初始化LCD、串口)
  91. M5.Power.begin(); // Init Power module. 初始化电源设置
  92. Wire.begin(
  93. 21, 22,
  94. 400000UL); // Set the frequency of the SDA SCL. 设置SDA和SCL的频率
  95. img.setColorDepth(1); // Set bits per pixel for colour. 设置色深为1
  96. img.setTextColor(TFT_WHITE); // Set the font foreground colour (background
  97. // is. 设置字体的前景色为TFT_WHITE
  98. img.createSprite(320, 240); // Create a sprite (bitmap) of defined width
  99. // and height 创建一个指定宽度和高度的Sprite图
  100. img.setBitmapColor(TFT_WHITE, 0); // Set the foreground and background
  101. // colour. 设置位图的前景色和背景颜色
  102. if (bmm150_initialization() != BMM150_OK) {
  103. img.fillSprite(0); // Fill the whole sprite with defined colour.
  104. // 用定义的颜色填充整个Sprite图
  105. img.drawCentreString("BMM150 init failed", 160, 110,
  106. 4); // Use font 4 in (160,110)draw string.
  107. // 使用字体4在(160,110)处绘制字符串
  108. img.pushSprite(
  109. 0,
  110. 0); // Push the sprite to the TFT at 0, 0. 将Sprite图打印在(0,0)处
  111. for (;;) {
  112. delay(100); // delay 100ms. 延迟100ms
  113. }
  114. }
  115. bmm150_offset_load();
  116. }
  117. void bmm150_calibrate(
  118. uint32_t calibrate_time) { // bbm150 data calibrate. bbm150数据校准
  119. uint32_t calibrate_timeout = 0;
  120. calibrate_timeout = millis() + calibrate_time;
  121. Serial.printf("Go calibrate, use %d ms \r\n",
  122. calibrate_time); // The serial port outputs formatting
  123. // characters. 串口输出格式化字符
  124. Serial.printf("running ...");
  125. while (calibrate_timeout > millis()) {
  126. bmm150_read_mag_data(&dev); // read the magnetometer data from
  127. // registers. 从寄存器读取磁力计数据
  128. if (dev.data.x) {
  129. mag_min.x = (dev.data.x < mag_min.x) ? dev.data.x : mag_min.x;
  130. mag_max.x = (dev.data.x > mag_max.x) ? dev.data.x : mag_max.x;
  131. }
  132. if (dev.data.y) {
  133. mag_max.y = (dev.data.y > mag_max.y) ? dev.data.y : mag_max.y;
  134. mag_min.y = (dev.data.y < mag_min.y) ? dev.data.y : mag_min.y;
  135. }
  136. if (dev.data.z) {
  137. mag_min.z = (dev.data.z < mag_min.z) ? dev.data.z : mag_min.z;
  138. mag_max.z = (dev.data.z > mag_max.z) ? dev.data.z : mag_max.z;
  139. }
  140. delay(100);
  141. }
  142. mag_offset.x = (mag_max.x + mag_min.x) / 2;
  143. mag_offset.y = (mag_max.y + mag_min.y) / 2;
  144. mag_offset.z = (mag_max.z + mag_min.z) / 2;
  145. bmm150_offset_save();
  146. Serial.printf("\n calibrate finish ... \r\n");
  147. Serial.printf("mag_max.x: %.2f x_min: %.2f \t", mag_max.x, mag_min.x);
  148. Serial.printf("y_max: %.2f y_min: %.2f \t", mag_max.y, mag_min.y);
  149. Serial.printf("z_max: %.2f z_min: %.2f \r\n", mag_max.z, mag_min.z);
  150. }
  151. void loop() {
  152. char text_string[100];
  153. M5.update(); // Read the press state of the key. 读取按键的状态
  154. bmm150_read_mag_data(&dev);
  155. float head_dir =
  156. atan2(dev.data.x - mag_offset.x, dev.data.y - mag_offset.y) * 180.0 /
  157. M_PI;
  158. Serial.printf("Magnetometer data, heading %.2f\n", head_dir);
  159. Serial.printf("MAG X : %.2f \t MAG Y : %.2f \t MAG Z : %.2f \n", dev.data.x,
  160. dev.data.y, dev.data.z);
  161. Serial.printf("MID X : %.2f \t MID Y : %.2f \t MID Z : %.2f \n",
  162. mag_offset.x, mag_offset.y, mag_offset.z);
  163. img.fillSprite(0);
  164. sprintf(text_string, "MAG X: %.2f", dev.data.x);
  165. img.drawString(text_string, 10, 20,
  166. 4); // draw string with padding. 绘制带有填充的字符串
  167. sprintf(text_string, "MAG Y: %.2f", dev.data.y);
  168. img.drawString(text_string, 10, 50, 4);
  169. sprintf(text_string, "MAG Z: %.2f", dev.data.z);
  170. img.drawString(text_string, 10, 80, 4);
  171. sprintf(text_string, "HEAD Angle: %.2f", head_dir);
  172. img.drawString(text_string, 10, 110, 4);
  173. img.drawCentreString("Press BtnA enter calibrate", 160, 150, 4);
  174. img.pushSprite(0, 0);
  175. if (M5.BtnA.wasPressed()) {
  176. img.fillSprite(0);
  177. img.drawCentreString("Flip + rotate core calibration", 160, 110, 4);
  178. img.pushSprite(0, 0);
  179. bmm150_calibrate(10000);
  180. }
  181. delay(100);
  182. }