初始化提交
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__
|
||||
@@ -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);
|
||||
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user