初始化提交

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,53 @@
#include <M5StickCPlus.h>
void setup()
{
M5.Lcd.begin();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen( BLACK );
M5.Lcd.setCursor(0, 0);
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.setTextSize(1);
M5.Lcd.fillScreen( BLACK );
M5.Lcd.setCursor(0, 0);
M5.Lcd.println("M5StickC I2C Tester");
//For HY2.0-4P
Wire.begin();
//For HAT
Wire1.begin(0,26);
delay(3000);
M5.Lcd.fillScreen( BLACK );
}
int textColor=YELLOW;
void loop()
{
int address;
int error;
int error1;
M5.Lcd.setCursor(0, 0);
M5.Lcd.println("scanning Address [HEX]");
for(address = 1; address < 127; address++ )
{
Wire.beginTransmission(address);
Wire1.beginTransmission(address);
error = Wire.endTransmission();
error1 = Wire1.endTransmission();
if((error==0)||(error1==0))
{
M5.Lcd.print(address,HEX);M5.Lcd.print(" ");
}
else M5.Lcd.print(".");
delay(10);
}
if(textColor==YELLOW) textColor=GREEN;
else textColor=YELLOW;
M5.Lcd.setTextColor(textColor,BLACK);
}

View File

@@ -0,0 +1,12 @@
#include <M5StickCPlus.h>
void setup() {
M5.begin();
// Display QRCode
M5.Lcd.qrcode("http://www.m5stack.com", 0, 0, 135);
// M5.Lcd.qrcode(const char *string, uint16_t x = 50, uint16_t y = 10, uint8_t width = 220, uint8_t version = 6);
}
void loop() {
}

View File

@@ -0,0 +1,49 @@
#include <M5StickCPlus.h>
#include "AXP192.h"
TFT_eSprite tftSprite = TFT_eSprite(&M5.Lcd);
void setup() {
M5.begin();
M5.Lcd.setRotation(3);
tftSprite.createSprite(160, 80);
tftSprite.setRotation(3);
M5.Axp.EnableCoulombcounter();
}
void loop() {
tftSprite.fillSprite(BLACK);
tftSprite.setCursor(0, 0, 1);
tftSprite.printf("AXP Temp: %.1fC \r\n", M5.Axp.GetTempInAXP192());
tftSprite.setCursor(0, 10);
tftSprite.printf("Bat:\r\n V: %.3fv I: %.3fma\r\n", M5.Axp.GetBatVoltage(), M5.Axp.GetBatCurrent());
tftSprite.setCursor(0, 30);
tftSprite.printf("USB:\r\n V: %.3fv I: %.3fma\r\n", M5.Axp.GetVBusVoltage(), M5.Axp.GetVBusCurrent());
tftSprite.setCursor(0, 50);
tftSprite.printf("5V-In:\r\n V: %.3fv I: %.3fma\r\n", M5.Axp.GetVinVoltage(), M5.Axp.GetVinCurrent());
tftSprite.setCursor(0, 70);
tftSprite.printf("Bat power %.3fmw", M5.Axp.GetBatPower());
tftSprite.pushSprite(40, 20);
// 0x01 long press(1s), 0x02 press
if(M5.Axp.GetBtnPress() == 0x02)
{
esp_restart();
}
if(M5.BtnA.wasPressed())
{
// close tft voltage output
M5.Axp.SetLDO2(false);
}
if(M5.BtnB.wasPressed())
{
// close tft voltage output
M5.Axp.SetLDO2(true);
}
// M5.Axp.SetChargeCurrent(CURRENT_100MA);
M5.update();
delay(100);
}

View File

@@ -0,0 +1,47 @@
#include <M5StickCPlus.h>
// the setup routine runs once when M5StickC starts up
void setup() {
// initialize the M5StickC object
M5.begin();
// Lcd display
M5.Lcd.fillScreen(WHITE);
delay(500);
M5.Lcd.fillScreen(RED);
delay(500);
M5.Lcd.fillScreen(GREEN);
delay(500);
M5.Lcd.fillScreen(BLUE);
delay(500);
M5.Lcd.fillScreen(BLACK);
delay(500);
// text print
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(0, 10);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setTextSize(1);
M5.Lcd.printf("Display Test!");
// draw graphic
delay(1000);
M5.Lcd.drawRect(15, 55, 50, 50, BLUE);
delay(1000);
M5.Lcd.fillRect(15, 55, 50, 50, BLUE);
delay(1000);
M5.Lcd.drawCircle(40, 80, 30, RED);
delay(1000);
M5.Lcd.fillCircle(40, 80, 30, RED);
delay(1000);
}
// the loop routine runs over and over again forever
void loop(){
//rand draw
M5.Lcd.fillTriangle(random(M5.Lcd.width()-1), random(M5.Lcd.height()-1), random(M5.Lcd.width()-1), random(M5.Lcd.height()-1), random(M5.Lcd.width()-1), random(M5.Lcd.height()-1), random(0xfffe));
//M5.update();
}

View File

@@ -0,0 +1,58 @@
#include <M5StickCPlus.h>
float accX = 0.0F;
float accY = 0.0F;
float accZ = 0.0F;
float gyroX = 0.0F;
float gyroY = 0.0F;
float gyroZ = 0.0F;
float pitch = 0.0F;
float roll = 0.0F;
float yaw = 0.0F;
void setup() {
// put your setup code here, to run once:
M5.begin();
M5.IMU.Init();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(80, 15);
M5.Lcd.println("IMU TEST");
M5.Lcd.setCursor(30, 30);
M5.Lcd.println(" X Y Z");
M5.Lcd.setCursor(30, 70);
M5.Lcd.println(" Pitch Roll Yaw");
}
float temp = 0;
/*****************************************
M5.IMU.getGyroData(&gyroX,&gyroY,&gyroZ);
M5.IMU.getAccelData(&accX,&accY,&accZ);
M5.IMU.getAhrsData(&pitch,&roll,&yaw);
M5.IMU.getTempData(&temp);
*****************************************/
void loop() {
// put your main code here, to run repeatedly:
M5.IMU.getGyroData(&gyroX,&gyroY,&gyroZ);
M5.IMU.getAccelData(&accX,&accY,&accZ);
M5.IMU.getAhrsData(&pitch,&roll,&yaw);
M5.IMU.getTempData(&temp);
M5.Lcd.setCursor(30, 40);
M5.Lcd.printf("%6.2f %6.2f %6.2f ", gyroX, gyroY, gyroZ);
M5.Lcd.setCursor(170, 40);
M5.Lcd.print("o/s");
M5.Lcd.setCursor(30, 50);
M5.Lcd.printf(" %5.2f %5.2f %5.2f ", accX, accY, accZ);
M5.Lcd.setCursor(170, 50);
M5.Lcd.print("G");
M5.Lcd.setCursor(30, 80);
M5.Lcd.printf(" %5.2f %5.2f %5.2f ", pitch, roll, yaw);
M5.Lcd.setCursor(30, 95);
M5.Lcd.printf("Temperature : %.2f C", temp);
delay(100);
}

View File

@@ -0,0 +1,42 @@
#include <M5StickCPlus.h>
float accX = 0;
float accY = 0;
float accZ = 0;
float gyroX = 0;
float gyroY = 0;
float gyroZ = 0;
float temp = 0;
void setup() {
// put your setup code here, to run once:
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(50, 15);
M5.Lcd.println("MPU6886 TEST");
M5.Lcd.setCursor(30, 30);
M5.Lcd.println(" X Y Z");
M5.Imu.Init();
}
void loop() {
// put your main code here, to run repeatedly:
M5.Imu.getGyroData(&gyroX,&gyroY,&gyroZ);
M5.Imu.getAccelData(&accX,&accY,&accZ);
M5.Imu.getTempData(&temp);
M5.Lcd.setCursor(30, 45);
M5.Lcd.printf("%.2f %.2f %.2f ", gyroX, gyroY,gyroZ);
M5.Lcd.setCursor(170, 45);
M5.Lcd.print("o/s");
M5.Lcd.setCursor(30, 60);
M5.Lcd.printf("%.2f %.2f %.2f ",accX * 1000,accY * 1000, accZ * 1000);
M5.Lcd.setCursor(185, 60);
M5.Lcd.print("mg");
M5.Lcd.setCursor(30, 75);
M5.Lcd.printf("Temperature : %.2f C", temp);
delay(100);
}

View File

@@ -0,0 +1,79 @@
#include <M5StickCPlus.h>
#include <driver/i2s.h>
#define PIN_CLK 0
#define PIN_DATA 34
#define READ_LEN (2 * 256)
#define GAIN_FACTOR 3
uint8_t BUFFER[READ_LEN] = {0};
uint16_t oldy[160];
int16_t *adcBuffer = NULL;
void showSignal(){
int y;
for (int n = 0; n < 160; n++){
y = adcBuffer[n] * GAIN_FACTOR;
y = map(y, INT16_MIN, INT16_MAX, 10, 70);
M5.Lcd.drawPixel(n, oldy[n],WHITE);
M5.Lcd.drawPixel(n,y,BLACK);
oldy[n] = y;
}
}
void mic_record_task (void* arg)
{
size_t bytesread;
while(1){
i2s_read(I2S_NUM_0,(char*) BUFFER, READ_LEN, &bytesread, (100 / portTICK_RATE_MS));
adcBuffer = (int16_t *)BUFFER;
showSignal();
vTaskDelay(100 / portTICK_RATE_MS);
}
}
void i2sInit()
{
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM),
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
.channel_format = I2S_CHANNEL_FMT_ALL_RIGHT,
.communication_format = I2S_COMM_FORMAT_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 2,
.dma_buf_len = 128,
};
i2s_pin_config_t pin_config;
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_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM_0, &pin_config);
i2s_set_clk(I2S_NUM_0, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
}
void setup() {
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(WHITE);
M5.Lcd.setTextColor(BLACK, WHITE);
M5.Lcd.println("mic test");
i2sInit();
xTaskCreate(mic_record_task, "mic_record_task", 2048, NULL, 1, NULL);
}
void loop() {
printf("loop cycling\n");
vTaskDelay(1000 / portTICK_RATE_MS); // otherwise the main task wastes half of the cpu cycles
}

View File

@@ -0,0 +1,39 @@
#include <M5StickCPlus.h>
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DateStruct;
void setup() {
// put your setup code here, to run once:
M5.begin();
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(60, 10, 2);
M5.Lcd.println("RTC TEST");
RTC_TimeTypeDef TimeStruct;
TimeStruct.Hours = 18;
TimeStruct.Minutes = 56;
TimeStruct.Seconds = 10;
M5.Rtc.SetTime(&TimeStruct);
RTC_DateTypeDef DateStruct;
DateStruct.WeekDay = 3;
DateStruct.Month = 3;
DateStruct.Date = 22;
DateStruct.Year = 2019;
M5.Rtc.SetData(&DateStruct);
}
void loop() {
// put your main code here, to run repeatedly:
M5.Rtc.GetTime(&RTC_TimeStruct);
M5.Rtc.GetData(&RTC_DateStruct);
M5.Lcd.setCursor(30, 35);
M5.Lcd.printf("Data: %04d-%02d-%02d\n",RTC_DateStruct.Year, RTC_DateStruct.Month,RTC_DateStruct.Date);
M5.Lcd.setCursor(30, 55);
M5.Lcd.printf("Week: %d\n",RTC_DateStruct.WeekDay);
M5.Lcd.setCursor(30, 75);
M5.Lcd.printf("Time: %02d : %02d : %02d\n",RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes, RTC_TimeStruct.Seconds);
delay(500);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,151 @@
#include "TFTTerminal.h"
TFTTerminal::TFTTerminal(TFT_eSprite *dis_buff_ptr)
{
_dis_buff_ptr = dis_buff_ptr;
memset(discharbuff, 0, 55 * 60);
}
TFTTerminal::~TFTTerminal()
{
}
void TFTTerminal::setcolor( uint16_t color, uint16_t bk_color )
{
_color = color;
_bkcolor = bk_color;
}
void TFTTerminal::setGeometry(uint16_t x, uint16_t y, uint16_t w, uint16_t h )
{
_win_x_pos = x;
_win_y_pos = y;
_win_w = w;
_win_h = h;
_line_x_limit = _win_w / _font_x_size;
_line_y_limit = _win_h / _font_y_size;
}
size_t TFTTerminal::write(uint8_t chardata)
{
bool flush_page_flag = false;
uint8_t dis_y_pos = 0;
if ((chardata == '\r') || (chardata == '\n'))
{
xpos = 0;
ypos++;
ypos = ypos % 60;
memset(discharbuff[ypos % 60], 0, 55);
return 1;
}
else if(xpos >= _line_x_limit)
{
xpos = 0;
ypos++;
ypos = ypos % 60;
memset(discharbuff[ypos % 60], 0, 55);
}
discharbuff[ypos][xpos] = chardata;
xpos++;
if ((dispos <= ypos) && ((ypos - dispos) > _line_y_limit))
{
dispos = ypos - _line_y_limit;
flush_page_flag = true;
}
else if ((dispos <= ypos) && ((ypos - dispos) <= _line_y_limit))
{
dis_y_pos = ypos - dispos;
flush_page_flag = false;
}
else if ((dispos > ypos) && ((60 - (dispos - ypos)) > _line_y_limit))
{
dispos = 60 - ( _line_y_limit - ypos );
flush_page_flag = true;
}
else if ((dispos > ypos) && ((60 - (dispos - ypos)) > _line_y_limit))
{
dis_y_pos = 60 - ( dispos - ypos );
flush_page_flag = false;
}
dispos = dispos % 60;
_dis_buff_ptr->setTextColor(_color);
_dis_buff_ptr->setTextSize(0);
if( flush_page_flag )
{
_dis_buff_ptr->fillSprite(_bkcolor);
for (size_t i = 0; i < _line_y_limit; i++)
{
_dis_buff_ptr->drawString((char *)discharbuff[(dispos + i) % 60], 0, i * 8);
}
}
else
{
_dis_buff_ptr->drawChar(chardata, ( xpos - 1 ) * _font_x_size, dis_y_pos * _font_y_size );
}
_dis_buff_ptr->pushSprite(_win_x_pos, _win_y_pos);
return 1;
}
size_t TFTTerminal::write(const uint8_t *buffer, size_t size)
{
while ((size != 0) && (*buffer != '\0'))
{
if ((*buffer == '\r') || (*buffer == '\n'))
{
xpos = 0;
ypos++;
ypos = ypos % 60;
memset(discharbuff[ypos % 60], 0, 55);
buffer++;
size--;
continue;
}
else if(xpos >= _line_x_limit)
{
xpos = 0;
ypos++;
ypos = ypos % 60;
memset(discharbuff[ypos % 60], 0, 55);
}
discharbuff[ypos][xpos] = *buffer;
xpos++;
buffer++;
size--;
}
if ((dispos <= ypos) && ((ypos - dispos) > _line_y_limit))
{
dispos = ypos - _line_y_limit;
}
else if ((dispos > ypos) && ((60 - (dispos - ypos)) > _line_y_limit))
{
dispos = 60- ( _line_y_limit - ypos );
}
dispos = dispos % 60;
_dis_buff_ptr->setTextColor(_color);
_dis_buff_ptr->setTextSize(0);
_dis_buff_ptr->fillSprite(_bkcolor);
//_dis_buff_ptr->fillRect(_win_x_pos, _win_y_pos, _win_w, _win_h, _bkcolor);
for (size_t i = 0; i < _line_y_limit; i++)
{
_dis_buff_ptr->drawString((char *)discharbuff[(dispos + i) % 60], 0, i * 8);
}
_dis_buff_ptr->pushSprite(_win_x_pos, _win_y_pos);
return 1;
}

View File

@@ -0,0 +1,34 @@
#ifndef _TFTTERMINAL_H_
#define _TFTTERMINAL_H_
#include <M5StickCPlus.h>
#include <Print.h>
class TFTTerminal : public Print
{
private:
TFT_eSprite *disptr;
char discharbuff[60][55];
uint32_t xpos = 0,ypos = 0, dispos = 0;
TFT_eSprite* _dis_buff_ptr = NULL;
uint16_t _bkcolor = TFT_BLACK;
uint16_t _color = TFT_GREEN;
uint16_t _win_x_pos = 0,_win_y_pos = 0,_win_w = 320,_win_h = 240;
uint16_t _font_x_size = 6,_font_y_size = 8;
uint16_t _line_x_limit = 53,_line_y_limit = 30;
public:
TFTTerminal(TFT_eSprite *dis_buff_ptr);
~TFTTerminal();
void setcolor( uint16_t color, uint16_t bk_color );
void setGeometry(uint16_t x, uint16_t y, uint16_t w, uint16_t h );
void setFontsize(uint8_t size);
size_t write(uint8_t) ;
size_t write(const uint8_t *buffer, size_t size);
};
#endif

View File

@@ -0,0 +1,693 @@
/*
ESP32 FFT
=========
This provides a vanilla radix-2 FFT implementation and a test example.
Author
------
This code was written by [Robin Scheibler](http://www.robinscheibler.org) during rainy days in October 2017.
License
-------
Copyright (c) 2017 Robin Scheibler
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 <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <complex.h>
#include "fft.h"
#define TWO_PI 6.28318530
#define USE_SPLIT_RADIX 1
#define LARGE_BASE_CASE 1
fft_config_t *fft_init(int size, fft_type_t type, fft_direction_t direction, float *input, float *output)
{
/*
* Prepare an FFT of correct size and types.
*
* If no input or output buffers are provided, they will be allocated.
*/
int k,m;
fft_config_t *config = (fft_config_t *)malloc(sizeof(fft_config_t));
// Check if the size is a power of two
if ((size & (size-1)) != 0) // tests if size is a power of two
return NULL;
// start configuration
config->flags = 0;
config->type = type;
config->direction = direction;
config->size = size;
// Allocate and precompute twiddle factors
config->twiddle_factors = (float *)malloc(2 * config->size * sizeof(float));
float two_pi_by_n = TWO_PI / config->size;
for (k = 0, m = 0 ; k < config->size ; k++, m+=2)
{
config->twiddle_factors[m] = cosf(two_pi_by_n * k); // real
config->twiddle_factors[m+1] = sinf(two_pi_by_n * k); // imag
}
// Allocate input buffer
if (input != NULL)
config->input = input;
else
{
if (config->type == FFT_REAL)
config->input = (float *)malloc(config->size * sizeof(float));
else if (config->type == FFT_COMPLEX)
config->input = (float *)malloc(2 * config->size * sizeof(float));
config->flags |= FFT_OWN_INPUT_MEM;
}
if (config->input == NULL)
return NULL;
// Allocate output buffer
if (output != NULL)
config->output = output;
else
{
if (config->type == FFT_REAL)
config->output = (float *)malloc(config->size * sizeof(float));
else if (config->type == FFT_COMPLEX)
config->output = (float *)malloc(2 * config->size * sizeof(float));
config->flags |= FFT_OWN_OUTPUT_MEM;
}
if (config->output == NULL)
return NULL;
return config;
}
void fft_destroy(fft_config_t *config)
{
if (config->flags & FFT_OWN_INPUT_MEM)
free(config->input);
if (config->flags & FFT_OWN_OUTPUT_MEM)
free(config->output);
free(config->twiddle_factors);
free(config);
}
void fft_execute(fft_config_t *config)
{
if (config->type == FFT_REAL && config->direction == FFT_FORWARD)
rfft(config->input, config->output, config->twiddle_factors, config->size);
else if (config->type == FFT_REAL && config->direction == FFT_BACKWARD)
irfft(config->input, config->output, config->twiddle_factors, config->size);
else if (config->type == FFT_COMPLEX && config->direction == FFT_FORWARD)
fft(config->input, config->output, config->twiddle_factors, config->size);
else if (config->type == FFT_COMPLEX && config->direction == FFT_BACKWARD)
ifft(config->input, config->output, config->twiddle_factors, config->size);
}
void fft(float *input, float *output, float *twiddle_factors, int n)
{
/*
* Forward fast Fourier transform
* DIT, radix-2, out-of-place implementation
*
* Parameters
* ----------
* input (float *)
* The input array containing the complex samples with
* real/imaginary parts interleaved [Re(x0), Im(x0), ..., Re(x_n-1), Im(x_n-1)]
* output (float *)
* The output array containing the complex samples with
* real/imaginary parts interleaved [Re(x0), Im(x0), ..., Re(x_n-1), Im(x_n-1)]
* n (int)
* The FFT size, should be a power of 2
*/
#if USE_SPLIT_RADIX
split_radix_fft(input, output, n, 2, twiddle_factors, 2);
#else
fft_primitive(input, output, n, 2, twiddle_factors, 2);
#endif
}
void ifft(float *input, float *output, float *twiddle_factors, int n)
{
/*
* Inverse fast Fourier transform
* DIT, radix-2, out-of-place implementation
*
* Parameters
* ----------
* input (float *)
* The input array containing the complex samples with
* real/imaginary parts interleaved [Re(x0), Im(x0), ..., Re(x_n-1), Im(x_n-1)]
* output (float *)
* The output array containing the complex samples with
* real/imaginary parts interleaved [Re(x0), Im(x0), ..., Re(x_n-1), Im(x_n-1)]
* n (int)
* The FFT size, should be a power of 2
*/
ifft_primitive(input, output, n, 2, twiddle_factors, 2);
}
void rfft(float *x, float *y, float *twiddle_factors, int n)
{
// This code uses the two-for-the-price-of-one strategy
#if USE_SPLIT_RADIX
split_radix_fft(x, y, n / 2, 2, twiddle_factors, 4);
#else
fft_primitive(x, y, n / 2, 2, twiddle_factors, 4);
#endif
// Now apply post processing to recover positive
// frequencies of the real FFT
float t = y[0];
y[0] = t + y[1]; // DC coefficient
y[1] = t - y[1]; // Center coefficient
// Apply post processing to quarter element
// this boils down to taking complex conjugate
y[n/2+1] = -y[n/2+1];
// Now process all the other frequencies
int k;
for (k = 2 ; k < n / 2 ; k += 2)
{
float xer, xei, xor_t, xoi, c, s, tr, ti;
c = twiddle_factors[k];
s = twiddle_factors[k+1];
// even half coefficient
xer = 0.5 * (y[k] + y[n-k]);
xei = 0.5 * (y[k+1] - y[n-k+1]);
// odd half coefficient
xor_t = 0.5 * (y[k+1] + y[n-k+1]);
xoi = - 0.5 * (y[k] - y[n-k]);
tr = c * xor_t + s * xoi;
ti = -s * xor_t + c * xoi;
y[k] = xer + tr;
y[k+1] = xei + ti;
y[n-k] = xer - tr;
y[n-k+1] = -(xei - ti);
}
}
void irfft(float *x, float *y, float *twiddle_factors, int n)
{
/*
* Destroys content of input vector
*/
int k;
// Here we need to apply a pre-processing first
float t = x[0];
x[0] = 0.5 * (t + x[1]);
x[1] = 0.5 * (t - x[1]);
x[n/2+1] = -x[n/2+1];
for (k = 2 ; k < n / 2 ; k += 2)
{
float xer, xei, xor_t, xoi, c, s, tr, ti;
c = twiddle_factors[k];
s = twiddle_factors[k+1];
xer = 0.5 * (x[k] + x[n-k]);
tr = 0.5 * (x[k] - x[n-k]);
xei = 0.5 * (x[k+1] - x[n-k+1]);
ti = 0.5 * (x[k+1] + x[n-k+1]);
xor_t = c * tr - s * ti;
xoi = s * tr + c * ti;
x[k] = xer - xoi;
x[k+1] = xor_t + xei;
x[n-k] = xer + xoi;
x[n-k+1] = xor_t - xei;
}
ifft_primitive(x, y, n / 2, 2, twiddle_factors, 4);
}
void fft_primitive(float *x, float *y, int n, int stride, float *twiddle_factors, int tw_stride)
{
/*
* This code will compute the FFT of the input vector x
*
* The input data is assumed to be real/imag interleaved
*
* The size n should be a power of two
*
* y is an output buffer of size 2n to accomodate for complex numbers
*
* Forward fast Fourier transform
* DIT, radix-2, out-of-place implementation
*
* For a complex FFT, call first stage as:
* fft(x, y, n, 2, 2);
*
* Parameters
* ----------
* x (float *)
* The input array containing the complex samples with
* real/imaginary parts interleaved [Re(x0), Im(x0), ..., Re(x_n-1), Im(x_n-1)]
* y (float *)
* The output array containing the complex samples with
* real/imaginary parts interleaved [Re(x0), Im(x0), ..., Re(x_n-1), Im(x_n-1)]
* n (int)
* The FFT size, should be a power of 2
* stride (int)
* The number of elements to skip between two successive samples
* tw_stride (int)
* The number of elements to skip between two successive twiddle factors
*/
int k;
float t;
#if LARGE_BASE_CASE
// End condition, stop at n=8 to avoid one trivial recursion
if (n == 8)
{
fft8(x, stride, y, 2);
return;
}
#else
// End condition, stop at n=2 to avoid one trivial recursion
if (n == 2)
{
y[0] = x[0] + x[stride];
y[1] = x[1] + x[stride + 1];
y[2] = x[0] - x[stride];
y[3] = x[1] - x[stride + 1];
return;
}
#endif
// Recursion -- Decimation In Time algorithm
fft_primitive(x, y, n / 2, 2 * stride, twiddle_factors, 2 * tw_stride); // even half
fft_primitive(x + stride, y+n, n / 2, 2 * stride, twiddle_factors, 2 * tw_stride); // odd half
// Stitch back together
// We can a few multiplications in the first step
t = y[0];
y[0] = t + y[n];
y[n] = t - y[n];
t = y[1];
y[1] = t + y[n+1];
y[n+1] = t - y[n+1];
for (k = 1 ; k < n / 2 ; k++)
{
float x1r, x1i, x2r, x2i, c, s;
c = twiddle_factors[k * tw_stride];
s = twiddle_factors[k * tw_stride + 1];
x1r = y[2 * k];
x1i = y[2 * k + 1];
x2r = c * y[n + 2 * k] + s * y[n + 2 * k + 1];
x2i = -s * y[n + 2 * k] + c * y[n + 2 * k + 1];
y[2 * k] = x1r + x2r;
y[2 * k + 1] = x1i + x2i;
y[n + 2 * k] = x1r - x2r;
y[n + 2 * k + 1] = x1i - x2i;
}
}
void split_radix_fft(float *x, float *y, int n, int stride, float *twiddle_factors, int tw_stride)
{
/*
* This code will compute the FFT of the input vector x
*
* The input data is assumed to be real/imag interleaved
*
* The size n should be a power of two
*
* y is an output buffer of size 2n to accomodate for complex numbers
*
* Forward fast Fourier transform
* Split-Radix
* DIT, radix-2, out-of-place implementation
*
* For a complex FFT, call first stage as:
* fft(x, y, n, 2, 2);
*
* Parameters
* ----------
* x (float *)
* The input array containing the complex samples with
* real/imaginary parts interleaved [Re(x0), Im(x0), ..., Re(x_n-1), Im(x_n-1)]
* y (float *)
* The output array containing the complex samples with
* real/imaginary parts interleaved [Re(x0), Im(x0), ..., Re(x_n-1), Im(x_n-1)]
* n (int)
* The FFT size, should be a power of 2
* stride (int)
* The number of elements to skip between two successive samples
* twiddle_factors (float *)
* The array of twiddle factors
* tw_stride (int)
* The number of elements to skip between two successive twiddle factors
*/
int k;
#if LARGE_BASE_CASE
// End condition, stop at n=2 to avoid one trivial recursion
if (n == 8)
{
fft8(x, stride, y, 2);
return;
}
else if (n == 4)
{
fft4(x, stride, y, 2);
return;
}
#else
// End condition, stop at n=2 to avoid one trivial recursion
if (n == 2)
{
y[0] = x[0] + x[stride];
y[1] = x[1] + x[stride + 1];
y[2] = x[0] - x[stride];
y[3] = x[1] - x[stride + 1];
return;
}
else if (n == 1)
{
y[0] = x[0];
y[1] = x[1];
return;
}
#endif
// Recursion -- Decimation In Time algorithm
split_radix_fft(x, y, n / 2, 2 * stride, twiddle_factors, 2 * tw_stride);
split_radix_fft(x + stride, y + n, n / 4, 4 * stride, twiddle_factors, 4 * tw_stride);
split_radix_fft(x + 3 * stride, y + n + n / 2, n / 4, 4 * stride, twiddle_factors, 4 * tw_stride);
// Stitch together the output
float u1r, u1i, u2r, u2i, x1r, x1i, x2r, x2i;
float t;
// We can save a few multiplications in the first step
u1r = y[0];
u1i = y[1];
u2r = y[n / 2];
u2i = y[n / 2 + 1];
x1r = y[n];
x1i = y[n + 1];
x2r = y[n / 2 + n];
x2i = y[n / 2 + n + 1];
t = x1r + x2r;
y[0] = u1r + t;
y[n] = u1r - t;
t = x1i + x2i;
y[1] = u1i + t;
y[n + 1] = u1i - t;
t = x2i - x1i;
y[n / 2] = u2r - t;
y[n + n / 2] = u2r + t;
t = x1r - x2r;
y[n / 2 + 1] = u2i - t;
y[n + n / 2 + 1] = u2i + t;
for (k = 1 ; k < n / 4 ; k++)
{
float u1r, u1i, u2r, u2i, x1r, x1i, x2r, x2i, c1, s1, c2, s2;
c1 = twiddle_factors[k * tw_stride];
s1 = twiddle_factors[k * tw_stride + 1];
c2 = twiddle_factors[3 * k * tw_stride];
s2 = twiddle_factors[3 * k * tw_stride + 1];
u1r = y[2 * k];
u1i = y[2 * k + 1];
u2r = y[2 * k + n / 2];
u2i = y[2 * k + n / 2 + 1];
x1r = c1 * y[n + 2 * k] + s1 * y[n + 2 * k + 1];
x1i = -s1 * y[n + 2 * k] + c1 * y[n + 2 * k + 1];
x2r = c2 * y[n / 2 + n + 2 * k] + s2 * y[n / 2 + n + 2 * k + 1];
x2i = -s2 * y[n / 2 + n + 2 * k] + c2 * y[n / 2 + n + 2 * k + 1];
t = x1r + x2r;
y[2 * k] = u1r + t;
y[2 * k + n] = u1r - t;
t = x1i + x2i;
y[2 * k + 1] = u1i + t;
y[2 * k + n + 1] = u1i - t;
t = x2i - x1i;
y[2 * k + n / 2] = u2r - t;
y[2 * k + n + n / 2] = u2r + t;
t = x1r - x2r;
y[2 * k + n / 2 + 1] = u2i - t;
y[2 * k + n + n / 2 + 1] = u2i + t;
}
}
void ifft_primitive(float *input, float *output, int n, int stride, float *twiddle_factors, int tw_stride)
{
#if USE_SPLIT_RADIX
split_radix_fft(input, output, n, stride, twiddle_factors, tw_stride);
#else
fft_primitive(input, output, n, stride, twiddle_factors, tw_stride);
#endif
int ks;
int ns = n * stride;
// reverse all coefficients from 1 to n / 2 - 1
for (ks = stride ; ks < ns / 2 ; ks += stride)
{
float t;
t = output[ks];
output[ks] = output[ns-ks];
output[ns-ks] = t;
t = output[ks+1];
output[ks+1] = output[ns-ks+1];
output[ns-ks+1] = t;
}
// Apply normalization
float norm = 1. / n;
for (ks = 0 ; ks < ns ; ks += stride)
{
output[ks] *= norm;
output[ks+1] *= norm;
}
}
inline void fft8(float *input, int stride_in, float *output, int stride_out)
{
/*
* Unrolled implementation of FFT8 for a little more performance
*/
float a0r, a1r, a2r, a3r, a4r, a5r, a6r, a7r;
float a0i, a1i, a2i, a3i, a4i, a5i, a6i, a7i;
float b0r, b1r, b2r, b3r, b4r, b5r, b6r, b7r;
float b0i, b1i, b2i, b3i, b4i, b5i, b6i, b7i;
float t;
float sin_pi_4 = 0.7071067812;
a0r = input[0];
a0i = input[1];
a1r = input[stride_in];
a1i = input[stride_in+1];
a2r = input[2*stride_in];
a2i = input[2*stride_in+1];
a3r = input[3*stride_in];
a3i = input[3*stride_in+1];
a4r = input[4*stride_in];
a4i = input[4*stride_in+1];
a5r = input[5*stride_in];
a5i = input[5*stride_in+1];
a6r = input[6*stride_in];
a6i = input[6*stride_in+1];
a7r = input[7*stride_in];
a7i = input[7*stride_in+1];
// Stage 1
b0r = a0r + a4r;
b0i = a0i + a4i;
b1r = a1r + a5r;
b1i = a1i + a5i;
b2r = a2r + a6r;
b2i = a2i + a6i;
b3r = a3r + a7r;
b3i = a3i + a7i;
b4r = a0r - a4r;
b4i = a0i - a4i;
b5r = a1r - a5r;
b5i = a1i - a5i;
// W_8^1 = 1/sqrt(2) - j / sqrt(2)
t = b5r + b5i;
b5i = (b5i - b5r) * sin_pi_4;
b5r = t * sin_pi_4;
// W_8^2 = -j
b6r = a2i - a6i;
b6i = a6r - a2r;
b7r = a3r - a7r;
b7i = a3i - a7i;
// W_8^3 = -1 / sqrt(2) + j / sqrt(2)
t = sin_pi_4 * (b7i - b7r);
b7i = - (b7r + b7i) * sin_pi_4;
b7r = t;
// Stage 2
a0r = b0r + b2r;
a0i = b0i + b2i;
a1r = b1r + b3r;
a1i = b1i + b3i;
a2r = b0r - b2r;
a2i = b0i - b2i;
// * j
a3r = b1i - b3i;
a3i = b3r - b1r;
a4r = b4r + b6r;
a4i = b4i + b6i;
a5r = b5r + b7r;
a5i = b5i + b7i;
a6r = b4r - b6r;
a6i = b4i - b6i;
// * j
a7r = b5i - b7i;
a7i = b7r - b5r;
// Stage 3
// X[0]
output[0] = a0r + a1r;
output[1] = a0i + a1i;
// X[4]
output[4*stride_out] = a0r - a1r;
output[4*stride_out+1] = a0i - a1i;
// X[2]
output[2*stride_out] = a2r + a3r;
output[2*stride_out+1] = a2i + a3i;
// X[6]
output[6*stride_out] = a2r - a3r;
output[6*stride_out+1] = a2i - a3i;
// X[1]
output[stride_out] = a4r + a5r;
output[stride_out+1] = a4i + a5i;
// X[5]
output[5*stride_out] = a4r - a5r;
output[5*stride_out+1] = a4i - a5i;
// X[3]
output[3*stride_out] = a6r + a7r;
output[3*stride_out+1] = a6i + a7i;
// X[7]
output[7*stride_out] = a6r - a7r;
output[7*stride_out+1] = a6i - a7i;
}
inline void fft4(float *input, int stride_in, float *output, int stride_out)
{
/*
* Unrolled implementation of FFT4 for a little more performance
*/
float t1, t2;
t1 = input[0] + input[2*stride_in];
t2 = input[stride_in] + input[3*stride_in];
output[0] = t1 + t2;
output[2*stride_out] = t1 - t2;
t1 = input[1] + input[2*stride_in+1];
t2 = input[stride_in+1] + input[3*stride_in+1];
output[1] = t1 + t2;
output[2*stride_out+1] = t1 - t2;
t1 = input[0] - input[2*stride_in];
t2 = input[stride_in+1] - input[3*stride_in+1];
output[stride_out] = t1 + t2;
output[3*stride_out] = t1 - t2;
t1 = input[1] - input[2*stride_in+1];
t2 = input[3*stride_in] - input[stride_in];
output[stride_out+1] = t1 + t2;
output[3*stride_out+1] = t1 - t2;
}

View File

@@ -0,0 +1,79 @@
/*
ESP32 FFT
=========
This provides a vanilla radix-2 FFT implementation and a test example.
Author
------
This code was written by [Robin Scheibler](http://www.robinscheibler.org) during rainy days in October 2017.
License
-------
Copyright (c) 2017 Robin Scheibler
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 __FFT_H__
#define __FFT_H__
typedef enum
{
FFT_REAL,
FFT_COMPLEX
} fft_type_t;
typedef enum
{
FFT_FORWARD,
FFT_BACKWARD
} fft_direction_t;
#define FFT_OWN_INPUT_MEM 1
#define FFT_OWN_OUTPUT_MEM 2
typedef struct
{
int size; // FFT size
float *input; // pointer to input buffer
float *output; // pointer to output buffer
float *twiddle_factors; // pointer to buffer holding twiddle factors
fft_type_t type; // real or complex
fft_direction_t direction; // forward or backward
unsigned int flags; // FFT flags
} fft_config_t;
fft_config_t *fft_init(int size, fft_type_t type, fft_direction_t direction, float *input, float *output);
void fft_destroy(fft_config_t *config);
void fft_execute(fft_config_t *config);
void fft(float *input, float *output, float *twiddle_factors, int n);
void ifft(float *input, float *output, float *twiddle_factors, int n);
void rfft(float *x, float *y, float *twiddle_factors, int n);
void irfft(float *x, float *y, float *twiddle_factors, int n);
void fft_primitive(float *x, float *y, int n, int stride, float *twiddle_factors, int tw_stride);
void split_radix_fft(float *x, float *y, int n, int stride, float *twiddle_factors, int tw_stride);
void ifft_primitive(float *input, float *output, int n, int stride, float *twiddle_factors, int tw_stride);
void fft8(float *input, int stride_in, float *output, int stride_out);
void fft4(float *input, int stride_in, float *output, int stride_out);
#endif // __FFT_H__

View File

@@ -0,0 +1,80 @@
/*
A couple of dices on a tiny 80x160px TFT display
Author: Alfonso de Cala <alfonso@el-magnifico.org>
*/
#include <M5StickCPlus.h>
#define DOT_SIZE 6
int dot[6][6][2] {
{{35,35}},
{{15,15},{55,55}},
{{15,15},{35,35},{55,55}},
{{15,15},{15,55},{55,15},{55,55}},
{{15,15},{15,55},{35,35},{55,15},{55,55}},
{{15,15},{15,35},{15,55},{55,15},{55,35},{55,55}},
};
float accX = 0;
float accY = 0;
float accZ = 0;
void setup(void) {
M5.begin();
M5.IMU.Init();
M5.Lcd.setRotation(1);
M5.Lcd.fillScreen(TFT_GREEN);
M5.Lcd.setTextColor(TFT_BLACK); // Adding a background colour erases previous text automatically
M5.Lcd.setCursor(10, 30);
M5.Lcd.setTextSize(3);
M5.Lcd.print("SHAKE ME");
delay(1000);
}
void draw_dice(int16_t x, int16_t y, int n) {
M5.Lcd.fillRect(x, y, 70, 70, WHITE);
for(int d = 0; d < 6; d++) {
if (dot[n][d][0] > 0) {
M5.Lcd.fillCircle(x+dot[n][d][0], y+dot[n][d][1], DOT_SIZE, TFT_BLACK);
}
}
}
void loop() {
while(1) {
M5.IMU.getAccelData(&accX,&accY,&accZ);
if (accX > 1.5 || accY > 1.5 ) {
break;
}
}
M5.Lcd.fillScreen(TFT_GREEN);
// Draw first dice
delay(500); // A little delay to increase suspense :-D
int number = random(0, 6);
draw_dice(50,30,number);
// Draw second dice
delay(500);
number = random(0, 6);
draw_dice(125,30,number);
}

View File

@@ -0,0 +1,370 @@
// By Ponticelli Domenico.
// 12NOV2020 EEPROM Working now, Modified by Zontex
// https://github.com/pcelli85/M5Stack_FlappyBird_game
#include <M5StickCPlus.h>
#include <EEPROM.h>
#define TFTW 135 // screen width
#define TFTH 240 // screen height
#define TFTW2 67 // half screen width
#define TFTH2 120 // half screen height
// game constant
#define SPEED 1
#define GRAVITY 9.8
#define JUMP_FORCE 2.15
#define SKIP_TICKS 20.0 // 1000 / 50fps
#define MAX_FRAMESKIP 5
// bird size
#define BIRDW 8 // bird width
#define BIRDH 8 // bird height
#define BIRDW2 4 // half width
#define BIRDH2 4 // half height
// pipe size
#define PIPEW 15 // pipe width
#define GAPHEIGHT 30 // pipe gap height
// floor size
#define FLOORH 20 // floor height (from bottom of the screen)
// grass size
#define GRASSH 4 // grass height (inside floor, starts at floor y)
int address = 0;
int maxScore = EEPROM.readInt(address);
const int buttonPin = 2;
// background
const unsigned int BCKGRDCOL = M5.Lcd.color565(138,235,244);
// bird
const unsigned int BIRDCOL = M5.Lcd.color565(255,254,174);
// pipe
const unsigned int PIPECOL = M5.Lcd.color565(99,255,78);
// pipe highlight
const unsigned int PIPEHIGHCOL = M5.Lcd.color565(250,255,250);
// pipe seam
const unsigned int PIPESEAMCOL = M5.Lcd.color565(0,0,0);
// floor
const unsigned int FLOORCOL = M5.Lcd.color565(246,240,163);
// grass (col2 is the stripe color)
const unsigned int GRASSCOL = M5.Lcd.color565(141,225,87);
const unsigned int GRASSCOL2 = M5.Lcd.color565(156,239,88);
// bird sprite
// bird sprite colors (Cx name for values to keep the array readable)
#define C0 BCKGRDCOL
#define C1 M5.Lcd.color565(195,165,75)
#define C2 BIRDCOL
#define C3 TFT_WHITE
#define C4 TFT_RED
#define C5 M5.Lcd.color565(251,216,114)
static unsigned int birdcol[] =
{ C0, C0, C1, C1, C1, C1, C1, C0, C0, C0, C1, C1, C1, C1, C1, C0,
C0, C1, C2, C2, C2, C1, C3, C1, C0, C1, C2, C2, C2, C1, C3, C1,
C0, C2, C2, C2, C2, C1, C3, C1, C0, C2, C2, C2, C2, C1, C3, C1,
C1, C1, C1, C2, C2, C3, C1, C1, C1, C1, C1, C2, C2, C3, C1, C1,
C1, C2, C2, C2, C2, C2, C4, C4, C1, C2, C2, C2, C2, C2, C4, C4,
C1, C2, C2, C2, C1, C5, C4, C0, C1, C2, C2, C2, C1, C5, C4, C0,
C0, C1, C2, C1, C5, C5, C5, C0, C0, C1, C2, C1, C5, C5, C5, C0,
C0, C0, C1, C5, C5, C5, C0, C0, C0, C0, C1, C5, C5, C5, C0, C0};
// bird structure
static struct BIRD {
long x, y, old_y;
long col;
float vel_y;
} bird;
// pipe structure
static struct PIPES {
long x, gap_y;
long col;
} pipes;
// score
int score;
// temporary x and y var
static short tmpx, tmpy;
// ---------------
// draw pixel
// ---------------
// faster drawPixel method by inlining calls and using setAddrWindow and pushColor
// using macro to force inlining
#define drawPixel(a, b, c) M5.Lcd.setAddrWindow(a, b, a, b); M5.Lcd.pushColor(c)
// ---------------
// game loop
// ---------------
void game_loop() {
// ===============
// prepare game variables
// draw floor
// ===============
// instead of calculating the distance of the floor from the screen height each time store it in a variable
unsigned char GAMEH = TFTH - FLOORH;
// draw the floor once, we will not overwrite on this area in-game
// black line
M5.Lcd.drawFastHLine(0, GAMEH, TFTW, TFT_BLACK);
// grass and stripe
M5.Lcd.fillRect(0, GAMEH+1, TFTW2, GRASSH, GRASSCOL);
M5.Lcd.fillRect(TFTW2, GAMEH+1, TFTW2, GRASSH, GRASSCOL2);
// black line
M5.Lcd.drawFastHLine(0, GAMEH+GRASSH, TFTW, TFT_BLACK);
// mud
M5.Lcd.fillRect(0, GAMEH+GRASSH+1, TFTW, FLOORH-GRASSH, FLOORCOL);
// grass x position (for stripe animation)
long grassx = TFTW;
// game loop time variables
double delta, old_time, next_game_tick, current_time;
next_game_tick = current_time = millis();
int loops;
// passed pipe flag to count score
bool passed_pipe = false;
// temp var for setAddrWindow
unsigned char px;
while (1) {
loops = 0;
while( millis() > next_game_tick && loops < MAX_FRAMESKIP) {
if(digitalRead(M5_BUTTON_HOME) == LOW){
//while(digitalRead(M5_BUTTON_HOME) == LOW);
if (bird.y > BIRDH2*0.5) bird.vel_y = -JUMP_FORCE;
// else zero velocity
else bird.vel_y = 0;
}
// ===============
// update
// ===============
// calculate delta time
// ---------------
old_time = current_time;
current_time = millis();
delta = (current_time-old_time)/1000;
// bird
// ---------------
bird.vel_y += GRAVITY * delta;
bird.y += bird.vel_y;
// pipe
// ---------------
pipes.x -= SPEED;
// if pipe reached edge of the screen reset its position and gap
if (pipes.x < -PIPEW) {
pipes.x = TFTW;
pipes.gap_y = random(10, GAMEH-(10+GAPHEIGHT));
}
// ---------------
next_game_tick += SKIP_TICKS;
loops++;
}
// ===============
// draw
// ===============
// pipe
// ---------------
// we save cycles if we avoid drawing the pipe when outside the screen
if (pipes.x >= 0 && pipes.x < TFTW) {
// pipe color
M5.Lcd.drawFastVLine(pipes.x+3, 0, pipes.gap_y, PIPECOL);
M5.Lcd.drawFastVLine(pipes.x+3, pipes.gap_y+GAPHEIGHT+1, GAMEH-(pipes.gap_y+GAPHEIGHT+1), PIPECOL);
// highlight
M5.Lcd.drawFastVLine(pipes.x, 0, pipes.gap_y, PIPEHIGHCOL);
M5.Lcd.drawFastVLine(pipes.x, pipes.gap_y+GAPHEIGHT+1, GAMEH-(pipes.gap_y+GAPHEIGHT+1), PIPEHIGHCOL);
// bottom and top border of pipe
drawPixel(pipes.x, pipes.gap_y, PIPESEAMCOL);
drawPixel(pipes.x, pipes.gap_y+GAPHEIGHT, PIPESEAMCOL);
// pipe seam
drawPixel(pipes.x, pipes.gap_y-6, PIPESEAMCOL);
drawPixel(pipes.x, pipes.gap_y+GAPHEIGHT+6, PIPESEAMCOL);
drawPixel(pipes.x+3, pipes.gap_y-6, PIPESEAMCOL);
drawPixel(pipes.x+3, pipes.gap_y+GAPHEIGHT+6, PIPESEAMCOL);
}
#if 1
// erase behind pipe
if (pipes.x <= TFTW)
M5.Lcd.drawFastVLine(pipes.x+PIPEW, 0, GAMEH, BCKGRDCOL);
//M5.Lcd.drawFastVLine(pipes.x, 0, GAMEH, BCKGRDCOL);
// PIPECOL
#endif
// bird
// ---------------
tmpx = BIRDW-1;
do {
px = bird.x+tmpx+BIRDW;
// clear bird at previous position stored in old_y
// we can't just erase the pixels before and after current position
// because of the non-linear bird movement (it would leave 'dirty' pixels)
tmpy = BIRDH - 1;
do {
drawPixel(px, bird.old_y + tmpy, BCKGRDCOL);
} while (tmpy--);
// draw bird sprite at new position
tmpy = BIRDH - 1;
do {
drawPixel(px, bird.y + tmpy, birdcol[tmpx + (tmpy * BIRDW)]);
} while (tmpy--);
} while (tmpx--);
// save position to erase bird on next draw
bird.old_y = bird.y;
// grass stripes
// ---------------
grassx -= SPEED;
if (grassx < 0) grassx = TFTW;
M5.Lcd.drawFastVLine( grassx %TFTW, GAMEH+1, GRASSH-1, GRASSCOL);
M5.Lcd.drawFastVLine((grassx+64)%TFTW, GAMEH+1, GRASSH-1, GRASSCOL2);
// ===============
// collision
// ===============
// if the bird hit the ground game over
if (bird.y > GAMEH-BIRDH) break;
// checking for bird collision with pipe
if (bird.x+BIRDW >= pipes.x-BIRDW2 && bird.x <= pipes.x+PIPEW-BIRDW) {
// bird entered a pipe, check for collision
if (bird.y < pipes.gap_y || bird.y+BIRDH > pipes.gap_y+GAPHEIGHT) break;
else passed_pipe = true;
}
// if bird has passed the pipe increase score
else if (bird.x > pipes.x+PIPEW-BIRDW && passed_pipe) {
passed_pipe = false;
// erase score with background color
M5.Lcd.setTextColor(BCKGRDCOL);
M5.Lcd.setCursor( TFTW2, 4);
M5.Lcd.print(score);
// set text color back to white for new score
M5.Lcd.setTextColor(TFT_WHITE);
// increase score since we successfully passed a pipe
score++;
}
// update score
// ---------------
M5.Lcd.setCursor( 2, 4);
M5.Lcd.print(score);
}
// add a small delay to show how the player lost
delay(1200);
}
void game_init() {
// clear screen
M5.Lcd.fillScreen(BCKGRDCOL);
// reset score
score = 0;
// init bird
bird.x = 30;
bird.y = bird.old_y = TFTH2 - BIRDH;
bird.vel_y = -JUMP_FORCE;
tmpx = tmpy = 0;
// generate new random seed for the pipe gape
randomSeed(analogRead(0));
// init pipe
pipes.x = 0;
pipes.gap_y = random(20, TFTH-60);
}
// ---------------
// game start
// ---------------
void game_start() {
M5.Lcd.fillScreen(TFT_BLACK);
M5.Lcd.fillRect(0, TFTH2 - 10, TFTW, 1, TFT_WHITE);
M5.Lcd.fillRect(0, TFTH2 + 15, TFTW, 1, TFT_WHITE);
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextSize(1);
// half width - num char * char width in pixels
M5.Lcd.setCursor( TFTW2-15, TFTH2 - 6);
M5.Lcd.println("FLAPPY");
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor( TFTW2-15, TFTH2 + 6);
M5.Lcd.println("-BIRD-");
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor( 15, TFTH2 - 21);
M5.Lcd.println("M5StickC");
M5.Lcd.setCursor( TFTW2 - 40, TFTH2 + 21);
M5.Lcd.println("please press home");
while (1) {
// wait for push button
if(digitalRead(M5_BUTTON_HOME) == LOW){
while(digitalRead(M5_BUTTON_HOME) == LOW);
break;
}
}
// init game settings
game_init();
}
// ---------------
// game over
// ---------------
void game_over() {
M5.Lcd.fillScreen(TFT_BLACK);
maxScore = EEPROM.readInt(address);
if(score>maxScore)
{
EEPROM.writeInt(address, score);
EEPROM.commit();
maxScore = score;
M5.Lcd.setTextColor(TFT_RED);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor( 0, TFTH2 - 16);
M5.Lcd.println("NEW HIGHSCORE");
}
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextSize(1);
// half width - num char * char width in pixels
M5.Lcd.setCursor( TFTW2 - 25, TFTH2 - 6);
M5.Lcd.println("GAME OVER");
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor( 1, 10);
M5.Lcd.print("score: ");
M5.Lcd.print(score);
M5.Lcd.setCursor( 5, TFTH2 + 6);
M5.Lcd.println("press button");
M5.Lcd.setCursor( 1, 21);
M5.Lcd.print("Max Score:");
M5.Lcd.print(maxScore);
while(1) {
// wait for push button
if(digitalRead(M5_BUTTON_HOME) == LOW){
while(digitalRead(M5_BUTTON_HOME) == LOW);
break;
}
}
}
void resetMaxScore()
{
EEPROM.writeInt(address, 0);
EEPROM.commit();
}
void setup() {
// put your setup code here, to run once:
M5.begin();
EEPROM.begin(1000);
pinMode(M5_BUTTON_HOME, INPUT);
//resetMaxScore();
Serial.println("last score:");
Serial.println(EEPROM.readInt(address));
}
void loop() {
// put your main code here, to run repeatedly:
game_start();
game_loop();
game_over();
}