初始化提交

This commit is contained in:
王立帮
2024-07-20 22:09:06 +08:00
commit c247dd07a6
6876 changed files with 2743096 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: 4-Relay. 4个继电器
* date: 2021/8/10
*******************************************************************************
Please connect to port A,Control 4 relays and demonstrate the asynchronous control relay LED
请连接A端口控制4继电器并演示异步控制继电器LED
-------------------------------------------------------------------------------
RELAY control reg | 0x10
-----------------------------------------------------------------------------
Relay_ctrl_mode_reg[0] | R/W | System control
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| R | R | R | R | R | R | R | Sync Mode |
| -Sync Mode:0 LED&Relay Async
| -Sync Mode:1 LED&Relay Sync
---------------------------------------------------------------------------------
Relay_ctrl_mode_reg[1] | R/W | Relay & LED control
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| LED1| LED2| LED3| LED4| RLY1| RLY2| RLY3| RLY4|
-------------------------------------------------------------------------------*/
#include <M5Core2.h>
#include "UNIT_4RELAY.h"
UNIT_4RELAY unit_4relay;
void setup() {
M5.begin(true,false,true,true); //Init M5Core2 And the I2C port(21,22). 初始化 M5Core2 和I2C(21,22)端口
M5.Lcd.setCursor(80, 0, 4); //Set the cursor position to (80,0). 将光标位置设置为(80,0)
M5.Lcd.print("4-RELAY UNIT\n\n");
M5.Lcd.print(" Relay State: \n Sync Mode: ");
M5.Lcd.setCursor(0, 220, 2);
M5.Lcd.print("Independent switch Sync/Async ALL relay");
unit_4relay.Init(0); //Set the lamp and relay to asynchronous mode(Async = 0,Sync = 1). 将灯和继电器设为非同步模式
}
char count_i = 0;
bool sync_flag = 0, all_flag= 0;
void loop() {
M5.update(); //Check button down state. 检测按键按下状态
if(M5.BtnA.wasPressed()){ //If button A is pressed. 如果按键A按下
M5.Lcd.fillRect(160, 50, 100, 20, BLACK);
M5.Lcd.setCursor(160, 50, 4);
if(count_i<4){
M5.Lcd.printf("%d ON", count_i+1);
if(sync_flag){
unit_4relay.relayWrite(count_i,1); //Open the relay at Count_i. 打开count_i处的继电器
}else unit_4relay.LEDWrite(count_i,1); //Turn on count_I to get led lights. 打开count_i出得led灯
}else{
M5.Lcd.printf("%d OFF", (count_i-3));
if(sync_flag){
unit_4relay.relayWrite((count_i-4),0); //Close the relay at Count_i. 关闭count_i处的继电器
}else unit_4relay.LEDWrite((count_i-4),0); //Turn off the COUNt_I leds. 关闭count_i出得led灯
}
count_i++;
if(count_i >= 8) count_i = 0;
}else if(M5.BtnB.wasPressed()){
sync_flag = !sync_flag;
unit_4relay.switchMode(sync_flag);
M5.Lcd.fillRect(160, 80, 100, 20, BLACK);
M5.Lcd.setCursor(160, 80, 4);
if(!sync_flag){
M5.Lcd.print("Async");
}else {
M5.Lcd.print("Sync");
}
}
if(M5.BtnC.wasPressed()){
all_flag = !all_flag;
M5.Lcd.fillRect(160, 50, 100, 20, BLACK);
M5.Lcd.setCursor(160, 50, 4);
if(all_flag){
M5.Lcd.printf("ALL.ON ");
if(sync_flag) unit_4relay.relayALL(1); //Open all the relays. 打开所有的继电器
else unit_4relay.LED_ALL(1); //Turn on all the lights. 打开所有的灯
}else{
M5.Lcd.printf("ALL.OFF");
if(sync_flag)unit_4relay.relayALL(0); //Close all relays. 关闭所有的继电器
else unit_4relay.LED_ALL(0); //Turn off all the lights. 关闭所有的灯
}
}
}

View File

@@ -0,0 +1,85 @@
/*
Description: Read ACCEL Unit three-axis acceleration
Please install library before compiling:
Arduino-ADXL345: https://github.com/jakalada/Arduino-ADXL345
*/
#include <M5Core2.h>
#include <ADXL345.h>
ADXL345 accel(ADXL345_ALT);
void setup() {
// put your setup code here, to run once:
M5.begin();
Wire.begin();
M5.Lcd.setCursor(140, 10, 4);
M5.Lcd.println("ACC");
M5.Lcd.setCursor(40, 100); M5.Lcd.print(" x ");
M5.Lcd.setCursor(140, 100); M5.Lcd.print(" y ");
M5.Lcd.setCursor(240, 100); M5.Lcd.print(" z ");
byte deviceID = accel.readDeviceID();
if (deviceID != 0) {
Serial.print("0x");
Serial.print(deviceID, HEX);
Serial.println("");
} else {
Serial.println("read device id: failed");
while(1) {
delay(100);
}
}
// Data Rate
// - ADXL345_RATE_3200HZ: 3200 Hz
// - ADXL345_RATE_1600HZ: 1600 Hz
// - ADXL345_RATE_800HZ: 800 Hz
// - ADXL345_RATE_400HZ: 400 Hz
// - ADXL345_RATE_200HZ: 200 Hz
// - ADXL345_RATE_100HZ: 100 Hz
// - ADXL345_RATE_50HZ: 50 Hz
// - ADXL345_RATE_25HZ: 25 Hz
// - ...
if (!accel.writeRate(ADXL345_RATE_200HZ)) {
Serial.println("write rate: failed");
while(1) {
delay(100);
}
}
// Data Range
// - ADXL345_RANGE_2G: +-2 g
// - ADXL345_RANGE_4G: +-4 g
// - ADXL345_RANGE_8G: +-8 g
// - ADXL345_RANGE_16G: +-16 g
if (!accel.writeRange(ADXL345_RANGE_16G)) {
Serial.println("write range: failed");
while(1) {
delay(100);
}
}
if (!accel.start()) {
Serial.println("start: failed");
while(1) {
delay(100);
}
}
}
void loop() {
// put your main code here, to run repeatedly:
if (accel.update()) {
M5.Lcd.fillRect(0, 130, 360, 30, BLACK);
M5.Lcd.setCursor(35, 130); M5.Lcd.print((int)(1000*accel.getX()));
M5.Lcd.setCursor(135, 130); M5.Lcd.print((int)(1000*accel.getY()));
M5.Lcd.setCursor(235, 130); M5.Lcd.print((int)(1000*accel.getZ()));
//M5.Lcd.setCursor(300, 130); M5.Lcd.print("mg");
} else {
Serial.println("update failed");
while(1) {
delay(100);
}
}
delay(100);
}

View File

@@ -0,0 +1,73 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: ADC. A/D转换器
* date: 2021/8/18
*******************************************************************************
Please connect to Port A,Use ADC Unit to convert 0 ~ 12V analog voltage into 16-bit data and display it on the screen.
请连接端口A,利用ADC单元将0 ~ 12V模拟电压转换成16位数据显示在屏幕上。
*/
#include <M5Core2.h>
#include "M5_ADS1100.h"
ADS1100 ads;
void setup(void)
{
M5.begin(); //Init M5Core2. 初始化M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
// The address can be changed making the option of connecting multiple devices
// 地址可以改变,以连接多个设备
ads.getAddr_ADS1100(ADS1100_DEFAULT_ADDRESS); // 0x48, 1001 000 (ADDR = GND)
//The ADC gain (PGA). ADC增益(PGA)
ads.setGain(GAIN_ONE); // 1x gain(default)
// ads.setGain(GAIN_TWO); // 2x gain
// ads.setGain(GAIN_FOUR); // 4x gain
// ads.setGain(GAIN_EIGHT); // 8x gain
//Device operating mode. 设备工作模式
ads.setMode(MODE_CONTIN); // Continuous conversion mode (default)
// ads.setMode(MODE_SINGLE); // Single-conversion mode
//Data rate. 数据速率
ads.setRate(RATE_8); // 8SPS (default)
// ads.setRate(RATE_16); // 16SPS
// ads.setRate(RATE_32); // 32SPS
// ads.setRate(RATE_128); // 128SPS
ads.setOSMode(OSMODE_SINGLE); // Set to start a single-conversion. 设置开始一次转换
ads.begin(); //Sets up the Hardware. 设置硬件
}
void loop(void)
{
byte error;
int8_t address;
address = ads.ads_i2cAddress;
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) //If the device is connected. 如果连接上设备
{
int16_t result;
result = ads.Measure_Differential();
M5.Lcd.fillScreen(BLACK);
char data[20] = { 0 };
sprintf(data, "%d", result);
M5.Lcd.drawCentreString(data, 160, 100, 4);
}
else
{
M5.Lcd.drawString("No Found ADC sensor.",20, 100, 2);
}
delay(1000);
}

View File

@@ -0,0 +1,39 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Angle. 角度计
* date: 2021/8/9
*******************************************************************************
Description:Connect to Port B, Read the Angle of the angometer and convert it to digital display
连接至Port B,读取角度计的角度,并转换为数字量显示
*/
#include <M5Core2.h>
int sensorPin = 36; // set the input pin for the potentiometer. 设置角度计的输入引脚
int last_sensorValue = 100; // Stores the value last read by the sensor. 存储传感器上次读取到的值
int cur_sensorValue = 0; // Stores the value currently read by the sensor. 存储传感器当前读取到的值
void setup() {
M5.begin(); //Init M5Core2. 初始化 M5Core2
pinMode(sensorPin, INPUT); //Sets the specified pin to input mode. 设置指定引脚为输入模式
dacWrite(25, 0);
M5.Lcd.setTextSize(2); //Set the font size to 2. 设置字体大小为2
M5.Lcd.print("the value of ANGLE: ");
}
void loop() {
cur_sensorValue = analogRead(sensorPin); // read the value from the sensor. 读取当前传感器的值
M5.Lcd.setCursor(0, 25); //Place the cursor at (0,25). 将光标固定在(0,25)
if(abs(cur_sensorValue - last_sensorValue) > 10){ //If the difference is more than 10. 如果差值超过10
M5.Lcd.fillRect(0, 25, 100, 25, BLACK);
M5.Lcd.print(cur_sensorValue);
last_sensorValue = cur_sensorValue;
}
delay(50);
}

View File

@@ -0,0 +1,215 @@
/*
An example analogue meter using a ILI9341 TFT LCD screen
Needs Font 2 (also Font 4 if using large scale label)
Make sure all the display driver and pin comnenctions are correct by
editting the User_Setup.h file in the TFT_eSPI library folder.
#########################################################################
###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
#########################################################################
Updated by Bodmer for variable meter size
*/
// Define meter size as 1 for M5.Lcd.rotation(0) or 1.3333 for M5.Lcd.rotation(1)
#define M_SIZE 1.3333
#include <M5Core2.h>
#include <Wire.h>
#include "ammeter.h"
Ammeter ammeter;
float page512_volt = 2000.0F;
ammeterGain_t now_gain = PAG_512;
#define TFT_GREY 0x5AEB
float ltx = 0; // Saved x coord of bottom of needle
uint16_t osx = M_SIZE*120, osy = M_SIZE*120; // Saved x & y coords
uint32_t updateTime = 0; // time for next update
int old_analog = -999; // Value last displayed
int value[6] = {0, 0, 0, 0, 0, 0};
int old_value[6] = { -1, -1, -1, -1, -1, -1};
int d = 0;
void setup(void) {
M5.begin();
Wire.begin();
ammeter.setMode(SINGLESHOT);
ammeter.setRate(RATE_8);
ammeter.setGain(PAG_512);
// | PAG | Max Input Voltage(V) |
// | PAG_6144 | 128 |
// | PAG_4096 | 64 |
// | PAG_2048 | 32 |
// | PAG_512 | 16 |
// | PAG_256 | 8 |
M5.Lcd.fillScreen(TFT_BLACK);
analogMeter(); // Draw analogue meter
updateTime = millis(); // Next update time
}
void loop() {
if (updateTime <= millis()) {
updateTime = millis() + 35; // Update emter every 35 milliseconds
float current = ammeter.getCurrent();
M5.Lcd.setCursor(0, 200);
M5.Lcd.setTextFont(4);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.printf("Cal volt: %.2f mA \r\n", current);
value[0] = current;
plotNeedle(value[0], 0); // It takes between 2 and 12ms to replot the needle with zero delay
}
}
// #########################################################################
// Draw the analogue meter on the screen
// #########################################################################
void analogMeter()
{
// Meter outline
M5.Lcd.fillRect(0, 0, M_SIZE*239, M_SIZE*126, TFT_GREY);
M5.Lcd.fillRect(5, 3, M_SIZE*230, M_SIZE*119, TFT_WHITE);
M5.Lcd.setTextColor(TFT_BLACK); // Text colour
// Draw ticks every 5 degrees from -50 to +50 degrees (100 deg. FSD swing)
for (int i = -50; i < 51; i += 5) {
// Long scale tick length
int tl = 15;
// Coodinates of tick to draw
float sx = cos((i - 90) * 0.0174532925);
float sy = sin((i - 90) * 0.0174532925);
uint16_t x0 = sx * (M_SIZE*100 + tl) + M_SIZE*120;
uint16_t y0 = sy * (M_SIZE*100 + tl) + M_SIZE*140;
uint16_t x1 = sx * M_SIZE*100 + M_SIZE*120;
uint16_t y1 = sy * M_SIZE*100 + M_SIZE*140;
// Coordinates of next tick for zone fill
float sx2 = cos((i + 5 - 90) * 0.0174532925);
float sy2 = sin((i + 5 - 90) * 0.0174532925);
int x2 = sx2 * (M_SIZE*100 + tl) + M_SIZE*120;
int y2 = sy2 * (M_SIZE*100 + tl) + M_SIZE*140;
int x3 = sx2 * M_SIZE*100 + M_SIZE*120;
int y3 = sy2 * M_SIZE*100 + M_SIZE*140;
// Orange zone limits
if (i >= 25 && i < 50) {
M5.Lcd.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_RED);
M5.Lcd.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_RED);
}
// Short scale tick length
if (i % 25 != 0) tl = 8;
// Recalculate coords incase tick lenght changed
x0 = sx * (M_SIZE*100 + tl) + M_SIZE*120;
y0 = sy * (M_SIZE*100 + tl) + M_SIZE*140;
x1 = sx * M_SIZE*100 + M_SIZE*120;
y1 = sy * M_SIZE*100 + M_SIZE*140;
// Draw tick
M5.Lcd.drawLine(x0, y0, x1, y1, TFT_BLACK);
// Check if labels should be drawn, with position tweaks
if (i % 25 == 0) {
// Calculate label positions
x0 = sx * (M_SIZE*100 + tl + 10) + M_SIZE*120;
y0 = sy * (M_SIZE*100 + tl + 10) + M_SIZE*140;
switch (i / 25) {
case -2: M5.Lcd.drawCentreString("0", x0, y0 - 12, 2); break;
case -1: M5.Lcd.drawCentreString("500", x0, y0 - 9, 2); break;
case 0: M5.Lcd.drawCentreString("1000", x0, y0 - 7, 2); break;
case 1: M5.Lcd.drawCentreString("1500", x0, y0 - 9, 2); break;
case 2: M5.Lcd.drawCentreString("2000", x0, y0 - 12, 2); break;
}
}
// Now draw the arc of the scale
sx = cos((i + 5 - 90) * 0.0174532925);
sy = sin((i + 5 - 90) * 0.0174532925);
x0 = sx * M_SIZE*100 + M_SIZE*120;
y0 = sy * M_SIZE*100 + M_SIZE*140;
// Draw scale arc, don't draw the last part
if (i < 50) M5.Lcd.drawLine(x0, y0, x1, y1, TFT_BLACK);
}
M5.Lcd.drawString("mA", M_SIZE*(5 + 230 - 40), M_SIZE*(119 - 20), 2); // Units at bottom right
M5.Lcd.drawCentreString("mA", M_SIZE*120, M_SIZE*70, 4); // Comment out to avoid font 4
M5.Lcd.drawRect(5, 3, M_SIZE*230, M_SIZE*119, TFT_BLACK); // Draw bezel line
plotNeedle(0, 0); // Put meter needle at 0
}
// #########################################################################
// Update needle position
// This function is blocking while needle moves, time depends on ms_delay
// 10ms minimises needle flicker if text is drawn within needle sweep area
// Smaller values OK if text not in sweep area, zero for instant movement but
// does not look realistic... (note: 100 increments for full scale deflection)
// #########################################################################
void plotNeedle(int value, byte ms_delay)
{
M5.Lcd.setTextColor(TFT_BLACK, TFT_WHITE);
char buf[8]; dtostrf(value, 4, 0, buf);
M5.Lcd.drawRightString(buf, M_SIZE*40, M_SIZE*(119 - 20), 2);
if (value < -200) value = -200; // Limit value to emulate needle end stops
if (value > 2200) value = 2200;
//
// // Move the needle until new value reached
while (!(value == old_analog)) {
// if (old_analog < value) old_analog++;
// else old_analog--;
if (ms_delay == 0) old_analog = value; // Update immediately if delay is 0
float sdeg = map(old_analog, -200, 2200, -150, -30); // Map value to angle
// Calcualte tip of needle coords
float sx = cos(sdeg * 0.0174532925);
float sy = sin(sdeg * 0.0174532925);
// Calculate x delta of needle start (does not start at pivot point)
float tx = tan((sdeg + 90) * 0.0174532925);
// Erase old needle image
M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx - 1), M_SIZE*(140 - 20), osx - 1, osy, TFT_WHITE);
M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx), M_SIZE*(140 - 20), osx, osy, TFT_WHITE);
// M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx + 1), M_SIZE*(140 - 20), osx + 1, osy, TFT_WHITE);
// Re-plot text under needle
M5.Lcd.setTextColor(TFT_BLACK);
M5.Lcd.drawCentreString("mA", M_SIZE*120, M_SIZE*70, 4); // // Comment out to avoid font 4
// Store new needle end coords for next erase
ltx = tx;
osx = M_SIZE*(sx * 98 + 120);
osy = M_SIZE*(sy * 98 + 140);
// Draw the needle in the new postion, magenta makes needle a bit bolder
// draws 3 lines to thicken needle
M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx - 1), M_SIZE*(140 - 20), osx - 1, osy, TFT_RED);
M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx), M_SIZE*(140 - 20), osx, osy, TFT_MAGENTA);
// M5.Lcd.drawLine(M_SIZE*(120 + 20 * ltx + 1), M_SIZE*(140 - 20), osx + 1, osy, TFT_RED);
// Slow needle down slightly as it approaches new postion
if (abs(old_analog - value) < 10) ms_delay += ms_delay / 5;
// Wait before next update
delay(ms_delay);
}
}

View File

@@ -0,0 +1,286 @@
#include "ammeter.h"
#include "Wire.h"
void Ammeter::i2cBegin() {
// Wire.begin();
}
bool Ammeter::i2cReadBytes(uint8_t addr, uint8_t reg_addr, uint8_t* buff, uint16_t len) {
Wire.beginTransmission(addr);
Wire.write(reg_addr);
uint8_t i = 0;
if (Wire.endTransmission(false) == 0 && Wire.requestFrom(addr, (uint8_t)len)) {
while (Wire.available()) {
buff[i++] = Wire.read();
}
return true;
}
return false;
}
bool Ammeter::i2cWriteBytes(uint8_t addr, uint8_t reg_addr, uint8_t* buff, uint16_t len) {
bool function_result = false;
Wire.beginTransmission(addr);
Wire.write(reg_addr);
for(int i = 0; i < len; i++) {
Wire.write(*(buff+i));
}
function_result = (Wire.endTransmission() == 0);
return function_result;
}
bool Ammeter::i2cReadU16(uint8_t addr, uint8_t reg_addr, uint16_t* value) {
uint8_t read_buf[2] = {0x00, 0x00};
bool result = i2cReadBytes(addr, reg_addr, read_buf, 2);
*value = (read_buf[0] << 8) | read_buf[1];
return result;
}
bool Ammeter::i2cWriteU16(uint8_t addr, uint8_t reg_addr, uint16_t value) {
uint8_t write_buf[2];
write_buf[0] = value >> 8;
write_buf[1] = value & 0xff;
return i2cWriteBytes(addr, reg_addr, write_buf, 2);
}
float Ammeter::getResolution(ammeterGain_t gain) {
switch (gain) {
case PAG_6144:
return ADS1115_MV_6144 / AMMETER_PRESSURE_COEFFICIENT;
case PAG_4096:
return ADS1115_MV_4096 / AMMETER_PRESSURE_COEFFICIENT;
case PAG_2048:
return ADS1115_MV_2048 / AMMETER_PRESSURE_COEFFICIENT;
case PAG_1024:
return ADS1115_MV_1024 / AMMETER_PRESSURE_COEFFICIENT;
case PAG_512:
return ADS1115_MV_512 / AMMETER_PRESSURE_COEFFICIENT;
case PAG_256:
return ADS1115_MV_256 / AMMETER_PRESSURE_COEFFICIENT;
default:
return ADS1115_MV_256 / AMMETER_PRESSURE_COEFFICIENT;
};
}
uint8_t Ammeter::getPGAEEEPROMAddr(ammeterGain_t gain) {
switch (gain) {
case PAG_6144:
return AMMETER_PAG_6144_CAL_ADDR;
case PAG_4096:
return AMMETER_PAG_4096_CAL_ADDR;
case PAG_2048:
return AMMETER_PAG_2048_CAL_ADDR;
case PAG_1024:
return AMMETER_PAG_1024_CAL_ADDR;
case PAG_512:
return AMMETER_PAG_512_CAL_ADDR;
case PAG_256:
return AMMETER_PAG_256_CAL_ADDR;
default:
return 0x00;
};
}
uint16_t Ammeter::getCoverTime(ammeterRate_t rate) {
switch (rate) {
case RATE_8:
return 1000 / 8;
case RATE_16:
return 1000 / 16;
case RATE_32:
return 1000 / 32;
case RATE_64:
return 1000 / 64;
case RATE_128:
return 1000 / 128;
case RATE_250:
return 1000 / 250;
case RATE_475:
return 1000 / 475;
case RATE_860:
return 1000 / 860;
default:
return 1000 / 128;
};
}
Ammeter::Ammeter(uint8_t ads1115_addr, uint8_t eeprom_addr) {
_ads1115_addr = ads1115_addr;
_eeprom_addr = eeprom_addr;
_gain = PAG_2048;
_mode = SINGLESHOT;
_rate = RATE_128;
calibration_factor = 1;
adc_raw = 0;
resolution = getResolution(_gain);
cover_time = getCoverTime(_rate);
}
void Ammeter::setGain(ammeterGain_t gain) {
uint16_t reg_value = 0;
bool result = i2cReadU16(_ads1115_addr, ADS1115_RA_CONFIG, &reg_value);
if (result == false) {
return;
}
reg_value &= ~(0b0111 << 9);
reg_value |= gain << 9;
result = i2cWriteU16(_ads1115_addr, ADS1115_RA_CONFIG, reg_value);
if (result) {
_gain = gain;
resolution = getResolution(gain);
int16_t hope = 1;
int16_t actual = 1;
if (readCalibrationFromEEPROM(gain, &hope, &actual)) {
calibration_factor = fabs((double)hope / actual);
}
}
}
void Ammeter::setRate(ammeterRate_t rate) {
uint16_t reg_value = 0;
bool result = i2cReadU16(_ads1115_addr, ADS1115_RA_CONFIG, &reg_value);
if (result == false) {
return;
}
reg_value &= ~(0b0111 << 5);
reg_value |= rate << 5;
result = i2cWriteU16(_ads1115_addr, ADS1115_RA_CONFIG, reg_value);
if (result) {
_rate = rate;
cover_time = getCoverTime(_rate);
}
return;
}
void Ammeter::setMode(ammeterMode_t mode) {
uint16_t reg_value = 0;
bool result = i2cReadU16(_ads1115_addr, ADS1115_RA_CONFIG, &reg_value);
if (result == false) {
return;
}
reg_value &= ~(0b0001 << 8);
reg_value |= mode << 8;
result = i2cWriteU16(_ads1115_addr, ADS1115_RA_CONFIG, reg_value);
if (result) {
_mode = mode;
}
return;
}
bool Ammeter::isInConversion() {
uint16_t value = 0x00;
i2cReadU16(_ads1115_addr, ADS1115_RA_CONFIG, &value);
return (value & (1 << 15)) ? false : true;
}
void Ammeter::startSingleConversion() {
uint16_t reg_value = 0;
bool result = i2cReadU16(_ads1115_addr, ADS1115_RA_CONFIG, &reg_value);
if (result == false) {
return;
}
reg_value &= ~(0b0001 << 15);
reg_value |= 0x01 << 15;
i2cWriteU16(_ads1115_addr, ADS1115_RA_CONFIG, reg_value);
}
float Ammeter::getCurrent(bool calibration) {
if (calibration) {
return resolution * calibration_factor * getConversion() * AMMETER_MEASURING_DIR;
} else {
return resolution * getConversion() * AMMETER_MEASURING_DIR;
}
}
int16_t Ammeter::getAdcRaw() {
uint16_t value = 0x00;
i2cReadU16(_ads1115_addr, ADS1115_RA_CONVERSION, &value);
adc_raw = value;
return value;
}
int16_t Ammeter::getConversion(uint16_t timeout) {
if (_mode == SINGLESHOT) {
startSingleConversion();
delay(cover_time);
uint64_t time = millis() + timeout;
while (time > millis() && isInConversion());
}
return getAdcRaw();
}
bool Ammeter::EEPORMWrite(uint8_t address, uint8_t* buff, uint8_t len) {
return i2cWriteBytes(_eeprom_addr, address, buff, len);
}
bool Ammeter::EEPORMRead(uint8_t address, uint8_t* buff, uint8_t len) {
return i2cReadBytes(_eeprom_addr, address, buff, len);
}
bool Ammeter::saveCalibration2EEPROM(ammeterGain_t gain, int16_t hope, int16_t actual) {
if (hope == 0 || actual == 0) {
return false;
}
uint8_t buff[8];
memset(buff, 0, 8);
buff[0] = gain;
buff[1] = hope >> 8;
buff[2] = hope & 0xFF;
buff[3] = actual >> 8;
buff[4] = actual & 0xFF;
for (uint8_t i = 0; i < 5; i++) {
buff[5] ^= buff[i];
}
uint8_t addr = getPGAEEEPROMAddr(gain);
return EEPORMWrite(addr, buff, 8);
}
bool Ammeter::readCalibrationFromEEPROM(ammeterGain_t gain, int16_t* hope, int16_t* actual) {
uint8_t addr = getPGAEEEPROMAddr(gain);
uint8_t buff[8];
memset(buff, 0, 8);
*hope = 1;
*actual = 1;
bool result = EEPORMRead(addr, buff, 8);
if (result == false) {
return false;
}
uint8_t xor_result = 0x00;
for (uint8_t i = 0; i < 5; i++) {
xor_result ^= buff[i];
}
if (xor_result != buff[5]) {
return false;
}
*hope = (buff[1] << 8) | buff[2];
*actual = (buff[3] << 8) | buff[4];
return true;
}

View File

@@ -0,0 +1,126 @@
#pragma once
#include "Arduino.h"
#define ADS115_ADDR 0x48
#define EEPROM_ADDR 0x51
#define ADS1115_RA_CONVERSION 0x00
#define ADS1115_RA_CONFIG 0x01
#define ADS1115_PGA_6144 0x00
#define ADS1115_PGA_4096 0x01
#define ADS1115_PGA_2048 0x02 // default
#define ADS1115_PGA_1024 0x03
#define ADS1115_PGA_512 0x04
#define ADS1115_PGA_256 0x05
#define ADS1115_MV_6144 0.187500F
#define ADS1115_MV_4096 0.125000F
#define ADS1115_MV_2048 0.062500F // default
#define ADS1115_MV_1024 0.031250F
#define ADS1115_MV_512 0.015625F
#define ADS1115_MV_256 0.007813F
#define ADS1115_RATE_8 0x00
#define ADS1115_RATE_16 0x01
#define ADS1115_RATE_32 0x02
#define ADS1115_RATE_64 0x03
#define ADS1115_RATE_128 0x04 // default
#define ADS1115_RATE_250 0x05
#define ADS1115_RATE_475 0x06
#define ADS1115_RATE_860 0x07
#define ADS1115_MUX_P0N1 0x00 // ammeter only support
#define ADS1115_COMP_MODE_HYSTERESIS 0x00 // default
#define ADS1115_COMP_MODE_WINDOW 0x01
#define ADS1115_MODE_CONTINUOUS 0x00
#define ADS1115_MODE_SINGLESHOT 0x01 // default
#define AMMETER_PRESSURE_COEFFICIENT 0.05
#define AMMETER_PAG_6144_CAL_ADDR 208
#define AMMETER_PAG_4096_CAL_ADDR 216
#define AMMETER_PAG_2048_CAL_ADDR 224
#define AMMETER_PAG_1024_CAL_ADDR 232
#define AMMETER_PAG_512_CAL_ADDR 240
#define AMMETER_PAG_256_CAL_ADDR 248
#define AMMETER_MEASURING_DIR -1
typedef enum {
PAG_6144 = ADS1115_PGA_6144,
PAG_4096 = ADS1115_PGA_4096,
PAG_2048 = ADS1115_PGA_2048, // default
PAG_1024 = ADS1115_PGA_1024,
PAG_512 = ADS1115_PGA_512,
PAG_256 = ADS1115_PGA_256,
} ammeterGain_t;
typedef enum {
RATE_8 = ADS1115_RATE_8,
RATE_16 = ADS1115_RATE_16,
RATE_32 = ADS1115_RATE_32,
RATE_64 = ADS1115_RATE_64,
RATE_128 = ADS1115_RATE_128, // default
RATE_250 = ADS1115_RATE_250,
RATE_475 = ADS1115_RATE_475,
RATE_860 = ADS1115_RATE_860,
} ammeterRate_t;
typedef enum {
SINGLESHOT = ADS1115_MODE_SINGLESHOT,
CONTINUOUS = ADS1115_MODE_CONTINUOUS,
} ammeterMode_t;
class Ammeter {
private:
void i2cBegin();
bool i2cReadBytes(uint8_t addr, uint8_t reg_addr, uint8_t* buff, uint16_t len);
bool i2cWriteBytes(uint8_t addr, uint8_t reg_addr, uint8_t* buff, uint16_t len);
bool i2cReadU16(uint8_t addr, uint8_t reg_addr, uint16_t* value);
bool i2cWriteU16(uint8_t addr, uint8_t reg_addr, uint16_t value);
float getResolution(ammeterGain_t gain);
uint16_t getCoverTime(ammeterRate_t rate);
uint8_t getPGAEEEPROMAddr(ammeterGain_t gain);
uint8_t _ads1115_addr;
uint8_t _eeprom_addr;
float pga_256_calibration_5v_value = 10187;
float pga_2048_calibration_25v_value = 6368;
public:
ammeterGain_t _gain;
ammeterRate_t _rate;
ammeterMode_t _mode;
float resolution;
uint16_t cover_time;
int16_t adc_raw;
float calibration_factor;
public:
Ammeter(uint8_t ads1115_addr=ADS115_ADDR, uint8_t eeprom_addr=EEPROM_ADDR);
void setGain(ammeterGain_t gain);
void setRate(ammeterRate_t rate);
void setMode(ammeterMode_t mode);
float getCurrent(bool calibration = true);
int16_t getConversion(uint16_t timeout = 125);
int16_t getAdcRaw();
bool isInConversion();
void startSingleConversion();
bool EEPORMWrite(uint8_t address, uint8_t* buff, uint8_t len);
bool EEPORMRead(uint8_t address, uint8_t* buff, uint8_t len);
bool saveCalibration2EEPROM(ammeterGain_t gain, int16_t hope, int16_t actual);
bool readCalibrationFromEEPROM(ammeterGain_t gain, int16_t* hope, int16_t* actual);
};

View File

@@ -0,0 +1,127 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Ameter_ADS1115. 电流计
* date: 2021/8/19
*******************************************************************************
Please connect to Port A,Measure current and display.
请连接端口A,测量电流并显示到屏幕上
Pay attention: EEPROM (0x51) has built-in calibration parameters when leaving the factory.
Please do not write to the EEPROM, otherwise the calibration data will be overwritten and the measurement results will be inaccurate.
注意: EEPROM (0x51)在出厂时具有内置的校准参数。请不要写入EEPROM否则校准数据会被覆盖测量结果会不准确。
*/
#include "M5Core2.h"
#include "M5_ADS1115.h"
Ammeter ammeter;
float page512_volt = 2000.0F;
int16_t volt_raw_list[10];
uint8_t raw_now_ptr = 0;
int16_t adc_raw = 0;
int16_t hope = 0.0;
ammeterGain_t now_gain = PAG_512;
void setup(void) {
M5.begin(); //Init M5Core2. 初始化M5Core2
Wire.begin();
ammeter.setMode(SINGLESHOT); /* | PAG | Max Input Voltage(V) | */
ammeter.setRate(RATE_8); /* | PAG_6144 | 128 | */
ammeter.setGain(PAG_512); /* | PAG_4096 | 64 | */
hope = page512_volt / ammeter.resolution; /* | PAG_2048 | 32 | */
/* | PAG_512 | 16 | */
/* | PAG_256 | 8 | */
M5.Lcd.setTextFont(4); //Set font to 4 point font. 设置字体为4号字体
M5.Lcd.setCursor(52, 210); //Set the cursor at (52,210). 将光标设置在(52, 210)
M5.Lcd.printf("2A SAVE");
}
void loop(void) {
M5.update(); //Check the status of the key. 检测按键的状态
if (M5.BtnA.wasPressed()) {
ammeter.setMode(SINGLESHOT); //Set the mode. 设置模式
ammeter.setRate(RATE_8); //Set the rate. 设置速率
ammeter.setGain(PAG_512);
now_gain = PAG_512;
hope = page512_volt / ammeter.resolution;
for (uint8_t i = 0; i < 10; i++) {
volt_raw_list[i] = 0;
}
}
if (M5.BtnC.wasPressed()) {
bool success = ammeter.saveCalibration2EEPROM(now_gain, hope, adc_raw);
M5.Lcd.setCursor(224, 210);
if (success) {
M5.Lcd.setTextColor(GREEN, BLACK);
} else {
M5.Lcd.setTextColor(RED, BLACK);
}
M5.Lcd.printf("SAVE");
delay(300);
M5.Lcd.setCursor(230, 210);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.printf("SAVE");
ammeter.setGain(now_gain);
}
float current = ammeter.getCurrent();
volt_raw_list[raw_now_ptr] = ammeter.adc_raw;
raw_now_ptr = (raw_now_ptr == 9) ? 0 : (raw_now_ptr + 1);
int count = 0;
int total = 0;
for (uint8_t i = 0; i < 10; i++) {
if (volt_raw_list[i] == 0) {
continue ;
}
total += volt_raw_list[i];
count += 1;
}
if (count == 0) {
adc_raw = 0;
} else {
adc_raw = total / count;
}
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.setCursor(10, 10);
M5.Lcd.printf("Hope volt: %.2f mA \r\n", page512_volt);
M5.Lcd.setCursor(10, 40);
M5.Lcd.printf("Hope ADC: %d \r\n", hope);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.setCursor(10, 80);
M5.Lcd.printf("Cal volt: %.2f mA \r\n", current);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.setCursor(10, 110);
M5.Lcd.printf("Cal ADC: %.0f \r\n", adc_raw * ammeter.calibration_factor);
M5.Lcd.setCursor(10, 150);
if (abs(adc_raw) <= hope * 1.005 && abs(adc_raw) >= hope * 0.995) {
M5.Lcd.setTextColor(GREEN, BLACK);
} else {
M5.Lcd.setTextColor(RED, BLACK);
}
M5.Lcd.printf("RAW ADC: %d \r\n", adc_raw);
}

View File

@@ -0,0 +1,40 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: BPS_BMP280. 压力传感器
* date: 2021/8/10
******************************************** ***********************************
Please connect to Port A,Read atmospheric pressure and temperature and display them on the display screen
请连接端口A,读取大气压强和温度并在显示屏上显示
*/
#include <M5Core2.h>
#include <Wire.h> //The BPS uses I2C comunication.
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
Adafruit_BMP280 bme;
void setup() {
M5.begin(); //Init M5Core2. 初始化 M5Core2
Wire.begin(); //Wire init, adding the I2C bus. Wire初始化, 加入i2c总线
while (!bme.begin(0x76)){ //Init this sensor,True if the init was successful, otherwise false. 初始化传感器,如果初始化成功返回1
M5.Lcd.println("Could not find a valid BMP280 sensor, check wiring!");
}
M5.Lcd.clear(); //Clear the screen. 清屏
}
float pressure,Temp; //Store the vuale of pressure and Temperature. 存储压力和温度()
void loop() {
pressure = bme.readPressure();
Temp = bme.readTemperature();
M5.Lcd.setCursor(0, 0); //将光标设置在(0 ,0). Set the cursor to (0,0)
M5.Lcd.setTextSize(3); //设置字体大小为3. Set the font size to 3
M5.Lcd.printf("Pressure:%2.0fPa\nTemperature:%2.0f^C", pressure,Temp);
delay(100);
}

View File

@@ -0,0 +1,35 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: BPS_QMP6988. 压力传感器
* date: 2021/8/10
******************************************************************************
Please connect to Port A,Read atmospheric pressure and display them on the display screen
请连接端口A,读取大气压强并在显示屏上显示
*/
#include <M5Core2.h>
#include "Wire.h" //The BPS uses I2C comunication.
#include "UNIT_ENV.h"
QMP6988 qmp6988;
void setup() {
M5.begin(true,false,true,true); //Init M5Core2 And the I2C port(21,22). 初始化 M5Core2和I2C端口(21,22)
}
void loop() {
while (!qmp6988.init()){ //Init qmp6988.True if the init was successful, otherwise false. 初始化qmp6988,如果初始化成功返回1
M5.lcd.setTextSize(1); //Set the text size to 1. 设置文字大小为1
M5.Lcd.println("\nCould not find a valid qmp6988 sensor, check wiring!");
}
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.lcd.setCursor(0,30); //Set the cursor at (0,30). 设置光标在(0,30)处
M5.lcd.fillScreen(BLACK); //Fill the screen with black (to clear the screen). 将屏幕填充满黑色(用来清屏)
M5.Lcd.printf("Pressure:%0.2f",qmp6988.calcPressure()); //Screen print format string. 屏幕打印格式化字符串
delay(2000); //Delay 2s. 延迟2s
}

View File

@@ -0,0 +1,49 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Button. 按键
* date: 2021/7/26
*******************************************************************************
Please connect to Port B,Read the button status of BUTTON Unit and display it on the screen
请连接端口B,读取按键的状态并在显示屏上显示
if you don't have M5GO BOTTOM, you need change the pinMode and the digitalRead to 33, But you will not be able to use any I2C operations.
如果你没有M5GO BOTTOM你需要改变pinMode和digitalRead到33,但是你将不能使用任何I2C操作.
*/
#include <M5Core2.h>
int last_value = 0;
int cur_value = 0;
void setup() {
M5.begin(); //Init M5Core2. 初始化 M5Core2
pinMode(36, INPUT); //set pin mode to input.设置引脚模式为输入模式
M5.Lcd.setTextColor(YELLOW); //Set the font color to yellow. 设置字体颜色为黄色
M5.Lcd.setTextSize(2); //Setting the Font size. 设置字号大小
M5.Lcd.setCursor(80, 0); //Set the cursor position to (80,0). 将光标位置设置为(80,0)
M5.Lcd.println("Button example");
M5.Lcd.setTextColor(WHITE);
}
void loop() {
cur_value = digitalRead(36); // read the value of BUTTON. 读取22号引脚的值
M5.Lcd.setCursor(80,25); M5.Lcd.print("Button");
M5.Lcd.setCursor(0,45); M5.Lcd.print("Value: ");
M5.Lcd.setCursor(0,85); M5.Lcd.print("State: ");
if(cur_value != last_value){
M5.Lcd.fillRect(85,45,75,85,BLACK); //Draw a black rectangle 75 by 85 at (85,45). 在(85,45)处绘制宽75,高85的黑色矩形
if(cur_value==0){
M5.Lcd.setCursor(95,45); M5.Lcd.print("0"); // display the status
M5.Lcd.setCursor(95,85); M5.Lcd.print("pre");
}
else{
M5.Lcd.setCursor(95,45); M5.Lcd.print("1"); // display the status
M5.Lcd.setCursor(95,85); M5.Lcd.print("rel");
}
last_value = cur_value;
}
}

View File

@@ -0,0 +1,299 @@
/**
* @section License
*
* The MIT License (MIT)
*
* Copyright (c) 2017, Thomas Barth, barth-dev.de
* 2017, Jaime Breva, jbreva@nayarsystems.com
* 2018, Michael Wagner, mw@iot-make.de
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include "CAN.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "esp_intr.h"
#include "soc/dport_reg.h"
#include <math.h>
#include "driver/gpio.h"
#include "can_regdef.h"
#include "CAN_config.h"
// CAN Filter - no acceptance filter
static CAN_filter_t __filter = { Dual_Mode, 0, 0, 0, 0, 0Xff, 0Xff, 0Xff, 0Xff };
static void CAN_read_frame_phy();
static void CAN_isr(void *arg_p);
static int CAN_write_frame_phy(const CAN_frame_t *p_frame);
static SemaphoreHandle_t sem_tx_complete;
static void CAN_isr(void *arg_p) {
// Interrupt flag buffer
__CAN_IRQ_t interrupt;
BaseType_t higherPriorityTaskWoken = pdFALSE;
// Read interrupt status and clear flags
interrupt = MODULE_CAN->IR.U;
// Handle RX frame available interrupt
if ((interrupt & __CAN_IRQ_RX) != 0)
CAN_read_frame_phy(&higherPriorityTaskWoken);
// Handle TX complete interrupt
// Handle error interrupts.
if ((interrupt & (__CAN_IRQ_TX | __CAN_IRQ_ERR //0x4
| __CAN_IRQ_DATA_OVERRUN // 0x8
| __CAN_IRQ_WAKEUP // 0x10
| __CAN_IRQ_ERR_PASSIVE // 0x20
| __CAN_IRQ_ARB_LOST // 0x40
| __CAN_IRQ_BUS_ERR // 0x80
)) != 0) {
xSemaphoreGiveFromISR(sem_tx_complete, &higherPriorityTaskWoken);
}
// check if any higher priority task has been woken by any handler
if (higherPriorityTaskWoken)
portYIELD_FROM_ISR();
}
static void CAN_read_frame_phy(BaseType_t *higherPriorityTaskWoken) {
// byte iterator
uint8_t __byte_i;
// frame read buffer
CAN_frame_t __frame;
// check if we have a queue. If not, operation is aborted.
if (CAN_cfg.rx_queue == NULL) {
// Let the hardware know the frame has been read.
MODULE_CAN->CMR.B.RRB = 1;
return;
}
// get FIR
__frame.FIR.U = MODULE_CAN->MBX_CTRL.FCTRL.FIR.U;
// check if this is a standard or extended CAN frame
// standard frame
if (__frame.FIR.B.FF == CAN_frame_std) {
// Get Message ID
__frame.MsgID = _CAN_GET_STD_ID;
// deep copy data bytes
for (__byte_i = 0; __byte_i < __frame.FIR.B.DLC; __byte_i++)
__frame.data.u8[__byte_i] = MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.data[__byte_i];
}
// extended frame
else {
// Get Message ID
__frame.MsgID = _CAN_GET_EXT_ID;
// deep copy data bytes
for (__byte_i = 0; __byte_i < __frame.FIR.B.DLC; __byte_i++)
__frame.data.u8[__byte_i] = MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.data[__byte_i];
}
// send frame to input queue
xQueueSendToBackFromISR(CAN_cfg.rx_queue, &__frame, higherPriorityTaskWoken);
// Let the hardware know the frame has been read.
MODULE_CAN->CMR.B.RRB = 1;
}
static int CAN_write_frame_phy(const CAN_frame_t *p_frame) {
// byte iterator
uint8_t __byte_i;
// copy frame information record
MODULE_CAN->MBX_CTRL.FCTRL.FIR.U = p_frame->FIR.U;
// standard frame
if (p_frame->FIR.B.FF == CAN_frame_std) {
// Write message ID
_CAN_SET_STD_ID(p_frame->MsgID);
// Copy the frame data to the hardware
for (__byte_i = 0; __byte_i < p_frame->FIR.B.DLC; __byte_i++)
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.data[__byte_i] = p_frame->data.u8[__byte_i];
}
// extended frame
else {
// Write message ID
_CAN_SET_EXT_ID(p_frame->MsgID);
// Copy the frame data to the hardware
for (__byte_i = 0; __byte_i < p_frame->FIR.B.DLC; __byte_i++)
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.data[__byte_i] = p_frame->data.u8[__byte_i];
}
// Transmit frame
MODULE_CAN->CMR.B.TR = 1;
return 0;
}
int CAN_init() {
// Time quantum
double __tq;
// enable module
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_CAN_CLK_EN);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_CAN_RST);
// configure TX pin
gpio_set_level(CAN_cfg.tx_pin_id, 1);
gpio_set_direction(CAN_cfg.tx_pin_id, GPIO_MODE_OUTPUT);
gpio_matrix_out(CAN_cfg.tx_pin_id, CAN_TX_IDX, 0, 0);
gpio_pad_select_gpio(CAN_cfg.tx_pin_id);
// configure RX pin
gpio_set_direction(CAN_cfg.rx_pin_id, GPIO_MODE_INPUT);
gpio_matrix_in(CAN_cfg.rx_pin_id, CAN_RX_IDX, 0);
gpio_pad_select_gpio(CAN_cfg.rx_pin_id);
// set to PELICAN mode
MODULE_CAN->CDR.B.CAN_M = 0x1;
// synchronization jump width is the same for all baud rates
MODULE_CAN->BTR0.B.SJW = 0x1;
// TSEG2 is the same for all baud rates
MODULE_CAN->BTR1.B.TSEG2 = 0x1;
// select time quantum and set TSEG1
switch (CAN_cfg.speed) {
case CAN_SPEED_1000KBPS:
MODULE_CAN->BTR1.B.TSEG1 = 0x4;
__tq = 0.125;
break;
case CAN_SPEED_800KBPS:
MODULE_CAN->BTR1.B.TSEG1 = 0x6;
__tq = 0.125;
break;
case CAN_SPEED_200KBPS:
MODULE_CAN->BTR1.B.TSEG1 = 0xc;
MODULE_CAN->BTR1.B.TSEG2 = 0x5;
__tq = 0.25;
break;
default:
MODULE_CAN->BTR1.B.TSEG1 = 0xc;
__tq = ((float) 1000 / CAN_cfg.speed) / 16;
}
// set baud rate prescaler
MODULE_CAN->BTR0.B.BRP = (uint8_t) round((((APB_CLK_FREQ * __tq) / 2) - 1) / 1000000) - 1;
/* Set sampling
* 1 -> triple; the bus is sampled three times; recommended for low/medium speed buses (class A and B) where
* filtering spikes on the bus line is beneficial 0 -> single; the bus is sampled once; recommended for high speed
* buses (SAE class C)*/
MODULE_CAN->BTR1.B.SAM = 0x1;
// enable all interrupts
MODULE_CAN->IER.U = 0xff;
// Set acceptance filter
MODULE_CAN->MOD.B.AFM = __filter.FM;
MODULE_CAN->MBX_CTRL.ACC.CODE[0] = __filter.ACR0;
MODULE_CAN->MBX_CTRL.ACC.CODE[1] = __filter.ACR1;
MODULE_CAN->MBX_CTRL.ACC.CODE[2] = __filter.ACR2;
MODULE_CAN->MBX_CTRL.ACC.CODE[3] = __filter.ACR3;
MODULE_CAN->MBX_CTRL.ACC.MASK[0] = __filter.AMR0;
MODULE_CAN->MBX_CTRL.ACC.MASK[1] = __filter.AMR1;
MODULE_CAN->MBX_CTRL.ACC.MASK[2] = __filter.AMR2;
MODULE_CAN->MBX_CTRL.ACC.MASK[3] = __filter.AMR3;
// set to normal mode
MODULE_CAN->OCR.B.OCMODE = __CAN_OC_NOM;
// clear error counters
MODULE_CAN->TXERR.U = 0;
MODULE_CAN->RXERR.U = 0;
(void) MODULE_CAN->ECC;
// clear interrupt flags
(void) MODULE_CAN->IR.U;
// install CAN ISR
esp_intr_alloc(ETS_CAN_INTR_SOURCE, 0, CAN_isr, NULL, NULL);
// allocate the tx complete semaphore
sem_tx_complete = xSemaphoreCreateBinary();
// Showtime. Release Reset Mode.
MODULE_CAN->MOD.B.RM = 0;
return 0;
}
int CAN_write_frame(const CAN_frame_t *p_frame) {
if (sem_tx_complete == NULL) {
return -1;
}
// Write the frame to the controller
CAN_write_frame_phy(p_frame);
// wait for the frame tx to complete
xSemaphoreTake(sem_tx_complete, portMAX_DELAY);
return 0;
}
int CAN_stop() {
// enter reset mode
MODULE_CAN->MOD.B.RM = 1;
return 0;
}
int CAN_config_filter(const CAN_filter_t* p_filter) {
__filter.FM = p_filter->FM;
__filter.ACR0 = p_filter->ACR0;
__filter.ACR1 = p_filter->ACR1;
__filter.ACR2 = p_filter->ACR2;
__filter.ACR3 = p_filter->ACR3;
__filter.AMR0 = p_filter->AMR0;
__filter.AMR1 = p_filter->AMR1;
__filter.AMR2 = p_filter->AMR2;
__filter.AMR3 = p_filter->AMR3;
return 0;
}

View File

@@ -0,0 +1,131 @@
/**
* @section License
*
* The MIT License (MIT)
*
* Copyright (c) 2017, Thomas Barth, barth-dev.de
* 2018, Michael Wagner, mw@iot-make.de
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __DRIVERS_CAN_H__
#define __DRIVERS_CAN_H__
#include <stdint.h>
#include "CAN_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief CAN frame type (standard/extended)
*/
typedef enum {
CAN_frame_std = 0, /**< Standard frame, using 11 bit identifer. */
CAN_frame_ext = 1 /**< Extended frame, using 29 bit identifer. */
} CAN_frame_format_t;
/**
* \brief CAN RTR
*/
typedef enum {
CAN_no_RTR = 0, /**< No RTR frame. */
CAN_RTR = 1 /**< RTR frame. */
} CAN_RTR_t;
/** \brief Frame information record type */
typedef union {
uint32_t U; /**< \brief Unsigned access */
struct {
uint8_t DLC : 4; /**< \brief [3:0] DLC, Data length container */
unsigned int unknown_2 : 2; /**< \brief \internal unknown */
CAN_RTR_t RTR : 1; /**< \brief [6:6] RTR, Remote Transmission Request */
CAN_frame_format_t FF : 1; /**< \brief [7:7] Frame Format, see# CAN_frame_format_t*/
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} CAN_FIR_t;
/** \brief CAN Frame structure */
typedef struct {
CAN_FIR_t FIR; /**< \brief Frame information record*/
uint32_t MsgID; /**< \brief Message ID */
union {
uint8_t u8[8]; /**< \brief Payload byte access*/
uint32_t u32[2]; /**< \brief Payload u32 access*/
uint64_t u64; /**< \brief Payload u64 access*/
} data;
} CAN_frame_t;
typedef enum {
Dual_Mode=0, /**< \brief The dual acceptance filter option is enabled (two filters, each with the length of 16 bit are active) */
Single_Mode=1 /**< \brief The single acceptance filter option is enabled (one filter with the length of 32 bit is active) */
} CAN_filter_mode_t;
/** \brief CAN Filter structure */
typedef struct {
CAN_filter_mode_t FM:1; /**< \brief [0:0] Filter Mode */
uint8_t ACR0; /**< \brief Acceptance Code Register ACR0 */
uint8_t ACR1; /**< \brief Acceptance Code Register ACR1 */
uint8_t ACR2; /**< \brief Acceptance Code Register ACR2 */
uint8_t ACR3; /**< \brief Acceptance Code Register ACR3 */
uint8_t AMR0; /**< \brief Acceptance Mask Register AMR0 */
uint8_t AMR1; /**< \brief Acceptance Mask Register AMR1 */
uint8_t AMR2; /**< \brief Acceptance Mask Register AMR2 */
uint8_t AMR3; /**< \brief Acceptance Mask Register AMR3 */
} CAN_filter_t;
/**
* \brief Initialize the CAN Module
*
* \return 0 CAN Module had been initialized
*/
int CAN_init(void);
/**
* \brief Send a can frame
*
* \param p_frame Pointer to the frame to be send, see #CAN_frame_t
* \return 0 Frame has been written to the module
*/
int CAN_write_frame(const CAN_frame_t *p_frame);
/**
* \brief Stops the CAN Module
*
* \return 0 CAN Module was stopped
*/
int CAN_stop(void);
/**
* \brief Config CAN Filter, must call before CANInit()
*
* \param p_filter Pointer to the filter, see #CAN_filter_t
* \return 0 CAN Filter had been initialized
*/
int CAN_config_filter(const CAN_filter_t* p_filter);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,104 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/can
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/can
*
* describe: can.
* date: 2021/9/1
*******************************************************************************
Please connect to PORT-B,Press buttonA or buttonB to Send message if received message, screen will display
请连接端口B,按钮A或按钮B发送消息如果收到消息屏幕将显示
*/
#include <M5Core2.h>
#include "ESP32CAN.h"
#include "CAN_config.h"
#define TX GPIO_NUM_26
#define RX GPIO_NUM_36
CAN_device_t CAN_cfg; // CAN Config
int i = 0;
void setup() {
M5.begin(true, false, true);
M5.Lcd.drawString("CAN Unit Send&Received", 40, 3, 4);
M5.Lcd.setCursor(0, 60, 4);
CAN_cfg.speed = CAN_SPEED_125KBPS; //Set the Can speed. 设置Can速度
CAN_cfg.tx_pin_id = TX; //Set the Pin foot. 设置引脚
CAN_cfg.rx_pin_id = RX;
CAN_cfg.rx_queue = xQueueCreate(10,sizeof(CAN_frame_t));
ESP32Can.CANInit(); // Init CAN Module. 初始化Can
}
void loop() {
CAN_frame_t rx_frame;
if(M5.BtnA.wasPressed()){
rx_frame.FIR.B.FF = CAN_frame_std;
rx_frame.MsgID = 1;
rx_frame.FIR.B.DLC = 8;
rx_frame.data.u8[0] = 'H';
rx_frame.data.u8[1] = 'e';
rx_frame.data.u8[2] = 'l';
rx_frame.data.u8[3] = 'l';
rx_frame.data.u8[4] = 'o';
rx_frame.data.u8[5] = 'C';
rx_frame.data.u8[6] = 'A';
rx_frame.data.u8[7] = 'N';
ESP32Can.CANWriteFrame(&rx_frame);
M5.Lcd.println("Send Message1");
}
if(M5.BtnB.wasPressed()){
rx_frame.FIR.B.FF = CAN_frame_std;
rx_frame.MsgID = 1;
rx_frame.FIR.B.DLC = 8;
rx_frame.data.u8[0] = 'M';
rx_frame.data.u8[1] = '5';
rx_frame.data.u8[2] = 'S';
rx_frame.data.u8[3] = 'T';
rx_frame.data.u8[4] = 'A';
rx_frame.data.u8[5] = 'C';
rx_frame.data.u8[6] = 'K';
rx_frame.data.u8[7] = ' ';
ESP32Can.CANWriteFrame(&rx_frame);
M5.Lcd.println("Send Message2");
Serial.println("B");
}
if(xQueueReceive(CAN_cfg.rx_queue,&rx_frame, 3*portTICK_PERIOD_MS)==pdTRUE){
M5.Lcd.fillRect(0, 60, 320, 180, BLACK);
M5.Lcd.setCursor(0, 60, 4);
//do stuff!
if(rx_frame.FIR.B.FF==CAN_frame_std){
printf("New standard frame");
M5.Lcd.printf("New standard frame");
} else{
printf("New extended frame");
M5.Lcd.printf("New extended frame");
}
if(rx_frame.FIR.B.RTR==CAN_RTR){
printf(" RTR from 0x%08x, DLC %d\r\n",rx_frame.MsgID, rx_frame.FIR.B.DLC);
M5.Lcd.printf(" RTR from 0x%08x, DLC %d\r\n",rx_frame.MsgID, rx_frame.FIR.B.DLC);
} else{
printf(" from 0x%08x, DLC %d\n",rx_frame.MsgID, rx_frame.FIR.B.DLC);
M5.Lcd.printf(" from 0x%08x, DLC %d\r\n",rx_frame.MsgID, rx_frame.FIR.B.DLC);
for(int i = 0; i < 8; i++){
printf("%c\t", (char)rx_frame.data.u8[i]);
M5.Lcd.printf("%c\t", (char)rx_frame.data.u8[i]);
}
printf("\n");
}
}
M5.update();
delay(200);
}

View File

@@ -0,0 +1,71 @@
/**
* @section License
*
* The MIT License (MIT)
*
* Copyright (c) 2017, Thomas Barth, barth-dev.de
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __DRIVERS_CAN_CFG_H__
#define __DRIVERS_CAN_CFG_H__
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "freertos/semphr.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \brief CAN Node Bus speed */
typedef enum {
CAN_SPEED_100KBPS = 100, /**< \brief CAN Node runs at 100kBit/s. */
CAN_SPEED_125KBPS = 125, /**< \brief CAN Node runs at 125kBit/s. */
CAN_SPEED_200KBPS = 200, /**< \brief CAN Node runs at 250kBit/s. */
CAN_SPEED_250KBPS = 250, /**< \brief CAN Node runs at 250kBit/s. */
CAN_SPEED_500KBPS = 500, /**< \brief CAN Node runs at 500kBit/s. */
CAN_SPEED_800KBPS = 800, /**< \brief CAN Node runs at 800kBit/s. */
CAN_SPEED_1000KBPS = 1000 /**< \brief CAN Node runs at 1000kBit/s. */
} CAN_speed_t;
/** \brief CAN configuration structure */
typedef struct {
CAN_speed_t speed; /**< \brief CAN speed. */
gpio_num_t tx_pin_id; /**< \brief TX pin. */
gpio_num_t rx_pin_id; /**< \brief RX pin. */
QueueHandle_t rx_queue; /**< \brief Handler to FreeRTOS RX queue. */
QueueHandle_t tx_queue; /**< \brief Handler to FreeRTOS TX queue. */
TaskHandle_t tx_handle; /**< \brief Handler to FreeRTOS TX task. */
TaskHandle_t rx_handle; /**< \brief Handler to FreeRTOS RX task. */
} CAN_device_t;
/** \brief CAN configuration reference */
extern CAN_device_t CAN_cfg;
#ifdef __cplusplus
}
#endif
#endif /* __DRIVERS_CAN_CFG_H__ */

View File

@@ -0,0 +1,20 @@
#include "ESP32CAN.h"
int ESP32CAN::CANInit()
{
return CAN_init();
}
int ESP32CAN::CANWriteFrame(const CAN_frame_t* p_frame)
{
return CAN_write_frame(p_frame);
}
int ESP32CAN::CANStop()
{
return CAN_stop();
}
int ESP32CAN::CANConfigFilter(const CAN_filter_t* p_filter)
{
return CAN_config_filter(p_filter);
}
ESP32CAN ESP32Can;

View File

@@ -0,0 +1,17 @@
#ifndef ESP32CAN_H
#define ESP32CAN_H
#include "CAN_config.h"
#include "CAN.h"
class ESP32CAN
{
public:
int CANInit();
int CANConfigFilter(const CAN_filter_t* p_filter);
int CANWriteFrame(const CAN_frame_t* p_frame);
int CANStop();
};
extern ESP32CAN ESP32Can;
#endif

View File

@@ -0,0 +1,279 @@
/**
* @section License
*
* The MIT License (MIT)
*
* Copyright (c) 2017, Thomas Barth, barth-dev.de
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __DRIVERS_CAN_REGDEF_H_
#define __DRIVERS_CAN_REGDEF_H_
#include "CAN.h" //CAN_FIR_t
#ifdef __cplusplus
extern "C" {
#endif
/** \brief Start address of CAN registers */
#define MODULE_CAN ((volatile CAN_Module_t *) 0x3ff6b000)
/** \brief Get standard message ID */
#define _CAN_GET_STD_ID \
(((uint32_t) MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[0] << 3) | (MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[1] >> 5))
/** \brief Get extended message ID */
#define _CAN_GET_EXT_ID \
(((uint32_t) MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[0] << 21) | \
(MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[1] << 13) | (MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[2] << 5) | \
(MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[3] >> 3))
/** \brief Set standard message ID */
#define _CAN_SET_STD_ID(x) \
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[0] = ((x) >> 3); \
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.STD.ID[1] = ((x) << 5);
/** \brief Set extended message ID */
#define _CAN_SET_EXT_ID(x) \
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[0] = ((x) >> 21); \
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[1] = ((x) >> 13); \
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[2] = ((x) >> 5); \
MODULE_CAN->MBX_CTRL.FCTRL.TX_RX.EXT.ID[3] = ((x) << 3);
/** \brief Interrupt status register */
typedef enum {
__CAN_IRQ_RX = BIT(0), /**< \brief RX Interrupt */
__CAN_IRQ_TX = BIT(1), /**< \brief TX Interrupt */
__CAN_IRQ_ERR = BIT(2), /**< \brief Error Interrupt */
__CAN_IRQ_DATA_OVERRUN = BIT(3), /**< \brief Data Overrun Interrupt */
__CAN_IRQ_WAKEUP = BIT(4), /**< \brief Wakeup Interrupt */
__CAN_IRQ_ERR_PASSIVE = BIT(5), /**< \brief Passive Error Interrupt */
__CAN_IRQ_ARB_LOST = BIT(6), /**< \brief Arbitration lost interrupt */
__CAN_IRQ_BUS_ERR = BIT(7), /**< \brief Bus error Interrupt */
} __CAN_IRQ_t;
/** \brief OCMODE options. */
typedef enum {
__CAN_OC_BOM = 0b00, /**< \brief bi-phase output mode */
__CAN_OC_TOM = 0b01, /**< \brief test output mode */
__CAN_OC_NOM = 0b10, /**< \brief normal output mode */
__CAN_OC_COM = 0b11, /**< \brief clock output mode */
} __CAN_OCMODE_t;
/**
* CAN controller (SJA1000).
*/
typedef struct {
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RM : 1; /**< \brief MOD.0 Reset Mode */
unsigned int LOM : 1; /**< \brief MOD.1 Listen Only Mode */
unsigned int STM : 1; /**< \brief MOD.2 Self Test Mode */
unsigned int AFM : 1; /**< \brief MOD.3 Acceptance Filter Mode */
unsigned int SM : 1; /**< \brief MOD.4 Sleep Mode */
unsigned int reserved_27 : 27; /**< \brief \internal Reserved */
} B;
} MOD;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int TR : 1; /**< \brief CMR.0 Transmission Request */
unsigned int AT : 1; /**< \brief CMR.1 Abort Transmission */
unsigned int RRB : 1; /**< \brief CMR.2 Release Receive Buffer */
unsigned int CDO : 1; /**< \brief CMR.3 Clear Data Overrun */
unsigned int GTS : 1; /**< \brief CMR.4 Go To Sleep */
unsigned int reserved_27 : 27; /**< \brief \internal Reserved */
} B;
} CMR;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RBS : 1; /**< \brief SR.0 Receive Buffer Status */
unsigned int DOS : 1; /**< \brief SR.1 Data Overrun Status */
unsigned int TBS : 1; /**< \brief SR.2 Transmit Buffer Status */
unsigned int TCS : 1; /**< \brief SR.3 Transmission Complete Status */
unsigned int RS : 1; /**< \brief SR.4 Receive Status */
unsigned int TS : 1; /**< \brief SR.5 Transmit Status */
unsigned int ES : 1; /**< \brief SR.6 Error Status */
unsigned int BS : 1; /**< \brief SR.7 Bus Status */
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} SR;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RI : 1; /**< \brief IR.0 Receive Interrupt */
unsigned int TI : 1; /**< \brief IR.1 Transmit Interrupt */
unsigned int EI : 1; /**< \brief IR.2 Error Interrupt */
unsigned int DOI : 1; /**< \brief IR.3 Data Overrun Interrupt */
unsigned int WUI : 1; /**< \brief IR.4 Wake-Up Interrupt */
unsigned int EPI : 1; /**< \brief IR.5 Error Passive Interrupt */
unsigned int ALI : 1; /**< \brief IR.6 Arbitration Lost Interrupt */
unsigned int BEI : 1; /**< \brief IR.7 Bus Error Interrupt */
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} IR;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RIE : 1; /**< \brief IER.0 Receive Interrupt Enable */
unsigned int TIE : 1; /**< \brief IER.1 Transmit Interrupt Enable */
unsigned int EIE : 1; /**< \brief IER.2 Error Interrupt Enable */
unsigned int DOIE : 1; /**< \brief IER.3 Data Overrun Interrupt Enable */
unsigned int WUIE : 1; /**< \brief IER.4 Wake-Up Interrupt Enable */
unsigned int EPIE : 1; /**< \brief IER.5 Error Passive Interrupt Enable */
unsigned int ALIE : 1; /**< \brief IER.6 Arbitration Lost Interrupt Enable */
unsigned int BEIE : 1; /**< \brief IER.7 Bus Error Interrupt Enable */
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} IER;
uint32_t RESERVED0;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int BRP : 6; /**< \brief BTR0[5:0] Baud Rate Prescaler */
unsigned int SJW : 2; /**< \brief BTR0[7:6] Synchronization Jump Width*/
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} BTR0;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int TSEG1 : 4; /**< \brief BTR1[3:0] Timing Segment 1 */
unsigned int TSEG2 : 3; /**< \brief BTR1[6:4] Timing Segment 2*/
unsigned int SAM : 1; /**< \brief BTR1.7 Sampling*/
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} BTR1;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int OCMODE : 2; /**< \brief OCR[1:0] Output Control Mode, see # */
unsigned int OCPOL0 : 1; /**< \brief OCR.2 Output Control Polarity 0 */
unsigned int OCTN0 : 1; /**< \brief OCR.3 Output Control Transistor N0 */
unsigned int OCTP0 : 1; /**< \brief OCR.4 Output Control Transistor P0 */
unsigned int OCPOL1 : 1; /**< \brief OCR.5 Output Control Polarity 1 */
unsigned int OCTN1 : 1; /**< \brief OCR.6 Output Control Transistor N1 */
unsigned int OCTP1 : 1; /**< \brief OCR.7 Output Control Transistor P1 */
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} OCR;
uint32_t RESERVED1[2];
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int ALC : 8; /**< \brief ALC[7:0] Arbitration Lost Capture */
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} ALC;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int ECC : 8; /**< \brief ECC[7:0] Error Code Capture */
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} ECC;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int EWLR : 8; /**< \brief EWLR[7:0] Error Warning Limit */
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} EWLR;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RXERR : 8; /**< \brief RXERR[7:0] Receive Error Counter */
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} RXERR;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int TXERR : 8; /**< \brief TXERR[7:0] Transmit Error Counter */
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} TXERR;
union {
struct {
uint32_t CODE[4]; /**< \brief Acceptance Message ID */
uint32_t MASK[4]; /**< \brief Acceptance Mask */
uint32_t RESERVED2[5];
} ACC; /**< \brief Acceptance filtering */
struct {
CAN_FIR_t FIR; /**< \brief Frame information record */
union {
struct {
uint32_t ID[2]; /**< \brief Standard frame message-ID*/
uint32_t data[8]; /**< \brief Standard frame payload */
uint32_t reserved[2];
} STD; /**< \brief Standard frame format */
struct {
uint32_t ID[4]; /**< \brief Extended frame message-ID*/
uint32_t data[8]; /**< \brief Extended frame payload */
} EXT; /**< \brief Extended frame format */
} TX_RX; /**< \brief RX/TX interface */
} FCTRL; /**< \brief Function control regs */
} MBX_CTRL; /**< \brief Mailbox control */
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RMC : 8; /**< \brief RMC[7:0] RX Message Counter */
unsigned int reserved_24 : 24; /**< \brief \internal Reserved Enable */
} B;
} RMC;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int RBSA : 8; /**< \brief RBSA[7:0] RX Buffer Start Address */
unsigned int reserved_24 : 24; /**< \brief \internal Reserved Enable */
} B;
} RBSA;
union {
uint32_t U; /**< \brief Unsigned access */
struct {
unsigned int COD : 3; /**< \brief CDR[2:0] CLKOUT frequency selector based of fOSC*/
unsigned int COFF : 1; /**< \brief CDR.3 CLKOUT off*/
unsigned int reserved_1 : 1; /**< \brief \internal Reserved */
unsigned int
RXINTEN : 1; /**< \brief CDR.5 This bit allows the TX1 output to be used as a dedicated receive interrupt
output*/
unsigned int
CBP : 1; /**< \brief CDR.6 allows to bypass the CAN input comparator and is only possible in reset mode.*/
unsigned int
CAN_M : 1; /**< \brief CDR.7 If CDR.7 is at logic 0 the CAN controller operates in BasicCAN mode. If set to
logic 1 the CAN controller operates in PeliCAN mode. Write access is only possible in reset
mode*/
unsigned int reserved_24 : 24; /**< \brief \internal Reserved */
} B;
} CDR;
uint32_t IRAM[2];
} CAN_Module_t;
#ifdef __cplusplus
}
#endif
#endif /* __DRIVERS_CAN_REGDEF_H_ */

View File

@@ -0,0 +1,201 @@
/*
*******************************************************************************
* Copyright (c) 2022 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more
information: https://docs.m5stack.com/en/unit/catm_gnss
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/module/catm_gnss
*
* describe: catm_gnss.
* date: 2022/03/03
*******************************************************************************
This case will use UNIT CATM+GNSS combined with M5Core
Connect to the CoAP server and send a request.
Before use, connect the UNIT CATM+GNSS to PORT C(G16/17)
Libraries:
- [TinyGSM](https://github.com/vshymanskyy/TinyGSM)
*/
#define RX2 13
#define TX2 14
#include <M5Core2.h>
#include "M5GFX.h"
#define TINY_GSM_MODEM_SIM7080
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
#define SerialAT Serial2
uint32_t lastReconnectAttempt = 0;
#define TINY_GSM_RX_BUFFER 650
#define TINY_GSM_DEBUG SerialMon
#define MODULE_BAUD 115200
// Your GPRS credentials, if any
const char apn[] = "YourAPN";
const char gprsUser[] = "";
const char gprsPass[] = "";
#include <TinyGsmClient.h>
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
M5GFX display;
M5Canvas canvas(&display);
unsigned long start;
typedef enum { GET = 1, POST, PUT, DELETE } coap_method_t;
inline String time() { return "..." + String((millis() - start) / 1000) + 's'; }
void log(String info) {
SerialMon.println(info);
canvas.println(info);
canvas.pushSprite(0, 0);
}
String waitMsg(unsigned long time) {
String restr = "";
unsigned long start = millis();
while (1) {
if (SerialAT.available() || (millis() - start) < time) {
String str = SerialAT.readString();
restr += str;
} else {
break;
}
}
return restr;
}
bool craeteCoAPPacket(String url, String url_query, coap_method_t method,
String payload) {
log("Create CoAPPacket");
// SerialAT.println("AT+CCOAPPARA=\"CODE\",4,uri-path,0,\"/m5stack-get\",uri-query,0,\"catm_test=1\",payload,0,\"hello
// world\"");
SerialAT.println("AT+CCOAPPARA=\"CODE\"," + String(method) +
",uri-path,0,\"" + url + "\",uri-query,0,\"" + url_query +
"\",payload,0,\"" + payload + "\"");
if (waitMsg(2000).indexOf("OK") != -1) {
return true;
} else {
return false;
}
}
bool connectCoAP(String ip, String port) {
SerialAT.println("AT+CNACT=0,0");
log(waitMsg(500));
SerialAT.println("AT+CNACT=0,1");
log(waitMsg(500));
SerialAT.println("AT+CCOAPINIT");
log(waitMsg(500));
SerialAT.println("AT+CCOAPURL=\"coap://120.77.157.90:5683\"");
String result = waitMsg(1000);
log(result);
if (result.indexOf("ERROR") != -1) {
SerialAT.println("AT+CCOAPTERM");
String result = waitMsg(1000);
return false;
} else {
return true;
}
}
String sendCoAPRequest() {
SerialAT.println("AT+CCOAPACTION");
String result = waitMsg(5000);
log(result);
if (result.indexOf("+CCOAPRECV") != -1) {
String str1 = result.substring(result.indexOf("+CCOAPRECV") + 11);
String str2 = str1.substring(1, str1.indexOf(","));
return str2;
} else {
return "ERROR";
}
}
String getCoAPreceive(String msgid) {
SerialAT.println("AT+CCOAPACTION=4");
log(waitMsg(2000));
// Read the packet header with messageidof 1and print
SerialAT.println("AT+CCOAPHEAD=" + msgid + ",1");
log(waitMsg(2000));
// Read the receive packet payload with messageid of 1
SerialAT.println("AT+CCOAPREAD=" + msgid);
log(waitMsg(2000));
}
void setup() {
M5.begin();
display.begin();
start = millis();
canvas.setColorDepth(1); // mono color
canvas.setFont(&fonts::efontCN_14);
canvas.createSprite(display.width(), display.height());
canvas.setTextSize(2);
canvas.setPaletteColor(1, GREEN);
canvas.setTextScroll(true);
log("Initializing modem..." + time());
// Set GSM module baud rate
if (TinyGsmAutoBaud(SerialAT, MODULE_BAUD, MODULE_BAUD) == 0) {
log("UART connect error" + time());
}
// modem.restart();
modem.init();
String modemInfo = modem.getModemInfo();
log("Modem Info: ");
log(modemInfo + time());
while (!modem.getSimStatus()) {
log("not sim card" + time());
}
}
void loop() {
log("Waiting for network...." + time());
if (!modem.waitForNetwork()) {
log("fail" + time());
log(waitMsg(1000));
return;
}
if (modem.isNetworkConnected()) {
log("Network connected" + time());
}
IPAddress local = modem.localIP();
log("REMOTE IP: " + local.toString());
int csq = modem.getSignalQuality();
log("RSSI:" + String(csq) + time());
log("IP:" + local.toString() + time());
if (connectCoAP("120.77.157.90", "5683")) {
log("connect successful, click button a to send request");
}
while (1) {
M5.update();
if (M5.BtnA.wasPressed()) {
craeteCoAPPacket("/m5stack-get", "catm_test=1", GET, "hello world");
String msgid = sendCoAPRequest();
log(msgid);
if (msgid != "ERROR") {
getCoAPreceive(msgid);
}
}
String result = waitMsg(0);
if (result != "") {
log(result);
}
}
}

View File

@@ -0,0 +1,178 @@
/*
*******************************************************************************
* Copyright (c) 2022 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more
information: https://docs.m5stack.com/en/unit/catm_gnss
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/module/catm_gnss
*
* describe: catm_gnss.
* date: 2022/03/03
*******************************************************************************
This case will use UNIT CATM+GNSS combined with M5Core
Obtain positioning information through GNSS
Before use, connect the UNIT CATM+GNSS to PORT C(G16/17)
Libraries:
- [TinyGSM](https://github.com/vshymanskyy/TinyGSM)
*/
#define RX2 13
#define TX2 14
#include <M5Core2.h>
#include "M5GFX.h"
#define TINY_GSM_MODEM_SIM7080
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
#define SerialAT Serial2
uint32_t lastReconnectAttempt = 0;
#define TINY_GSM_RX_BUFFER 650
#define TINY_GSM_DEBUG SerialMon
#define MODULE_BAUD 115200
// Your GPRS credentials, if any
const char apn[] = "YourAPN";
const char gprsUser[] = "";
const char gprsPass[] = "";
#include <TinyGsmClient.h>
#include <PubSubClient.h>
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
M5GFX display;
M5Canvas canvas(&display);
const char* broker = "mqtt.m5stack.com";
const char* topic_up = "cat1/up";
const char* topic_down = "cat1/down";
PubSubClient mqtt(client);
unsigned long start;
inline String time() {
return "..." + String((millis() - start) / 1000) + 's';
}
void log(String info) {
SerialMon.println(info);
canvas.println(info);
canvas.pushSprite(0, 0);
}
void mqttCallback(char* topic, byte* payload, unsigned int len) {
log("Message arrived :");
log(topic);
log("payload: ");
char _payload[len];
memcpy(_payload, payload, len);
_payload[len] = '\0';
log(_payload);
}
boolean mqttConnect() {
log("Connecting to ");
log(broker);
// Connect to MQTT Broker
boolean status = mqtt.connect("GsmClientTest");
// Or, if you want to authenticate MQTT:
// boolean status = mqtt.connect("GsmClientName", "mqtt_user", "mqtt_pass");
if (status == false) {
SerialMon.println(" fail");
return false;
}
SerialMon.println(" success");
mqtt.publish(topic_up, "GsmClientTest started");
mqtt.subscribe(topic_down);
log("Subscribe Topic: " + String(topic_down));
return mqtt.connected();
}
void setup() {
M5.begin();
display.begin();
start = millis();
canvas.setColorDepth(1); // mono color
canvas.setFont(&fonts::efontCN_14);
canvas.createSprite(display.width(), display.height());
canvas.setTextSize(2);
canvas.setPaletteColor(1, GREEN);
canvas.setTextScroll(true);
log("Initializing modem..." + time());
// Set GSM module baud rate
if (TinyGsmAutoBaud(SerialAT, MODULE_BAUD, MODULE_BAUD) == 0) {
log("UART connect error" + time());
}
// modem.restart();
modem.init();
String modemInfo = modem.getModemInfo();
log("Modem Info: ");
log(modemInfo + time());
}
bool gps_flag = false;
void loop() {
canvas.println("INIT GNSS" + time());
canvas.pushSprite(0, 0);
while (1) {
DBG("Enabling GPS/GNSS/GLONASS and waiting 15s for warm-up");
modem.enableGPS();
delay(15000L);
float lat2 = 0;
float lon2 = 0;
float speed2 = 0;
float alt2 = 0;
int vsat2 = 0;
int usat2 = 0;
float accuracy2 = 0;
int year2 = 0;
int month2 = 0;
int day2 = 0;
int hour2 = 0;
int min2 = 0;
int sec2 = 0;
for (int8_t i = 15; i; i--) {
DBG("Requesting current GPS/GNSS/GLONASS location");
if (modem.getGPS(&lat2, &lon2, &speed2, &alt2, &vsat2, &usat2,
&accuracy2, &year2, &month2, &day2, &hour2, &min2,
&sec2)) {
log("Latitude:" + String(lat2, 8) +
"\tLongitude:" + String(lon2, 8));
log("Speed:" + String(speed2) +
"\tAltitude:" + String(alt2));
log("Visible Satellites:" + String(vsat2) +
"\tUsed Satellites:" + String(usat2));
log("Accuracy:" + String(accuracy2));
log("Year:" + String(year2) + "\tMonth:" +
String(month2) + "\tDay:" + String(day2));
log("Hour:" + String(hour2) + "\tMinute:" +
String(min2) + "\tSecond:" + String(sec2));
break;
} else {
log("Get GPS/GNSS/GLONASS location.." + time());
DBG("Couldn't get GPS/GNSS/GLONASS location, retrying in 10s.");
delay(10000L);
}
}
// modem.disableGPS();
}
while (1) {
delay(100);
}
}

View File

@@ -0,0 +1,201 @@
/*
*******************************************************************************
* Copyright (c) 2022 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more
information: https://docs.m5stack.com/en/unit/catm_gnss
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/module/catm_gnss
*
* describe: catm_gnss.
* date: 2022/03/03
*******************************************************************************
This case will use UNIT CATM+GNSS combined with M5Core to implement MQTT
Client. After successfully connecting to MQTT, press button B to realize data
publishing.
Before use, connect the UNIT CATM+GNSS to PORT C(G16/17)
Libraries:
- [TinyGSM](https://github.com/vshymanskyy/TinyGSM)
- [PubSubClient](https://github.com/knolleary/pubsubclient.git)
*/
#define RX2 13
#define TX2 14
#include <M5Core2.h>
#include "M5GFX.h"
#define TINY_GSM_MODEM_SIM7080
// Set serial for debug console (to the Serial Monitor, default speed 115200)
#define SerialMon Serial
#define SerialAT Serial2
uint32_t lastReconnectAttempt = 0;
#define TINY_GSM_RX_BUFFER 650
#define TINY_GSM_DEBUG SerialMon
#define MODULE_BAUD 115200
// Your GPRS credentials, if any
const char apn[] = "YourAPN";
const char gprsUser[] = "";
const char gprsPass[] = "";
#include <TinyGsmClient.h>
#include <PubSubClient.h>
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
M5GFX display;
M5Canvas canvas(&display);
const char* broker = "mqtt.m5stack.com";
const char* topic_up = "cat1/up";
const char* topic_down = "cat1/down";
PubSubClient mqtt(client);
unsigned long start;
inline String time() { return "..." + String((millis() - start) / 1000) + 's'; }
void log(String info) {
SerialMon.println(info);
canvas.println(info);
canvas.pushSprite(0, 0);
}
void mqttCallback(char* topic, byte* payload, unsigned int len) {
log("Message arrived :");
log(topic);
log("payload: ");
char _payload[len];
memcpy(_payload, payload, len);
_payload[len] = '\0';
log(_payload);
}
boolean mqttConnect() {
log("Connecting to ");
log(broker);
// Connect to MQTT Broker
boolean status = mqtt.connect("GsmClientTest");
// Or, if you want to authenticate MQTT:
// boolean status = mqtt.connect("GsmClientName", "mqtt_user", "mqtt_pass");
if (status == false) {
SerialMon.println(" fail");
return false;
}
SerialMon.println(" success");
mqtt.publish(topic_up, "GsmClientTest started");
mqtt.subscribe(topic_down);
log("Subscribe Topic: " + String(topic_down));
return mqtt.connected();
}
void setup() {
M5.begin();
display.begin();
start = millis();
canvas.setColorDepth(1); // mono color
canvas.setFont(&fonts::efontCN_14);
canvas.createSprite(display.width(), display.height());
canvas.setTextSize(2);
canvas.setPaletteColor(1, GREEN);
canvas.setTextScroll(true);
log("Initializing modem..." + time());
// Set GSM module baud rate
if (TinyGsmAutoBaud(SerialAT, MODULE_BAUD, MODULE_BAUD) == 0) {
log("UART connect error" + time());
}
// modem.restart();
modem.init();
String modemInfo = modem.getModemInfo();
log("Modem Info: ");
log(modemInfo + time());
while (!modem.getSimStatus()) {
log("not sim card" + time());
}
}
void loop() {
log("Waiting for network...." + time());
if (!modem.waitForNetwork()) {
log("fail" + time());
delay(10000);
return;
}
if (modem.isNetworkConnected()) {
log("Network connected" + time());
}
log("GPRS connect..." + time());
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
log("fail");
delay(10000);
return;
}
if (modem.isGprsConnected()) {
log("GPRS connected");
}
String ccid = modem.getSimCCID();
log("CCID: ");
log(ccid);
String imei = modem.getIMEI();
log("IMEI: " + imei);
String imsi = modem.getIMSI();
log("IMSI: " + imsi);
String cop = modem.getOperator();
log("Operator: " + cop);
IPAddress local = modem.localIP();
log("REMOTE IP: " + local.toString());
int csq = modem.getSignalQuality();
log("RSSI:" + String(csq) + time());
log("IP:" + local.toString() + time());
// MQTT Broker setup
mqtt.setServer(broker, 1883);
mqtt.setCallback(mqttCallback);
while (true) {
M5.update();
if (!mqtt.connected()) {
log("=== MQTT NOT CONNECTED ===");
// Reconnect every 10 seconds
uint32_t t = millis();
if (t - lastReconnectAttempt > 3000L) {
lastReconnectAttempt = t;
if (mqttConnect()) {
lastReconnectAttempt = 0;
log("mqtt.m5stack.com" + time());
log("MQTT Connected!" + time());
log("Press Btn B to Publish");
log("Topic: " + String(topic_up));
}
}
delay(100);
} else {
mqtt.loop();
M5.update();
if (M5.BtnB.wasPressed()) {
log("Publish:" + String(topic_up));
mqtt.publish(topic_up, "Hello From UNIT CATM+GNSS");
}
}
}
}

View File

@@ -0,0 +1,70 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: COLOR_TCS3472. 颜色识别
* date: 2021/8/11
*******************************************************************************
Please connect to Port A,Use COLOR Unit to read C, R, G, B values
请连接端口A,使用COLOR Unit读取C, R, G, B值
*/
#include <M5Core2.h>
#include "Adafruit_TCS34725.h"
#define commonAnode true //set to false if using a common cathode LED. //如果使用普通阴极LED则设置为false
byte gammatable[256]; // our RGB -> eye-recognized gamma color
static uint16_t color16(uint16_t r, uint16_t g, uint16_t b) {
uint16_t _color;
_color = (uint16_t)(r & 0xF8) << 8;
_color |= (uint16_t)(g & 0xFC) << 3;
_color |= (uint16_t)(b & 0xF8) >> 3;
return _color;
}
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
void setup() {
M5.begin(); //Init M5Core2. 初始化 M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.lcd.println("Color View Test!");
while(!tcs.begin()){ //如果color unit未能初始化
M5.lcd.println("No TCS34725 found ... check your connections");
M5.Lcd.drawString("No Found sensor.",50, 100, 4);
delay(1000);
}
tcs.setIntegrationTime(TCS34725_INTEGRATIONTIME_154MS); //Sets the integration time for the TC34725. 设置TC34725的集成时间
tcs.setGain(TCS34725_GAIN_4X); //Adjusts the gain on the TCS34725. 调整TCS34725上的增益
}
void loop() {
uint16_t clear, red, green, blue;
tcs.getRawData(&red, &green, &blue, &clear); //Reads the raw red, green, blue and clear channel values. 读取原始的红、绿、蓝和清晰的通道值
// Figure out some basic hex code for visualization. 生成对应的十六进制代码
uint32_t sum = clear;
float r, g, b;
r = red; r /= sum;
g = green; g /= sum;
b = blue; b /= sum;
r *= 256; g *= 256; b *= 256;
uint16_t _color = color16((int)r, (int)g, (int)b);
M5.lcd.setCursor(0,20); //Place the cursor at (0,0). 将光标固定在(0,0)
M5.lcd.fillRect(0,20,120,80,BLACK); //Fill the screen with a black rectangle. 将屏幕填充黑色矩形
M5.Lcd.print("C:"); M5.Lcd.println(clear);
M5.Lcd.print("R:"); M5.Lcd.println(red);
M5.Lcd.print("G:"); M5.Lcd.println(green);
M5.Lcd.print("B:"); M5.Lcd.println(blue);
M5.Lcd.print("0x");
M5.Lcd.print((int)r, HEX); M5.Lcd.print((int)g, HEX); M5.Lcd.print((int)b, HEX);
delay(1000);
}

View File

@@ -0,0 +1,40 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: CardKB. 键盘
* date: 2021/8/11
*******************************************************************************
Please connect to Port A,Read the characters entered by CardKB Unit and display them on the screen.
请连接端口A,读取CardKB Unit输入的字符并显示在屏幕上。
*/
#include <M5Core2.h>
#define CARDKB_ADDR 0x5F //Define the I2C address of CardKB. 定义CardKB的I2C地址
void setup() {
M5.begin(); //Init M5Core2. 初始化 M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.printf("IIC Address: 0x5F\n");
M5.Lcd.printf(">>");
Wire.begin();
}
void loop() {
Wire.requestFrom(
CARDKB_ADDR,
1); //Request 1 byte from the slave device. 向从设备请求1字节
while (Wire.available()) //If received data is detected. 如果检测到收到数据
{
char c = Wire.read(); // Store the received data. 将接收到的数据存储
if (c != 0) {
M5.Lcd.printf("%c", c);
Serial.println(c, HEX);
}
}
}

View File

@@ -0,0 +1,44 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: DAC_MCP4725. 数模转换
* date: 2021/8/16
*******************************************************************************
Please connect to Port A,Use DAC Unit to output 0 ~ 3.3V voltage with an accuracy of 12 bits.
请连接端口A,使用DAC Unit 输出12位精度的0 ~ 3.3V电压。
*/
#include <M5Core2.h>
#include <Adafruit_MCP4725.h>
#define DAC_ADDR 0x60 // For Adafruit MCP4725A1 the address is 0x62 (default) or 0x63 (ADDR pin tied to VCC)
// For MCP4725A0 the address is 0x60 or 0x61
// For MCP4725A2 the address is 0x64 or 0x65
Adafruit_MCP4725 dac;
void setup(void) {
M5.begin(true, false, false); //Init M5Core2. 初始化 M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.print(" DAC MCP4725 demo.");
dac.begin(0x60); //Setups the hardware address and checks the DAC was found. 设置硬件地址并检查是否找到DAC
dac.setVoltage(2048, false);
}
void loop(void) {
M5.Lcd.setCursor(100,60);
M5.Lcd.print("1.2V");
dac.setVoltage(1024, false); //Set the voltage to 1.2V and retain the current voltage output after power off or reset. 设置电压为1.2v,关闭断电或复位后保留当前电压输出
delay(1000);
M5.Lcd.fillRect(100,60,120,40,BLACK); //Draw a black rectangle at (100,60) with a width of 120 and a height of 40. 在(100,60)处绘制一个宽为120,高为40的黑色矩形
M5.Lcd.print("2.4V");
dac.setVoltage(2048, false); //2.4v
delay(1000);
M5.Lcd.fillRect(100,60,120,40,BLACK);
}

View File

@@ -0,0 +1,63 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Button_Two. 双按键
* date: 2021/8/9
*******************************************************************************
Please connect to Port B,Read the button status of BUTTON Unit and display it on the screen
请连接端口B,读取按键的状态并在显示屏上显示
if you don't have M5GO BOTTOM, you need change the pinMode and the digitalRead to 33、32, But you will not be able to use any I2C operations.
如果你没有M5GO BOTTOM你需要改变pinMode和digitalRead到 33,32,但是你将不能使用任何I2C操作.
*/
#include <M5Core2.h>
int last_value1 = 0,last_value2 = 0;
int cur_value1 = 0,cur_value2 = 0;
void setup() {
M5.begin(); //Init M5Core2. 初始化 M5Core2
pinMode(36, INPUT); //set pin mode to input.设置引脚模式为输入模式
pinMode(26, INPUT);
M5.Lcd.setTextColor(YELLOW); //Set the font color to yellow. 设置字体颜色为黄色
M5.Lcd.setTextSize(2); //Setting the Font size. 设置字号大小
M5.Lcd.setCursor(80, 0); //Set the cursor position to (80,0). 将光标位置设置为(80,0)
M5.Lcd.println("Button example");
M5.Lcd.setTextColor(WHITE);
}
void loop() {
cur_value1 = digitalRead(36); // read the value of BUTTON. 读取22号引脚的值
cur_value2 = digitalRead(26);
M5.Lcd.setCursor(90,25); M5.Lcd.print("Btn.1 Btn.2");
M5.Lcd.setCursor(0,45); M5.Lcd.print("Value: ");
M5.Lcd.setCursor(0,85); M5.Lcd.print("State: ");
if(cur_value1 != last_value1){
M5.Lcd.fillRect(85,45,75,85,BLACK); //Draw a black rectangle 75 by 85 at (85,45). 在(85,45)处绘制宽75,高85的黑色矩形
if(cur_value1==0){
M5.Lcd.setCursor(95,45); M5.Lcd.print("0"); // display the status
M5.Lcd.setCursor(95,85); M5.Lcd.print("pre");
}
else{
M5.Lcd.setCursor(95,45); M5.Lcd.print("1"); // display the status
M5.Lcd.setCursor(95,85); M5.Lcd.print("rel");
}
last_value1 = cur_value1;
}
if(cur_value2 != last_value2){
M5.Lcd.fillRect(170,45,75,85,BLACK);
if(cur_value2==0){
M5.Lcd.setCursor(185,45); M5.Lcd.print("0"); // display the status
M5.Lcd.setCursor(185,85); M5.Lcd.print("pre");
}
else{
M5.Lcd.setCursor(185,45); M5.Lcd.print("1"); // display the status
M5.Lcd.setCursor(185,85); M5.Lcd.print("rel");
}
last_value2 = cur_value2;
}
}

View File

@@ -0,0 +1,32 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: EARTH. 土壤湿度
* date: 2021/8/11
*******************************************************************************
Please connect to Port B,Read the analog quantity and digital quantity returned by the EARTH unit, and convert the analog quantity into 12-bit data and display it on the screen.
请连接端口B,读取EARTH Unit 返回的模拟量和数字量并将模拟量转换为12位数据显示在屏幕上。
*/
#include <M5Stack.h>
void setup() {
M5.begin(); //Init M5Stack. 初始化M5Stack
M5.Power.begin(); //Init power 初始化电源模块
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.printf("UNIT_EARTH EXAMPLE\n");
pinMode(26, INPUT);
dacWrite(25, 0); //disable the speak noise. 禁用喇叭
}
void loop() {
M5.Lcd.setCursor(0, 80); //Set the cursor at (0,80). 将光标设置在(0,80)
M5.Lcd.printf("AnalogRead:%d\n", analogRead(36));
M5.Lcd.printf("DigitalRead:%d\n", digitalRead(26));
delay(1000);
}

View File

@@ -0,0 +1,47 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: ENVIII_SHT30_QMP6988. 环境传感器
* date: 2021/8/17
*******************************************************************************
Please connect to Port A,Read temperature, humidity and atmospheric pressure and display them on the display screen
请连接端口A,读取温度、湿度和大气压强并在显示屏上显示
*/
#include <M5Core2.h>
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include "UNIT_ENV.h"
SHT3X sht30;
QMP6988 qmp6988;
float tmp = 0.0;
float hum = 0.0;
float pressure = 0.0;
void setup() {
M5.begin(); //Init M5Core2. 初始化M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
Wire.begin(); //Wire init, adding the I2C bus. Wire初始化, 加入i2c总线
qmp6988.init();
M5.lcd.println(F("ENV Unit III test"));
}
void loop() {
pressure = qmp6988.calcPressure();
if(sht30.get()==0){ //Obtain the data of shT30. 获取sht30的数据
tmp = sht30.cTemp; //Store the temperature obtained from shT30. 将sht30获取到的温度存储
hum = sht30.humidity; //Store the humidity obtained from the SHT30. 将sht30获取到的湿度存储
}else{
tmp=0,hum=0;
}
M5.lcd.fillRect(0,20,100,60,BLACK); //Fill the screen with black (to clear the screen). 将屏幕填充黑色(用来清屏)
M5.lcd.setCursor(0,20);
M5.Lcd.printf("Temp: %2.1f \r\nHumi: %2.0f%% \r\nPressure:%2.0fPa\r\n", tmp, hum, pressure);
delay(2000);
}

View File

@@ -0,0 +1,46 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: ENVII_SHT30_BMP280. 环境传感器
* date: 2021/8/11
*******************************************************************************
Please connect to Port A,Read temperature, humidity and atmospheric pressure and display them on the display screen
请连接端口A,读取温度、湿度和大气压强并在显示屏上显示
*/
#include <M5Core2.h>
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include "UNIT_ENV.h"
SHT3X sht30;
Adafruit_BMP280 bme;
float tmp = 0.0;
float hum = 0.0;
float pressure = 0.0;
void setup() {
M5.begin(); //Init M5Core2. 初始化 M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.lcd.println(F("ENV Unit(SHT30 and BMP280) test...\n"));
Wire.begin(); //Wire init, adding the I2C bus. Wire初始化, 加入i2c总线
}
void loop() {
while (!bme.begin(0x76)){ //初始化bme传感器. Init the sensor of bme
M5.Lcd.println("Could not find a valid BMP280 sensor, check wiring!");
}
pressure = bme.readPressure(); //Stores the pressure gained by BMP. 存储bmp获取到的压强
sht30.get(); //Obtain the data of shT30. 获取sht30的数据
tmp = sht30.cTemp; //Store the temperature obtained from shT30. 将sht30获取到的温度存储
hum = sht30.humidity; //Store the humidity obtained from the SHT30. 将sht30获取到的湿度存储
M5.lcd.setCursor(0,50);
M5.lcd.fillRect(0,50,100,60,BLACK); //Fill the screen with black (to clear the screen). 将屏幕填充满黑色(用来清屏)
M5.Lcd.printf("Temp: %2.1f \r\nHumi: %2.0f%% \r\nPressure:%2.0fPa\r\n", tmp, hum, pressure);
delay(2000);
}

View File

@@ -0,0 +1,43 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: ENVII_DH12_BMP280. 环境传感器
* date: 2021/8/17
*******************************************************************************
Please connect to Port A,Read temperature, humidity and atmospheric pressure and display them on the display screen
请连接端口A,读取温度、湿度和大气压强并在显示屏上显示
*/
#include <M5Core2.h>
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include "UNIT_ENV.h"
DHT12 dht12;
Adafruit_BMP280 bme;
void setup() {
M5.begin(); //Init M5Core2. 初始化M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
Wire.begin(); //Wire init, adding the I2C bus. Wire初始化, 加入i2c总线
M5.Lcd.println(F("ENV Unit(DHT12 and BMP280) test"));
}
void loop() {
while (!bme.begin(0x76)){
M5.Lcd.println("Could not find a valid BMP280 sensor, check wiring!");
}
float tmp = dht12.readTemperature(); //Store the temperature obtained from dht12. 将dht12获取到的温度存储
float hum = dht12.readHumidity(); //Store the humidity obtained from the dht12. 将dht12获取到的湿度存储
float pressure = bme.readPressure(); //Stores the pressure gained by BMP. 存储bmp获取到的压强
M5.lcd.fillRect(0,20,100,60,BLACK); //Fill the screen with black (to clear the screen). 将屏幕填充黑色(用来清屏)
M5.lcd.setCursor(0,20);
M5.Lcd.printf("Temp: %2.1f \r\nHumi: %2.0f%% \r\nPressure:%2.0fPa\r\n", tmp, hum, pressure);
delay(2000);
}

View File

@@ -0,0 +1,59 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/extio
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/extio
*
* describe: extio.
* date: 2021/8/30
*******************************************************************************
Please connect to Port A,Control the 8 extended IOs on the EXT.IO Unit to cycle high and low level changes.
请连接端口 A,在EXT.IO Unit上控制8个扩展的IO来循环高电平和低电平的变化。
*/
#include <M5Core2.h>
#include "PCA9554.h"
PCA9554 ioCon1(0x27); // Create an object at this address. 在这个地址上创建一个对象
uint8_t res;
void setup()
{
M5.begin();
Wire.begin();
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.setCursor(70, 0);
M5.Lcd.print("UNIT_IO EXAMPLE\n");
ioCon1.twiWrite(21, 22); //Sets the I2C pin of the connection. 设置连接的I2C引脚
delay(10);
res = 1;
ioCon1.twiRead(res);
Serial.printf("res:%d\r\n", res);
ioCon1.portMode(ALLOUTPUT); //Set the port as all output. 设置所有引脚为输出模式
}
void loop()
{
for(int i=0;i<8;i++) ioCon1.digitalWrite(i, LOW);
delay(1000);
for(int i=0;i<8;i++) ioCon1.digitalWrite(i, HIGH);
delay(1000);
// write 0-7 HIGH. 设置0~7号引脚为高电平
Serial.println(ioCon1.digitalWritePort(0xff));
delay(200);
// write 0-7 LOW. 设置0~7号引脚为低电平
Serial.println(ioCon1.digitalWritePort(0x00));
delay(200);
// write Port, the same read
for (byte i = 0; i < 8; i++) {
ioCon1.digitalWritePort((1 << i));
delay(200);
}
}

View File

@@ -0,0 +1,55 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/fader
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/fader
*
* describe: UNIT FADER. 滑动电位器/推子
* date: 2021/8/20
*******************************************************************************
Connect UNIT FADER to port B and push the FADER slider to adjust the input value and light brightness
将UNIT FADER连接到B端口, 推动FADER滑杆即可实现调整输入数值大小与灯光亮度
*/
#include "M5Core2.h"
#include "FastLED.h"
// How many leds in your strip?
#define NUM_LEDS 14
#define INPUT_PINS 36
#define DATA_PIN 26
// Define the array of leds
CRGB leds[NUM_LEDS];
uint8_t beginHue = 0;
uint8_t deltaHue = 30;
uint8_t brightness = 100;
uint16_t rawADC = 0;
void setup()
{
M5.begin();
M5.Lcd.setTextDatum(MC_DATUM);
M5.Lcd.drawString("FADER UNIT TEST", 160, 60, 4);
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
delay(1000);
pinMode(36, INPUT);
fill_rainbow(leds, NUM_LEDS, beginHue, deltaHue);
}
void loop()
{
rawADC = analogRead(INPUT_PINS); //Read ADC value 读取ADC数值
brightness = map(rawADC, 0, 4095, 0, 255); //The mapping ADC value is the brightness value range 映射ADC值为亮度值范围
FastLED.setBrightness(brightness); //Adjust the brightness of the FADER LED 调整FADER LED灯亮度
FastLED.show();
Serial.printf("%d\r\n", rawADC);
M5.Lcd.fillRect(0, 120, 320, 100, BLACK);
M5.Lcd.drawString("value: "+String(rawADC), 160, 160, 4);
delay(100);
}

View File

@@ -0,0 +1,36 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Fan. 风扇
* date: 2021/8/16
*******************************************************************************
Please connect to Port B, Adjust the speed of FAN Unit through PWM.
请连接端口B,通过PWM调节风扇单元的转速。
*/
#include <M5Core2.h>
#define motor_pin 26
int freq = 10000;
int ledChannel = 0;
int resolution = 10;
void setup() {
M5.begin(); //Init M5Core2. 初始化M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.setCursor(80, 10); //Set the cursor at (80,10). 将光标设置在(80,10)处
M5.Lcd.println("Fan");
ledcSetup(ledChannel, freq, resolution); //Sets the frequency and number of counts corresponding to the channel. 设置通道对应的频率和计数位数
ledcAttachPin(motor_pin, ledChannel); //Binds the specified channel to the specified I/O port for output. 将指定通道绑定到指定 IO 口上以实现输出
}
void loop() {
ledcWrite(ledChannel, 1024); //Output PWM. 输出PWM
delay(1000);
ledcWrite(ledChannel, 0);
delay(1000);
}

View File

@@ -0,0 +1,98 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Finger Unit example
* date: 2021/10/28
*******************************************************************************
Description: FINGER UNIT use case: Press the left button to enter the fingerprint entry mode. Press the middle button to enter the fingerprint identification modeRight click to delete all saved users
FINGER UNIT 使用案例按左键进入指纹录入模式,短按中间键进入指纹识别模式,按下右键删除所有保存的用户
*/
#include <M5Core2.h>
#include "M5_FPC1020A.h"
FingerPrint FP_M;
void setup() {
M5.begin();
M5.Lcd.setTextColor(GREEN);
M5.Lcd.setTextSize(2);
FP_M.begin();
M5.Lcd.drawString("Add User", 10, 210);
M5.Lcd.drawString("Verify", 125, 210);
M5.Lcd.drawString("Del User", 220, 210);
M5.Lcd.setCursor(0, 20);
M5.Lcd.println("Finger Unit TEST");
M5.Lcd.println("1. delete all user");
M5.Lcd.println("2. add a user fingerprint");
M5.Lcd.println("3. verify user permission");
}
void loop(){
uint8_t res1;
//ButtonA: Add user. 添加用户
if(M5.BtnA.wasPressed()){
M5.Lcd.fillRect(0, 0, 320, 200, BLACK);
Serial.println("Start Fingerprint Typing");
Serial.println("Put Your Finger on the sensor");
Serial.println("wating....");
M5.Lcd.println("Start Fingerprint Typing");
M5.Lcd.println("Put Your Finger on the sensor");
M5.Lcd.println("wating....");
res1 = FP_M.fpm_addUser(22,1); //(user_num, userPermission)
if(res1 == ACK_SUCCESS){
M5.Lcd.println("Success");
Serial.println("Success");
}else{
M5.Lcd.println("Fail");
Serial.println("Fail");
}
}
//ButtonB: Matching. 匹配指纹
if(M5.BtnB.wasPressed()){
M5.Lcd.fillRect(0, 0, 320, 100, BLACK);
Serial.println("Start Verify Fingerprint");
res1 = FP_M.fpm_compareFinger();
if(res1 == ACK_SUCCESS){
Serial.println("Success");
Serial.print("User ID: ");
Serial.println(FP_M.fpm_getUserId());
M5.Lcd.println("Success");
M5.Lcd.print("User ID: ");
M5.Lcd.println(FP_M.fpm_getUserId());
}else{
Serial.println("No Such User");
M5.Lcd.println("No Such User");
}
}
//ButtonC: Delete All User. 删除所有用户
if(M5.BtnC.wasPressed()){
M5.Lcd.fillRect(0, 0, 320, 100, BLACK);
Serial.println("Start Delete Fingerprint");
M5.Lcd.println("Start Delete Fingerprint");
res1 = FP_M.fpm_deleteAllUser();
if(res1 == ACK_SUCCESS){
Serial.println("Delete All User Successful");
M5.Lcd.println("Delete All User Successful");
}
else{
Serial.println("Delete All User Failed");
M5.Lcd.println("Delete All User Failed");
}
}
M5.Lcd.setCursor(0, 20);
M5.update();
}

View File

@@ -0,0 +1,165 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/gps
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/gps
*
* describe: GPS.
* date: 2021/8/26
*******************************************************************************
Connect UNIT GPS to port C, Use GPS Unit to get the coordinate data and time of the current location.
将UNIT GPS 连接到C端口,使用GPS单元获取当前位置的坐标数据和时间。
*/
#include <M5Core2.h>
#include <TinyGPSPlus.h>
static const uint32_t GPSBaud = 9600;
//Creat The TinyGPS++ object. 创建GPS实例
TinyGPSPlus gps;
// The serial connection to the GPS device. 与GPS设备的串行连接
HardwareSerial ss(2);
void setup()
{
M5.begin();
ss.begin(GPSBaud, SERIAL_8N1, 13, 14); //It requires the use of SoftwareSerial, and assumes that you have a 4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx). 它需要使用SoftwareSerial并假设您有一个4800波特的串行GPS设备连接在引脚4(rx)和3(tx)。
M5.Lcd.println(F("Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum"));
M5.Lcd.println(F(" (deg) (deg) Age Age (m) --- from GPS ---- ---- to London ---- RX RX Fail"));
M5.Lcd.println(F("---------------------------------------------------------------------------------------------------------"));
}
void loop()
{
M5.Lcd.setCursor(0, 70);
M5.Lcd.setTextColor(WHITE, BLACK);
static const double LONDON_LAT = 51.508131, LONDON_LON = -0.128002;
printInt(gps.satellites.value(), gps.satellites.isValid(), 5);
printInt(gps.hdop.value(), gps.hdop.isValid(), 5);
printFloat(gps.location.lat(), gps.location.isValid(), 11, 6);
printFloat(gps.location.lng(), gps.location.isValid(), 12, 6);
printInt(gps.location.age(), gps.location.isValid(), 5);
printDateTime(gps.date, gps.time);
printFloat(gps.altitude.meters(), gps.altitude.isValid(), 7, 2);
printFloat(gps.course.deg(), gps.course.isValid(), 7, 2);
printFloat(gps.speed.kmph(), gps.speed.isValid(), 6, 2);
printStr(gps.course.isValid() ? TinyGPSPlus::cardinal(gps.course.deg()) : "*** ", 6);
unsigned long distanceKmToLondon =
(unsigned long)TinyGPSPlus::distanceBetween(
gps.location.lat(),
gps.location.lng(),
LONDON_LAT,
LONDON_LON) / 1000;
printInt(distanceKmToLondon, gps.location.isValid(), 9);
double courseToLondon =
TinyGPSPlus::courseTo(
gps.location.lat(),
gps.location.lng(),
LONDON_LAT,
LONDON_LON);
printFloat(courseToLondon, gps.location.isValid(), 7, 2);
const char *cardinalToLondon = TinyGPSPlus::cardinal(courseToLondon);
printStr(gps.location.isValid() ? cardinalToLondon : "*** ", 6);
printInt(gps.charsProcessed(), true, 6);
printInt(gps.sentencesWithFix(), true, 10);
printInt(gps.failedChecksum(), true, 9);
M5.Lcd.println();
smartDelay(1000);
if (millis() > 5000 && gps.charsProcessed() < 10)
M5.Lcd.println(F("No GPS data received: check wiring"));
}
// This custom version of delay() ensures that GPS objects work properly. 这个自定义版本的delay()确保gps对象正常工作。
static void smartDelay(unsigned long ms)
{
unsigned long start = millis();
do
{
while (ss.available())
gps.encode(ss.read());
} while (millis() - start < ms);
}
static void printFloat(float val, bool valid, int len, int prec)
{
if (!valid)
{
while (len-- > 1)
M5.Lcd.print('*');
M5.Lcd.print(' ');
}
else
{
M5.Lcd.print(val, prec);
int vi = abs((int)val);
int flen = prec + (val < 0.0 ? 2 : 1); // . and -
flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
for (int i=flen; i<len; ++i)
M5.Lcd.print(' ');
}
smartDelay(0);
}
static void printInt(unsigned long val, bool valid, int len)
{
char sz[32] = "*****************";
if (valid)
sprintf(sz, "%ld", val);
sz[len] = 0;
for (int i=strlen(sz); i<len; ++i)
sz[i] = ' ';
if (len > 0)
sz[len-1] = ' ';
M5.Lcd.print(sz);
smartDelay(0);
}
static void printDateTime(TinyGPSDate &d, TinyGPSTime &t)
{
if (!d.isValid())
{
M5.Lcd.print(F("********** "));
}
else
{
char sz[32];
sprintf(sz, "%02d/%02d/%02d ", d.month(), d.day(), d.year());
M5.Lcd.print(sz);
}
if (!t.isValid())
{
M5.Lcd.print(F("******** "));
}
else
{
char sz[32];
sprintf(sz, "%02d:%02d:%02d ", t.hour(), t.minute(), t.second());
M5.Lcd.print(sz);
}
printInt(d.age(), d.isValid(), 5);
smartDelay(0);
}
static void printStr(const char *str, int len)
{
int slen = strlen(str);
for (int i=0; i<len; ++i)
M5.Lcd.print(i<slen ? str[i] : ' ');
smartDelay(0);
}

View File

@@ -0,0 +1,35 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Hall. 霍尔传感器
* date: 2021/8/18
*******************************************************************************
Please connect to Port B,Displays a string on the screen.
请连接端口B,在屏幕上显示字符串。
Low-level signal can be generated when the magnet S pole is close to the front of the sensor
当磁体S极靠近传感器前端时会产生低电平信号
OR the N pole is close to the back, and the internal LED indicator will light up, the screen wiil display 0.
或N极靠近背面内部LED指示灯亮起屏幕显示0。
*/
#include <M5Core2.h>
#define HALL 36
void setup() {
M5.begin(); //Init M5Core2. 初始化M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.print(" HALL Sensor");
pinMode(HALL, INPUT); //Set the pins to which the Hall sensor is connected to the input mode. 将霍尔传感器所连接的引脚设置为输入模式
}
void loop() {
bool status = digitalRead(HALL);
M5.Lcd.setCursor(20, 80);
M5.Lcd.printf("Hall status : %d", status);
}

View File

@@ -0,0 +1,58 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Heart Rate. 心率
* date: 2021/8/16
*******************************************************************************
Please connect to Port A, HEART Unit obtains the original value of the heart rate detection and displays it on the screen. The user can also use the Arduino IDE Serial Plotter to view the line graph output.
请连接端口A,HEART Unit获取心率检测的原始值并显示在屏幕上。用户还可以使用Arduino IDE Serial Plotter查看线图输出。
*/
#include <M5Core2.h>
#include "MAX30100.h"
#define SAMPLING_RATE MAX30100_SAMPRATE_100HZ
#define IR_LED_CURRENT MAX30100_LED_CURR_24MA
#define RED_LED_CURRENT MAX30100_LED_CURR_27_1MA
#define PULSE_WIDTH MAX30100_SPC_PW_1600US_16BITS
#define HIGHRES_MODE true
MAX30100 sensor; // Instantiate a MAX30100 sensor class. 实例化一个MAX30100传感器类
void setup()
{
M5.begin(); //Init M5Core2. 初始化M5Core2
Serial.print("Initializing MAX30100..");
while (!sensor.begin()) { // Initialize the sensor. 初始化传感器
M5.Lcd.setTextFont(4);
M5.Lcd.setCursor(50, 100, 4);
M5.Lcd.println("Sensor not found");
delay(1000);
}
M5.Lcd.fillScreen(BLACK);
// Set up the wanted parameters. 设置所需的参数
sensor.setMode(MAX30100_MODE_SPO2_HR);
sensor.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT);
sensor.setLedsPulseWidth(PULSE_WIDTH);
sensor.setSamplingRate(SAMPLING_RATE);
sensor.setHighresModeEnabled(HIGHRES_MODE);
}
void loop()
{
uint16_t ir, red;
sensor.update(); //更新传感器读取到的数据
while (sensor.getRawValues(&ir, &red)) { //如果获取到数据
M5.Lcd.setTextFont(4);
M5.Lcd.setCursor(100, 100, 4);
M5.Lcd.printf("IR:%d ",ir);
M5.Lcd.setCursor(100, 130, 4);
M5.Lcd.printf("RED:%d ",red);
}
}

View File

@@ -0,0 +1,154 @@
/*
Description: This example shows how the HEART Unit obtains the original value of the heart rate detection and displays the line graph on the screen. Before the program runs, put the finger to the sensor detection position.
Please install library before compiling:
Arduino-MAX30100: https://github.com/oxullo/Arduino-MAX30100
*/
#include <M5Core2.h>
#include "MAX30100.h"
#include <math.h>
#define SAMPLING_RATE MAX30100_SAMPRATE_50HZ
// The LEDs currents must be set to a level that avoids clipping and maximises the
// dynamic range
#define IR_LED_CURRENT MAX30100_LED_CURR_11MA
#define RED_LED_CURRENT MAX30100_LED_CURR_11MA
// The pulse width of the LEDs driving determines the resolution of
// the ADC (which is a Sigma-Delta).
// set HIGHRES_MODE to true only when setting PULSE_WIDTH to MAX30100_SPC_PW_1600US_16BITS
#define PULSE_WIDTH MAX30100_SPC_PW_400US_14BITS
#define HIGHRES_MODE true
TFT_eSprite Disbuff = TFT_eSprite(&M5.Lcd);
MAX30100 sensor;
uint64_t realTime[4], time_count = 0;
bool k_ready = false;
void setup() {
// put your setup code here, to run once:
M5.begin();
M5.Lcd.setSwapBytes(false);
Disbuff.createSprite(160, 160);
Disbuff.setSwapBytes(true);
Disbuff.createSprite(160, 160);
if (!sensor.begin())
{
Serial.println("FAILED");
for(;;);
}
else
{
Serial.println("SUCCESS");
}
sensor.setMode(MAX30100_MODE_SPO2_HR);
sensor.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT);
sensor.setLedsPulseWidth(PULSE_WIDTH);
sensor.setSamplingRate(SAMPLING_RATE);
sensor.setHighresModeEnabled(HIGHRES_MODE);
sensor.resetFifo();
}
uint16_t line[2][320] = {0};
int16_t k_number[320]={0};
int16_t raw_data[512];
int16_t k_min;
int16_t k_threshold;
uint32_t k_pos_buff[32];
double k_pos_time[32];
double k_standard_deviation, k_sumdata;
uint32_t k_pos, k_pos_count = 0;
uint32_t led_pos = 0, ir_Pos = 0;
uint16_t ir_max = 0, led_max = 0, ir_min = 0, led_min = 0, ir_last = 0, led_last = 0;
int16_t k_number_min = 0, k_number_max = 0, k_last = 0;
uint16_t ir_last_raw = 0, led_last_raw = 0, k_last_raw = 0;
uint16_t ir_disdata, led_disdata, k_disdata;
uint16_t Alpha = 0.3 * 256;
uint16_t count_min = 0, count_max = 0;
void loop() {
// put your main code here, to run repeatedly:
uint16_t ir, red;
//Serial.printf("raed fifo Length :%d\n", read_length);
while(sensor.getRawValues(&ir, &red) == false)
{
delay(10);
sensor.update();
}
while (1)
{
line[0][( led_pos + 160 )%320] = ( led_last_raw * ( 256 - Alpha ) + red * Alpha )/ 256;
line[1][( ir_Pos + 160 )%320] = ( ir_last_raw * ( 256 - Alpha ) + ir * Alpha )/ 256;
k_number[( led_pos + 160 )%320] = line[0][( led_pos + 160 )%320] - led_last_raw;
led_last_raw = line[0][( led_pos + 160 )%320];
ir_last_raw = line[1][( led_pos + 160 )%320];
led_pos ++;
ir_Pos ++;
if(sensor.getRawValues(&ir, &red) == false)
{
break;
}
}
sensor.resetFifo();
for (int i = 0; i < 160; i++)
{
if( i == 0 )
{
led_max = led_min = line[0][( led_pos + i ) %320];
ir_max = ir_min = line[1][( ir_Pos + i ) %320];
k_number_min = k_number_max = k_number[( ir_Pos + i ) %320];
}
else
{
led_max = ( line[0][( led_pos + i ) %320] > led_max ) ? line[0][( led_pos + i ) %320] : led_max;
led_min = ( line[0][( led_pos + i ) %320] < led_min ) ? line[0][( led_pos + i ) %320] : led_min;
ir_max = ( line[1][( ir_Pos + i ) %320] > ir_max ) ? line[1][( ir_Pos + i ) %320] : ir_max;
ir_min = ( line[1][( ir_Pos + i ) %320] < ir_min ) ? line[1][( ir_Pos + i ) %320] : ir_min;
k_number_max = ( k_number[( ir_Pos + i ) %320] > k_number_max ) ? k_number[( ir_Pos + i ) %320] : k_number_max;
k_number_min = ( k_number[( ir_Pos + i ) %320] < k_number_min ) ? k_number[( ir_Pos + i ) %320] : k_number_min;
}
}
Disbuff.fillRect(0,0,160,160,BLACK);
for (int i = 0; i < 160; i++ )
{
led_disdata = map( line[0][( led_pos + i ) %320] , led_max, led_min, 0, 160);
ir_disdata = map( line[1][( ir_Pos + i ) %320] , ir_max, ir_min, 0, 160);
k_disdata = map( k_number[( ir_Pos + i ) %320] , k_number_max, k_number_min, 0, 160);
{
Disbuff.drawLine( i, led_last, i + 1, led_disdata, WHITE);
Disbuff.drawLine( i, ir_last, i + 1, ir_disdata, RED);
Disbuff.drawLine( i, k_last, i + 1, k_disdata, GREEN);
}
ir_last = ir_disdata;
led_last = led_disdata;
k_last = k_disdata;
}
Disbuff.setTextSize(1);
Disbuff.setTextColor(WHITE);
Disbuff.setCursor(5,5);
Disbuff.printf("led:%d,%d,%d",led_max, led_min, led_max - led_min );
Disbuff.setCursor(5,15);
Disbuff.printf("ir:%d,%d,%d",ir_max, ir_min, ir_max - ir_min );
Disbuff.pushSprite(0,0);
delay(10);
}

View File

@@ -0,0 +1,49 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/ir
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/ir
*
* describe: ir.
* date: 2021/8/27
*******************************************************************************
Please connect to Port B,Use IR Unit to receive and test infrared receiving and transmitting
请连接端口B,使用红外单元接收和测试红外接收和发射.
*/
#include <M5Core2.h>
int ir_recv_pin = 36; // set the input pin. 设置引脚
int ir_send_pin = 26;
int last_recv_value = 0;
int cur_recv_value = 0;
void setup() {
M5.begin();
pinMode(ir_recv_pin, INPUT);
pinMode(ir_send_pin, OUTPUT);
//send infrared light. 发送红外线
//now, you can see the infrared light through mobile phone camera. 现在,你可以通过手机摄像头看到红外光
digitalWrite(ir_send_pin, 1);
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(0, 0);
M5.Lcd.print("Test for IR receiver: ");
}
void loop() {
//now, once you press the button on a remote controller to send infrared light. 现在,一旦你按下遥控器上的按钮发送红外线
//the screen will display "detected!" 屏幕将显示“检测到!”
cur_recv_value = digitalRead(ir_recv_pin);
if(last_recv_value != cur_recv_value){
M5.Lcd.setCursor(0, 25);
M5.Lcd.fillRect(0, 25, 150, 25, BLACK);
if(cur_recv_value == 0){ //0: detected 1: not detected, 0检测到,1没有检测到
M5.Lcd.print("detected!");
}
last_recv_value = cur_recv_value;
}
Serial.println(cur_recv_value);
}

View File

@@ -0,0 +1,44 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/iso485
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/iso485
*
* describe: iso485.
* date: 2021/8/30
*******************************************************************************
Please connect to PortC,Pressed ButtonA :send "hello world"
请连接端口C,Pressed ButtonA :send "hello world"
*/
#include <M5Core2.h>
String str = "";
void setup() {
M5.begin(true,false,true,false);
M5.Lcd.drawString("ISO485", 20, 0, 2);
Serial2.begin(115200, SERIAL_8N1, 14, 13);
M5.Lcd.setCursor(0, 20);
}
void loop() {
if (M5.BtnA.wasPressed()){
Serial2.write("Hello World\r\n");
Serial.println("1");
}
if (Serial2.available()) {
char ch = Serial2.read();
str += ch;
Serial.println("2");
if (str.endsWith("\r\n")) {
Serial.print(str);
M5.Lcd.print(str);
str = "";
}
}
M5.update();
}

View File

@@ -0,0 +1,48 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/joystick
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/joystick
*
* describe: JOYSTICK.
* date: 2021/8/30
*******************************************************************************
Please connect to PortA,Read JOYSTICK Unit X, Y axis offset data and button status
请连接端口A,读取操纵杆单位X, Y轴偏移数据和按钮状态
*/
#include <M5Core2.h>
#define JOY_ADDR 0x52 //define Joystick I2C address. 定义摇杆的I2C地址
void setup() {
M5.begin();
M5.Lcd.setCursor(70, 0, 4);
M5.Lcd.println(("Joystick Test"));
dacWrite(25, 0); //disable the speak noise. 禁用语音噪音
Wire.begin(32, 33, 400000UL);
}
char data[100];
void loop() {
static uint8_t x_data, y_data, button_data;
M5.Lcd.setCursor(100, 50, 4);
M5.Lcd.printf("X:%d ", x_data);
M5.Lcd.setCursor(100, 80, 4);
M5.Lcd.printf("Y:%d ", y_data);
M5.Lcd.setCursor(100, 110, 4);
M5.Lcd.printf("B:%d ", button_data);
Wire.requestFrom(
JOY_ADDR,
3); //Request 3 bytes from the slave device. 向从设备请求3个字节
if (Wire.available()) { //If data is received. 如果接收到数据
x_data = Wire.read();
y_data = Wire.read();
button_data = Wire.read();
sprintf(data, "x:%d y:%d button:%d\n", x_data, y_data, button_data);
Serial.print(data);
}
delay(200);
}

View File

@@ -0,0 +1,86 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core sample source code
* 配套 M5Core 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/gray
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/gray
*
* describe: Hall. 霍尔传感器
* date: 2021/8/18
*******************************************************************************
Please connect to Port B,LASER Unit wireless UART application: burn the program to two M5Cores
And connect LASER.TX and LASER.RX
Point LASER.TX to LASER.RX and press the button on the panel to send characters to the receiver of LASER.RX.
请连接端口B,在屏幕上显示字符串。LASER Unit无线UART应用:刻录程序到两个M5Core并分别连接 LASER RX 和 LASER TX
然后按下LASER TX面板上的按钮将字符发送到LASER.RX接收器。
*/
#include <M5Core2.h>
char ch;
#define RX
void setup() {
M5.begin(); //Init M5Core2. 初始化M5Core2
// Serial2.begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert)
Serial2.begin(9600, SERIAL_8N1, 13, 14);
pinMode(5, OUTPUT);
digitalWrite(5, 1);
M5.Lcd.setTextSize(4);
M5.Lcd.setTextColor(GREEN);
M5.Lcd.setCursor(60, 50);
#ifdef RX
M5.Lcd.print("LASER RX");
#elif defined TX
M5.Lcd.print("LASER TX");
#else
M5.Lcd.setCursor(30, 50);
M5.Lcd.print("LASER TX/RX");
M5.Lcd.setCursor(50, 200);
M5.Lcd.print('A');
M5.Lcd.setCursor(150, 200);
M5.Lcd.print('B');
M5.Lcd.setCursor(240, 200);
M5.Lcd.print('C');
#endif
M5.Lcd.setCursor(0, 100);
}
void loop() {
#ifdef RX
M5.update();
if(Serial2.available()) {
char ch = Serial2.read();
M5.Lcd.print(ch);
}
if (M5.BtnA.wasReleased()) {
M5.Lcd.clear();
M5.Lcd.setCursor(0, 0);
}
#elif defined TX
Serial2.write('A');
delay(50);
#else
if (M5.BtnA.wasReleased()) {
ch = 'A';
Serial2.write(ch);
} else if (M5.BtnB.wasReleased()) {
ch = 'B';
Serial2.write(ch);
} else if (M5.BtnC.wasReleased()) {
ch = 'C';
Serial2.write(ch);
}
M5.update();
if(Serial2.available()) {
char ch = Serial2.read();
M5.Lcd.print(ch);
}
#endif
}

View File

@@ -0,0 +1,56 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core sample source code
* 配套 M5Core 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/gray
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/gray
*
* describe: LCD. 显示屏
* date: 2021/8/18
*******************************************************************************
Please connect to Port A,Displays a string on the screen.
请连接端口A,在屏幕上显示字符串。
*/
#include <M5Core2.h>
#include <M5UnitLCD.h>
M5UnitLCD display;
M5Canvas canvas(&display);
static constexpr char text[] = "Hello world ! こんにちは世界! this is long long string sample. 寿限無、寿限無、五劫の擦り切れ、海砂利水魚の、水行末・雲来末・風来末、喰う寝る処に住む処、藪ら柑子の藪柑子、パイポ・パイポ・パイポのシューリンガン、シューリンガンのグーリンダイ、グーリンダイのポンポコピーのポンポコナの、長久命の長助";
static constexpr size_t textlen = sizeof(text) / sizeof(text[0]);
int textpos = 0;
int scrollstep = 2;
void setup(void)
{
M5.begin();
display.init(); //Initialize the display. 初始化显示屏
display.setRotation(3); //Rotating display. 旋转显示屏
canvas.setColorDepth(1); // Set the color depth. 设置色深
canvas.setFont(&fonts::lgfxJapanMinchoP_32); //Set the font. 设置字体
canvas.setTextSize(2); //Set the font size. 设置字号
canvas.createSprite(display.width() + 64, 72); //Create a canvas with a wide display width of +64 and a height of 72. 创建一块宽显示屏宽度+64,高72的画布
}
void loop(void)
{
int32_t cursor_x = canvas.getCursorX() - scrollstep;
if (cursor_x <= 0)
{
textpos = 0;
cursor_x = display.width();
}
canvas.setCursor(cursor_x, 0); //Set the cursor position. 设置光标的位置
canvas.scroll(-scrollstep, 0); //Set the rolling. 设置滚动
while (textpos < textlen && cursor_x <= display.width())
{
canvas.print(text[textpos++]);
cursor_x = canvas.getCursorX();
}
display.waitDisplay();
canvas.pushSprite(&display, 0, (display.height() - canvas.height()) >> 1); //Displays the contents of the canvas. 显示画布上的内容
}

View File

@@ -0,0 +1,36 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Light. 环境光传感器
* date: 2021/8/18
*******************************************************************************
Please connect to Port B,Use the Light Unit screen to display the current ambient lighting value
请连接端口 B ,使用Light Unit 屏幕显示当前环境光照值。
*/
#include <M5Core2.h>
void setup() {
M5.begin(); //Init M5Core2. 初始化M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.printf("UNIT_LIGHT EXAMPLE\n\n");
M5.Lcd.println("Analog:");
M5.Lcd.println("Digital:");
pinMode(26, INPUT); //Set pin 26 as input mode. 设置引脚26为输入模式
}
void loop() {
static uint16_t digitalRead_value = 0, analogRead_value = 0;
analogRead_value = analogRead(36); //Store the analog quantity read from pin 36. 将36号引脚读取到的模拟量存储
digitalRead_value = digitalRead(26); //Store the number read from pin 26. 将26号引脚读取到的数字量存储
M5.Lcd.setCursor(90, 30);
M5.Lcd.printf("%d\n", analogRead_value);
M5.Lcd.setCursor(90, 50);
M5.Lcd.printf("%d\n", digitalRead_value);
delay(10);
}

View File

@@ -0,0 +1,179 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/lorawan470
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/lorawan470
*
* describe: LoRaWAN470.
* date: 2021/8/31
*******************************************************************************
Please connect to Port C,请连接端口C
*/
#include "M5Core2.h"
#include "freertos/queue.h"
#include <M5GFX.h>
M5GFX display;
M5Canvas canvas(&display);
String waitRevice(){
String recvStr;
do{
recvStr = Serial2.readStringUntil('\n');
} while (recvStr.length() == 0);
canvas.println(recvStr);
return recvStr;
}
void sendATCMD(String cmdStr){
Serial2.print(cmdStr);
delay(100);
}
int sendATCMDAndRevice(String cmdStr){
Serial2.print(cmdStr);
delay(100);
waitRevice();
String recvStr = waitRevice();
if (recvStr.indexOf("OK") != -1){
return 0;
}else{
return -1;
}
}
void setup()
{
M5.begin();
Serial2.begin(115200, SERIAL_8N1, 13, 14);
Serial2.flush();
delay(100);
display.begin();
display.setTextSize(2);
canvas.setColorDepth(1); // mono color
canvas.createSprite(display.width(), display.height());
canvas.setTextSize((float)canvas.width() / 160);
canvas.setTextScroll(true);
sendATCMD("AT?\r\n");
delay(100);
Serial2.flush();
sendATCMDAndRevice("AT+ILOGLVL=0\r\n");
sendATCMDAndRevice("AT+CSAVE\r\n");
sendATCMDAndRevice("AT+IREBOOT=0\r\n");
display.println("LoraWan Rebooting");
delay(2000);
display.println("LoraWan config");
//Set Join Mode OTAA.
sendATCMDAndRevice("AT+CJOINMODE=0\r\n");
sendATCMDAndRevice("AT+CDEVEUI=0037CAE1FC3542B9\r\n");
sendATCMDAndRevice("AT+CAPPEUI=70B3D57ED003E04E\r\n");
sendATCMDAndRevice("AT+CAPPKEY=67FA4ED1075A20573BCDD7594C458698\r\n");
sendATCMDAndRevice("AT+CULDLMODE=2\r\n");
//Set ClassC mode
sendATCMDAndRevice("AT+CCLASS=2\r\n");
sendATCMDAndRevice("AT+CWORKMODE=2\r\n");
sendATCMDAndRevice("AT+CRXP=0,0,505300000\r\n");
// TX Freq
// 486.3
// 486.5
// 486.7
// 486.9
// 487.1
// 487.3
// 487.5
// 487.7
//MARK 0000 0100 0000 0000 | 0x0400
sendATCMDAndRevice("AT+CFREQBANDMASK=0400\r");
// RX Freq
//506.7 (RX1)
//506.9 (RX1)
//507.1 (RX1)
//507.3 (RX1)
//507.5 (RX1)
//507.7 (RX1)
//507.9 (RX1)
//508.1 (RX1)
//505.3 (RX2)| 505300000
sendATCMDAndRevice("AT+CJOIN=1,0,10,8\r\n");
}
enum systemstate{
kIdel = 0,
kJoined,
kSending,
kWaitSend,
kEnd,
};
int system_fsm = kIdel;
int loraWanSendNUM = -1;
int loraWanSendCNT = -1;
void loop()
{
String recvStr = waitRevice();
if (recvStr.indexOf("+CJOIN:") != -1)
{
if (recvStr.indexOf("OK") != -1)
{
canvas.printf("LoraWan JOIN");
system_fsm = kJoined;
}
else
{
canvas.printf("LoraWan JOIN FAIL");
system_fsm = kIdel;
}
}
else if (recvStr.indexOf("OK+RECV") != -1)
{
if (system_fsm == kJoined)
{
system_fsm = kSending;
}
else if (system_fsm == kWaitSend)
{
system_fsm = kSending;
char strbuff[128];
if(( loraWanSendCNT < 5 )&&( loraWanSendNUM == 8 ))
{
sprintf(strbuff,"TSET OK CNT: %d",loraWanSendCNT);
canvas.print(strbuff);
}
else
{
sprintf(strbuff,"FAILD NUM:%d CNT:%d",loraWanSendNUM,loraWanSendCNT);
canvas.print(strbuff);
}
}
}
else if(recvStr.indexOf("OK+SEND") != -1)
{
String snednum = recvStr.substring(8);
canvas.printf(" [ INFO ] SEND NUM %s \r\n",snednum.c_str());
loraWanSendNUM = snednum.toInt();
}
else if(recvStr.indexOf("OK+SENT") != -1)
{
String snedcnt = recvStr.substring(8);
canvas.printf(" [ INFO ] SEND CNT %s \r\n",snedcnt.c_str());
loraWanSendCNT = snedcnt.toInt();
}
if (system_fsm == kSending)
{
canvas.println("LoraWan Sending");
sendATCMD("AT+DTRX=1,8,8,4655434b20535443\r\n");
system_fsm = kWaitSend;
}
canvas.pushSprite(0, 0);
delay(10);
}

View File

@@ -0,0 +1,224 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/lorawan868
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/lorawan868
*
* describe: LoRaWAN868.
* date: 2021/8/31
*******************************************************************************
Please connect to Port C,请连接端口C
*/
#include "M5Core2.h"
#include "freertos/queue.h"
#include <M5GFX.h>
M5GFX display;
M5Canvas canvas(&display);
String waitRevice()
{
String recvStr;
do
{
recvStr = Serial2.readStringUntil('\n');
} while (recvStr.length() == 0);
canvas.println(recvStr);
return recvStr;
}
uint16_t ypos = 55;
void drawLineStr(String str, uint16_t color)
{
M5.Lcd.setTextColor(color);
M5.Lcd.drawString(str, 10, ypos, 4);
ypos += 32;
}
void sendATCMD(String cmdStr)
{
Serial2.print(cmdStr);
delay(100);
}
int sendATCMDAndRevice(String cmdStr)
{
Serial2.print(cmdStr);
delay(10);
waitRevice();
String recvStr = waitRevice();
if (recvStr.indexOf("OK") != -1)
{
return 0;
}
else
{
return -1;
}
}
void setup()
{
M5.begin();
Serial2.begin(115200, SERIAL_8N1, 13, 14);
Serial2.flush();
delay(100);
display.begin();
display.setTextSize(2);
display.println("LoRaWAN868");
canvas.setColorDepth(1); // mono color
canvas.createSprite(display.width(), display.height());
canvas.setTextSize((float)canvas.width() / 160);
canvas.setTextScroll(true);
sendATCMD("AT?\r");
delay(100);
Serial2.flush();
sendATCMDAndRevice("AT+ILOGLVL=0\r");
sendATCMDAndRevice("AT+CSAVE\r");
sendATCMDAndRevice("AT+IREBOOT=0\r");
display.println("LoraWan Rebooting");
delay(2000);
display.println("LoraWan config");
sendATCMDAndRevice("AT+CJOINMODE=0\r");
sendATCMDAndRevice("AT+CDEVEUI=00bb9da5b97addf1\r");
sendATCMDAndRevice("AT+CAPPEUI=70B3D57ED004247E\r");//70B3D57ED003B699
sendATCMDAndRevice("AT+CAPPKEY=27DFE264CA33AC1957C005EB48BA4721\r");
sendATCMDAndRevice("AT+CULDLMODE=2\r");
sendATCMDAndRevice("AT+CCLASS=2\r");
sendATCMDAndRevice("AT+CWORKMODE=2\r");
sendATCMDAndRevice("AT+CNBTRIALS=0,5\r");
sendATCMDAndRevice("AT+CNBTRIALS=1,5\r");
// TX Freq
// 868.1 - SF7BW125 to SF12BW125
// 868.3 - SF7BW125 to SF12BW125 and SF7BW250
// 868.5 - SF7BW125 to SF12BW125
// 867.1 - SF7BW125 to SF12BW125
// 867.3 - SF7BW125 to SF12BW125
// 867.5 - SF7BW125 to SF12BW125
// 867.7 - SF7BW125 to SF12BW125
// 867.9 - SF7BW125 to SF12BW125
// 868.8 - FSK
sendATCMDAndRevice("AT+CFREQBANDMASK=0001\r");
//869.525 - SF9BW125 (RX2) | 869525000
//sendATCMDAndRevice("AT+CRXP=0,0,869525000\r");
sendATCMDAndRevice("AT+CSAVE\r");
sendATCMDAndRevice("AT+CJOIN=1,0,10,8\r");
}
enum systemstate
{
kIdel = 0,
kJoined,
kSending,
kWaitSend,
kEnd,
};
int system_fsm = kIdel;
int loraWanSendNUM = -1;
int loraWanSendCNT = -1;
int loraWanupLinkCNT = 0;
int loraWanupLinkReviceCNT = 0;
void loop()
{
String recvStr = waitRevice();
if (recvStr.indexOf("+CJOIN:") != -1)
{
if (recvStr.indexOf("OK") != -1)
{
canvas.println("[ INFO ] JOIN IN SUCCESSFUL");
system_fsm = kJoined;
}
else
{
canvas.println("[ INFO ] JOIN IN FAIL");
system_fsm = kIdel;
}
}
else if (recvStr.indexOf("OK+RECV") != -1)
{
if (system_fsm == kJoined)
{
system_fsm = kSending;
}
else if (system_fsm == kWaitSend)
{
system_fsm = kEnd;
char strbuff[128];
loraWanupLinkReviceCNT ++;
//if(( loraWanSendCNT < 5 )&&( loraWanSendNUM == 8 ))
//{
// loraWanupLinkReviceCNT ++;
// sprintf(strbuff,"SEND CNT: %d (%d/%d)",loraWanSendCNT,loraWanupLinkReviceCNT,loraWanupLinkCNT);
// M5.Lcd.fillRect(0,183,320,32,TFT_BLACK);
// M5.Lcd.setTextColor(TFT_GREEN);
// M5.Lcd.drawString(strbuff, 10, 183, 4);
// //drawLineStr(strbuff, TFT_GREEN);
//
//}
//else
//{
// sprintf(strbuff,"FAILD NUM:%d CNT:%d (%d/%d)",loraWanSendNUM,loraWanSendCNT,loraWanupLinkReviceCNT,loraWanupLinkCNT);
// M5.Lcd.fillRect(0,183,320,32,TFT_BLACK);
// M5.Lcd.setTextColor(TFT_RED);
// M5.Lcd.drawString(strbuff, 10, 183, 4);
// drawLineStr(strbuff, TFT_RED);
//}
delay(500);
system_fsm = kSending;
}
}
else if(recvStr.indexOf("OK+SEND") != -1)
{
String snednum = recvStr.substring(8);
canvas.printf(" [ INFO ] SEND NUM %s \r\n",snednum.c_str());
loraWanSendNUM = snednum.toInt();
}
else if(recvStr.indexOf("OK+SENT") != -1)
{
String snedcnt = recvStr.substring(8);
canvas.printf(" [ INFO ] SEND CNT %s \r\n",snedcnt.c_str());
loraWanSendCNT = snedcnt.toInt();
}
else if(recvStr.indexOf("ERR+SENT") != -1)
{
char strbuff[128];
String ErrorCodeStr = recvStr.substring(9);
sprintf(strbuff,"ERROR Code:%d (%d/%d)",ErrorCodeStr.toInt(),loraWanupLinkReviceCNT,loraWanupLinkCNT);
canvas.println(strbuff);
delay(500);
system_fsm = kSending;
}
else if(recvStr.indexOf("+CLINKCHECK:") != -1)
{
String checkStr = recvStr.substring(String("+CLINKCHECK:").length());
char strbuff[128];
sprintf(strbuff,"%s (%d/%d)",checkStr.c_str(),loraWanupLinkReviceCNT,loraWanupLinkCNT);
canvas.println(strbuff);
}
if (system_fsm == kSending)
{
canvas.println("LoraWan Sending");
sendATCMD("AT+CLINKCHECK=1\r");
loraWanupLinkCNT ++;
system_fsm = kWaitSend;
}
canvas.pushSprite(0, 0);
delay(10);
}

View File

@@ -0,0 +1,39 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/ncir
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/ncir
*
* describe: ncir. 单点红外测温传感器
* date: 2021/8/27
*******************************************************************************
Please connect to Port A,Use NCIR Unit to measure the temperature without contact and display the value on the screen.
请连接端口A,使用NCIR单元无接触测量温度并在屏幕上显示。
*/
#include <M5Core2.h>
void setup() {
M5.begin();
Wire.begin();
M5.Lcd.setTextSize(3);
M5.Lcd.setCursor(120, 0);
M5.Lcd.print("NCIR");
}
void loop() {
static uint16_t result;
static float temperature;
Wire.beginTransmission(0x5A); // Send Initial Signal and I2C Bus Address 发送初始信号和I2C总线地址
Wire.write(0x07); // Send data only once and add one address automatically. 只发送一次数据,并自动添加一个地址。
Wire.endTransmission(false); // Stop signal 停止信号
Wire.requestFrom(0x5A, 2); // Get 2 consecutive data from 0x5A, and the data is stored only. 从0x5A中获取2个连续的数据并且只存储这些数据。
result = Wire.read(); // Receive DATA 接收数据
result |= Wire.read() << 8; // Receive DATA 接收数据
temperature = result * 0.02 - 273.15;
M5.Lcd.setCursor(70, 100);
M5.Lcd.printf("Temp:%.3f",temperature);
delay(500);
}

View File

@@ -0,0 +1,55 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/oled
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/oled
*
* describe: OLED. 显示屏
* date: 2021/8/31
*******************************************************************************
Please connect to Port A,Displays a string on the screen.
请连接端口A,在屏幕上显示字符串。
*/
#include <M5UnitOLED.h>
M5UnitOLED display;
M5Canvas canvas(&display);
static constexpr char text[] = "Hello world ! こんにちは世界! this is long long string sample. 寿限無、寿限無、五劫の擦り切れ、海砂利水魚の、水行末・雲来末・風来末、喰う寝る処に住む処、藪ら柑子の藪柑子、パイポ・パイポ・パイポのシューリンガン、シューリンガンのグーリンダイ、グーリンダイのポンポコピーのポンポコナの、長久命の長助";
static constexpr size_t textlen = sizeof(text) / sizeof(text[0]);
int textpos = 0;
int scrollstep = 2;
void setup(void)
{
display.init(); //Initialize the display. 初始化显示屏
display.setRotation(2); //Rotating display. 旋转显示屏
canvas.setColorDepth(1); // Set the color depth. 设置色深
canvas.setFont(&fonts::lgfxJapanMinchoP_32); //Set the font. 设置字体
canvas.setTextWrap(false);
canvas.setTextSize(2); //Set the font size. 设置字号
canvas.createSprite(display.width() + 64, 72); //Create a canvas with a wide display width of +64 and a height of 72. 创建一块宽显示屏宽度+64,高72的画布
}
void loop(void)
{
int32_t cursor_x = canvas.getCursorX() - scrollstep;
if (cursor_x <= 0)
{
textpos = 0;
cursor_x = display.width();
}
canvas.setCursor(cursor_x, 0); //Set the cursor position. 设置光标的位置
canvas.scroll(-scrollstep, 0); //Set the rolling. 设置滚动
while (textpos < textlen && cursor_x <= display.width())
{
canvas.print(text[textpos++]);
cursor_x = canvas.getCursorX();
}
display.waitDisplay();
canvas.pushSprite(&display, 0, (display.height() - canvas.height()) >> 1); //Displays the contents of the canvas. 显示画布上的内容
}

View File

@@ -0,0 +1,29 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: OP 180/90. 非接触式光电限位开关
* date: 2021/8/16
*******************************************************************************
Please connect to Port B,Detect the current OP 90/180 Unit Photoelectric switch status.
请连接端口B,检测当前OP 90/180单元光电开关状态。
*/
#include <M5Core2.h>
void setup() {
M5.begin(); //Init M5Core2. 初始化M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.setCursor(80, 10); //Set the cursor at (80,10). 将光标设置在(80,10)处
M5.Lcd.println("90/180 OPTICAL");
pinMode(36,INPUT_PULLUP); //Set pin 36 to input pull-up mode. 设置36号引脚为输入上拉模式
}
void loop() {
M5.Lcd.setCursor(80, 120);
M5.Lcd.printf("IR Receive: %d",digitalRead(36)); //Output the value of pin 36. 输出36号引脚的值
}

View File

@@ -0,0 +1,196 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/pdm
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/pdm
*
* describe: pdm. 麦克风
* date: 2022/3/12
*******************************************************************************
Please connect to Port A,Read the microphone data of the PDM Unit and display
the audio frequency spectrum. 请连接端口A,读取PDM
Unit的麦克风数据显示音频频谱。 Note: Remove the M5GO base when using this
example, otherwise it will not work properly 注意:在使用本示例时删除M5GO
base否则它将无法正常工作
*/
#include <M5Core2.h>
#include <driver/i2s.h>
#include "fft.h"
#define PIN_CLK 33
#define PIN_DATA 32
#define MODE_MIC 0
TFT_eSprite DisFFTbuff = TFT_eSprite(&M5.Lcd);
static QueueHandle_t fftvalueQueue = nullptr;
static QueueHandle_t i2sstateQueue = nullptr;
typedef struct {
uint8_t state;
void* audioPtr;
uint32_t audioSize;
} i2sQueueMsg_t;
bool InitI2SSpakerOrMic(int mode) {
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER), // Set the I2S operating mode.
// 设置I2S工作模式
.sample_rate = 44100, // Set the I2S sampling rate. 设置I2S采样率
.bits_per_sample =
I2S_BITS_PER_SAMPLE_16BIT, // Fixed 12-bit stereo MSB.
// 固定为12位立体声MSB
.channel_format =
I2S_CHANNEL_FMT_ONLY_RIGHT, // Set the channel format. 设置频道格式
#if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 1, 0)
.communication_format =
I2S_COMM_FORMAT_STAND_I2S, // Set the format of the communication.
#else // 设置通讯格式
.communication_format = I2S_COMM_FORMAT_I2S,
#endif
.intr_alloc_flags =
ESP_INTR_FLAG_LEVEL1, // Set the interrupt flag. 设置中断的标志
.dma_buf_count = 2, // DMA buffer count. DMA缓冲区计数
.dma_buf_len = 128, // DMA buffer length. DMA缓冲区长度
};
if (mode == MODE_MIC) {
i2s_config.mode =
(i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM);
}
i2s_driver_install(I2S_NUM_0, &i2s_config, 0,
NULL); // Install and drive I2S. 安装并驱动I2S
i2s_pin_config_t pin_config;
#if (ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 3, 0))
tx_pin_config.mck_io_num = I2S_PIN_NO_CHANGE;
#endif
pin_config.bck_io_num = I2S_PIN_NO_CHANGE;
pin_config.ws_io_num = PIN_CLK;
pin_config.data_out_num = I2S_PIN_NO_CHANGE;
pin_config.data_in_num = PIN_DATA;
i2s_set_pin(I2S_NUM_0, &pin_config);
i2s_set_clk(I2S_NUM_0, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
return true;
}
static void i2sMicroFFTtask(void* arg) {
uint8_t FFTDataBuff[128];
uint8_t FFTValueBuff[24];
uint8_t* microRawData = (uint8_t*)calloc(2048, sizeof(uint8_t));
size_t bytesread;
int16_t* buffptr;
double data = 0;
float adc_data;
uint16_t ydata;
uint32_t subData;
uint8_t state = MODE_MIC;
i2sQueueMsg_t QueueMsg;
while (1) {
if (xQueueReceive(i2sstateQueue, &QueueMsg, (TickType_t)0) == pdTRUE) {
// Serial.println("Queue Now");
if (QueueMsg.state == MODE_MIC) {
InitI2SSpakerOrMic(MODE_MIC);
state = MODE_MIC;
}
} else if (state == MODE_MIC) {
fft_config_t* real_fft_plan =
fft_init(1024, FFT_REAL, FFT_FORWARD, NULL, NULL);
i2s_read(I2S_NUM_0, (char*)microRawData, 2048, &bytesread,
(100 / portTICK_RATE_MS));
buffptr = (int16_t*)microRawData;
for (int count_n = 0; count_n < real_fft_plan->size; count_n++) {
adc_data = (float)map(buffptr[count_n], INT16_MIN, INT16_MAX,
-2000, 2000);
real_fft_plan->input[count_n] = adc_data;
}
fft_execute(real_fft_plan);
for (int count_n = 1; count_n < real_fft_plan->size / 4;
count_n++) {
data = sqrt(real_fft_plan->output[2 * count_n] *
real_fft_plan->output[2 * count_n] +
real_fft_plan->output[2 * count_n + 1] *
real_fft_plan->output[2 * count_n + 1]);
if ((count_n - 1) < 128) {
data = (data > 2000) ? 2000 : data;
ydata = map(data, 0, 2000, 0, 255);
FFTDataBuff[128 - count_n] = ydata;
}
}
for (int count = 0; count < 24; count++) {
subData = 0;
for (int count_i = 0; count_i < 5; count_i++) {
subData += FFTDataBuff[count * 5 + count_i];
}
subData /= 5;
FFTValueBuff[count] = map(subData, 0, 255, 0, 8);
}
xQueueSend(fftvalueQueue, (void*)&FFTValueBuff, 0);
fft_destroy(real_fft_plan);
} else {
delay(10);
}
}
}
void microPhoneSetup() {
fftvalueQueue = xQueueCreate(5, 24 * sizeof(uint8_t));
if (fftvalueQueue == 0) {
return;
}
i2sstateQueue = xQueueCreate(5, sizeof(i2sQueueMsg_t));
if (i2sstateQueue == 0) {
return;
}
InitI2SSpakerOrMic(MODE_MIC);
xTaskCreatePinnedToCore(i2sMicroFFTtask, "microPhoneTask", 4096, NULL, 3,
NULL, 0);
DisFFTbuff.createSprite(320, 54);
}
void MicroPhoneFFT() {
uint8_t FFTValueBuff[24];
xQueueReceive(fftvalueQueue, (void*)&FFTValueBuff, portMAX_DELAY);
DisFFTbuff.fillRect(0, 0, 320, 54, DisFFTbuff.color565(0x00, 0x00, 0x00));
uint32_t colorY = DisFFTbuff.color565(0xff, 0x9c, 0x00);
uint32_t colorG = DisFFTbuff.color565(0x66, 0xff, 0x00);
uint32_t colorRect;
for (int x = 0; x < 24; x++) {
for (int y = 0; y < 9; y++) {
if (y < FFTValueBuff[23 - x]) {
colorRect = colorY;
} else if (y == FFTValueBuff[23 - x]) {
colorRect = colorG;
} else {
continue;
}
DisFFTbuff.fillRect(x * 12, 54 - y * 6 - 5, 5, 5, colorRect);
}
}
DisFFTbuff.pushSprite(20, 120);
}
void setup() {
M5.begin(true, true, true, true);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextSize(1);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.fillRect(0, 0, 320, 30, BLACK);
M5.Lcd.setTextDatum(TC_DATUM);
M5.Lcd.drawString("PDM Unit", 160, 3, 4);
microPhoneSetup();
}
void loop() { MicroPhoneFFT(); }

View File

@@ -0,0 +1,38 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: PIR. 人体红外
* date: 2021/8/11
*******************************************************************************
Please connect to Port B,Human body detection using PIR Unit.
请连接端口B,使用PIR Unit进行人体检测。
*/
#include <M5Core2.h>
void setup() {
M5.begin(); //Init M5Core2. 初始化 M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.println("PIR example");
M5.Lcd.setCursor(0, 25); //Position the cursor at (0,25). 将光标固定在(0,25)
M5.Lcd.println("Status: \nValue: ");
pinMode(36, INPUT); //Set pin 36 to input mode. 设置36号引脚为输入模式
}
void loop() {
M5.Lcd.fillRect(90,25,180,50,BLACK); //Draw a black rectangle 180 by 50 at (90,25). 在(90,25)处画一个宽180高50的黑的矩形
if(digitalRead(36)==1){ //If pin 36 reads a value of 1. 如果36号引脚的读取到的值为1
M5.Lcd.setCursor(95, 25);M5.Lcd.print("Sensing");
M5.Lcd.setCursor(95, 45);M5.Lcd.print("1");
}
else{
M5.Lcd.setCursor(95, 25);M5.Lcd.print("Not Sensed");
M5.Lcd.setCursor(95, 45);M5.Lcd.print("0");
}
delay(500);
}

View File

@@ -0,0 +1,64 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/pahub
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/pahub
*
* describe: PaHUB.
* date: 2021/8/31
*******************************************************************************
Please connect to Port A, Use PaHUB Unit to expand multiple I2C devices and scan the I2C addresses of the slave devices in order.
请连接端口A, 使用PaHUB Unit扩展多个I2C设备并依次扫描从设备的I2C地址。
*/
#include <M5Core2.h>
#include "ClosedCube_TCA9548A.h"
#define FRONT 2
#define X_LOCAL 100
#define Y_LOCAL 35
#define X_OFFSET 160
#define Y_OFFSET 34
#define PaHub_I2C_ADDRESS 0x70
ClosedCube::Wired::TCA9548A tca9548a;
void setup()
{
M5.begin();
Wire.begin();
tca9548a.address(PaHub_I2C_ADDRESS); //Set the I2C address. 设置I2C地址
M5.Lcd.setTextFont(4);
M5.Lcd.setCursor(70, 0, 4);
M5.Lcd.setTextColor(YELLOW,TFT_BLACK);
M5.Lcd.println(("PaHUB Example"));
M5.Lcd.setTextColor(TFT_WHITE,TFT_BLACK);
}
void loop()
{
uint8_t returnCode = 0;
uint8_t address;
for( uint8_t channel=0; channel<TCA9548A_MAX_CHANNELS; channel++ ) {
M5.Lcd.setCursor(X_LOCAL, Y_LOCAL + Y_OFFSET*channel , FRONT);
M5.Lcd.printf(" ");
M5.Lcd.setCursor(X_LOCAL, Y_LOCAL + Y_OFFSET*channel , FRONT);
M5.Lcd.printf("CH%d : ",channel);
returnCode = tca9548a.selectChannel(channel);
if( returnCode == 0 ) {
for(address = 0x01; address < 0x7F; address++ ) {
Wire.beginTransmission(address);
returnCode = Wire.endTransmission();
if (returnCode == 0) {
Serial.print("I2C device = ");
M5.Lcd.printf("0X%X ",address);
}
}
}
delay(200);
}
}

View File

@@ -0,0 +1,36 @@
/*
Description: Use Pbhub to read the analog input value of the slave device, or drive multiple sets of RGB LEDs.
*/
#include <M5Core2.h>
#include <Wire.h>
#include "porthub.h"
#define X_OFFSET 10
#define Y_OFFSET 18
PortHub porthub;
uint8_t HUB_ADDR[6]={HUB1_ADDR,HUB2_ADDR,HUB3_ADDR,HUB4_ADDR,HUB5_ADDR,HUB6_ADDR};
void setup() {
M5.begin(true, false, true);
porthub.begin();
M5.Lcd.clear(BLACK);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setTextSize(4);
}
void loop() {
M5.Lcd.clear(BLACK);
for(int i = 0; i < 6; i++){
M5.Lcd.setCursor(8*X_OFFSET,(i*2)*Y_OFFSET);
M5.Lcd.printf("%d:%d",i+1,porthub.hub_a_read_value(HUB_ADDR[i]));
}
for(int i = 0; i < 6; i++){
porthub.hub_wire_setBrightness(HUB_ADDR[i],1);
porthub.hub_wire_fill_color(HUB_ADDR[i],0,15,250,250,250);
}
delay(1000);
}

View File

@@ -0,0 +1,146 @@
#include "porthub.h"
PortHub::PortHub(){
}
void PortHub::begin(){
Wire.begin();
}
uint16_t PortHub::hub_a_read_value(uint8_t reg){
Wire.beginTransmission(IIC_ADDR);
Wire.write(reg | 0x06);
Wire.endTransmission();
uint8_t RegValue_L,RegValue_H;
Wire.requestFrom(IIC_ADDR,2);
while(Wire.available()){
RegValue_L = Wire.read();
RegValue_H = Wire.read();
}
return (RegValue_H<<8) | RegValue_L;
}
uint8_t PortHub::hub_d_read_value_A(uint8_t reg){
Wire.beginTransmission(IIC_ADDR);
Wire.write(reg | 0x04);
Wire.endTransmission();
uint8_t RegValue;
Wire.requestFrom(IIC_ADDR,1);
while(Wire.available()){
RegValue = Wire.read();
}
return RegValue;
}
uint8_t PortHub::hub_d_read_value_B(uint8_t reg){
Wire.beginTransmission(IIC_ADDR);
Wire.write(reg | 0x05);
Wire.endTransmission();
uint8_t RegValue;
Wire.requestFrom(IIC_ADDR,1);
while(Wire.available()){
RegValue = Wire.read();
}
return RegValue;
}
void PortHub::hub_d_wire_value_A(uint8_t reg,uint16_t level){
Wire.beginTransmission(IIC_ADDR);
Wire.write(reg | 0x00);
Wire.write(level & 0xff);
Wire.endTransmission();
}
void PortHub::hub_d_wire_value_B(uint8_t reg,uint16_t level){
Wire.beginTransmission(IIC_ADDR);
Wire.write(reg | 0x01);
Wire.write(level & 0xff);
Wire.endTransmission();
}
void PortHub::hub_a_wire_value_A(uint8_t reg,uint16_t duty){
Wire.beginTransmission(IIC_ADDR);
Wire.write(reg | 0x02);
Wire.write(duty & 0xff);
Wire.endTransmission();
}
void PortHub::hub_a_wire_value_B(uint8_t reg,uint16_t duty){
Wire.beginTransmission(IIC_ADDR);
Wire.write(reg | 0x03);
Wire.write(duty & 0xff);
Wire.endTransmission();
}
void PortHub::hub_wire_length(uint8_t reg,uint16_t length){
Wire.beginTransmission(IIC_ADDR);
Wire.write(reg | 0x08);
Wire.write(length & 0xff);
Wire.write(length>>8);
Wire.endTransmission();
}
void PortHub::hub_wire_index_color(uint8_t reg,uint16_t num,uint8_t r,int8_t g,uint8_t b){
Wire.beginTransmission(IIC_ADDR);
Wire.write(reg | 0x09);
Wire.write(num & 0xff);
Wire.write(num>>8);
Wire.write(r);
Wire.write(g);
Wire.write(b);
Wire.endTransmission();
}
void PortHub::hub_wire_fill_color(uint8_t reg,uint16_t first, uint16_t count, uint8_t r,int8_t g,uint8_t b){
Wire.beginTransmission(IIC_ADDR);
Wire.write(reg | 0x0a);
Wire.write(first & 0xff);
Wire.write(first>>8);
Wire.write(count & 0xff);
Wire.write(count>>8);
Wire.write(r);
Wire.write(g);
Wire.write(b);
Wire.endTransmission();
}
void PortHub::hub_wire_setBrightness(uint8_t reg,uint8_t brightness){
Wire.beginTransmission(IIC_ADDR);
Wire.write(reg | 0x0b);
Wire.write(brightness & 0xff);
Wire.endTransmission();
}

View File

@@ -0,0 +1,50 @@
#ifndef __PORTHUB_H__
#define __PORTHUB_H__
#include <Wire.h>
#define IIC_ADDR 0x61
#define HUB1_ADDR 0x40
#define HUB2_ADDR 0x50
#define HUB3_ADDR 0x60
#define HUB4_ADDR 0x70
#define HUB5_ADDR 0x80
#define HUB6_ADDR 0xA0
class PortHub {
public:
PortHub();
void begin();
uint16_t hub_a_read_value(uint8_t reg);
uint8_t hub_d_read_value_A(uint8_t reg);
uint8_t hub_d_read_value_B(uint8_t reg);
void hub_d_wire_value_A(uint8_t reg,uint16_t level);
void hub_d_wire_value_B(uint8_t reg,uint16_t level);
void hub_a_wire_value_A(uint8_t reg,uint16_t duty);
void hub_a_wire_value_B(uint8_t reg,uint16_t duty);
void hub_wire_length(uint8_t reg,uint16_t length);
void hub_wire_index_color(uint8_t reg,uint16_t num,uint8_t r,int8_t g,uint8_t b);
void hub_wire_fill_color(uint8_t reg,uint16_t first, uint16_t count, uint8_t r,int8_t g,uint8_t b);
void hub_wire_setBrightness(uint8_t reg,uint8_t brightness);
public:
private:
private:
};
#endif

View File

@@ -0,0 +1,88 @@
/*
Description:
Use UNIT PoESP32 to create HTTP request
UNIT PoESP32 Connect to M5Core2 PORT-C (G13/14)
before compiling:
M5Core2: https://github.com/m5stack/M5Core2
M5GFX: https://github.com/m5stack/M5GFX
UNIT_PoESP32: https://github.com/m5stack/UNIT_PoESP32
*/
#include "UNIT_PoESP32.h"
#include "M5Core2.h"
#include "M5GFX.h"
UNIT_PoESP32 eth;
String readstr;
M5GFX display;
M5Canvas canvas(&display);
void setup() {
M5.begin();
display.begin();
canvas.setColorDepth(1); // mono color
canvas.setFont(&fonts::efontCN_14);
canvas.setTextSize(2);
canvas.setPaletteColor(1, GREEN);
canvas.createSprite(display.width(), display.height());
canvas.setTextScroll(true);
eth.Init(&Serial2, 9600, 13, 14);
delay(10);
canvas.println("wait device connect");
canvas.pushSprite(0, 0);
while (!eth.checkDeviceConnect()) {
delay(10);
}
canvas.println("device connected");
canvas.println("wait ethernet connect");
canvas.pushSprite(0, 0);
while (!eth.checkETHConnect()) {
delay(10);
}
canvas.println("ethernet connected");
canvas.pushSprite(0, 0);
readstr = eth.createHTTPClient(HEAD, APPLICATION_X_WWW_FORM_URLENCODED,
"http://httpbin.org/get");
Serial.println(readstr);
canvas.println(readstr);
canvas.pushSprite(0, 0);
readstr = eth.createHTTPClient(GET, APPLICATION_X_WWW_FORM_URLENCODED,
"http://httpbin.org/get");
Serial.println(readstr);
canvas.println(readstr);
canvas.pushSprite(0, 0);
readstr = eth.createHTTPClient(POST, APPLICATION_X_WWW_FORM_URLENCODED,
"http://httpbin.org/post",
"field1=value1&field2=value2");
Serial.println(readstr);
canvas.println(readstr);
canvas.pushSprite(0, 0);
readstr = eth.createHTTPClient(PUT, APPLICATION_X_WWW_FORM_URLENCODED,
"http://httpbin.org/put");
Serial.println(readstr);
canvas.println(readstr);
canvas.pushSprite(0, 0);
readstr = eth.createHTTPClient(DELETE, APPLICATION_X_WWW_FORM_URLENCODED,
"http://httpbin.org/delete");
Serial.println(readstr);
canvas.println(readstr);
canvas.pushSprite(0, 0);
}
void loop() {
if (Serial.available()) {
char ch = Serial.read();
Serial2.write(ch);
}
if (Serial2.available()) {
char ch = Serial2.read();
Serial.write(ch);
}
}

View File

@@ -0,0 +1,68 @@
/*
Description:
Use UNIT PoESP32 connect to MQTT Server
UNIT PoESP32 Connect to M5Core2 PORT-C (G13/14)
before compiling:
M5Core2: https://github.com/m5stack/M5Core2
M5GFX: https://github.com/m5stack/M5GFX
UNIT_PoESP32: https://github.com/m5stack/UNIT_PoESP32
*/
#include "UNIT_PoESP32.h"
#include "M5Core2.h"
#include "M5GFX.h"
UNIT_PoESP32 eth;
String readstr;
M5GFX display;
M5Canvas canvas(&display);
void setup() {
M5.begin();
display.begin();
canvas.setColorDepth(1); // mono color
canvas.setFont(&fonts::efontCN_14);
canvas.setTextSize(2);
canvas.setPaletteColor(1, GREEN);
canvas.createSprite(display.width(), display.height());
canvas.setTextScroll(true);
eth.Init(&Serial2, 9600, 13, 14);
delay(10);
canvas.println("wait device connect");
canvas.pushSprite(0, 0);
while (!eth.checkDeviceConnect()) {
delay(10);
}
canvas.println("device connected");
canvas.println("wait ethernet connect");
canvas.pushSprite(0, 0);
while (!eth.checkETHConnect()) {
delay(10);
}
canvas.println("ethernet connected");
canvas.println("wait mqtt connect");
canvas.pushSprite(0, 0);
while (!eth.createMQTTClient("120.77.157.90", "1883", "client_id",
"user_name", "password")) {
delay(10);
}
canvas.println("mqtt connected");
canvas.pushSprite(0, 0);
while (!eth.subscribeMQTTMsg("PoESP32_MQTT_D", "2")) {
delay(10);
}
}
void loop() {
if (Serial2.available()) {
readstr = Serial2.readString();
Serial.println(readstr);
canvas.println(readstr);
canvas.pushSprite(0, 0);
}
eth.publicMQTTMsg("PoESP32_MQTT_U", "Hello From PoESP32", "2");
delay(2000);
}

View File

@@ -0,0 +1,76 @@
/*
Description:
Use UNIT PoESP32 connect to TCP Server
UNIT PoESP32 Connect to M5Core2 PORT-C (G13/14)
before compiling:
M5Core2: https://github.com/m5stack/M5Core2
M5GFX: https://github.com/m5stack/M5GFX
UNIT_PoESP32: https://github.com/m5stack/UNIT_PoESP32
*/
#include "UNIT_PoESP32.h"
#include "M5Core2.h"
#include "M5GFX.h"
UNIT_PoESP32 eth;
uint8_t data[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x10};
M5GFX display;
M5Canvas canvas(&display);
void setup() {
M5.begin();
display.begin();
canvas.setColorDepth(1); // mono color
canvas.setFont(&fonts::efontCN_14);
canvas.setTextSize(2);
canvas.setPaletteColor(1, GREEN);
canvas.createSprite(display.width(), display.height());
canvas.setTextScroll(true);
eth.Init(&Serial2, 9600, 13, 14);
delay(10);
canvas.println("wait device connect");
canvas.pushSprite(0, 0);
while (!eth.checkDeviceConnect()) {
delay(10);
}
canvas.println("device connected");
canvas.println("wait ethernet connect");
canvas.pushSprite(0, 0);
while (!eth.checkETHConnect()) {
delay(10);
}
canvas.println("ethernet connected");
canvas.println("Config TCP Client");
canvas.println("wait tcp connect");
canvas.pushSprite(0, 0);
// AT+CIPSTART="TCP","192.168.3.102",8080
while (!eth.createTCPClient("120.77.157.90", 1883)) {
delay(10);
}
// while (!eth.configTCPClient("192.168.1.5", 60000)) {
// delay(10);
// }
canvas.println("tcp connected");
canvas.pushSprite(0, 0);
if (eth.sendTCPData(data, sizeof(data))) {
canvas.println("send ok");
} else {
canvas.println("send fail");
}
canvas.pushSprite(0, 0);
}
void loop() {
if (Serial.available()) {
char ch = Serial.read();
Serial2.write(ch);
}
if (Serial2.available()) {
char ch = Serial2.read();
Serial.write(ch);
}
}

View File

@@ -0,0 +1,37 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Relay. 继电器
* date: 2021/8/16
*******************************************************************************
Please connect to Port B,Use RELAY to switch on and off the circuit.
请连接端口B,使用继电器开关电路。
*/
#include <M5Core2.h>
void setup() {
M5.begin(); //Init M5Core2. 初始化 M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.setCursor(50, 0);
M5.Lcd.println(("Relay Example"));
dacWrite(25, 0); //disable the speak noise
pinMode(26, OUTPUT);
}
void loop(void) {
M5.Lcd.setCursor(100, 40);
M5.Lcd.print("ON");
digitalWrite(26, HIGH);
delay(1000);
M5.Lcd.fillRect(100,40,60,50,BLACK);
M5.Lcd.print("OFF");
digitalWrite(26, LOW);
delay(1000);
M5.Lcd.fillRect(100,40,60,50,BLACK);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,407 @@
/**
* MFRC522_I2C.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS I2C BY AROZCAN
* MFRC522_I2C.h - Based on ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI Library BY COOQROBOT.
* Based on code Dr.Leong ( WWW.B2CQSHOP.COM )
* Created by Miguel Balboa (circuitito.com), Jan, 2012.
* Rewritten by Søren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.)
* Extended by Tom Clement with functionality to write to sector 0 of UID changeable Mifare cards.
* Extended by Ahmet Remzi Ozcan with I2C functionality.
* Author: arozcan @ https://github.com/arozcan/MFRC522-I2C-Library
* Released into the public domain.
*
* Please read this file for an overview and then MFRC522.cpp for comments on the specific functions.
* Search for "mf-rc522" on ebay.com to purchase the MF-RC522 board.
*
* There are three hardware components involved:
* 1) The micro controller: An Arduino
* 2) The PCD (short for Proximity Coupling Device): NXP MFRC522 Contactless Reader IC
* 3) The PICC (short for Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203.
*
* The microcontroller and card reader uses I2C for communication.
* The protocol is described in the MFRC522 datasheet: http://www.nxp.com/documents/data_sheet/MFRC522.pdf
*
* The card reader and the tags communicate using a 13.56MHz electromagnetic field.
* The protocol is defined in ISO/IEC 14443-3 Identification cards -- Contactless integrated circuit cards -- Proximity cards -- Part 3: Initialization and anticollision".
* A free version of the final draft can be found at http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf
* Details are found in chapter 6, Type A Initialization and anticollision.
*
* If only the PICC UID is wanted, the above documents has all the needed information.
* To read and write from MIFARE PICCs, the MIFARE protocol is used after the PICC has been selected.
* The MIFARE Classic chips and protocol is described in the datasheets:
* 1K: http://www.nxp.com/documents/data_sheet/MF1S503x.pdf
* 4K: http://www.nxp.com/documents/data_sheet/MF1S703x.pdf
* Mini: http://www.idcardmarket.com/download/mifare_S20_datasheet.pdf
* The MIFARE Ultralight chip and protocol is described in the datasheets:
* Ultralight: http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf
* Ultralight C: http://www.nxp.com/documents/short_data_sheet/MF0ICU2_SDS.pdf
*
* MIFARE Classic 1K (MF1S503x):
* Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes.
* The blocks are numbered 0-63.
* Block 3 in each sector is the Sector Trailer. See http://www.nxp.com/documents/data_sheet/MF1S503x.pdf sections 8.6 and 8.7:
* Bytes 0-5: Key A
* Bytes 6-8: Access Bits
* Bytes 9: User data
* Bytes 10-15: Key B (or user data)
* Block 0 is read-only manufacturer data.
* To access a block, an authentication using a key from the block's sector must be performed first.
* Example: To read from block 10, first authenticate using a key from sector 3 (blocks 8-11).
* All keys are set to FFFFFFFFFFFFh at chip delivery.
* Warning: Please read section 8.7 "Memory Access". It includes this text: if the PICC detects a format violation the whole sector is irreversibly blocked.
* To use a block in "value block" mode (for Increment/Decrement operations) you need to change the sector trailer. Use PICC_SetAccessBits() to calculate the bit patterns.
* MIFARE Classic 4K (MF1S703x):
* Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes.
* The blocks are numbered 0-255.
* The last block in each sector is the Sector Trailer like above.
* MIFARE Classic Mini (MF1 IC S20):
* Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes.
* The blocks are numbered 0-19.
* The last block in each sector is the Sector Trailer like above.
*
* MIFARE Ultralight (MF0ICU1):
* Has 16 pages of 4 bytes = 64 bytes.
* Pages 0 + 1 is used for the 7-byte UID.
* Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2)
* Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0.
* Pages 4-15 are read/write unless blocked by the lock bytes in page 2.
* MIFARE Ultralight C (MF0ICU2):
* Has 48 pages of 4 bytes = 192 bytes.
* Pages 0 + 1 is used for the 7-byte UID.
* Page 2 contains the last check digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2)
* Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0.
* Pages 4-39 are read/write unless blocked by the lock bytes in page 2.
* Page 40 Lock bytes
* Page 41 16 bit one way counter
* Pages 42-43 Authentication configuration
* Pages 44-47 Authentication key
*/
#ifndef MFRC522_h
#define MFRC522_h
#include <Arduino.h>
#include <Wire.h>
// Firmware data for self-test
// Reference values based on firmware version
// Hint: if needed, you can remove unused self-test data to save flash memory
//
// Version 0.0 (0x90)
// Philips Semiconductors; Preliminary Specification Revision 2.0 - 01 August 2005; 16.1 Sefttest
const byte MFRC522_firmware_referenceV0_0[] PROGMEM = {
0x00, 0x87, 0x98, 0x0f, 0x49, 0xFF, 0x07, 0x19,
0xBF, 0x22, 0x30, 0x49, 0x59, 0x63, 0xAD, 0xCA,
0x7F, 0xE3, 0x4E, 0x03, 0x5C, 0x4E, 0x49, 0x50,
0x47, 0x9A, 0x37, 0x61, 0xE7, 0xE2, 0xC6, 0x2E,
0x75, 0x5A, 0xED, 0x04, 0x3D, 0x02, 0x4B, 0x78,
0x32, 0xFF, 0x58, 0x3B, 0x7C, 0xE9, 0x00, 0x94,
0xB4, 0x4A, 0x59, 0x5B, 0xFD, 0xC9, 0x29, 0xDF,
0x35, 0x96, 0x98, 0x9E, 0x4F, 0x30, 0x32, 0x8D
};
// Version 1.0 (0x91)
// NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 Self test
const byte MFRC522_firmware_referenceV1_0[] PROGMEM = {
0x00, 0xC6, 0x37, 0xD5, 0x32, 0xB7, 0x57, 0x5C,
0xC2, 0xD8, 0x7C, 0x4D, 0xD9, 0x70, 0xC7, 0x73,
0x10, 0xE6, 0xD2, 0xAA, 0x5E, 0xA1, 0x3E, 0x5A,
0x14, 0xAF, 0x30, 0x61, 0xC9, 0x70, 0xDB, 0x2E,
0x64, 0x22, 0x72, 0xB5, 0xBD, 0x65, 0xF4, 0xEC,
0x22, 0xBC, 0xD3, 0x72, 0x35, 0xCD, 0xAA, 0x41,
0x1F, 0xA7, 0xF3, 0x53, 0x14, 0xDE, 0x7E, 0x02,
0xD9, 0x0F, 0xB5, 0x5E, 0x25, 0x1D, 0x29, 0x79
};
// Version 2.0 (0x92)
// NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 Self test
const byte MFRC522_firmware_referenceV2_0[] PROGMEM = {
0x00, 0xEB, 0x66, 0xBA, 0x57, 0xBF, 0x23, 0x95,
0xD0, 0xE3, 0x0D, 0x3D, 0x27, 0x89, 0x5C, 0xDE,
0x9D, 0x3B, 0xA7, 0x00, 0x21, 0x5B, 0x89, 0x82,
0x51, 0x3A, 0xEB, 0x02, 0x0C, 0xA5, 0x00, 0x49,
0x7C, 0x84, 0x4D, 0xB3, 0xCC, 0xD2, 0x1B, 0x81,
0x5D, 0x48, 0x76, 0xD5, 0x71, 0x61, 0x21, 0xA9,
0x86, 0x96, 0x83, 0x38, 0xCF, 0x9D, 0x5B, 0x6D,
0xDC, 0x15, 0xBA, 0x3E, 0x7D, 0x95, 0x3B, 0x2F
};
// Clone
// Fudan Semiconductor FM17522 (0x88)
const byte FM17522_firmware_reference[] PROGMEM = {
0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18,
0x2A, 0xB8, 0x7A, 0x7F, 0xD3, 0x6A, 0xCF, 0x0B,
0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE, 0x91, 0xC7,
0xC3, 0x97, 0xAE, 0x77, 0xF4, 0x37, 0xD7, 0x9B,
0x7C, 0xF5, 0x3C, 0x11, 0x8F, 0x15, 0xC3, 0xD7,
0xC1, 0x5B, 0x00, 0x2A, 0xD0, 0x75, 0xDE, 0x9E,
0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB,
0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62
};
class MFRC522 {
public:
// MFRC522 registers. Described in chapter 9 of the datasheet.
enum PCD_Register {
// Page 0: Command and status
// 0x00 // reserved for future use
CommandReg = 0x01 , // starts and stops command execution
ComIEnReg = 0x02 , // enable and disable interrupt request control bits
DivIEnReg = 0x03 , // enable and disable interrupt request control bits
ComIrqReg = 0x04 , // interrupt request bits
DivIrqReg = 0x05 , // interrupt request bits
ErrorReg = 0x06 , // error bits showing the error status of the last command executed
Status1Reg = 0x07 , // communication status bits
Status2Reg = 0x08 , // receiver and transmitter status bits
FIFODataReg = 0x09 , // input and output of 64 byte FIFO buffer
FIFOLevelReg = 0x0A , // number of bytes stored in the FIFO buffer
WaterLevelReg = 0x0B , // level for FIFO underflow and overflow warning
ControlReg = 0x0C , // miscellaneous control registers
BitFramingReg = 0x0D , // adjustments for bit-oriented frames
CollReg = 0x0E , // bit position of the first bit-collision detected on the RF interface
// 0x0F // reserved for future use
// Page 1: Command
// 0x10 // reserved for future use
ModeReg = 0x11 , // defines general modes for transmitting and receiving
TxModeReg = 0x12 , // defines transmission data rate and framing
RxModeReg = 0x13 , // defines reception data rate and framing
TxControlReg = 0x14 , // controls the logical behavior of the antenna driver pins TX1 and TX2
TxASKReg = 0x15 , // controls the setting of the transmission modulation
TxSelReg = 0x16 , // selects the internal sources for the antenna driver
RxSelReg = 0x17 , // selects internal receiver settings
RxThresholdReg = 0x18 , // selects thresholds for the bit decoder
DemodReg = 0x19 , // defines demodulator settings
// 0x1A // reserved for future use
// 0x1B // reserved for future use
MfTxReg = 0x1C , // controls some MIFARE communication transmit parameters
MfRxReg = 0x1D , // controls some MIFARE communication receive parameters
// 0x1E // reserved for future use
SerialSpeedReg = 0x1F , // selects the speed of the serial UART interface
// Page 2: Configuration
// 0x20 // reserved for future use
CRCResultRegH = 0x21 , // shows the MSB and LSB values of the CRC calculation
CRCResultRegL = 0x22 ,
// 0x23 // reserved for future use
ModWidthReg = 0x24 , // controls the ModWidth setting?
// 0x25 // reserved for future use
RFCfgReg = 0x26 , // configures the receiver gain
GsNReg = 0x27 , // selects the conductance of the antenna driver pins TX1 and TX2 for modulation
CWGsPReg = 0x28 , // defines the conductance of the p-driver output during periods of no modulation
ModGsPReg = 0x29 , // defines the conductance of the p-driver output during periods of modulation
TModeReg = 0x2A , // defines settings for the internal timer
TPrescalerReg = 0x2B , // the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg.
TReloadRegH = 0x2C , // defines the 16-bit timer reload value
TReloadRegL = 0x2D ,
TCounterValueRegH = 0x2E , // shows the 16-bit timer value
TCounterValueRegL = 0x2F ,
// Page 3: Test Registers
// 0x30 // reserved for future use
TestSel1Reg = 0x31 , // general test signal configuration
TestSel2Reg = 0x32 , // general test signal configuration
TestPinEnReg = 0x33 , // enables pin output driver on pins D1 to D7
TestPinValueReg = 0x34 , // defines the values for D1 to D7 when it is used as an I/O bus
TestBusReg = 0x35 , // shows the status of the internal test bus
AutoTestReg = 0x36 , // controls the digital self test
VersionReg = 0x37 , // shows the software version
AnalogTestReg = 0x38 , // controls the pins AUX1 and AUX2
TestDAC1Reg = 0x39 , // defines the test value for TestDAC1
TestDAC2Reg = 0x3A , // defines the test value for TestDAC2
TestADCReg = 0x3B // shows the value of ADC I and Q channels
// 0x3C // reserved for production tests
// 0x3D // reserved for production tests
// 0x3E // reserved for production tests
// 0x3F // reserved for production tests
};
// MFRC522 commands. Described in chapter 10 of the datasheet.
enum PCD_Command {
PCD_Idle = 0x00, // no action, cancels current command execution
PCD_Mem = 0x01, // stores 25 bytes into the internal buffer
PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number
PCD_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self test
PCD_Transmit = 0x04, // transmits data from the FIFO buffer
PCD_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit
PCD_Receive = 0x08, // activates the receiver circuits
PCD_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission
PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader
PCD_SoftReset = 0x0F // resets the MFRC522
};
// MFRC522 RxGain[2:0] masks, defines the receiver's signal voltage gain factor (on the PCD).
// Described in 9.3.3.6 / table 98 of the datasheet at http://www.nxp.com/documents/data_sheet/MFRC522.pdf
enum PCD_RxGain {
RxGain_18dB = 0x00 << 4, // 000b - 18 dB, minimum
RxGain_23dB = 0x01 << 4, // 001b - 23 dB
RxGain_18dB_2 = 0x02 << 4, // 010b - 18 dB, it seems 010b is a duplicate for 000b
RxGain_23dB_2 = 0x03 << 4, // 011b - 23 dB, it seems 011b is a duplicate for 001b
RxGain_33dB = 0x04 << 4, // 100b - 33 dB, average, and typical default
RxGain_38dB = 0x05 << 4, // 101b - 38 dB
RxGain_43dB = 0x06 << 4, // 110b - 43 dB
RxGain_48dB = 0x07 << 4, // 111b - 48 dB, maximum
RxGain_min = 0x00 << 4, // 000b - 18 dB, minimum, convenience for RxGain_18dB
RxGain_avg = 0x04 << 4, // 100b - 33 dB, average, convenience for RxGain_33dB
RxGain_max = 0x07 << 4 // 111b - 48 dB, maximum, convenience for RxGain_48dB
};
// Commands sent to the PICC.
enum PICC_Command {
// The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4)
PICC_CMD_REQA = 0x26, // REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame.
PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision.
PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1
PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 2
PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 3
PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT.
// The commands used for MIFARE Classic (from http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9)
// Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector.
// The read/write commands can also be used for MIFARE Ultralight.
PICC_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A
PICC_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B
PICC_CMD_MF_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight.
PICC_CMD_MF_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight.
PICC_CMD_MF_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register.
PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register.
PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register.
PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block.
// The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
// The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight.
PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC.
};
// MIFARE constants that does not fit anywhere else
enum MIFARE_Misc {
MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK.
MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes.
};
// PICC types we can detect. Remember to update PICC_GetTypeName() if you add more.
enum PICC_Type {
PICC_TYPE_UNKNOWN = 0,
PICC_TYPE_ISO_14443_4 = 1, // PICC compliant with ISO/IEC 14443-4
PICC_TYPE_ISO_18092 = 2, // PICC compliant with ISO/IEC 18092 (NFC)
PICC_TYPE_MIFARE_MINI = 3, // MIFARE Classic protocol, 320 bytes
PICC_TYPE_MIFARE_1K = 4, // MIFARE Classic protocol, 1KB
PICC_TYPE_MIFARE_4K = 5, // MIFARE Classic protocol, 4KB
PICC_TYPE_MIFARE_UL = 6, // MIFARE Ultralight or Ultralight C
PICC_TYPE_MIFARE_PLUS = 7, // MIFARE Plus
PICC_TYPE_TNP3XXX = 8, // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure
PICC_TYPE_NOT_COMPLETE = 255 // SAK indicates UID is not complete.
};
// Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more.
enum StatusCode {
STATUS_OK = 1, // Success
STATUS_ERROR = 2, // Error in communication
STATUS_COLLISION = 3, // Collission detected
STATUS_TIMEOUT = 4, // Timeout in communication.
STATUS_NO_ROOM = 5, // A buffer is not big enough.
STATUS_INTERNAL_ERROR = 6, // Internal error in the code. Should not happen ;-)
STATUS_INVALID = 7, // Invalid argument.
STATUS_CRC_WRONG = 8, // The CRC_A does not match
STATUS_MIFARE_NACK = 9 // A MIFARE PICC responded with NAK.
};
// A struct used for passing the UID of a PICC.
typedef struct {
byte size; // Number of bytes in the UID. 4, 7 or 10.
byte uidByte[10];
byte sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection.
} Uid;
// A struct used for passing a MIFARE Crypto1 key
typedef struct {
byte keyByte[MF_KEY_SIZE];
} MIFARE_Key;
// Member variables
Uid uid; // Used by PICC_ReadCardSerial().
// Size of the MFRC522 FIFO
static const byte FIFO_SIZE = 64; // The FIFO is 64 bytes.
/////////////////////////////////////////////////////////////////////////////////////
// Functions for setting up the Arduino
/////////////////////////////////////////////////////////////////////////////////////
MFRC522(byte chipAddress);
/////////////////////////////////////////////////////////////////////////////////////
// Basic interface functions for communicating with the MFRC522
/////////////////////////////////////////////////////////////////////////////////////
void PCD_WriteRegister(byte reg, byte value);
void PCD_WriteRegister(byte reg, byte count, byte *values);
byte PCD_ReadRegister(byte reg);
void PCD_ReadRegister(byte reg, byte count, byte *values, byte rxAlign = 0);
void setBitMask(unsigned char reg, unsigned char mask);
void PCD_SetRegisterBitMask(byte reg, byte mask);
void PCD_ClearRegisterBitMask(byte reg, byte mask);
byte PCD_CalculateCRC(byte *data, byte length, byte *result);
/////////////////////////////////////////////////////////////////////////////////////
// Functions for manipulating the MFRC522
/////////////////////////////////////////////////////////////////////////////////////
void PCD_Init();
void PCD_Reset();
void PCD_AntennaOn();
void PCD_AntennaOff();
byte PCD_GetAntennaGain();
void PCD_SetAntennaGain(byte mask);
bool PCD_PerformSelfTest();
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with PICCs
/////////////////////////////////////////////////////////////////////////////////////
byte PCD_TransceiveData(byte *sendData, byte sendLen, byte *backData, byte *backLen, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false);
byte PCD_CommunicateWithPICC(byte command, byte waitIRq, byte *sendData, byte sendLen, byte *backData = NULL, byte *backLen = NULL, byte *validBits = NULL, byte rxAlign = 0, bool checkCRC = false);
byte PICC_RequestA(byte *bufferATQA, byte *bufferSize);
byte PICC_WakeupA(byte *bufferATQA, byte *bufferSize);
byte PICC_REQA_or_WUPA(byte command, byte *bufferATQA, byte *bufferSize);
byte PICC_Select(Uid *uid, byte validBits = 0);
byte PICC_HaltA();
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with MIFARE PICCs
/////////////////////////////////////////////////////////////////////////////////////
byte PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid);
void PCD_StopCrypto1();
byte MIFARE_Read(byte blockAddr, byte *buffer, byte *bufferSize);
byte MIFARE_Write(byte blockAddr, byte *buffer, byte bufferSize);
byte MIFARE_Decrement(byte blockAddr, long delta);
byte MIFARE_Increment(byte blockAddr, long delta);
byte MIFARE_Restore(byte blockAddr);
byte MIFARE_Transfer(byte blockAddr);
byte MIFARE_Ultralight_Write(byte page, byte *buffer, byte bufferSize);
byte MIFARE_GetValue(byte blockAddr, long *value);
byte MIFARE_SetValue(byte blockAddr, long value);
/////////////////////////////////////////////////////////////////////////////////////
// Support functions
/////////////////////////////////////////////////////////////////////////////////////
byte PCD_MIFARE_Transceive(byte *sendData, byte sendLen, bool acceptTimeout = false);
// old function used too much memory, now name moved to flash; if you need char, copy from flash to memory
//const char *GetStatusCodeName(byte code);
const __FlashStringHelper *GetStatusCodeName(byte code);
byte PICC_GetType(byte sak);
// old function used too much memory, now name moved to flash; if you need char, copy from flash to memory
//const char *PICC_GetTypeName(byte type);
const __FlashStringHelper *PICC_GetTypeName(byte type);
void PICC_DumpToSerial(Uid *uid);
void PICC_DumpMifareClassicToSerial(Uid *uid, byte piccType, MIFARE_Key *key);
void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector);
void PICC_DumpMifareUltralightToSerial();
void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3);
bool MIFARE_OpenUidBackdoor(bool logErrors);
bool MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors);
bool MIFARE_UnbrickUidSector(bool logErrors);
/////////////////////////////////////////////////////////////////////////////////////
// Convenience functions - does not add extra functionality
/////////////////////////////////////////////////////////////////////////////////////
bool PICC_IsNewCardPresent();
bool PICC_ReadCardSerial();
private:
byte _chipAddress;
byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low)
byte MIFARE_TwoStepHelper(byte command, byte blockAddr, long data);
};
#endif

View File

@@ -0,0 +1,43 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: RFID.
* date: 2021/8/19
*******************************************************************************
Please connect to Port A,Use the RFID Unit to read the Fudan card ID and display the ID on the screen.
请连接端口A,使用RFID Unit 读取ID卡并在屏幕上显示。
*/
#include <M5Core2.h>
#include "MFRC522_I2C.h"
MFRC522 mfrc522(0x28); // Create MFRC522 instance. 创建MFRC522实例
void setup() {
M5.begin(); //Init M5Core2. 初始化M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.println("MFRC522 Test");
Wire.begin(); //Wire init, adding the I2C bus. Wire初始化, 加入i2c总线
mfrc522.PCD_Init(); // Init MFRC522. 初始化 MFRC522
M5.Lcd.println("Please put the card\n\nUID:");
}
void loop() {
M5.Lcd.setCursor(40,47);
if (!mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial()) { //如果没有读取到新的卡片
delay(200);
return;
}
M5.Lcd.fillRect(42,47,320,20,BLACK);
for (byte i = 0; i < mfrc522.uid.size; i++) {
M5.Lcd.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
M5.Lcd.print(mfrc522.uid.uidByte[i], HEX);
}
M5.Lcd.println("");
}

View File

@@ -0,0 +1,41 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: RGB. 多彩灯
* date: 2021/8/11
*******************************************************************************
Please connect to Port B,Control RGB Unit to scroll through three colors of red, green and blue
请连接端口B,控制RGB单元滚动红、绿、蓝三种颜色.
*/
#include <M5Core2.h>
#include <Adafruit_NeoPixel.h>
#define PIN 26 //定义NeoPixel的控制引脚
#define NUMPIXELS 3 //定义NeoPixel控制灯灯数量
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); //set number of LEDs, pin number, LED type. 设置灯的数量,控制引脚编号,灯灯类型
void setup() {
M5.begin(); //Init M5Core2. 初始化 M5Core2
pixels.begin(); //Init the NeoPixel library. 初始化NeoPixel库
M5.Lcd.println(("RGB Example"));
}
int i=0,j=1,k=2;
void loop() {
pixels.setPixelColor(i++, pixels.Color(100, 0, 0)); // Bright red
pixels.setPixelColor(j++, pixels.Color(0,100,0)); // Bright green
pixels.setPixelColor(k++, pixels.Color(0,0,100)); // Bright blue
pixels.show(); //sends the updated color to the hardware. 将更新后的颜色发送到硬件。
delay(100);
if(i==3) i=0;
else if(j==3) j=0;
else if(k==3) k=0;
}

View File

@@ -0,0 +1,40 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/rs485
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/rs485
*
* describe: rs485.
* date: 2021/8/30
*******************************************************************************
Please connect to Port C,Use RS485 Unit for serial communication, continuously send "Hello", and display the received content on the screen.
请连接端口 C,采用RS485单元串行通信连续发送“Hello”接收到的内容显示在屏幕上。
*/
#include <M5Core2.h>
#define RX_PIN 13
#define TX_PIN 14
#define X_OFF 160
#define Y_OFF 30
int i=0,s=0;
void setup() {
M5.begin();
M5.Lcd.setTextSize(1);
M5.Lcd.drawString("RS485 Unit test", 75, 3, 4);
Serial2.begin(115200, SERIAL_8N1, RX_PIN, TX_PIN); //Set the baud rate of serial port 2 to 115200,8 data bits, no parity bits, and 1 stop bit, and set RX to 13 and TX to 14. 设置串口二的波特率为115200,8位数据位,没有校验位,1位停止位,并设置RX为13,TX为14
}
void loop() {
Serial2.write("Hello\n");
if(Serial2.available()){
M5.Lcd.print(char(Serial2.read()));
}
delay(100);
}

View File

@@ -0,0 +1,54 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: RTC. 实时时钟
* date: 2021/8/18
*******************************************************************************
Please connect to Port A,The time is displayed on the screen.
请连接端口A,屏幕上显示时间。
*/
#include "M5Core2.h"
#include "M5_BM8563.h"
BM8563 RTC;
rtc_time_type RTCtime;
rtc_date_type RTCdate;
char str_buffer[64];
void setup()
{
M5.begin(); //Init M5Core2. 初始化M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.print(" RTC");
RTC.begin(); //Example Initialize the RTC clock. 初始化RTC时钟
RTCtime.Hours = 14; //Set the RTC clock time. 设置RTC时钟时间
RTCtime.Minutes = 40;
RTCtime.Seconds = 5;
RTCdate.WeekDay = 4; //Set the RTC clock date. 设置RTC时钟日期
RTCdate.Month = 7;
RTCdate.Date = 15;
RTCdate.Year = 2021;
RTC.setTime(&RTCtime); //Example Synchronize the set time to the RTC. 将设置的时间同步至RTC
RTC.setDate(&RTCdate); //Synchronize the set date to the RTC. 将设置的日期同步至RTC
}
void loop()
{
RTC.getTime(&RTCtime); //To get the time. 获取时间
RTC.getDate(&RTCdate); //Get the date. 获取日期
M5.Lcd.setCursor(0,20);
M5.Lcd.printf("RTC Time Now is \n%02d:%02d:%02d\n",RTCtime.Hours, RTCtime.Minutes, RTCtime.Seconds);
M5.Lcd.printf("RTC Date Now is \n%02d:%02d:%02d WeekDay:%02d\n",RTCdate.Year, RTCdate.Month, RTCdate.Date, RTCdate.WeekDay);
delay(1000);
M5.Lcd.fillRect(0,20,320,140,BLACK);
}

View File

@@ -0,0 +1,70 @@
/**
* @copyright (C) 2017 Melexis N.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef _MLX640_API_H_
#define _MLX640_API_H_
#define SCALEALPHA 0.000001
typedef struct
{
int16_t kVdd;
int16_t vdd25;
float KvPTAT;
float KtPTAT;
uint16_t vPTAT25;
float alphaPTAT;
int16_t gainEE;
float tgc;
float cpKv;
float cpKta;
uint8_t resolutionEE;
uint8_t calibrationModeEE;
float KsTa;
float ksTo[5];
int16_t ct[5];
uint16_t alpha[768];
uint8_t alphaScale;
int16_t offset[768];
int8_t kta[768];
uint8_t ktaScale;
int8_t kv[768];
uint8_t kvScale;
float cpAlpha[2];
int16_t cpOffset[2];
float ilChessC[3];
uint16_t brokenPixels[5];
uint16_t outlierPixels[5];
} paramsMLX90640;
int MLX90640_DumpEE(uint8_t slaveAddr, uint16_t *eeData);
int MLX90640_GetFrameData(uint8_t slaveAddr, uint16_t *frameData);
int MLX90640_ExtractParameters(uint16_t *eeData, paramsMLX90640 *mlx90640);
float MLX90640_GetVdd(uint16_t *frameData, const paramsMLX90640 *params);
float MLX90640_GetTa(uint16_t *frameData, const paramsMLX90640 *params);
void MLX90640_GetImage(uint16_t *frameData, const paramsMLX90640 *params, float *result);
void MLX90640_CalculateTo(uint16_t *frameData, const paramsMLX90640 *params, float emissivity, float tr, float *result);
int MLX90640_SetResolution(uint8_t slaveAddr, uint8_t resolution);
int MLX90640_GetCurResolution(uint8_t slaveAddr);
int MLX90640_SetRefreshRate(uint8_t slaveAddr, uint8_t refreshRate);
int MLX90640_GetRefreshRate(uint8_t slaveAddr);
int MLX90640_GetSubPageNumber(uint16_t *frameData);
int MLX90640_GetCurMode(uint8_t slaveAddr);
int MLX90640_SetInterleavedMode(uint8_t slaveAddr);
int MLX90640_SetChessMode(uint8_t slaveAddr);
void MLX90640_BadPixelsCorrection(uint16_t *pixels, float *to, int mode, paramsMLX90640 *params);
#endif

View File

@@ -0,0 +1,107 @@
/**
@copyright (C) 2017 Melexis N.V.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include <Arduino.h>
#include <Wire.h>
#include "MLX90640_I2C_Driver.h"
void MLX90640_I2CInit()
{
}
//Read a number of words from startAddress. Store into Data array.
//Returns 0 if successful, -1 if error
int MLX90640_I2CRead(uint8_t _deviceAddress, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data)
{
//Caller passes number of 'unsigned ints to read', increase this to 'bytes to read'
uint16_t bytesRemaining = nWordsRead * 2;
//It doesn't look like sequential read works. Do we need to re-issue the address command each time?
uint16_t dataSpot = 0; //Start at beginning of array
//Setup a series of chunked I2C_BUFFER_LENGTH byte reads
while (bytesRemaining > 0)
{
Wire.beginTransmission(_deviceAddress);
Wire.write(startAddress >> 8); //MSB
Wire.write(startAddress & 0xFF); //LSB
if (Wire.endTransmission(false) != 0) //Do not release bus
{
Serial.println("No ack read");
return (0); //Sensor did not ACK
}
uint16_t numberOfBytesToRead = bytesRemaining;
if (numberOfBytesToRead > I2C_BUFFER_LENGTH) numberOfBytesToRead = I2C_BUFFER_LENGTH;
Wire.requestFrom((uint8_t)_deviceAddress, numberOfBytesToRead);
if (Wire.available())
{
for (uint16_t x = 0 ; x < numberOfBytesToRead / 2; x++)
{
//Store data into array
data[dataSpot] = Wire.read() << 8; //MSB
data[dataSpot] |= Wire.read(); //LSB
dataSpot++;
}
}
bytesRemaining -= numberOfBytesToRead;
startAddress += numberOfBytesToRead / 2;
}
return (0); //Success
}
//Set I2C Freq, in kHz
//MLX90640_I2CFreqSet(1000) sets frequency to 1MHz
void MLX90640_I2CFreqSet(int freq)
{
//i2c.frequency(1000 * freq);
Wire.setClock((long)1000 * freq);
}
//Write two bytes to a two byte address
int MLX90640_I2CWrite(uint8_t _deviceAddress, unsigned int writeAddress, uint16_t data)
{
Wire.beginTransmission((uint8_t)_deviceAddress);
Wire.write(writeAddress >> 8); //MSB
Wire.write(writeAddress & 0xFF); //LSB
Wire.write(data >> 8); //MSB
Wire.write(data & 0xFF); //LSB
if (Wire.endTransmission() != 0)
{
//Sensor did not ACK
Serial.println("Error: Sensor did not ack");
return (-1);
}
uint16_t dataCheck;
MLX90640_I2CRead(_deviceAddress, writeAddress, 1, &dataCheck);
if (dataCheck != data)
{
//Serial.println("The write request didn't stick");
return -2;
}
return (0); //Success
}

View File

@@ -0,0 +1,53 @@
/**
@copyright (C) 2017 Melexis N.V.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _MLX90640_I2C_Driver_H_
#define _MLX90640_I2C_Driver_H_
#include <stdint.h>
//Define the size of the I2C buffer based on the platform the user has
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
//I2C_BUFFER_LENGTH is defined in Wire.H
#define I2C_BUFFER_LENGTH BUFFER_LENGTH
#elif defined(__SAMD21G18A__)
//SAMD21 uses RingBuffer.h
#define I2C_BUFFER_LENGTH SERIAL_BUFFER_SIZE
#elif __MK20DX256__
//Teensy
#elif ARDUINO_ARCH_ESP32
//ESP32 based platforms
#else
//The catch-all default is 32
#define I2C_BUFFER_LENGTH 32
#endif
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
void MLX90640_I2CInit(void);
int MLX90640_I2CRead(uint8_t slaveAddr, unsigned int startAddress, unsigned int nWordsRead, uint16_t *data);
int MLX90640_I2CWrite(uint8_t slaveAddr, unsigned int writeAddress, uint16_t data);
void MLX90640_I2CFreqSet(int freq);
#endif

View File

@@ -0,0 +1,423 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/thermal
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/thermal
*
* describe: thermal.
* date: 2021/8/31
*******************************************************************************
Please connect to Port A, Read the THERMAL Unit (MLX90640 IR array) temperature pixels and display it on the screen.
请连接端口A, 读取热单元(MLX90640红外阵列)温度像素,并显示在屏幕上。
*/
#include <M5Core2.h>
#include "MLX90640_API.h"
#include "MLX90640_I2C_Driver.h"
const byte MLX90640_address = 0x33; //Default 7-bit unshifted address of the MLX90640. MLX90640的默认7位未移位地址
#define TA_SHIFT 8 //Default shift for MLX90640 in open air. MLX90640在户外的默认移位
#define COLS 32
#define ROWS 24
#define COLS_2 (COLS * 2)
#define ROWS_2 (ROWS * 2)
float pixelsArraySize = COLS * ROWS;
float pixels[COLS * ROWS];
float pixels_2[COLS_2 * ROWS_2];
float reversePixels[COLS * ROWS];
byte speed_setting = 2 ; // High is 1 , Low is 2
bool reverseScreen = false;
#define INTERPOLATED_COLS 32
#define INTERPOLATED_ROWS 32
static float mlx90640To[COLS * ROWS];
paramsMLX90640 mlx90640;
float signedMag12ToFloat(uint16_t val);
//low range of the sensor (this will be blue on the screen). 传感器的低量程(屏幕上显示为蓝色)
int MINTEMP = 24; // For color mapping. 颜色映射
int min_v = 24; //Value of current min temp. 当前最小温度的值
int min_cam_v = -40; // Spec in datasheet. 规范的数据表
//high range of the sensor (this will be red on the screen). 传感器的高量程(屏幕上显示为红色)
int MAXTEMP = 35; // For color mapping. 颜色映射
int max_v = 35; //Value of current max temp. 当前最大温度值
int max_cam_v = 300; // Spec in datasheet. 规范的数据表
int resetMaxTemp = 45;
//the colors we will be using. 我们将要使用的颜色
const uint16_t camColors[] = {0x480F,
0x400F, 0x400F, 0x400F, 0x4010, 0x3810, 0x3810, 0x3810, 0x3810, 0x3010, 0x3010,
0x3010, 0x2810, 0x2810, 0x2810, 0x2810, 0x2010, 0x2010, 0x2010, 0x1810, 0x1810,
0x1811, 0x1811, 0x1011, 0x1011, 0x1011, 0x0811, 0x0811, 0x0811, 0x0011, 0x0011,
0x0011, 0x0011, 0x0011, 0x0031, 0x0031, 0x0051, 0x0072, 0x0072, 0x0092, 0x00B2,
0x00B2, 0x00D2, 0x00F2, 0x00F2, 0x0112, 0x0132, 0x0152, 0x0152, 0x0172, 0x0192,
0x0192, 0x01B2, 0x01D2, 0x01F3, 0x01F3, 0x0213, 0x0233, 0x0253, 0x0253, 0x0273,
0x0293, 0x02B3, 0x02D3, 0x02D3, 0x02F3, 0x0313, 0x0333, 0x0333, 0x0353, 0x0373,
0x0394, 0x03B4, 0x03D4, 0x03D4, 0x03F4, 0x0414, 0x0434, 0x0454, 0x0474, 0x0474,
0x0494, 0x04B4, 0x04D4, 0x04F4, 0x0514, 0x0534, 0x0534, 0x0554, 0x0554, 0x0574,
0x0574, 0x0573, 0x0573, 0x0573, 0x0572, 0x0572, 0x0572, 0x0571, 0x0591, 0x0591,
0x0590, 0x0590, 0x058F, 0x058F, 0x058F, 0x058E, 0x05AE, 0x05AE, 0x05AD, 0x05AD,
0x05AD, 0x05AC, 0x05AC, 0x05AB, 0x05CB, 0x05CB, 0x05CA, 0x05CA, 0x05CA, 0x05C9,
0x05C9, 0x05C8, 0x05E8, 0x05E8, 0x05E7, 0x05E7, 0x05E6, 0x05E6, 0x05E6, 0x05E5,
0x05E5, 0x0604, 0x0604, 0x0604, 0x0603, 0x0603, 0x0602, 0x0602, 0x0601, 0x0621,
0x0621, 0x0620, 0x0620, 0x0620, 0x0620, 0x0E20, 0x0E20, 0x0E40, 0x1640, 0x1640,
0x1E40, 0x1E40, 0x2640, 0x2640, 0x2E40, 0x2E60, 0x3660, 0x3660, 0x3E60, 0x3E60,
0x3E60, 0x4660, 0x4660, 0x4E60, 0x4E80, 0x5680, 0x5680, 0x5E80, 0x5E80, 0x6680,
0x6680, 0x6E80, 0x6EA0, 0x76A0, 0x76A0, 0x7EA0, 0x7EA0, 0x86A0, 0x86A0, 0x8EA0,
0x8EC0, 0x96C0, 0x96C0, 0x9EC0, 0x9EC0, 0xA6C0, 0xAEC0, 0xAEC0, 0xB6E0, 0xB6E0,
0xBEE0, 0xBEE0, 0xC6E0, 0xC6E0, 0xCEE0, 0xCEE0, 0xD6E0, 0xD700, 0xDF00, 0xDEE0,
0xDEC0, 0xDEA0, 0xDE80, 0xDE80, 0xE660, 0xE640, 0xE620, 0xE600, 0xE5E0, 0xE5C0,
0xE5A0, 0xE580, 0xE560, 0xE540, 0xE520, 0xE500, 0xE4E0, 0xE4C0, 0xE4A0, 0xE480,
0xE460, 0xEC40, 0xEC20, 0xEC00, 0xEBE0, 0xEBC0, 0xEBA0, 0xEB80, 0xEB60, 0xEB40,
0xEB20, 0xEB00, 0xEAE0, 0xEAC0, 0xEAA0, 0xEA80, 0xEA60, 0xEA40, 0xF220, 0xF200,
0xF1E0, 0xF1C0, 0xF1A0, 0xF180, 0xF160, 0xF140, 0xF100, 0xF0E0, 0xF0C0, 0xF0A0,
0xF080, 0xF060, 0xF040, 0xF020, 0xF800,
};
float get_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
void set_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y, float f);
void get_adjacents_1d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
void get_adjacents_2d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
float cubicInterpolate(float p[], float x);
float bicubicInterpolate(float p[], float x, float y);
void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols, float *dest, uint8_t dest_rows, uint8_t dest_cols);
long loopTime, startTime, endTime, fps;
void setup()
{
M5.begin();
Wire.begin();
Wire.setClock(450000); //Increase I2C clock speed to 400kHz. 增加I2C时钟速度到400kHz
while (!Serial); //Wait for user to open terminal. 等待用户打开终端
Serial.println("M5Stack MLX90640 IR Camera");
M5.Lcd.setTextSize(2);
//Get device parameters - We only have to do this once. 获取设备参数——我们只需要做一次
int status;
uint16_t eeMLX90640[832];//32 * 24 = 768
status = MLX90640_DumpEE(MLX90640_address, eeMLX90640);
if (status != 0)
Serial.println("Failed to load system parameters");
status = MLX90640_ExtractParameters(eeMLX90640, &mlx90640);
if (status != 0)
Serial.println("Parameter extraction failed");
int SetRefreshRate;
//Setting MLX90640 device at slave address 0x33 to work with 16Hz refresh rate:
//设置从地址0x33的MLX90640设备以16Hz刷新率工作:
// 0x00 0.5Hz
// 0x01 1Hz
// 0x02 2Hz
// 0x03 4Hz
// 0x04 8Hz // OK
// 0x05 16Hz // OK
// 0x06 32Hz // Fail
// 0x07 64Hz
SetRefreshRate = MLX90640_SetRefreshRate (0x33, 0x05);
//Once params are extracted, we can release eeMLX90640 array. 一旦提取了参数我们就可以释放eeMLX90640数组
//Display bottom side colorList and info. 显示底部的颜色列表和信息
M5.Lcd.fillScreen(TFT_BLACK);
int icolor = 0;
for (int icol = 0; icol <= 248; icol++)
{
//Color bar. 彩色条
M5.Lcd.drawRect(36, 208, icol, 284 , camColors[icolor]);
icolor++;
}
infodisplay();
}
void loop(){
M5.update();
loopTime = millis();
startTime = loopTime;
//Set Min Value - LongPress. 长按设置最小值
if (M5.BtnA.pressedFor(1000)) {
if (MINTEMP <= 5 ){
MINTEMP = MAXTEMP - 5;
}else{
MINTEMP = MINTEMP - 5;
}
infodisplay();
}
//Set Min Value - SortPress. 短按设置最小值
if (M5.BtnA.wasPressed()) {
if (MINTEMP <= 0){
MINTEMP = MAXTEMP - 1;
}else{
MINTEMP--;
}
infodisplay();
}
// Reset settings. 重置设置
if (M5.BtnB.wasPressed()) {
MINTEMP = min_v - 1;
MAXTEMP = max_v + 1;
infodisplay();
}
// Power Off. 关闭电源
// if (M5.BtnB.pressedFor(1000)) {
// M5.Lcd.fillScreen(TFT_BLACK);
// M5.Lcd.setTextColor(YELLOW, BLACK);
// M5.Lcd.drawCentreString("Power Off...", 160, 80, 4);
// delay(1000);
// M5.powerOFF();
// }
//Set Max Value - LongPress 长按设置最大值
if (M5.BtnC.pressedFor(1000)) {
if (MAXTEMP >= max_cam_v){
MAXTEMP = MINTEMP + 1;
}else{
MAXTEMP = MAXTEMP + 5;
}
infodisplay();
}
// Set Max Value - SortPress 短按设置最大值
if (M5.BtnC.wasPressed()) {
if (MAXTEMP >= max_cam_v ){
MAXTEMP = MINTEMP + 1;
}else{
MAXTEMP++;
}
infodisplay();
}
for (byte x = 0 ; x < speed_setting ; x++) // x < 2 Read both subpages
{
uint16_t mlx90640Frame[834];
int status = MLX90640_GetFrameData(MLX90640_address, mlx90640Frame);
if (status < 0){
Serial.print("GetFrame Error: ");
Serial.println(status);
}
float vdd = MLX90640_GetVdd(mlx90640Frame, &mlx90640);
float Ta = MLX90640_GetTa(mlx90640Frame, &mlx90640);
float tr = Ta - TA_SHIFT; //Reflected temperature based on the sensor ambient temperature. 根据传感器环境温度反射温度
float emissivity = 0.95;
MLX90640_CalculateTo(mlx90640Frame, &mlx90640, emissivity, tr, pixels); //save pixels temp to array (pixels). 保存像素temp到数组(像素)
int mode_ = MLX90640_GetCurMode(MLX90640_address);
//amendment. 修正案
MLX90640_BadPixelsCorrection((&mlx90640)->brokenPixels, pixels, mode_, &mlx90640);
}
//Reverse image (order of Integer array). 反向图像(整数数组的顺序)
if (reverseScreen == 1)
{
for (int x = 0 ; x < pixelsArraySize ; x++)
{
if (x % COLS == 0) //32 values wide. 32宽值
{
for (int j = 0 + x, k = (COLS-1) + x; j < COLS + x ; j++, k--)
{
reversePixels[j] = pixels[k];
// Serial.print(x);Serial.print(" = Rev "); Serial.print(j);Serial.print(" , Nor ");Serial.println(k);
}
}
}
}
float dest_2d[INTERPOLATED_ROWS * INTERPOLATED_COLS];
int ROWS_i,COLS_j;
if (reverseScreen == 1)
{
// ** reversePixels 反向像素
interpolate_image(reversePixels, ROWS, COLS, dest_2d, INTERPOLATED_ROWS, INTERPOLATED_COLS);
}
else
{
interpolate_image(pixels, ROWS, COLS, dest_2d, INTERPOLATED_ROWS, INTERPOLATED_COLS);
// 32 * 24 = 768
// 63 * 48 = 3072
//pixels_2
for(int y = 0;y < ROWS;y++)
{
for(int x = 0;x < COLS;x++)
{
// 原始数据
pixels_2[(((y * 2) * (COLS*2)) + (x * 2))] = pixels[y*COLS+x];
if(x != 31)
pixels_2[(((y * 2) * (COLS*2)) + (x * 2)+1)] = ( pixels_2[(((y * 2) * (COLS*2)) + (x * 2))] + pixels_2[(((y * 2) * (COLS*2)) + (x * 2)+2)]) / 2;
else
pixels_2[(((y * 2) * (COLS*2)) + (x * 2)+1)] = ( pixels_2[(((y * 2) * (COLS*2)) + (x * 2))] );
//Serial.print(pixels_2[(((y * 2) * (COLS*2)) + (x * 2))]);
//Serial.print(pixels[y*COLS+x]);
//Serial.print(" ");
}
//Serial.println("\r\n");
}
/*
//-------------------------
// 计算x间隔插入数据
for(int y = 0;y < ROWS;y++)//24
{
for(int x = 0;x < COLS;x++)//32
{
if(x != 31)
pixels_2[(((y * 2) * (COLS*2)) + (x * 2)+1)] = ( pixels_2[(((y * 2) * (COLS*2)) + (x * 2))] + pixels_2[(((y * 2) * (COLS*2)) + (x * 2)+2)]) / 2;
else
pixels_2[(((y * 2) * (COLS*2)) + (x * 2)+1)] = ( pixels_2[(((y * 2) * (COLS*2)) + (x * 2))] );
}
}
*/
///*
// 计算y间隔插入数据
for(int y = 0;y < ROWS;y++)//24
{
for(int x = 0;x < COLS_2;x++)//64
{
if(y != 23)
pixels_2[(((y * 2) + 1) * (COLS_2)) + x] = ( pixels_2[(((y * 2) * COLS_2) + x)] + pixels_2[((((y * 2) + 2) * COLS_2) + x)] ) / 2;
else
pixels_2[(((y * 2) + 1) * (COLS_2)) + x] = ( pixels_2[(((y * 2) * COLS_2) + x)] + pixels_2[(((y * 2) * COLS_2) + x)] ) / 2;
}
}
//*/
/*
//打印数据
for(int y = 0;y < ROWS_2;y++)
{
for(int x = 0;x < COLS_2;x++)
{
Serial.print(pixels_2[y * COLS_2 + x]);
Serial.print(" ");
}
Serial.println("\r\n");
}
//-------------------------
// */
}
uint16_t boxsize = min(M5.Lcd.width() / INTERPOLATED_ROWS, M5.Lcd.height() / INTERPOLATED_COLS);
uint16_t boxWidth = M5.Lcd.width() / INTERPOLATED_ROWS;
//uint16_t boxWidth = 192 / INTERPOLATED_ROWS;
uint16_t boxHeight = (M5.Lcd.height() - 31) / INTERPOLATED_COLS; // 31 for bottom info
//drawpixels(pixels, 24, INTERPOLATED_COLS, 8, 8, false);
//drawpixels(pixels_2, 48, 64, 5, 5, false);
drawpixels(dest_2d, INTERPOLATED_ROWS, INTERPOLATED_COLS, boxWidth, boxHeight, false);
max_v = MINTEMP;
min_v = MAXTEMP;
int spot_v = pixels[360];
spot_v = pixels[768/2];
//while(1);
for ( int itemp = 0; itemp < sizeof(pixels) / sizeof(pixels[0]); itemp++ )
{
if ( pixels[itemp] > max_v )
{
max_v = pixels[itemp];
}
if ( pixels[itemp] < min_v )
{
min_v = pixels[itemp];
}
}
M5.Lcd.setTextSize(2);
M5.Lcd.fillRect(164, 220, 75, 18, TFT_BLACK); // clear max temp text. 清除最大温度文本
M5.Lcd.fillRect(60, 220, 200, 18, TFT_BLACK); // clear spot temp text. 清除点临时文本
int icolor = 0;
//for (int icol = 0; icol <= 248; icol++)
//{
// M5.Lcd.drawRect(36, 208, icol, 284 , camColors[icolor]);
// icolor++;
//}
M5.Lcd.setCursor(60, 222); // update min & max temp. 更新最小和最大温度
M5.Lcd.setTextColor(TFT_WHITE);
if (max_v > max_cam_v | max_v < min_cam_v ) {
M5.Lcd.setTextColor(TFT_RED);
M5.Lcd.printf("Error", 1);
}
else
{
M5.Lcd.print("Min:");
M5.Lcd.print(min_v, 1);
M5.Lcd.print("C ");
M5.Lcd.print("Max:");
M5.Lcd.print(max_v, 1);
M5.Lcd.print("C");
M5.Lcd.setCursor(180, 94); // update spot temp text. 更新现场温度文本
M5.Lcd.print(spot_v, 1);
M5.Lcd.printf("C");
M5.Lcd.drawCircle(160, 120, 6, TFT_WHITE); // update center spot icon. 更新中心点图标
M5.Lcd.drawLine(160, 110, 160, 130, TFT_WHITE); // vertical line. 垂直的线
M5.Lcd.drawLine(150, 120, 170, 120, TFT_WHITE); // horizontal line. 水平线
}
loopTime = millis();
endTime = loopTime;
fps = 1000 / (endTime - startTime);
M5.Lcd.fillRect(300, 209, 20, 12, TFT_BLACK); //Clear fps text area. 清除fps文本区域
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(284, 210);
M5.Lcd.print("fps:" + String( fps ));
M5.Lcd.setTextSize(1);
}
/***infodisplay()*****/
void infodisplay(void) {
M5.Lcd.fillRect(0, 198, 320, 4, TFT_WHITE);
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.fillRect(284, 223, 320, 240, TFT_BLACK); //Clear MaxTemp area. 清除MaxTemp区域
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(284, 222); //move to bottom right. 移至右下
M5.Lcd.print(MAXTEMP , 1); // update MAXTEMP. 更新MAXTEMP
M5.Lcd.print("C");
M5.Lcd.setCursor(0, 222); // update MINTEMP text. 更新MINTEMP文本
M5.Lcd.fillRect(0, 222, 36, 16, TFT_BLACK);
M5.Lcd.print(MINTEMP , 1);
M5.Lcd.print("C");
M5.Lcd.setCursor(106, 224);
}
void drawpixels(float *p, uint8_t rows, uint8_t cols, uint8_t boxWidth, uint8_t boxHeight, boolean showVal) {
int colorTemp;
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < cols; x++)
{
float val = get_point(p, rows, cols, x, y);
if (val >= MAXTEMP)
colorTemp = MAXTEMP;
else if (val <= MINTEMP)
colorTemp = MINTEMP;
else colorTemp = val;
uint8_t colorIndex = map(colorTemp, MINTEMP, MAXTEMP, 0, 255);
colorIndex = constrain(colorIndex, 0, 255);// 0 ~ 255
//draw the pixels!
uint16_t color;
color = val * 2;
M5.Lcd.fillRect(boxWidth * x, boxHeight * y, boxWidth, boxHeight, camColors[colorIndex]);
}
}
}
//Returns true if the MLX90640 is detected on the I2C bus. 如果在I2C总线上检测到MLX90640则返回true
boolean isConnected()
{
Wire.beginTransmission((uint8_t)MLX90640_address);
if (Wire.endTransmission() != 0)
return (false); //Sensor did not ACK.
return (true);
}

View File

@@ -0,0 +1,106 @@
#include <Arduino.h>
float get_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
void set_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y, float f);
void get_adjacents_1d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
void get_adjacents_2d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y);
float cubicInterpolate(float p[], float x);
float bicubicInterpolate(float p[], float x, float y);
void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols,
float *dest, uint8_t dest_rows, uint8_t dest_cols);
float get_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y) {
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x >= cols) x = cols - 1;
if (y >= rows) y = rows - 1;
return p[y * cols + x];
}
void set_point(float *p, uint8_t rows, uint8_t cols, int8_t x, int8_t y, float f) {
if ((x < 0) || (x >= cols)) return;
if ((y < 0) || (y >= rows)) return;
p[y * cols + x] = f;
}
// src is a grid src_rows * src_cols
// dest is a pre-allocated grid, dest_rows*dest_cols
void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols,
float *dest, uint8_t dest_rows, uint8_t dest_cols) {
float mu_x = (src_cols - 1.0) / (dest_cols - 1.0);
float mu_y = (src_rows - 1.0) / (dest_rows - 1.0);
float adj_2d[16]; // matrix for storing adjacents
for (uint8_t y_idx=0; y_idx < dest_rows; y_idx++) {
for (uint8_t x_idx=0; x_idx < dest_cols; x_idx++) {
float x = x_idx * mu_x;
float y = y_idx * mu_y;
//Serial.print("("); Serial.print(y_idx); Serial.print(", "); Serial.print(x_idx); Serial.print(") = ");
//Serial.print("("); Serial.print(y); Serial.print(", "); Serial.print(x); Serial.print(") = ");
get_adjacents_2d(src, adj_2d, src_rows, src_cols, x, y);
/*
Serial.print("[");
for (uint8_t i=0; i<16; i++) {
Serial.print(adj_2d[i]); Serial.print(", ");
}
Serial.println("]");
*/
float frac_x = x - (int)x; // we only need the ~delta~ between the points
float frac_y = y - (int)y; // we only need the ~delta~ between the points
float out = bicubicInterpolate(adj_2d, frac_x, frac_y);
//Serial.print("\tInterp: "); Serial.println(out);
set_point(dest, dest_rows, dest_cols, x_idx, y_idx, out);
}
}
}
// p is a list of 4 points, 2 to the left, 2 to the right
float cubicInterpolate(float p[], float x) {
float r = p[1] + (0.5 * x * (p[2] - p[0] + x*(2.0*p[0] - 5.0*p[1] + 4.0*p[2] - p[3] + x*(3.0*(p[1] - p[2]) + p[3] - p[0]))));
/*
Serial.print("interpolating: [");
Serial.print(p[0],2); Serial.print(", ");
Serial.print(p[1],2); Serial.print(", ");
Serial.print(p[2],2); Serial.print(", ");
Serial.print(p[3],2); Serial.print("] w/"); Serial.print(x); Serial.print(" = ");
Serial.println(r);
*/
return r;
}
// p is a 16-point 4x4 array of the 2 rows & columns left/right/above/below
float bicubicInterpolate(float p[], float x, float y) {
float arr[4] = {0,0,0,0};
arr[0] = cubicInterpolate(p+0, x);
arr[1] = cubicInterpolate(p+4, x);
arr[2] = cubicInterpolate(p+8, x);
arr[3] = cubicInterpolate(p+12, x);
return cubicInterpolate(arr, y);
}
// src is rows*cols and dest is a 4-point array passed in already allocated!
void get_adjacents_1d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y) {
//Serial.print("("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.println(")");
// pick two items to the left
dest[0] = get_point(src, rows, cols, x-1, y);
dest[1] = get_point(src, rows, cols, x, y);
// pick two items to the right
dest[2] = get_point(src, rows, cols, x+1, y);
dest[3] = get_point(src, rows, cols, x+2, y);
}
// src is rows*cols and dest is a 16-point array passed in already allocated!
void get_adjacents_2d(float *src, float *dest, uint8_t rows, uint8_t cols, int8_t x, int8_t y) {
//Serial.print("("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.println(")");
float arr[4];
for (int8_t delta_y = -1; delta_y < 3; delta_y++) { // -1, 0, 1, 2
float *row = dest + 4 * (delta_y+1); // index into each chunk of 4
for (int8_t delta_x = -1; delta_x < 3; delta_x++) { // -1, 0, 1, 2
row[delta_x+1] = get_point(src, rows, cols, x+delta_x, y+delta_y);
}
}
}

View File

@@ -0,0 +1,146 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: ToF. 激光测距
* date: 2021/8/16
*******************************************************************************
Please connect to Port A,Use ToF Unit to detect distance and display distance data on the screen in real time.
请连接端口A,使用ToF Unit检测距离并在屏幕上实时显示距离数据。
*/
#include <M5Core2.h>
#define VL53L0X_REG_IDENTIFICATION_MODEL_ID 0xc0
#define VL53L0X_REG_IDENTIFICATION_REVISION_ID 0xc2
#define VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD 0x50
#define VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x70
#define VL53L0X_REG_SYSRANGE_START 0x00
#define VL53L0X_REG_RESULT_INTERRUPT_STATUS 0x13
#define VL53L0X_REG_RESULT_RANGE_STATUS 0x14
#define address 0x29 //I2C address
byte gbuf[16];
uint16_t bswap(byte b[]) {
// Big Endian unsigned short to little endian unsigned short
uint16_t val = ((b[0] << 8) & b[1]);
return val;
}
uint16_t makeuint16(int lsb, int msb) {
return ((msb & 0xFF) << 8) | (lsb & 0xFF);
}
void write_byte_data(byte data) {
Wire.beginTransmission(address);
Wire.write(data);
Wire.endTransmission();
}
void write_byte_data_at(byte reg, byte data) {
// write data word at address and register
Wire.beginTransmission(address);
Wire.write(reg);
Wire.write(data);
Wire.endTransmission();
}
void write_word_data_at(byte reg, uint16_t data) {
// write data word at address and register
byte b0 = (data &0xFF);
byte b1 = ((data >> 8) && 0xFF);
Wire.beginTransmission(address);
Wire.write(reg);
Wire.write(b0);
Wire.write(b1);
Wire.endTransmission();
}
byte read_byte_data() {
Wire.requestFrom(address, 1);
while (Wire.available() < 1) delay(1);
byte b = Wire.read();
return b;
}
byte read_byte_data_at(byte reg) {
//write_byte_data((byte)0x00);
write_byte_data(reg);
Wire.requestFrom(address, 1);
while (Wire.available() < 1) delay(1);
byte b = Wire.read();
return b;
}
uint16_t read_word_data_at(byte reg) {
write_byte_data(reg);
Wire.requestFrom(address, 2);
while (Wire.available() < 2) delay(1);
gbuf[0] = Wire.read();
gbuf[1] = Wire.read();
return bswap(gbuf);
}
void read_block_data_at(byte reg, int sz) {
int i = 0;
write_byte_data(reg);
Wire.requestFrom(address, sz);
for (i=0; i<sz; i++) {
while (Wire.available() < 1) delay(1);
gbuf[i] = Wire.read();
}
}
uint16_t VL53L0X_decode_vcsel_period(short vcsel_period_reg) {
// Converts the encoded VCSEL period register value into the real
// period in PLL clocks
uint16_t vcsel_period_pclks = (vcsel_period_reg + 1) << 1;
return vcsel_period_pclks;
}
void setup() {
// put your setup code here, to run once:
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(115200); // start serial for output
Serial.println("VLX53LOX test started.");
//---osmar
M5.begin();
M5.Lcd.setCursor(50, 0, 4);
M5.Lcd.println(("VLX53LOX Example"));
//---osmar
}
void loop() {
write_byte_data_at(VL53L0X_REG_SYSRANGE_START, 0x01);
byte val = 0;
int cnt = 0;
while (cnt < 100) { // 1 second waiting time max
delay(10);
val = read_byte_data_at(VL53L0X_REG_RESULT_RANGE_STATUS);
if (val & 0x01) break;
cnt++;
}
if (val & 0x01) Serial.println("ready"); else Serial.println("not ready");
read_block_data_at(0x14, 12);
uint16_t acnt = makeuint16(gbuf[7], gbuf[6]);
uint16_t scnt = makeuint16(gbuf[9], gbuf[8]);
uint16_t dist = makeuint16(gbuf[11], gbuf[10]);
byte DeviceRangeStatusInternal = ((gbuf[0] & 0x78) >> 3);
M5.Lcd.fillRect(0, 35, 319, 239, BLACK);
M5.Lcd.setCursor(0, 35, 4);
M5.Lcd.print("ambient count: "); M5.Lcd.println(acnt);
M5.Lcd.print("signal count: "); M5.Lcd.println(scnt);
M5.Lcd.print("distance: "); M5.Lcd.println(dist);
M5.Lcd.print("status: "); M5.Lcd.println(DeviceRangeStatusInternal);
delay(1000);
}

View File

@@ -0,0 +1,62 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/trace
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/trace
*
* describe: TRACE.
* date: 2021/9/1
*******************************************************************************
Please connect to PORT-A, Read the status of the four line-tracking sensors of TRACE Unit and output them through UART.
请连接端口A,读取TRACE Unit四个线跟踪传感器的状态并通过UART输出。
*/
#include <M5Core2.h>
// #define VALUE_SPLIT
uint8_t value;
int SensorArray[4] = {0};
void SensorStatus(void){
Wire.beginTransmission(0x5a); //The data transfer to 0x5A begins. 开始向0x5a传输数据
Wire.write(0x00);
Wire.endTransmission(); //End the data transmission.结束数据传输
Wire.requestFrom(0x5a,1); //Request a byte from 0x5a. 向0x5a请求一个字节
while(Wire.available()){ //If data is received. 如果数据被接收到
value = Wire.read();
}
M5.Lcd.print(" value = ");
M5.Lcd.println(value, HEX);
#ifdef VALUE_SPLIT
SensorArray[3] = (value&0x08)>>3;
SensorArray[2] = (value&0x04)>>2;
SensorArray[1] = (value&0x02)>>1;
SensorArray[0] = (value&0x01)>>0;
M5.Lcd.println(" After splitting... ");
M5.Lcd.print(" SensorArray[0] = "); M5.Lcd.println(SensorArray[0]);
M5.Lcd.print(" SensorArray[1] = "); M5.Lcd.println(SensorArray[1]);
M5.Lcd.print(" SensorArray[2] = "); M5.Lcd.println(SensorArray[2]);
M5.Lcd.print(" SensorArray[3] = "); M5.Lcd.println(SensorArray[3]);
#endif
}
void setup() {
M5.begin();
Wire.begin();
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(80, 0);
M5.Lcd.println("TRACE example");
M5.Lcd.setTextColor(WHITE);
}
void loop(){
M5.Lcd.fillRect(0,20,320,180,BLACK);
M5.Lcd.setCursor(100,70);
SensorStatus();
delay(100);
}

View File

@@ -0,0 +1,56 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/tvoc
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/tvoc
*
* describe: TVOC/eCO2.
* date: 2021/8/26
*******************************************************************************
Description: The screen will display TVOC and CO2. 屏幕将显示TVOC和CO2。
Note: SGP30 needs 15 seconds to initialize calibration after power on. SGP30开机后需要15秒进行初始校准。
*/
#include <M5Core2.h>
#include "Adafruit_SGP30.h"
Adafruit_SGP30 sgp;
long last_millis = 0;
void setup() {
M5.begin(true, false, true, true);
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(80,0);
M5.Lcd.println("TVOC TEST");
if (!sgp.begin()){ //Init the sensor. 初始化传感器
M5.Lcd.println("Sensor not found");
while (1);
}
M5.Lcd.setCursor(0,80);
M5.Lcd.println("\nInitialization...");
}
void loop() {
static int i = 15;
while(i > 0) {
if(millis()- last_millis > 1000) {
last_millis = millis();
i--;
M5.Lcd.fillRect(20, 120, 60, 30, BLACK);
M5.Lcd.drawNumber(i, 20, 120, 2);
}
}
M5.Lcd.fillRect(0, 80, 90, 100, BLACK);
if (! sgp.IAQmeasure()) { //Commands the sensor to take a single eCO2/VOC measurement. 命令传感器进行一次eCO2/VOC测量
Serial.println("Measurement failed");
return;
}
M5.Lcd.fillRect(100, 40, 220, 90, TFT_BLACK);
M5.Lcd.setCursor(0,50);
M5.Lcd.printf("TVOC:%d ppb\n",sgp.TVOC);
M5.Lcd.printf("eCO2:%d ppm\n",sgp.eCO2);
delay(500);
}

View File

@@ -0,0 +1,55 @@
#include <M5Core2.h>
TFT_eSprite Terminalbuff = TFT_eSprite(&M5.Lcd);
void setup() {
// put your setup code here, to run once:
M5.begin();
Wire.begin(32,33);
Terminalbuff.createSprite(160, 80);
Terminalbuff.fillRect(80,20,160,80,BLACK);
Terminalbuff.pushSprite(80,20);
Terminalbuff.setTextFont(4);
M5.Lcd.setCursor(105, 0, 4);
M5.Lcd.print("Ultrasonic");
}
float readEUS()
{
uint32_t data;
Wire.beginTransmission(0x57);
Wire.write(0x01);
Wire.endTransmission();
delay(120);
Wire.requestFrom(0x57,3);
data = Wire.read();data <<= 8;
data |= Wire.read();data <<= 8;
data |= Wire.read();
return float(data) / 1000;
}
void loop() {
float newvalue = 0;
while(1)
{
newvalue = readEUS();
Terminalbuff.fillRect(80,20,160,80,BLACK);
Terminalbuff.setCursor(30,50);
if(( newvalue < 1500 )&&( newvalue > 20 ))
{
Terminalbuff.printf("%.2fmm",newvalue);
Terminalbuff.pushSprite(80,20);
}
delay(100);
}
}

View File

@@ -0,0 +1,47 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Ultrasonic. 超声波测距传感器
* date: 2021/8/19
*******************************************************************************
Please connect to Port A,Display the distance measured by ultrasonic
请连接端口A,显示超声波测量的距离
*/
#include <M5Core2.h>
void setup() {
M5.begin(); //Init M5Core2. 初始化M5Core2
Wire.begin(32, 33);
M5.Lcd.setCursor(105, 0, 4); //Set the cursor at (105,0) and set the font to a 4 point font. 将光标设置在(105,0)处,且设置字体为4号字体
M5.Lcd.print("Ultrasonic\nDistance:");
}
float readEUS()
{
uint32_t data;
Wire.beginTransmission(0x57); //Transfer data to 0x57. 将数据传输到0x57
Wire.write(0x01);
Wire.endTransmission(); //Stop data transmission with the Ultrasonic Unit. 停止与Ultrasonic Unit的数据传输
delay(120);
Wire.requestFrom(0x57,3); //Request 3 bytes from Ultrasonic Unit. 向Ultrasonic Unit请求3个字节。
data = Wire.read();data <<= 8;
data |= Wire.read();data <<= 8;
data |= Wire.read();
return float(data) / 1000;
}
void loop() {
static float newvalue = 0;
newvalue = readEUS();
if(( newvalue < 1500 )&&( newvalue > 20 )){
M5.Lcd.setCursor(105,27);
M5.Lcd.printf("%.2fmm",newvalue);
}
delay(100);
}

View File

@@ -0,0 +1,36 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Vibrator. 震动电机
* date: 2021/8/19
*******************************************************************************
Please connect to Port B,Adjust the speed of VIBRATOR Unit through PWM.
请连接端口B,通过PWM调节Vibrator Unit的速度。
*/
#include <M5Core2.h>
#define motor_pin 26
int freq = 10000;
int ledChannel = 0;
int resolution = 10;
void setup() {
M5.begin(); //Init M5Core2. 初始化M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
M5.Lcd.setCursor(110, 10); //Set the cursor at (110,10). 将光标设置在(110,10)处
M5.Lcd.println("Vibrator");
ledcSetup(ledChannel, freq, resolution); //Sets the frequency and number of counts corresponding to the channel. 设置通道对应的频率和计数位数
ledcAttachPin(motor_pin, ledChannel); //Binds the specified channel to the specified I/O port for output. 将指定通道绑定到指定 IO 口上以实现输出
}
void loop() {
ledcWrite(ledChannel, 512); //Output PWM. 输出PWM
delay(1000);
ledcWrite(ledChannel, 0);
delay(1000);
}

View File

@@ -0,0 +1,148 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/unit/ameter
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/unit/ameter
*
* describe: Vmeter_ADS1115. 电流计
* date: 2021/8/27
*******************************************************************************
Please connect to Port A,Measure voltage and display in the screen.
请连接端口A,测量电压并显示到屏幕上
Pay attention: EEPROM (0x53) has built-in calibration parameters when leaving the factory.
Please do not write to the EEPROM, otherwise the calibration data will be overwritten and the measurement results will be inaccurate.
注意: EEPROM (0x53)在出厂时具有内置的校准参数。请不要写入EEPROM否则校准数据会被覆盖测量结果会不准确。
*/
#include "M5Core2.h"
#include "voltmeter.h"
Voltmeter voltmeter;
float page512_volt = 5000.0F;
float page4096_volt = 60000.0F;
int16_t volt_raw_list[10];
uint8_t raw_now_ptr = 0;
int16_t adc_raw = 0;
int16_t hope = 0.0;
voltmeterGain_t now_gain = PAG_512;
void setup() {
M5.begin();
Wire.begin();
voltmeter.setMode(SINGLESHOT); // | PAG | Max Input Voltage(V) |
voltmeter.setRate(RATE_8); // | PAG_6144 | 128 |
voltmeter.setGain(PAG_512); // | PAG_4096 | 64 |
hope = page512_volt / voltmeter.resolution; // | PAG_2048 | 32 |
// | PAG_512 | 16 |
// | PAG_256 | 8 |
M5.Lcd.setTextFont(4); //Set font to 4 point font. 设置字体为4号字体
M5.Lcd.setCursor(52, 210); //Set the cursor at (52,210). 将光标设置在(52, 210)
M5.Lcd.printf("5V 60V SAVE");
}
void loop(void) {
M5.update(); //Check the status of the key. 检测按键的状态
if (M5.BtnA.wasPressed()) {
voltmeter.setMode(SINGLESHOT); //Set the mode. 设置模式
voltmeter.setRate(RATE_8); //Set the rate. 设置速率
voltmeter.setGain(PAG_512);
now_gain = PAG_512;
hope = page512_volt / voltmeter.resolution;
for (uint8_t i = 0; i < 10; i++) {
volt_raw_list[i] = 0;
}
}
if (M5.BtnB.wasPressed()) {
voltmeter.setMode(SINGLESHOT);
voltmeter.setRate(RATE_8);
voltmeter.setGain(PAG_4096);
now_gain = PAG_4096;
hope = page4096_volt / voltmeter.resolution;
for (uint8_t i = 0; i < 10; i++) {
volt_raw_list[i] = 0;
}
}
if (M5.BtnC.wasPressed()) {
bool success = voltmeter.saveCalibration2EEPROM(now_gain, hope, adc_raw);
M5.Lcd.setCursor(230, 210);
if (success) {
M5.Lcd.setTextColor(GREEN, BLACK);
} else {
M5.Lcd.setTextColor(RED, BLACK);
}
M5.Lcd.printf("SAVE");
delay(300);
M5.Lcd.setCursor(230, 210);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.printf("SAVE");
voltmeter.setGain(now_gain);
}
voltmeter.getVoltage();
volt_raw_list[raw_now_ptr] = voltmeter.adc_raw;
raw_now_ptr = (raw_now_ptr == 9) ? 0 : (raw_now_ptr + 1);
int count = 0;
int total = 0;
for (uint8_t i = 0; i < 10; i++) {
if (volt_raw_list[i] == 0) {
continue ;
}
total += volt_raw_list[i];
count += 1;
}
if (count == 0) {
adc_raw = 0;
} else {
adc_raw = total / count;
}
M5.Lcd.setTextColor(WHITE, BLACK);
if (now_gain == PAG_512) {
M5.Lcd.setCursor(10, 10);
M5.Lcd.printf("Hope volt: %.2f mv \r\n", page512_volt);
} else {
M5.Lcd.setCursor(10, 10);
M5.Lcd.printf("Hope volt: %.2f mv \r\n", page4096_volt);
}
M5.Lcd.setCursor(10, 40);
M5.Lcd.printf("Hope ADC: %d \r\n", hope);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.setCursor(10, 80);
M5.Lcd.printf("Cal volt: %.2f mv \r\n", adc_raw * voltmeter.resolution * voltmeter.calibration_factor);
M5.Lcd.setTextColor(WHITE, BLACK);
M5.Lcd.setCursor(10, 110);
M5.Lcd.printf("Cal ADC: %.0f \r\n", adc_raw * voltmeter.calibration_factor);
M5.Lcd.setCursor(10, 150);
if (adc_raw <= hope * 1.001 && adc_raw >= hope * 0.999) {
M5.Lcd.setTextColor(GREEN, BLACK);
} else {
M5.Lcd.setTextColor(RED, BLACK);
}
M5.Lcd.printf("RAW ADC: %d \r\n", adc_raw);
}

View File

@@ -0,0 +1,286 @@
#include "voltmeter.h"
#include "Wire.h"
void Voltmeter::i2cBegin() {
// Wire.begin();
}
bool Voltmeter::i2cReadBytes(uint8_t addr, uint8_t reg_addr, uint8_t* buff, uint16_t len) {
Wire.beginTransmission(addr);
Wire.write(reg_addr);
uint8_t i = 0;
if (Wire.endTransmission(false) == 0 && Wire.requestFrom(addr, (uint8_t)len)) {
while (Wire.available()) {
buff[i++] = Wire.read();
}
return true;
}
return false;
}
bool Voltmeter::i2cWriteBytes(uint8_t addr, uint8_t reg_addr, uint8_t* buff, uint16_t len) {
bool function_result = false;
Wire.beginTransmission(addr);
Wire.write(reg_addr);
for(int i = 0; i < len; i++) {
Wire.write(*(buff+i));
}
function_result = (Wire.endTransmission() == 0);
return function_result;
}
bool Voltmeter::i2cReadU16(uint8_t addr, uint8_t reg_addr, uint16_t* value) {
uint8_t read_buf[2] = {0x00, 0x00};
bool result = i2cReadBytes(addr, reg_addr, read_buf, 2);
*value = (read_buf[0] << 8) | read_buf[1];
return result;
}
bool Voltmeter::i2cWriteU16(uint8_t addr, uint8_t reg_addr, uint16_t value) {
uint8_t write_buf[2];
write_buf[0] = value >> 8;
write_buf[1] = value & 0xff;
return i2cWriteBytes(addr, reg_addr, write_buf, 2);
}
float Voltmeter::getResolution(voltmeterGain_t gain) {
switch (gain) {
case PAG_6144:
return ADS1115_MV_6144 / VOLTMETER_PRESSURE_COEFFICIENT;
case PAG_4096:
return ADS1115_MV_4096 / VOLTMETER_PRESSURE_COEFFICIENT;
case PAG_2048:
return ADS1115_MV_2048 / VOLTMETER_PRESSURE_COEFFICIENT;
case PAG_1024:
return ADS1115_MV_1024 / VOLTMETER_PRESSURE_COEFFICIENT;
case PAG_512:
return ADS1115_MV_512 / VOLTMETER_PRESSURE_COEFFICIENT;
case PAG_256:
return ADS1115_MV_256 / VOLTMETER_PRESSURE_COEFFICIENT;
default:
return ADS1115_MV_256 / VOLTMETER_PRESSURE_COEFFICIENT;
};
}
uint8_t Voltmeter::getPGAEEEPROMAddr(voltmeterGain_t gain) {
switch (gain) {
case PAG_6144:
return VOLTMETER_PAG_6144_CAL_ADDR;
case PAG_4096:
return VOLTMETER_PAG_4096_CAL_ADDR;
case PAG_2048:
return VOLTMETER_PAG_2048_CAL_ADDR;
case PAG_1024:
return VOLTMETER_PAG_1024_CAL_ADDR;
case PAG_512:
return VOLTMETER_PAG_512_CAL_ADDR;
case PAG_256:
return VOLTMETER_PAG_256_CAL_ADDR;
default:
return 0x00;
};
}
uint16_t Voltmeter::getCoverTime(voltmeterRate_t rate) {
switch (rate) {
case RATE_8:
return 1000 / 8;
case RATE_16:
return 1000 / 16;
case RATE_32:
return 1000 / 32;
case RATE_64:
return 1000 / 64;
case RATE_128:
return 1000 / 128;
case RATE_250:
return 1000 / 250;
case RATE_475:
return 1000 / 475;
case RATE_860:
return 1000 / 860;
default:
return 1000 / 128;
};
}
Voltmeter::Voltmeter(uint8_t ads1115_addr, uint8_t eeprom_addr) {
_ads1115_addr = ads1115_addr;
_eeprom_addr = eeprom_addr;
_gain = PAG_2048;
_mode = SINGLESHOT;
_rate = RATE_128;
calibration_factor = 1;
adc_raw = 0;
resolution = getResolution(_gain);
cover_time = getCoverTime(_rate);
}
void Voltmeter::setGain(voltmeterGain_t gain) {
uint16_t reg_value = 0;
bool result = i2cReadU16(_ads1115_addr, ADS1115_RA_CONFIG, &reg_value);
if (result == false) {
return;
}
reg_value &= ~(0b0111 << 9);
reg_value |= gain << 9;
result = i2cWriteU16(_ads1115_addr, ADS1115_RA_CONFIG, reg_value);
if (result) {
_gain = gain;
resolution = getResolution(gain);
int16_t hope = 1;
int16_t actual = 1;
if (readCalibrationFromEEPROM(gain, &hope, &actual)) {
calibration_factor = (double)hope / actual;
}
}
}
void Voltmeter::setRate(voltmeterRate_t rate) {
uint16_t reg_value = 0;
bool result = i2cReadU16(_ads1115_addr, ADS1115_RA_CONFIG, &reg_value);
if (result == false) {
return;
}
reg_value &= ~(0b0111 << 5);
reg_value |= rate << 5;
result = i2cWriteU16(_ads1115_addr, ADS1115_RA_CONFIG, reg_value);
if (result) {
_rate = rate;
cover_time = getCoverTime(_rate);
}
return;
}
void Voltmeter::setMode(voltmeterMode_t mode) {
uint16_t reg_value = 0;
bool result = i2cReadU16(_ads1115_addr, ADS1115_RA_CONFIG, &reg_value);
if (result == false) {
return;
}
reg_value &= ~(0b0001 << 8);
reg_value |= mode << 8;
result = i2cWriteU16(_ads1115_addr, ADS1115_RA_CONFIG, reg_value);
if (result) {
_mode = mode;
}
return;
}
bool Voltmeter::isInConversion() {
uint16_t value = 0x00;
i2cReadU16(_ads1115_addr, ADS1115_RA_CONFIG, &value);
return (value & (1 << 15)) ? false : true;
}
void Voltmeter::startSingleConversion() {
uint16_t reg_value = 0;
bool result = i2cReadU16(_ads1115_addr, ADS1115_RA_CONFIG, &reg_value);
if (result == false) {
return;
}
reg_value &= ~(0b0001 << 15);
reg_value |= 0x01 << 15;
i2cWriteU16(_ads1115_addr, ADS1115_RA_CONFIG, reg_value);
}
float Voltmeter::getVoltage(bool calibration) {
if (calibration) {
return resolution * calibration_factor * getConversion() * VOLTMETER_MEASURING_DIR;
} else {
return resolution * getConversion() * VOLTMETER_MEASURING_DIR;
}
}
int16_t Voltmeter::getAdcRaw() {
uint16_t value = 0x00;
i2cReadU16(_ads1115_addr, ADS1115_RA_CONVERSION, &value);
adc_raw = value;
return value;
}
int16_t Voltmeter::getConversion(uint16_t timeout) {
if (_mode == SINGLESHOT) {
startSingleConversion();
delay(cover_time);
uint64_t time = millis() + timeout;
while (time > millis() && isInConversion());
}
return getAdcRaw();
}
bool Voltmeter::EEPORMWrite(uint8_t address, uint8_t* buff, uint8_t len) {
return i2cWriteBytes(_eeprom_addr, address, buff, len);
}
bool Voltmeter::EEPORMRead(uint8_t address, uint8_t* buff, uint8_t len) {
return i2cReadBytes(_eeprom_addr, address, buff, len);
}
bool Voltmeter::saveCalibration2EEPROM(voltmeterGain_t gain, int16_t hope, int16_t actual) {
if (hope == 0 || actual == 0) {
return false;
}
uint8_t buff[8];
memset(buff, 0, 8);
buff[0] = gain;
buff[1] = hope >> 8;
buff[2] = hope & 0xFF;
buff[3] = actual >> 8;
buff[4] = actual & 0xFF;
for (uint8_t i = 0; i < 5; i++) {
buff[5] ^= buff[i];
}
uint8_t addr = getPGAEEEPROMAddr(gain);
return EEPORMWrite(addr, buff, 8);
}
bool Voltmeter::readCalibrationFromEEPROM(voltmeterGain_t gain, int16_t* hope, int16_t* actual) {
uint8_t addr = getPGAEEEPROMAddr(gain);
uint8_t buff[8];
memset(buff, 0, 8);
*hope = 1;
*actual = 1;
bool result = EEPORMRead(addr, buff, 8);
if (result == false) {
return false;
}
uint8_t xor_result = 0x00;
for (uint8_t i = 0; i < 5; i++) {
xor_result ^= buff[i];
}
if (xor_result != buff[5]) {
return false;
}
*hope = (buff[1] << 8) | buff[2];
*actual = (buff[3] << 8) | buff[4];
return true;
}

View File

@@ -0,0 +1,125 @@
#pragma once
#include "Arduino.h"
#define ADS115_ADDR 0x49
#define EEPROM_ADDR 0x53
#define ADS1115_RA_CONVERSION 0x00
#define ADS1115_RA_CONFIG 0x01
#define ADS1115_PGA_6144 0x00
#define ADS1115_PGA_4096 0x01
#define ADS1115_PGA_2048 0x02 // default
#define ADS1115_PGA_1024 0x03
#define ADS1115_PGA_512 0x04
#define ADS1115_PGA_256 0x05
#define ADS1115_MV_6144 0.187500F
#define ADS1115_MV_4096 0.125000F
#define ADS1115_MV_2048 0.062500F // default
#define ADS1115_MV_1024 0.031250F
#define ADS1115_MV_512 0.015625F
#define ADS1115_MV_256 0.007813F
#define ADS1115_RATE_8 0x00
#define ADS1115_RATE_16 0x01
#define ADS1115_RATE_32 0x02
#define ADS1115_RATE_64 0x03
#define ADS1115_RATE_128 0x04 // default
#define ADS1115_RATE_250 0x05
#define ADS1115_RATE_475 0x06
#define ADS1115_RATE_860 0x07
#define VOLTMETER_MEASURING_DIR -1
#define ADS1115_MUX_P0N1 0x00 // voltmeter only support
#define ADS1115_COMP_MODE_HYSTERESIS 0x00 // default
#define ADS1115_COMP_MODE_WINDOW 0x01
#define ADS1115_MODE_CONTINUOUS 0x00
#define ADS1115_MODE_SINGLESHOT 0x01 // default
#define VOLTMETER_PRESSURE_COEFFICIENT 0.015918958F
#define VOLTMETER_PAG_6144_CAL_ADDR 208
#define VOLTMETER_PAG_4096_CAL_ADDR 216
#define VOLTMETER_PAG_2048_CAL_ADDR 224
#define VOLTMETER_PAG_1024_CAL_ADDR 232
#define VOLTMETER_PAG_512_CAL_ADDR 240
#define VOLTMETER_PAG_256_CAL_ADDR 248
#define VOLTMETER_FILTER_NUMBER 10
typedef enum {
PAG_6144 = ADS1115_PGA_6144,
PAG_4096 = ADS1115_PGA_4096,
PAG_2048 = ADS1115_PGA_2048, // default
PAG_1024 = ADS1115_PGA_1024,
PAG_512 = ADS1115_PGA_512,
PAG_256 = ADS1115_PGA_256,
} voltmeterGain_t;
typedef enum {
RATE_8 = ADS1115_RATE_8,
RATE_16 = ADS1115_RATE_16,
RATE_32 = ADS1115_RATE_32,
RATE_64 = ADS1115_RATE_64,
RATE_128 = ADS1115_RATE_128, // default
RATE_250 = ADS1115_RATE_250,
RATE_475 = ADS1115_RATE_475,
RATE_860 = ADS1115_RATE_860,
} voltmeterRate_t;
typedef enum {
SINGLESHOT = ADS1115_MODE_SINGLESHOT,
CONTINUOUS = ADS1115_MODE_CONTINUOUS,
} voltmeterMode_t;
class Voltmeter {
private:
void i2cBegin();
bool i2cReadBytes(uint8_t addr, uint8_t reg_addr, uint8_t* buff, uint16_t len);
bool i2cWriteBytes(uint8_t addr, uint8_t reg_addr, uint8_t* buff, uint16_t len);
bool i2cReadU16(uint8_t addr, uint8_t reg_addr, uint16_t* value);
bool i2cWriteU16(uint8_t addr, uint8_t reg_addr, uint16_t value);
float getResolution(voltmeterGain_t gain);
uint16_t getCoverTime(voltmeterRate_t rate);
uint8_t getPGAEEEPROMAddr(voltmeterGain_t gain);
uint8_t _ads1115_addr;
uint8_t _eeprom_addr;
public:
voltmeterGain_t _gain;
voltmeterRate_t _rate;
voltmeterMode_t _mode;
float resolution;
uint16_t cover_time;
int16_t adc_raw;
float calibration_factor;
public:
Voltmeter(uint8_t ads1115_addr=ADS115_ADDR, uint8_t eeprom_addr=EEPROM_ADDR);
void setGain(voltmeterGain_t gain);
void setRate(voltmeterRate_t rate);
void setMode(voltmeterMode_t mode);
float getVoltage(bool calibration = true);
int16_t getConversion(uint16_t timeout = 125);
int16_t getAdcRaw();
bool isInConversion();
void startSingleConversion();
bool EEPORMWrite(uint8_t address, uint8_t* buff, uint8_t len);
bool EEPORMRead(uint8_t address, uint8_t* buff, uint8_t len);
void setCalibration(int8_t voltage, uint16_t actual);
bool saveCalibration2EEPROM(voltmeterGain_t gain, int16_t hope, int16_t actual);
bool readCalibrationFromEEPROM(voltmeterGain_t gain, int16_t* hope, int16_t* actual);
};

View File

@@ -0,0 +1,53 @@
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with M5Core2 sample source code
* 配套 M5Core2 示例源代码
* Visit the website for more information: https://docs.m5stack.com/en/core/core2
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/core2
*
* describe: Weight.
* date: 2021/8/20
*******************************************************************************
Please connect to Port B,Use WEIGHT Unit to read the analog value returned by the pressure sensor,
convert it into intuitive weight data and send it to M5Core,Press ButtonA to calibrate
请连接端口B,使用WEIGHT Unit读取压力传感器返回的模拟值将其转换为直观的重量数据发送到M5Core按下按钮A进行校准
*/
#include<M5Core2.h>
#include "HX711.h"
// HX711 related pin Settings. HX711 相关引脚设置
#define LOADCELL_DOUT_PIN 36
#define LOADCELL_SCK_PIN 26
HX711 scale;
const long LOADCELL_OFFSET = 50682624;
const long LOADCELL_DIVIDER = 5895655;
void setup() {
M5.begin(); //Init M5Core2. 初始化M5Core2
M5.lcd.setTextSize(2); //Set the text size to 2. 设置文字大小为2
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN); // Initialize library with data output pin, clock input pin and gain factor. 初始化库的数据输出引脚,时钟输入引脚和增益因子。
scale.set_scale(LOADCELL_DIVIDER); //set the SCALE value this value is used to convert the raw data to measure units. 设置SCALE值,该值用于将原始数据转换为度量单位
scale.set_offset(LOADCELL_OFFSET); //Set the tare weight. 设置皮重
scale.set_scale(61.2f); // this value is obtained by calibrating the scale with known weights; see the README for details. 这个值是通过校正已知权重的刻度而得到的
scale.tare(); // reset the scale to 0. 将比例重置为0
M5.Lcd.print(" Weight Unit\nConnect the Weight Unit to PortB");
M5.Lcd.setCursor(20,210,1);
M5.Lcd.print("Calibration");
}
void loop() {
M5.update();
if (M5.BtnA.wasPressed()) { //If button A is pressed. 如果按键A按下
scale.set_offset(LOADCELL_OFFSET + scale.read());
scale.set_scale(61.2f);
scale.tare();
}
int weight = scale.get_units(5);
M5.Lcd.fillRect(75, 80, 320, 80, BLACK);
M5.Lcd.setCursor(75,80);
M5.Lcd.printf("Weight:%1d g", weight);
}