Skip to content

Instantly share code, notes, and snippets.

@shikarunochi
Created October 12, 2018 09:44
Show Gist options
  • Save shikarunochi/faac47931052a028e5f8080adf857f53 to your computer and use it in GitHub Desktop.
Save shikarunochi/faac47931052a028e5f8080adf857f53 to your computer and use it in GitHub Desktop.
M5Stack Spinner for Arduino
#include <M5Stack.h>
#include <SD.h>
#include <Wire.h>
#include <JPEGDecoder.h>
#define PI 3.141592653589793
const int DOT_SIZE = 5;
#define SIZE_X 48
#define SIZE_Y 48
uint16_t cgData[SIZE_X][SIZE_Y] = {
};
float angle;
const float deltaAngle = 5;
int delayValue;
boolean flag1000;
void renderJPEG();
#define minimum(a,b) (((a) < (b)) ? (a) : (b))
//データ生成
void setup() {
Serial.begin(115200); // SERIAL
M5.begin(); // M5STACK INITIALIZE
M5.Lcd.setBrightness(200); // BRIGHTNESS = MAX 255
M5.Lcd.fillScreen(BLACK); // CLEAR SCREEN
delay(3000);
SD.begin();
Serial.print("SD Begin");
Serial.print("InitialStart");
//ファイル名は"M5StackSpinner48x48.jpg"固定です。
File jpgFile = SD.open( "/M5StackSpinner48x48.jpg", FILE_READ);
if(!jpgFile){
Serial.println("File not exist");
M5.Lcd.print("File not exist.");
while(1);
}
JpegDec.decodeSdFile(jpgFile);
renderJPEG();
Serial.print("InitialEnd");
angle = 0;
delayValue = 2800;//microSeconds
flag1000 = false;
}
int drawLine(float angle){ //角度 angle の向きで、データ中心からMAX(24*1.4 = 34)ドットの絵を描く
int color = 0;
int xPos = 120 - DOT_SIZE / 2;
for(int yCount = 0;yCount < 34;yCount++){
//中心から、角度 angle度にyCount
int x = (int)((float)yCount * cos(angle/(180/PI))) + 24;
int y = (int)((float)yCount * sin(angle/(180/PI))) + 24;
uint16_t color = 0;
if(x >= 0 && x< 48 && y >= 0 && y < 48){//ドットデータ外なら色は黒
color = cgData[x][y];
}
//中心から外向きに描く
M5.Lcd.fillRect(160 + yCount * DOT_SIZE - DOT_SIZE / 2, xPos ,DOT_SIZE, DOT_SIZE * 2 , color); //縦倍
xPos = xPos + DOT_SIZE / 5 * 3;
//Serial.print("Angle:");
//Serial.print(angle);
//Serial.print(": yCount:");
//Serial.print(yCount);
//Serial.print(": x:");
//Serial.print(x);
//Serial.print(": y:");
//Serial.print(y);
//Serial.print(": color:");
//Serial.print(cgData[x][y]);
//Serial.print("\n");
}
}
void displayDelay(){
if(delayValue < 0){delayValue = 0;}
M5.Lcd.fillRect(0, 0, 50, 20, BLACK);
M5.Lcd.setCursor(0, 0);
M5.Lcd.printf("%1.1f",delayValue / 1000.0);
if(flag1000){
M5.Lcd.setCursor(0, 10);
M5.Lcd.print("[x10]");
}
}
//表示
void loop() {
drawLine(angle);
angle = angle + deltaAngle;
if(angle >=360){
angle = 0;
}
if(M5.BtnA.wasPressed()){
if(flag1000){
delayValue = delayValue - 1000;
flag1000 = false;
}else{
delayValue = delayValue - 100;
}
displayDelay();
}
if(M5.BtnB.wasPressed()){
flag1000 = !flag1000;
displayDelay();
}
if(M5.BtnC.wasPressed()){
if(flag1000){
delayValue = delayValue + 1000;
flag1000 = false;
}else{
delayValue = delayValue + 100;
}
displayDelay();
}
M5.update();
delayMicroseconds(delayValue);
}
void testPrint(){
for(int x = 0;x < 32;x++){
for(int y = 0;y < 32;y++){
M5.Lcd.fillRect(x * 4, y * 4 , 4, 4, cgData[x][y]);
}
}
M5.update();
while(1);
}
void renderJPEG() {
// retrieve infomration about the image
uint16_t *pImg;
uint16_t mcu_w = JpegDec.MCUWidth;
uint16_t mcu_h = JpegDec.MCUHeight;
uint32_t max_x = JpegDec.width;
uint32_t max_y = JpegDec.height;
// Jpeg images are draw as a set of image block (tiles) called Minimum Coding Units (MCUs)
// Typically these MCUs are 16x16 pixel blocks
// Determine the width and height of the right and bottom edge image blocks
uint32_t min_w = minimum(mcu_w, max_x % mcu_w);
uint32_t min_h = minimum(mcu_h, max_y % mcu_h);
// save the current image block size
uint32_t win_w = mcu_w;
uint32_t win_h = mcu_h;
// record the current time so we can measure how long it takes to draw an image
uint32_t drawTime = millis();
// save the coordinate of the right and bottom edges to assist image cropping
// to the screen size
//max_x += xpos;
//max_y += ypos;
// read each MCU block until there are no more
while ( JpegDec.read()) {
// save a pointer to the image block
pImg = JpegDec.pImage;
// calculate where the image block should be drawn on the screen
int mcu_x = JpegDec.MCUx * mcu_w;// + xpos;
int mcu_y = JpegDec.MCUy * mcu_h;// + ypos;
// check if the image block size needs to be changed for the right and bottom edges
if (mcu_x + mcu_w <= max_x) win_w = mcu_w;
else win_w = min_w;
if (mcu_y + mcu_h <= max_y) win_h = mcu_h;
else win_h = min_h;
// calculate how many pixels must be drawn
uint32_t mcu_pixels = win_w * win_h;
// draw image block if it will fit on the screen
if ( ( mcu_x + win_w) <= SIZE_X && ( mcu_y + win_h) <= SIZE_Y) {
// open a window onto the screen to paint the pixels into
//TFTscreen.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1);
for(int by = mcu_y;by < mcu_y + win_h;by++){
for(int bx = mcu_x;bx < mcu_x + win_w;bx++){
if(bx < SIZE_X && by < SIZE_Y){
cgData[bx][by] = *pImg;
}
*pImg++;
}
}
//TFTscreen.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1);
// push all the image block pixels to the screen
//while (mcu_pixels--) TFTscreen.pushColor(*pImg++); // Send to TFT 16 bits at a time
}
// stop drawing blocks if the bottom of the screen has been reached
// the abort function will close the file
else if ( ( mcu_y + win_h) >= SIZE_Y) JpegDec.abort();
}
// calculate how long it took to draw the image
drawTime = millis() - drawTime; // Calculate the time it took
// print the results to the serial port
Serial.print ("Total render time was : "); Serial.print(drawTime); Serial.println(" ms");
Serial.println("=====================================");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment