Task 2: Add an Output Device
This week’s challenge:
- Explore output devices
- To a microcontroller board you’ve designed
- Program it to do something.
For this week I explored Micro Servo Motor SG90 and I2C & SPI Displays
Micro Servo Motor SG90 (Controlled by Potentiometer)
A servo is a motor that can rotate approximately 180 degrees (90 in each direction). Servo comes in different sizes and power/torque. Some servos can rotate 360 degree too (continuous servo). Servos are great devices perfect for adding motion and automation to your projects - it comes in both analog and digital variant.
The Micro Servo Motor SG90 uses Pulse Width Modulation (PWM) to control their position. PWM involves sending a series of pulses of varying widths to the servo motor. The signal uses rectangular wave with a varying duty cycle thus generates analog signals from digital devices usually it is within a specific frequency (around 50Hz). The duty cycle of these pulses determines the position of the servo motor shaft.
- Higher duty cycle (wider pulse width) tells the servo to move usually in a clockwise direction.
- Lower duty cycle (narrower pulse width) tells it to move usually countere-clockwise.
I am using Potentiometer as an Input to move the Servo. The logic is when I turn the Potentiometer the expected outcome for the Servo is to follow the direction of the rotation of the potentiometer.
The system diagram looks like this. The Micro Servo comes in 3 pins, VCC,GND,SIGNAL. The signal pins goes to one of the digital pins that has PWM capability. In Arduino those digital pins have “~”. All of Xiao’s digital pin has 10 PWM interfaces (D1-D10)
Servos already has an established library that you have to include when writing down your code “Servo.h”
Potentiometer as an input device comes with three pins VCC,GND, SIGNAL. Signal pin goes to analog pin.
We will have to map the servo’s angle of motion degree values (0-180) to the potentiometer values. As we can see that the potentiometer uses analog signal, microcontrollers measure value of agnalog signals through a built-in analog-to-digital converter (ADC). The arduino’s ADC comes in 10-bit, this means it can represent an analog input voltage with 2^10, or 1024, digital levels. The range of values is from 0 to 1023, giving 1024 distinct values (since it starts counting from 0).
// Code by Rico & Kurumi
#include <Servo.h>
Servo myServo;
int val;
void setup() {
myServo.attach(D3);
pinMode (A1, INPUT);
pinMode (D3, OUTPUT);
}
void loop() {
//Servo - time
//myServo.write(0);
//delay(3000);
//myServo.write(180);
//delay(3000);
// Servo - Potentiometer
int val = analogRead(A1);
val = map(val,0,1023,0,180); //10 bit value ranges from 0-1023, servo values 0-180
myServo.write(val);
delay (15);
}
Displays
My final project requires to use Display as an output - I explored 3 displays which were
- OLED LCD Display SSD1306, an I2C Display
- TFT ILI9225, SPI Display
- TFT ILI9341, SPI Display
128x64 OLED Display SSD1306
OLED Display is made of self-illuminating pixels that emit light when current is passes through. It has no backlight and has superior contrast ratios and true blacks (pixels can completely turn off).
This particular inexpensive OLED Display is easily available and easy to use for starters. It has many Arduino library support. Moreover, it requires less pins to be used compared to other displays due to I2C connection (SDA/SCL). It is compatible with many display libraries - but the most widely used one is the Adafruit GFX Library, the ‘core’ class that all other graphics libraries derive from.
I used the standardised Wokwi animation programming to test out this SSD1306 display is working.
As you can see this code displays a simple eye animation. To get your image displayed you need to convert it intp Bitmap.Use image2cpp tool to convert any images to Bitmap. For more information how to use image2cpp, check out this tutorial
When you convert your image to bitmap code - the image data is stored in a PROGMEM
array. PROGMEM is a keyword used to store data in the microcontroller’s program memory (flash memory) instead of RAM.
This is because image data, especially for animations, can can quickly fill up the limited RAM space in MCUs. By storing the bitmap code in PROGMEM you keep your RAM available for more function while still having access to the image data.
The animation data can be understood through
FRAME_DELAY
: This variable defines the delay between animation frames in milliseconds (42ms).FRAME_WIDTH
,FRAME_HEIGHT:
: This variable defines the width and height of each animation frame (64p x 64p)FRAME_COUNT
: This variable defines the total number of frames in the animation (calculated from the size of the frames array).
Testing out with Elaine’s Devlopment Board (using Xiao ESP32S3) - System Diagram
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Define OLED
#define SCREEN_I2C_ADDR 0x3C // or 0x3C
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RST_PIN -1 // Reset pin (-1 if not available)
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RST_PIN);
// OLED Animation: eye
// Code auto-generated by https://wokwi.com/animator, graphics by icons8.com
#define FRAME_DELAY (42)
#define FRAME_WIDTH (64)
#define FRAME_HEIGHT (64)
#define FRAME_COUNT (sizeof(frames) / sizeof(frames[0]))
const byte PROGMEM frames[][512] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,255,255,252,0,0,0,0,255,255,255,255,0,0,0,3,255,252,63,255,192,0,0,7,254,0,0,127,224,0,0,31,248,7,224,31,248,0,0,63,240,15,240,15,252,0,0,127,112,31,248,14,254,0,1,252,96,63,252,6,63,128,3,240,96,63,252,6,15,192,7,192,96,63,252,6,7,224,15,128,96,63,252,6,1,240,30,0,96,63,252,6,0,248,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,3,255,255,192,62,0,1,240,255,255,255,255,15,128,3,231,255,255,255,255,231,192,7,255,240,63,252,15,255,224,15,254,96,63,252,6,127,240,31,240,96,63,252,6,15,248,63,128,96,63,252,6,1,252,124,0,112,31,248,14,0,62,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,127,255,255,255,255,255,255,254,127,255,255,255,255,255,255,254,60,0,120,15,240,30,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,124,0,0,0,0,0,0,62,63,128,0,0,0,0,1,252,31,240,0,0,0,0,15,248,15,254,0,0,0,0,127,240,7,255,224,0,0,7,255,224,3,207,255,0,0,255,243,192,0,241,255,255,255,255,143,0,0,120,15,255,255,240,30,0,0,62,1,255,255,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,31,0,0,0,0,0,0,248,15,128,0,0,0,0,1,240,7,192,0,0,0,0,3,224,3,240,0,0,0,0,15,192,0,252,0,0,0,0,63,0,0,127,0,0,0,0,254,0,0,63,192,0,0,3,252,0,0,15,240,0,0,15,240,0,0,7,254,0,0,127,224,0,0,1,255,224,7,255,128,0,0,0,127,255,255,254,0,0,0,0,31,255,255,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,0,254,0,0,0,0,127,0,0,31,128,0,0,1,248,0,0,7,224,0,0,7,224,0,0,3,248,0,0,31,192,0,0,0,255,0,0,255,0,0,0,0,127,224,7,252,0,0,0,0,127,255,255,252,0,0,0,0,1,255,255,136,0,0,0,0,0,31,248,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,223,128,0,0,1,251,192,3,135,224,0,0,7,225,192,0,3,248,0,0,31,192,0,0,0,255,0,0,255,0,0,0,0,127,224,7,252,0,0,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,12,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,159,128,0,0,1,249,192,7,135,224,0,0,7,225,224,7,3,248,0,0,31,192,224,14,0,255,0,0,255,0,112,12,0,127,224,7,252,0,48,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,14,0,0,0,0,224,1,128,14,0,0,0,0,192,1,128,14,0,0,0,1,192,1,128,6,0,0,0,0,128,1,128,6,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,1,254,0,0,0,0,127,128,3,223,128,0,0,1,251,192,3,135,224,0,0,7,225,192,0,3,248,0,0,31,192,0,0,0,255,0,0,255,0,0,0,0,127,224,7,252,0,0,0,0,127,255,255,252,0,0,0,0,97,255,255,156,0,0,0,0,224,31,248,12,0,0,0,0,224,1,128,12,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,60,0,0,0,0,0,0,60,30,0,0,0,0,0,0,120,15,0,0,0,0,0,0,240,7,128,0,0,0,0,1,224,3,224,0,0,0,0,7,192,1,240,0,0,0,0,15,128,0,248,0,0,0,0,31,0,0,254,0,0,0,0,127,0,0,31,128,0,0,1,248,0,0,7,224,0,0,7,224,0,0,3,248,0,0,31,192,0,0,0,255,0,0,255,0,0,0,0,127,224,7,252,0,0,0,0,127,255,255,252,0,0,0,0,1,255,255,136,0,0,0,0,0,31,248,0,0,0,0,0,0,1,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,30,120,0,0,0,0,0,0,30,62,0,0,0,0,0,0,124,31,0,0,0,0,0,0,248,15,192,0,0,0,0,3,240,7,240,0,0,0,0,15,224,3,252,0,0,0,0,63,192,0,255,0,0,0,0,255,0,0,127,224,0,0,7,254,0,0,63,252,0,0,63,252,0,0,15,255,224,7,255,240,0,0,7,207,255,255,243,224,0,0,1,240,255,255,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,0,0,0,0,240,30,0,0,0,0,0,0,120,60,0,0,0,0,0,0,60,120,0,0,0,0,0,0,62,127,128,0,0,0,0,1,254,63,252,0,0,0,0,63,252,31,255,252,0,0,63,255,248,15,63,255,255,255,255,252,240,7,128,255,255,255,255,1,224,3,192,15,255,255,240,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,0,0,1,248,0,0,62,0,0,0,0,124,0,0,124,0,0,0,0,62,0,1,240,0,0,0,0,15,128,3,224,0,0,0,0,7,192,7,128,0,0,0,0,1,224,15,0,0,255,255,0,0,240,30,127,255,255,255,255,254,120,63,255,255,255,255,255,255,252,127,252,112,31,248,14,63,254,126,0,112,31,248,14,0,126,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,248,0,0,31,192,0,0,7,224,0,0,7,224,0,0,31,128,31,248,1,248,0,0,62,7,255,255,224,124,0,0,124,127,255,255,254,62,0,1,243,255,63,252,255,207,128,3,255,240,63,252,15,255,192,7,255,96,63,252,6,255,224,15,248,96,63,252,6,31,240,31,224,96,63,252,6,7,248,63,0,96,63,252,6,0,252,124,0,112,31,248,14,0,62,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,255,255,252,0,0,0,0,255,255,255,255,0,0,0,3,255,224,7,255,192,0,0,7,252,0,0,63,224,0,0,31,248,7,224,31,248,0,0,63,240,15,240,15,252,0,0,126,112,31,248,14,126,0,1,252,96,63,252,6,63,128,3,240,96,63,252,6,15,192,7,192,96,63,252,6,3,224,15,128,96,63,252,6,1,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,248,0,0,0,0,0,1,255,255,128,0,0,0,0,15,255,255,240,0,0,0,0,63,248,31,252,0,0,0,0,255,0,0,255,0,0,0,3,252,0,0,63,192,0,0,7,248,0,0,31,224,0,0,31,184,7,224,29,248,0,0,62,112,15,240,14,124,0,0,124,112,31,248,14,62,0,1,240,96,63,252,6,15,128,3,224,96,63,252,6,7,192,7,192,96,63,252,6,3,224,15,0,96,63,252,6,0,240,30,0,96,63,252,6,0,120,60,0,96,63,252,6,0,60,120,0,112,31,248,14,0,30,120,0,112,31,248,14,0,30,60,0,48,7,224,12,0,60,30,0,56,0,0,28,0,120,15,0,28,0,0,56,0,240,7,128,28,0,0,56,1,224,3,192,14,0,0,112,3,192,0,240,7,0,0,224,15,0,0,120,3,192,3,192,30,0,0,62,1,248,31,128,124,0,0,15,0,255,255,0,240,0,0,7,192,63,252,3,224,0,0,1,240,0,0,15,128,0,0,0,126,0,0,126,0,0,0,0,31,192,3,248,0,0,0,0,7,255,255,224,0,0,0,0,0,255,255,0,0,0,0,0,0,7,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
};
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, SCREEN_I2C_ADDR);
}
int frame = 0;
void loop() {
display.clearDisplay();
display.drawBitmap(32, 0, frames[frame], FRAME_WIDTH, FRAME_HEIGHT, 1);
display.display();
frame = (frame + 1) % FRAME_COUNT;
// delay(FRAME_DELAY);
}
I2C vs SPI?
The I2C’s display are often chosen because it is good enough for transferring small amounts of data and requires less pin to use. However for my project - I would require a bigger display with colour. Unfortunately I couldn’t find any I2C displays that fit the requirements. The cheap coloured display I could find readily available here in Indonesia are the TFT Displays. They mainly use SPI connections (MISO,MOSI,SCK,SS). As such these displays require more pins. Good thing my custom Elaineduino had enough pins to make sure these TFT displays could be programmed.
2.0” TFT ILI9225 LCD Screen
A thin-film-transistor liquid-crystal display (TFT LCD) is a type of LCD Display that uses thin-film-transistor technology. Each pixel in the display has a tiny transistor that controls the amount of light that passes through it. This allows for much more precise control over the image. TFT displays are considered “active matrix” displays. This means each pixel is controlled by its own transistor, allowing for sharper images and better viewing angles.Most TFT Displays uses the SPI module.
I bought this LCD Screen at first but realised that it has limited libraries compared to other TFT Screens. Please be aware that this particular TFT Display doesn’t support Adafruit GFX Library. The main library to be utilised is the TFT_22_ILI9225.h
Check more about ILI9225 from Arnov Sharma
In his documentation, this was how he used his TFT Display as a shield.
And so I adapted the pin-outs to Xiao ESP32S3
- CS = D7. In some forums, D7 was considered the Chip Select/Slave Select pin. However I found any digital pins would work with the Xiao ESP32.
- RST = A0 Following the analog pin placement.
- RS = A1 Following the analog pin placement.
- SDA = D10 The hardware names this pin SDA however the code labels it SDI and reserves it for MOSI. So I adapted to Xiao ESP32’s MOSI pin which is D10
- CLK = D8 The code suggests an SCK pin. SCK in Xiao ESP32 is D8
System Diagram
Code from Arnov Sharma
#include "SPI.h"
#include "TFT_22_ILI9225.h"
#include "math.h"
#define TFT_RST A0
#define TFT_RS A1
#define TFT_CS D7 // SS
#define TFT_SDI D10 // MOSI
#define TFT_CLK D8 // SCK
#define TFT_LED 0 // 0 if wired to +5V directly
#define TFT_BRIGHTNESS 200 // Initial brightness of TFT backlight (optional)
#define ROTATE_ANGLE 10 // Angle in degrees to rotate the triangle
struct _point
{
int16_t x;
int16_t y;
};
// Use hardware SPI (faster - on Uno: 13-SCK, 12-MISO, 11-MOSI)
TFT_22_ILI9225 tft = TFT_22_ILI9225(TFT_RST, TFT_RS, TFT_CS, TFT_SDI, TFT_CLK, TFT_LED);
// Variables and constants
_point c1, c2, c3, cc;
// Setup
void setup() {
tft.begin();
// Define triangle start coordinates
c1.x = 30; c1.y = 30;
c2.x = 120; c2.y = 80;
c3.x = 80; c3.y = 130;
// Determine the rotation point, i.e. the center of the triangle
cc = getCoordCentroid(c1, c2, c3);
tft.clear();
}
// Loop
void loop() {
// Calculate the number of steps to rotate the triangle a full rotation
int16_t steps = (int16_t)(360 / ROTATE_ANGLE);
// Draw solid triangle
tft.fillTriangle(30, 190, 80, 150, 130, 210, COLOR_BLUE);
for (int8_t i = 0; i < steps; i++) {
// Draw triangle
tft.drawTriangle(c1.x, c1.y, c2.x, c2.y, c3.x, c3.y, COLOR_GREEN);
// Rotate triangle
rotateTriangle(c1, c2, c3, cc, ROTATE_ANGLE);
delay(50);
}
delay(5000);
tft.clear();
}
// Get centroid of triangle
_point getCoordCentroid( _point a, _point b, _point c ) {
_point o;
o.x = (int16_t)((a.x + b.x + c.x) / 3);
o.y = (int16_t)((a.y + b.y + c.y) / 3);
return o;
}
// Rotate triangle around point r
void rotateTriangle( _point &a, _point &b, _point &c, _point r, int16_t deg ) {
// Convert degrees to radians
float angle = (float)deg * 1000 / 57296;
// Rotate each individual point
a = rotatePoint( r, angle, a);
b = rotatePoint( r, angle, b);
c = rotatePoint( r, angle, c);
}
// Rotate each point p around c
_point rotatePoint( _point c, float angle, _point p ) {
_point r;
// 1. translate point back to origin
// 2. rotate point
// 3. translate point back
r.x = cos(angle) * (p.x - c.x) - sin(angle) * (p.y - c.y) + c.x;
r.y = sin(angle) * (p.x - c.x) + cos(angle) * (p.y - c.y) + c.y;
return r;
}
2.8” TFT ILI9341 LCD Screen
This particular TFT Screen is widely used and has touchscreen capabilities. Adafruit GFX Library supports this display however the library TFT_eSPI is more widely used and it works best for 32-bit processor MCUs. Since this library is more popular, there is also a significant amount of people in the community providing widgets and design contribution for the library.
To use this library follow this tutorial. It requires a specific set up.
HOWEVER
I couldn’t get this the eSPI Library to work at all with the Xiao ESP32.... so I just decided to program with the Adafruit GFX Library.
System Diagram
Example Code
Original Code from electronoob adapted for XIAO ESP32S3
/***************************************************
This is our GFX example for the Adafruit ILI9341 Breakout and Shield
----> http://www.adafruit.com/products/1651
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#define ILI9341_BLACK 0x0000 ///< 0, 0, 0
#define ILI9341_NAVY 0x000F ///< 0, 0, 123
#define ILI9341_DARKGREEN 0x03E0 ///< 0, 125, 0
#define ILI9341_DARKCYAN 0x03EF ///< 0, 125, 123
#define ILI9341_MAROON 0x7800 ///< 123, 0, 0
#define ILI9341_PURPLE 0x780F ///< 123, 0, 123
#define ILI9341_OLIVE 0x7BE0 ///< 123, 125, 0
#define ILI9341_LIGHTGREY 0xC618 ///< 198, 195, 198
#define ILI9341_DARKGREY 0x7BEF ///< 123, 125, 123
#define ILI9341_BLUE 0x001F ///< 0, 0, 255
#define ILI9341_GREEN 0x07E0 ///< 0, 255, 0
#define ILI9341_CYAN 0x07FF ///< 0, 255, 255
#define ILI9341_RED 0xF800 ///< 255, 0, 0
#define ILI9341_MAGENTA 0xF81F ///< 255, 0, 255
#define ILI9341_YELLOW 0xFFE0 ///< 255, 255, 0
#define ILI9341_WHITE 0xFFFF ///< 255, 255, 255
#define ILI9341_ORANGE 0xFD20 ///< 255, 165, 0
#define ILI9341_GREENYELLOW 0xAFE5 ///< 173, 255, 41
#define ILI9341_PINK 0xFC18 ///< 255, 130, 198
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
// For the Adafruit shield, these are the default.
#define TFT_RST A0
#define TFT_DC A1
#define TFT_CS D7 // SS
#define TFT_MOSI D10 // MOSI
#define TFT_MISO D9
#define TFT_CLK D8 // SCK
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
void setup() {
Serial.begin(9600);
Serial.println("ILI9341 Test!");
tft.begin();
// read diagnostics (optional but can help debug problems)
uint8_t x = tft.readcommand8(ILI9341_RDMODE);
Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDMADCTL);
Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDPIXFMT);
Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDIMGFMT);
Serial.print("Image Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDSELFDIAG);
Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
void loop(void) {
tft.fillScreen(ILI9341_NAVY);
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1);
tft.println("Hello World!");
tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
tft.println(1234.56);
tft.setTextColor(ILI9341_RED); tft.setTextSize(3);
tft.println(0xDEADBEEF, HEX);
tft.println();
tft.setTextColor(ILI9341_GREEN);
tft.setTextSize(5);
tft.println("Groop");
tft.setTextSize(2);
tft.println("I implore thee,");
tft.setTextSize(1);
tft.println("my foonting turlingdromes.");
tft.println("And hooptiously drangle me");
tft.println("with crinkly bindlewurdles,");
tft.println("Or I will rend thee");
tft.println("in the gobberwarts");
tft.println("with my blurglecruncheon,");
tft.println("see if I don't!");
delay(5000);
}
unsigned long testFillScreen() {
unsigned long start = micros();
tft.fillScreen(ILI9341_BLACK);
yield();
tft.fillScreen(ILI9341_RED);
yield();
tft.fillScreen(ILI9341_GREEN);
yield();
tft.fillScreen(ILI9341_BLUE);
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
return micros() - start;
}
unsigned long testText() {
tft.fillScreen(ILI9341_BLACK);
unsigned long start = micros();
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1);
tft.println("Hello World!");
tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
tft.println(1234.56);
tft.setTextColor(ILI9341_RED); tft.setTextSize(3);
tft.println(0xDEADBEEF, HEX);
tft.println();
tft.setTextColor(ILI9341_GREEN);
tft.setTextSize(5);
tft.println("Groop");
tft.setTextSize(2);
tft.println("I implore thee,");
tft.setTextSize(1);
tft.println("my foonting turlingdromes.");
tft.println("And hooptiously drangle me");
tft.println("with crinkly bindlewurdles,");
tft.println("Or I will rend thee");
tft.println("in the gobberwarts");
tft.println("with my blurglecruncheon,");
tft.println("see if I don't!");
return micros() - start;
}
unsigned long testLines(uint16_t color) {
unsigned long start, t;
int x1, y1, x2, y2,
w = tft.width(),
h = tft.height();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = y1 = 0;
y2 = h - 1;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = w - 1;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t = micros() - start; // fillScreen doesn't count against timing
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = w - 1;
y1 = 0;
y2 = h - 1;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = 0;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t += micros() - start;
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = 0;
y1 = h - 1;
y2 = 0;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = w - 1;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t += micros() - start;
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = w - 1;
y1 = h - 1;
y2 = 0;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = 0;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
yield();
return micros() - start;
}
unsigned long testFastLines(uint16_t color1, uint16_t color2) {
unsigned long start;
int x, y, w = tft.width(), h = tft.height();
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);
return micros() - start;
}
unsigned long testRects(uint16_t color) {
unsigned long start;
int n, i, i2,
cx = tft.width() / 2,
cy = tft.height() / 2;
tft.fillScreen(ILI9341_BLACK);
n = min(tft.width(), tft.height());
start = micros();
for(i=2; i<n; i+=6) {
i2 = i / 2;
tft.drawRect(cx-i2, cy-i2, i, i, color);
}
return micros() - start;
}
unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
unsigned long start, t = 0;
int n, i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
n = min(tft.width(), tft.height());
for(i=n; i>0; i-=6) {
i2 = i / 2;
start = micros();
tft.fillRect(cx-i2, cy-i2, i, i, color1);
t += micros() - start;
// Outlines are not included in timing results
tft.drawRect(cx-i2, cy-i2, i, i, color2);
yield();
}
return t;
}
unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
unsigned long start;
int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(x=radius; x<w; x+=r2) {
for(y=radius; y<h; y+=r2) {
tft.fillCircle(x, y, radius, color);
}
}
return micros() - start;
}
unsigned long testCircles(uint8_t radius, uint16_t color) {
unsigned long start;
int x, y, r2 = radius * 2,
w = tft.width() + radius,
h = tft.height() + radius;
// Screen is not cleared for this one -- this is
// intentional and does not affect the reported time.
start = micros();
for(x=0; x<w; x+=r2) {
for(y=0; y<h; y+=r2) {
tft.drawCircle(x, y, radius, color);
}
}
return micros() - start;
}
unsigned long testTriangles() {
unsigned long start;
int n, i, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
n = min(cx, cy);
start = micros();
for(i=0; i<n; i+=5) {
tft.drawTriangle(
cx , cy - i, // peak
cx - i, cy + i, // bottom left
cx + i, cy + i, // bottom right
tft.color565(i, i, i));
}
return micros() - start;
}
unsigned long testFilledTriangles() {
unsigned long start, t = 0;
int i, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(i=min(cx,cy); i>10; i-=5) {
start = micros();
tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
tft.color565(0, i*10, i*10));
t += micros() - start;
tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
tft.color565(i*10, i*10, 0));
yield();
}
return t;
}
unsigned long testRoundRects() {
unsigned long start;
int w, i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
w = min(tft.width(), tft.height());
start = micros();
for(i=0; i<w; i+=6) {
i2 = i / 2;
tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
}
return micros() - start;
}
unsigned long testFilledRoundRects() {
unsigned long start;
int i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(i=min(tft.width(), tft.height()); i>20; i-=6) {
i2 = i / 2;
tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
yield();
}
return micros() - start;
}
Simple Menu with Rotary Encoder
Inspired by this video, I adapted the code for ILI9341 with the help of chatgpt.
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
// Define pins for the ILI9341 display
#define TFT_RST D4
#define TFT_DC D5
#define TFT_CS D3 // SS
#define TFT_MOSI D10 // MOSI
#define TFT_MISO D9
#define TFT_CLK D8 // SCK
// Define pins for the rotary encoder
#define ENCODER_CLK D0
#define ENCODER_DT D1
#define ENCODER_SW D2
Adafruit_ILI9341 display = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
int menuitem = 1;
int page = 1;
int volume = 50;
String language[3] = { "EN", "ES", "EL" };
int selectedLanguage = 0;
String difficulty[2] = { "EASY", "HARD" };
int selectedDifficulty = 0;
volatile boolean up = false;
volatile boolean down = false;
volatile boolean middle = false;
volatile int lastClk = HIGH;
unsigned long lastButtonPress = 0;
void setup() {
pinMode(ENCODER_CLK, INPUT_PULLUP);
pinMode(ENCODER_DT, INPUT_PULLUP);
pinMode(ENCODER_SW, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, CHANGE);
attachInterrupt(digitalPinToInterrupt(ENCODER_SW), readButton, FALLING);
display.begin();
display.setRotation(4);
display.fillScreen(ILI9341_BLACK);
drawMenu();
}
void loop() {
bool needRedraw = false;
if (up) {
up = false;
if (page == 1) {
if (menuitem > 1) {
menuitem--;
} else {
menuitem = 3;
}
needRedraw = true;
} else {
if (menuitem == 1 && volume > 0) {
volume--;
needRedraw = true;
} else if (menuitem == 2 && selectedLanguage > 0) {
selectedLanguage--;
needRedraw = true;
} else if (menuitem == 3 && selectedDifficulty > 0) {
selectedDifficulty--;
needRedraw = true;
}
}
}
if (down) {
down = false;
if (page == 1) {
if (menuitem < 3) {
menuitem++;
} else {
menuitem = 1;
}
needRedraw = true;
} else {
if (menuitem == 1 && volume < 100) {
volume++;
needRedraw = true;
} else if (menuitem == 2 && selectedLanguage < 2) {
selectedLanguage++;
needRedraw = true;
} else if (menuitem == 3 && selectedDifficulty < 1) {
selectedDifficulty++;
needRedraw = true;
}
}
}
if (middle) {
middle = false;
page = (page == 1) ? 2 : 1;
needRedraw = true;
}
if (needRedraw) {
drawMenu();
}
}
void drawMenu() {
display.fillScreen(ILI9341_BLACK);
display.setTextSize(2);
display.setTextColor(ILI9341_WHITE);
if (page == 1) {
display.setCursor(10, 10);
display.print("MAIN MENU");
display.setCursor(10, 40);
display.setTextColor(menuitem == 1 ? ILI9341_YELLOW : ILI9341_WHITE);
display.print("Volume");
display.setCursor(10, 70);
display.setTextColor(menuitem == 2 ? ILI9341_YELLOW : ILI9341_WHITE);
display.print("Language");
display.setCursor(10, 100);
display.setTextColor(menuitem == 3 ? ILI9341_YELLOW : ILI9341_WHITE);
display.print("Difficulty");
} else if (page == 2) {
display.setCursor(10, 10);
if (menuitem == 1) {
display.print("Volume");
display.setCursor(10, 40);
display.print(volume);
} else if (menuitem == 2) {
display.print("Language");
display.setCursor(10, 40);
display.print(language[selectedLanguage]);
} else if (menuitem == 3) {
display.print("Difficulty");
display.setCursor(10, 40);
display.print(difficulty[selectedDifficulty]);
}
}
}
void readEncoder() {
int clkValue = digitalRead(ENCODER_CLK);
if (clkValue != lastClk) {
if (digitalRead(ENCODER_DT) != clkValue) {
down = true;
} else {
up = true;
}
}
lastClk = clkValue;
}
void readButton() {
unsigned long currentTime = millis();
if (currentTime - lastButtonPress > 200) { // debounce time
middle = true;
lastButtonPress = currentTime;
}
}