2020年5月20日 星期三

氬銲考題練習


用黑扁鐵練習時F,V,H,O,四個位置間隙為2.4mm
考試用的版子仰銲位置間隙用3.2mm

F(平) 間隙2.4mm 電流65~70A
V(立) 間隙2.4mm 電流70A
H(橫) 間隙2.4mm 電流80A
O(仰) 間隙3.2mm 電流80A
基隆訓練場考試OTC焊機電流再各加5A

仰銲位置料要填高很多,短電弧<1.5mm,角度將近90度




分租的空間限制比較多,練習區是在3樓的陽台


仰銲的背面滲透
仰銲正面
填料接一接

橫銲正面
橫銲背面











般到小瓶子後才有辦法扛上3樓

風大也是要擋風


間隙就抓2.4mm

練習材料用25mm 黑扁鐵,切成150mm長度









用黑扁鐵練習時F,V,H,O,四個位置間隙為2.4mm
考試用的版子仰銲位置間隙用3.2mm



未提供相片說明。

以下為亂搞部分




2019年12月31日 星期二

STM32 on Arduino IDE



Arduino 1.8.13 
//-------------------------------------------------------------------------------------------------------------------

Arduino STM32 Nucleo-64 開發環境設定 

https://moon-half.info/p/2373

https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/master/STM32/package_stm_index.json


https://dl.espressif.com/dl/package_esp32_index.json,http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/master/STM32/package_stm_index.json



Tools -->  Board:   --->  Boards Manager  

search :  stm32f1  

Install  STM32F1xx/ .. ... ..



ST Link SWD Upload ..........

https://www.st.com/en/development-tools/stm32cubeprog.html

install   STM32CubeProgrammer



Serial Com Port upload ......
FTDI  Pin to STM32 Board pin

5V     ----------   5V
Gnd  ----------   Gnd
Rx    ----------   A9
Tx    ----------   A10   

Tools --> Upload method:  Serial

Tools -->  select Port : 


Pin  Boot0  --> 1  

RESET Board 
Sketch Upload  .....

電源不穩可能會上傳失敗


https://www.st.com/en/microcontrollers/stm32f103.html?querycriteria=productId=LN1565


https://www.st.com/resource/en/datasheet/stm32f103rc.pdf


https://translate.google.com/translate?hl=zh-TW&sl=zh-CN&u=http://www.makerlab.me/guides/2/articles/8&prev=search






//============================================================
Arduino IDE 1.8.4   or  other

//------- only STM32F1  --------------------------------------------------------------------------
File  ->  Preferences--> Additional Board Manager URLs:

http://dan.drown.org/stm32duino/package_STM32duino_index.json     --> OK


//--------keep ESP32 & ESP8266 ----------------------------------------------------------------------------------
ESP8266
ESP32
STM32

https://dl.espressif.com/dl/package_esp32_index.json,http://arduino.esp8266.com/stable/package_esp8266com_index.json,http://dan.drown.org/stm32duino/package_STM32duino_index.json



選擇不同板子在編譯時所佔記憶體容量的差異性






2019年2月16日 星期六

String 逗號分隔範例 strtok_r & String



//  strtok_r_comma_split   


//  String strKey1 = (char*)keyData;                                                       // 字元陣列 to 串流  keyData  to  String

//  strKey1.toCharArray((char*)keyData, strKey1.length() + 1);        //  串流 to 字元陣列  string   to  keyData.

/*
   http://forum.arduino.cc/index.php?topic=186687.0

*/
// strtok_r_comma_split_testOK

//------------------ EEPROM  結構 -------------------------------------------------------------
struct espConf {
  char wifiSsid[20];
  char wifiPass[20];
  char iotKey[16];
  char set_1[4];
  char set_2[4];
};

espConf config_1 = {  "1100",  "74sjfekjtrhe",  "------!","63", "31" };

String adminConfString = "2100,wsderf4321543d,IoT_Write_KEY_16,70,4";

void setup () {
  Serial.begin (115200);
delay(200);
Serial.println("---------read   struct ------------");
Serial.println((char*)config_1.wifiSsid);
Serial.println((char*)config_1.wifiPass);
Serial.println((char*)config_1.iotKey);
Serial.println((char*)config_1.set_1);
Serial.println((char*)config_1.set_2);
Serial.println();
delay(200);




  int strLng = adminConfString.length() + 1;
  char sz[strLng];
  adminConfString.toCharArray(sz, strLng);                        // Convert string to array.  串流  轉 字元陣列sz


  char *str;
  // char sz[] = "2100,poiuytrewqpoi,IoT_Write_KEY_16,70,4";      // char array
  char *p = sz;                                                   // char array
  static int i = 0;
  String g0, g1, g2;
  String g3, g4;
  while (( str = strtok_r(p, ",", &p)) != NULL) {                  // NULL就可以了,代表我没有数据给你,你就用剩下的数据就可以了。
    if (i == 0) g0 = str;
    if (i == 1) g1 = str;
    if (i == 2) g2 = str;
    if (i == 3) g3 = str;
    if (i == 4) g4 = str;
    i++;
    Serial.println(str);     // String
  }
  int c_g3 = g3.toInt();                       // String to int
  int c_g4 = g4.toInt();                       // String to int
  Serial.print(g0); Serial.print(",");          // ptint String g0
  Serial.print(g1); Serial.print(",");          // ptint String g1
  Serial.print(g2); Serial.print(",");          // ptint String g2
  Serial.print(c_g3, DEC); Serial.print(",");   // ptint int c_g3
  Serial.print(c_g4, DEC); Serial.println(" "); // ptint int c_g4

  g0.toCharArray(config_1.wifiSsid, g0.length() + 1); // Convert string to array.  串流  轉 字元陣列
  g1.toCharArray(config_1.wifiPass, g1.length() + 1); // Convert string to array.  串流  轉 字元陣列
  g2.toCharArray(config_1.iotKey,   g2.length() + 1); // Convert string to array.  串流  轉 字元陣列
  g3.toCharArray(config_1.set_1,    g3.length() + 1); // Convert string to array.  串流  轉 字元陣列
  g4.toCharArray(config_1.set_2,    g4.length() + 1); // Convert string to array.  串流  轉 字元陣列
//  config_1.set_1 = c_g3;
//  config_1.set_2 = c_g4;



Serial.println("---------write  struct ------------");
Serial.println((char*)config_1.wifiSsid);
Serial.println((char*)config_1.wifiPass);
Serial.println((char*)config_1.iotKey);
Serial.println((char*)config_1.set_1);
Serial.println((char*)config_1.set_2);
Serial.println();
delay(200);

}


//  String strKey1 = (char*)keyData;                            // 字元陣列 to 串流  keyData  to  String
//  strKey1.toCharArray((char*)keyData, strKey1.length() + 1);  //  串流 to 字元陣列  string   to  keyData.


void loop () { }






//  String_comma_split   

https://stackoverflow.com/questions/11068450/arduino-c-language-parsing-string-with-delimiter-input-through-serial-interfa



String myString = ",daqwete0,rec23123ipt,weiqweght,timadsdasde,dasdasdasdasdte,";

// the setup routine runs once when you press reset:
void setup() {
  Serial.begin(115200);

  int Index1 = myString.indexOf(',');
  int Index2 = myString.indexOf(',', Index1 + 1);
  int Index3 = myString.indexOf(',', Index2 + 1);
  int Index4 = myString.indexOf(',', Index3 + 1);
  int Index5 = myString.indexOf(',', Index4 + 1);
  int Index6 = myString.indexOf(',', Index5 + 1);
  String Value_1 = myString.substring(Index1 + 1, Index2);
  String Value_2 = myString.substring(Index2 + 1, Index3);
  String Value_3 = myString.substring(Index3 + 1, Index4);
  String Value_4 = myString.substring(Index4 + 1, Index5);
  String Value_5 = myString.substring(Index5 + 1, Index6);
  //Serial.println(Index1);

  Serial.println(Value_1);
  Serial.println(Value_2);
  Serial.println(Value_3);
  Serial.println(Value_4);
  Serial.println(Value_5);

}


// the loop routine runs over and over again forever:
void loop() {

}


2019年2月8日 星期五

CharArray_Write EEPROM & Read EEPROM

/*
   2019-02-08 test OK by yulie
*/

char WifiName[] = "jigu";                               // Wifi name
char WifiPass[] = "0000";                               // Wifi password
//char WifiName[] = "M8_1";                             // Wifi name
//char WifiPass[] = "poiuytrewqpoi";                    // Wifi password


#include <EEPROM.h>

void setup() {
  Serial.begin(115200);
  //  EEPROM.begin(2048); // only for  ESP Chip


  //------------ write EEPROM to WifiName --------------------------------------------------------
  //  saveChar( WifiName, sizeof(WifiName), 0x10);  //將 WifiName 寫入EEPROM 0x10位置

  //------------ write EEPROM to WifiPass ----------------------------------------------------
  //  saveChar( WifiPass, sizeof(WifiPass), 0x20);  //將 WifiName 寫入EEPROM 0x20位置

  Serial.print("OLD_SSID: ");   Serial.write(WifiName, sizeof(WifiName)); Serial.println();
  Serial.print("OLD_PASS: ");   Serial.write(WifiPass, sizeof(WifiPass)); Serial.println();

  Serial.println("Read SSID & PASS  form EEPROM ... ");

  //------------ read EEPROM to WifiName --------------------------------------------------------
  String strName = (char*)readChar(0x10);                         // 將0x10讀到的字元陣列轉換成串流(strName)
  uint8_t lenN = strName.length();                                 // 取得串流長度
  char WifiName[lenN];                                          //字元陣列長度重設
  for (word i = 0; i < lenN; i++)WifiName[i] = strName.charAt(i);  // 將strName串流轉換成WifiName字元陣列
  Serial.print("New_SSID: "); Serial.write(WifiName, sizeof(WifiName)); Serial.println();

  //------------- read EEPROM to WifiPass -------------------------------------------------------
  String strPass = (char*)readChar(0x20);                         // 將0x20讀到的字元陣列轉換成串流(strPass)
  uint8_t lenP = strPass.length();                                // 取得串流長度
  char WifiPass[lenP];                                         //字元陣列長度重設
  for (word i = 0; i < lenP; i++)WifiPass[i] = strPass.charAt(i); // 將strPass串流轉換成WifiPass字元陣列
  Serial.print("New_PASS: "); Serial.write(WifiPass, sizeof(WifiPass)); Serial.println();

}

//----------------------- read EEPROM char array function return -----------
char* readChar (word addr) {
  uint8_t len = EEPROM.read(addr);                           // 讀取串流長度
  static  char buf[32];                                         // max len 32 char
  addr = addr + 1 ;   len = len + 1;
  for (word i = 0; i < len; i++) buf[i] = EEPROM.read(addr + i);
  //  Serial.write(buf, sizeof(buf)); Serial.println();
  return buf;
}


//---------- char array function return demo -----------
char* foo () {
  static char buf [100] = "But does it get goat's blood out?";
  return buf;
}  // end of foo




  //<< ========== write char[] to EEPROM =============================================
void saveChar(char charName[], byte lenIn, word addr) {  //Ex: saveChar( WifiName, sizeof(WifiName), 0x00);
  uint8_t len = lenIn - 1;        // 取得串流長度
  EEPROM.write(addr, len);     // 紀錄串流長度
  delay(5);                       // write takes 3.3 ms to complete
  addr = addr + 1 ;   len = len + 1;
  for (word i = 0; i < len; i++) {
    EEPROM.write(addr + i, charName[i]);
    delay(5); // write takes 3.3 ms to complete
  }
  delay(200);
//  Serial.print("write char: "); Serial.write(charName, len);      // 顯示字元陣列內容
//  Serial.print("  len: ");    Serial.print(len);
  Serial.print("  address : 0x"); Serial.print(addr, HEX); Serial.print(" ~ 0x"); Serial.println(addr + len, HEX);
  //  EEPROM.commit(); // Buffer SAVE to flase  (ESP8266 Only)
  //  delay(200);
}

/*
  //<< ========== read char[] form EEPROM =============================================
  byte readChar(char charName[],  word addr) {           //Ex:   readChar( WifiName, 0x00);
  uint8_t len = EEPROM.read(addr);                           // 讀取串流長度
  Serial.print("read  len: ");    Serial.println(len);
  addr = addr + 1 ;   len = len + 1;
  for (word i = 0; i < len; i++) {
    charName[i] = EEPROM.read(addr + i);
    delay(5);
  }
  delay(20);
  Serial.print("read char: "); Serial.write(charName, len);      // 顯示字元陣列內容
  Serial.print("  len: ");    Serial.print(len);
  Serial.print("  address : 0x"); Serial.print(addr, HEX); Serial.print(" ~ 0x"); Serial.println(addr + len, HEX);
  //  EEPROM.commit(); // Buffer SAVE to flase  (ESP8266 Only)
  //  delay(200);
  len = len - 1;
  Serial.print(" return len: "); Serial.println(len);
  return len  ;
  }
*/

void loop() {}

String_Write EEPROM & Read EEPROM

/*
   Circuits4you.com
   Reading and Writing String to EEPROM Example Code
   Oct 2018
   https://circuits4you.com/2018/10/16/arduino-reading-and-writing-string-to-eeprom/

   佔用空間為字串長度 + 1 ,需注意
*/

//String key1 = "1000000000";
//String key2 = "20000000-";
//String key3 = "300000000--";

String key1 = "FAPOUNY1BRB3HIH2";
String key2 = "G1RZYYND9TV636UF";
String key3 = "GT34WTYAZ6E0HGK7";

#include <EEPROM.h>

//void writeString(char add,String data);
//String read_String(char add);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);


  //------------ write EEPROM to WifiName --------------------------------------------------------
  writeString(0xA0, key1);  //Address 0xA0 and String type key1 (char array +1 )
  writeString(0xB1, key2);  //Address 0xB0 and String type key2 (char array +1 )
  writeString(0xC2, key3);  //Address 0xC0 and String type key3 (char array +1 )


  //------------ read EEPROM to WifiName --------------------------------------------------------
  key1 = read_String(0xA0);   // read Address 0xA0 to String key1
  key2 = read_String(0xB1);   // read Address 0xA0 to String key1
  key3 = read_String(0xC2);   // read Address 0xA0 to String key1

  Serial.print("Read Data key1:");  Serial.println(key1);
  Serial.print("Read Data key2:");  Serial.println(key2);
  Serial.print("Read Data key3:");  Serial.println(key3);


  /*
    //-----write -----------------------
    String data = "Hello World";
    Serial.print("Writing Data:");
    Serial.println(data);
    writeString(10, data);  //Address 10 and String type data
    delay(10);


    //-----read -----------------------
    String recivedData;
    recivedData = read_String(10);
    Serial.print("Read Data:");
    Serial.println(recivedData);
    delay(1000);
  */

  // 串流String 內容固定長度方式
  //  Serial.println(key1); Serial.println(key2); Serial.println(key3);
  //Serial.println(key4); Serial.println(key5); Serial.println(key6);
  // saveKey(key1,0x80);  // 0x80 ~ 0x8F  (16 Byte)
  // saveKey(key2,0x90);  // 0x90 ~ 0x9F  (16 Byte)
  // saveKey(key3,0xA0);  // 0xA0 ~ 0xAF  (16 Byte)

  //  readKey(key1, 0x80); // 0x80 ~ 0x8F  (16 Byte)
  //  readKey(key2, 0x90); // 0x90 ~ 0x9F  (16 Byte)
  //  readKey(key3, 0xA0); // 0xA0 ~ 0xAF  (16 Byte)      // 將key3 從 EEPROM帶回來


}





void loop() {
  // put your main code here, to run repeatedly:

}


//<< ==== EEPROM  write_String    =============================================
void writeString(byte addr, String data) {
  int _size = data.length();
  int i;
  for (i = 0; i < _size; i++) {
    EEPROM.write(addr + i, data[i]);
  }
  EEPROM.write(addr + _size, '\0'); //Add termination null character for String Data 加入空白結束字符
//  Serial.print("write char: "); Serial.write(data, _size);      // 顯示字元陣列內容
//  Serial.print("  len: ");    Serial.print(_size);
  Serial.print("write address : 0x"); Serial.print(addr, HEX); Serial.print(" ~ 0x"); Serial.println(addr + _size , HEX);
}


//<< ==== EEPROM  read_String    =============================================
String read_String(byte addr) {
  int i;
  char data[126];                     //Max 126 Bytes
  int len = 0;
  unsigned char k;
  k = EEPROM.read(addr);
  while (k != '\0' && len < 500) {    //Read until null character 讀取直到null字符
    k = EEPROM.read(addr + len);
    data[len] = k;
    len++;
  }
  data[len] = '\0';                   // 先找出(while)  空白結束字符(\0),帶入 string 長度(len)
  return String(data);
}


  //<< ========== save key String to EEPROM =============================================
byte saveKey(String strKey, word addr) {
  String keystr = String((String)strKey);
  uint8_t len = keystr.length();                               // 自動取得串流長度
  uint8_t keyData[len];
  //  for(word i=0;i < len;i++)keyData[i] = keystr.charAt(i);    // 將keystr串流轉換成keyData字元陣列
  for (word i = 0; i < len; i++) {
    keyData[i] = keystr.charAt(i);                                //來源為串流才使用將(串流)轉換成 (字元陣列)
    EEPROM.write(addr + i, keyData[i]);
  }
  Serial.write(keyData, len);                                  // 顯示字元陣列內容
  Serial.print("  len="); Serial.println(len);
  //  EEPROM.commit(); // Buffer SAVE to flase  (ESP8266 Only)
  delay(200);
}


  //<< ========== read key EEPROM to Stringg   ==========================================
byte readKey(String &strKey, word addr) {                          // &將 EEPROM read帶回來的值 寫回帶進來的變數key_
  uint8_t len = strKey.length();                                   // 串流長度
  uint8_t keyData[len];
  for (word i = 0; i < len; i++)keyData[i] = EEPROM.read(addr + i);
  Serial.write(keyData, len); delay(100); Serial.println(" ");      // 顯示字元陣列內容
  String strKey1 = (char*)keyData;                                 // uint8_t    將字元陣列keyData  轉換成串流keystr
  strKey = strKey1;
}


2018年12月24日 星期一

ST7567 12864LCD Arduino 328 使用U8g2 空間不足的問題


328使用U8g2會有空間不足的問題


ST7567 用 ST7565 的Library 畫面的對比度過高
就算調到0 還是太黑


對比度粗調位置 0x24   /* range 0x20~0x27 */

下列為測試檔和修改過的library

Test PDE

#include "ST7565.h"

int ledPin =  13;    // LED connected to digital pin 13

// the LCD backlight is connected up to a pin so you can turn it on & off


// pin 9 - Serial data out (SID)
// pin 8 - Serial clock out (SCLK)
// pin 7 - Data/Command select (RS or A0)
// pin 6 - LCD reset (RST)
// pin 5 - LCD chip select (CS)
//ST7565 glcd(9, 8, 7, 6, 5);

//ST7565 glcd(SDA, SCK, RS/DC, RST, CS);

ST7565 glcd(5, 6, 4, 3, 2);
#define Power_3v3 7
#define Power_Gnd 8
#define BACKLIGHT_LED 9

//ST7565 glcd(9, 8, 7, 6, 5);
#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16 

// a bitmap of a 16x16 fruit icon
const static unsigned char __attribute__ ((progmem)) logo16_glcd_bmp[]={
0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0xf8, 0xbe, 0x9f, 0xff, 0xf8, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 
0x20, 0x3c, 0x3f, 0x3f, 0x1f, 0x19, 0x1f, 0x7b, 0xfb, 0xfe, 0xfe, 0x07, 0x07, 0x07, 0x03, 0x00, };

// The setup() method runs once, when the sketch starts
void setup()   {                
  Serial.begin(115200);

  pinMode(Power_3v3, OUTPUT);  digitalWrite(Power_3v3, HIGH);
  pinMode(Power_Gnd, OUTPUT);  digitalWrite(Power_Gnd, LOW);
//  pinMode(BACKLIGHT_LED, OUTPUT); 
 // analogWrite(BACKLIGHT_LED, 64);


#ifdef __AVR__
  Serial.print(freeRam());
#endif

  // turn on backlight


  // initialize and set the contrast to 0x18
  glcd.begin(0x08);
  delay(200);
  glcd.st7565_set_pre_contrast(0x20);/*0x20~0x27*/
//  glcd.st7565_set_brightness(0x00);
  
  glcd.display(); // show splashscreen
  delay(2000);
  glcd.clear();

  // draw a single pixel
  glcd.setpixel(10, 10, BLACK);
  glcd.display();        // show the changes to the buffer
  delay(2000);
  glcd.clear();

  // draw many lines
  testdrawline();
  glcd.display();       // show the lines
  delay(2000);
  glcd.clear();

  // draw rectangles
  testdrawrect();
  glcd.display();
  delay(2000);
  glcd.clear();

  // draw multiple rectangles
  testfillrect();
  glcd.display();
  delay(2000);
  glcd.clear();

  // draw mulitple circles
  testdrawcircle();
  glcd.display();
  delay(2000);
  glcd.clear();

  // draw a black circle, 10 pixel radius, at location (32,32)
  glcd.fillcircle(32, 32, 10, BLACK);
  glcd.display();
  delay(2000);
  glcd.clear();

  // draw the first ~120 characters in the font
  testdrawchar();
  glcd.display();
  delay(2000);
  glcd.clear();

  // draw a string at location (0,0)
  glcd.drawstring(0, 0, "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation");
  glcd.display();
  delay(2000);
  glcd.clear();

  // draw a bitmap icon and 'animate' movement
  testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH);
}


void loop()                     
{}

#ifdef __AVR__
// this handy function will return the number of bytes currently free in RAM, great for debugging!   
int freeRam(void)
{
  extern int  __bss_end; 
  extern int  *__brkval; 
  int free_memory; 
  if((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__bss_end); 
  }
  else {
    free_memory = ((int)&free_memory) - ((int)__brkval); 
  }
  return free_memory; 

#endif

#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2

void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  uint8_t icons[NUMFLAKES][3];
  randomSeed(666);     // whatever seed

  // initialize
  for (uint8_t f=0; f< NUMFLAKES; f++) {
    icons[f][XPOS] = random(128);
    icons[f][YPOS] = 0;
    icons[f][DELTAY] = random(5) + 1;
  }

  while (1) {
    // draw each icon
    for (uint8_t f=0; f< NUMFLAKES; f++) {
      glcd.drawbitmap(icons[f][XPOS], icons[f][YPOS], logo16_glcd_bmp, w, h, BLACK);
    }
    glcd.display();
    delay(200);
    
    // then erase it + move it
    for (uint8_t f=0; f< NUMFLAKES; f++) {
      glcd.drawbitmap(icons[f][XPOS], icons[f][YPOS],  logo16_glcd_bmp, w, h, 0);
      // move it
      icons[f][YPOS] += icons[f][DELTAY];
      // if its gone, reinit
      if (icons[f][YPOS] > 64) {
icons[f][XPOS] = random(128);
icons[f][YPOS] = 0;
icons[f][DELTAY] = random(5) + 1;
      }
    }
  }
}


void testdrawchar(void) {
  for (uint8_t i=0; i < 168; i++) {
    glcd.drawchar((i % 21) * 6, i/21, i);
  }    
}

void testdrawcircle(void) {
  for (uint8_t i=0; i<64; i+=2) {
    glcd.drawcircle(63, 31, i, BLACK);
  }
}


void testdrawrect(void) {
  for (uint8_t i=0; i<64; i+=2) {
    glcd.drawrect(i, i, 128-i, 64-i, BLACK);
  }
}

void testfillrect(void) {
  for (uint8_t i=0; i<64; i++) {
      // alternate colors for moire effect
    glcd.fillrect(i, i, 128-i, 64-i, i%2);
  }
}

void testdrawline() {
  for (uint8_t i=0; i<128; i+=4) {
    glcd.drawline(0, 0, i, 63, BLACK);
  }
  for (uint8_t i=0; i<64; i+=4) {
    glcd.drawline(0, 0, 127, i, BLACK);
  }

  glcd.display();
  delay(1000);

  for (uint8_t i=0; i<128; i+=4) {
    glcd.drawline(i, 63, 0, 0, WHITE);
  }
  for (uint8_t i=0; i<64; i+=4) {
    glcd.drawline(127, i, 0, 0, WHITE);
  }
}





ST7565.h

/*
$Id:$

ST7565 LCD library!

Copyright (C) 2010 Limor Fried, Adafruit Industries

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

// some of this code was written by <cstone@pobox.com> originally; it is in the public domain.
*/

#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

#define swap(a, b) { uint8_t t = a; a = b; b = t; }

#define BLACK 1
#define WHITE 0

#define LCDWIDTH 128
#define LCDHEIGHT 64

#define CMD_DISPLAY_OFF   0xAE
#define CMD_DISPLAY_ON    0xAF

#define CMD_SET_DISP_START_LINE  0x40
#define CMD_SET_PAGE  0xB0

#define CMD_SET_COLUMN_UPPER  0x10
#define CMD_SET_COLUMN_LOWER  0x00

#define CMD_SET_ADC_NORMAL  0xA0
#define CMD_SET_ADC_REVERSE 0xA1

#define CMD_SET_DISP_NORMAL 0xA6
#define CMD_SET_DISP_REVERSE 0xA7

#define CMD_SET_ALLPTS_NORMAL 0xA4
#define CMD_SET_ALLPTS_ON  0xA5
#define CMD_SET_BIAS_9 0xA2 
#define CMD_SET_BIAS_7 0xA3

#define CMD_RMW  0xE0
#define CMD_RMW_CLEAR 0xEE
#define CMD_INTERNAL_RESET  0xE2
#define CMD_SET_COM_NORMAL  0xC0
#define CMD_SET_COM_REVERSE  0xC8
#define CMD_SET_POWER_CONTROL  0x28
#define CMD_SET_RESISTOR_RATIO  0x20
#define CMD_SET_PRE_CONTRAST  0x24        /*2018-12-19 add  range 0x20~0x27*/
#define CMD_SET_VOLUME_FIRST  0x81
#define  CMD_SET_VOLUME_SECOND  0
#define CMD_SET_STATIC_OFF  0xAC
#define  CMD_SET_STATIC_ON  0xAD
#define CMD_SET_STATIC_REG  0x0
#define CMD_SET_BOOSTER_FIRST  0xF8
#define CMD_SET_BOOSTER_234  0
#define  CMD_SET_BOOSTER_5  1
#define  CMD_SET_BOOSTER_6  3
#define CMD_NOP  0xE3
#define CMD_TEST  0xF0

class ST7565 {
 public:
  ST7565(int8_t SID, int8_t SCLK, int8_t A0, int8_t RST, int8_t CS) :sid(SID), sclk(SCLK), a0(A0), rst(RST), cs(CS) {}
  ST7565(int8_t SID, int8_t SCLK, int8_t A0, int8_t RST) :sid(SID), sclk(SCLK), a0(A0), rst(RST), cs(-1) {}


  void st7565_init(void);
  void begin(uint8_t contrast);
  void st7565_command(uint8_t c);
  void st7565_data(uint8_t c);
  void st7565_set_brightness(uint8_t val);
  void st7565_set_pre_contrast(uint8_t pval);   /*  2018-12-19 add     */
  void clear_display(void);
  void clear();
  void display();

  void setpixel(uint8_t x, uint8_t y, uint8_t color);
  uint8_t getpixel(uint8_t x, uint8_t y);
  void fillcircle(uint8_t x0, uint8_t y0, uint8_t r, 
  uint8_t color);
  void drawcircle(uint8_t x0, uint8_t y0, uint8_t r, 
  uint8_t color);
  void drawrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, 
uint8_t color);
  void fillrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, 
uint8_t color);
  void drawline(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, 
uint8_t color);
  void drawchar(uint8_t x, uint8_t line, char c);
  void drawstring(uint8_t x, uint8_t line, char *c);
  void drawstring_P(uint8_t x, uint8_t line, const char *c);

  void drawbitmap(uint8_t x, uint8_t y, 
  const uint8_t *bitmap, uint8_t w, uint8_t h,
  uint8_t color);

 private:
  int8_t sid, sclk, a0, rst, cs;
  void spiwrite(uint8_t c);

  void my_setpixel(uint8_t x, uint8_t y, uint8_t color);

  //uint8_t buffer[128*64/8]; 
};




ST7665.cpp

/*
$Id:$

ST7565 LCD library!

Copyright (C) 2010 Limor Fried, Adafruit Industries

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

// some of this code was written by <cstone@pobox.com> originally; it is in the public domain.
*/

//#include <Wire.h>
#ifdef __AVR__
#include <avr/pgmspace.h>
#include <util/delay.h>
#endif

#ifndef _delay_ms
  #define _delay_ms(t) delay(t)
#endif

#ifndef _BV
  #define _BV(bit) (1<<(bit))
#endif


#include <stdlib.h>

#include "ST7565.h"

#define ST7565_STARTBYTES 1

uint8_t is_reversed = 0;

// a handy reference to where the pages are on the screen
//const uint8_t pagemap[] = { 3, 2, 1, 0, 7, 6, 5, 4 };
const uint8_t pagemap[] = { 7, 6, 5, 4, 3, 2, 1, 0 }; /* 2019-01-20 add  */

// a 5x7 font table
const extern uint8_t PROGMEM font[];

// the memory buffer for the LCD
uint8_t st7565_buffer[1024] = { 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 

0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x3, 0x7, 0xF, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x7, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x7F, 0x3F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x1F, 0x3F, 0x70, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x6, 0x0, 0x0, 0x0, 0x3, 0x3, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 

0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0xF, 0x7, 0x7, 
0x7, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF, 0x3F, 
0x70, 0x60, 0x60, 0x60, 0x60, 0x30, 0x7F, 0x3F, 0x0, 0x0, 0x1F, 0x3F, 0x70, 0x60, 0x60, 0x60, 
0x60, 0x39, 0xFF, 0xFF, 0x0, 0x6, 0x1F, 0x39, 0x60, 0x60, 0x60, 0x60, 0x30, 0x3F, 0x7F, 0x0, 
0x0, 0x60, 0xFF, 0xFF, 0x60, 0x60, 0x0, 0x7F, 0x7F, 0x70, 0x60, 0x60, 0x40, 0x0, 0x7F, 0x7F, 
0x0, 0x0, 0x0, 0x0, 0x7F, 0x7F, 0x0, 0x0, 0x0, 0x7F, 0x7F, 0x0, 0x0, 0x60, 0xFF, 0xFF, 
0x60, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 

0x80, 0xF8, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xE7, 0xE7, 0xE3, 
0xF3, 0xF9, 0xFF, 0xFF, 0xFF, 0xF7, 0x7, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x3F, 0x3F, 0x1F, 0xF, 0x7, 0x3, 0x0, 0x0, 0x0, 0xC0, 
0xE0, 0x60, 0x20, 0x20, 0x60, 0xE0, 0xE0, 0xE0, 0x0, 0x0, 0x80, 0xC0, 0xE0, 0x60, 0x20, 0x60, 
0x60, 0xE0, 0xE0, 0xE0, 0x0, 0x0, 0x80, 0xC0, 0x60, 0x60, 0x20, 0x60, 0x60, 0xE0, 0xE0, 0x0, 
0x0, 0x0, 0xE0, 0xE0, 0x0, 0x0, 0x0, 0xE0, 0xE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xE0, 
0x60, 0x60, 0x60, 0x60, 0xE0, 0x80, 0x0, 0x0, 0x0, 0xE0, 0xE0, 0x0, 0x0, 0x0, 0xE0, 0xE0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 

0x0, 0x0, 0x0, 0x3, 0x7, 0x1F, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xF1, 0xE3, 
0xE3, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFC, 0x7F, 0x3F, 0x3F, 0x3F, 0x3F, 0x7F, 0xFF, 0xFF, 
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xF0, 0xE0, 0x80, 0x0, 0x0, 0x0, 0xC, 
0x1C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7F, 0x7F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1C, 0xC, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 

0x0, 0x7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFC, 0xF8, 
0xF8, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFF, 
0xFF, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xE0, 0xC0, 0xC0, 0xC0, 0xFF, 0x7F, 0x0, 0x0, 0x1E, 0x7F, 
0xE1, 0xC0, 0xC0, 0xC0, 0xC0, 0x61, 0xFF, 0xFF, 0x0, 0x0, 0xFE, 0xFF, 0x1, 0x0, 0x0, 0x0, 
0xFF, 0xFF, 0x0, 0x0, 0x21, 0xF9, 0xF8, 0xDC, 0xCC, 0xCF, 0x7, 0x0, 0xC0, 0xFF, 0xFF, 0xC0, 
0x80, 0x0, 0xFF, 0xFF, 0xC0, 0xC0, 0x80, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0x1F, 0x7F, 0xF9, 
0xC8, 0xC8, 0xC8, 0xC8, 0x79, 0x39, 0x0, 0x0, 0x71, 0xF9, 0xD8, 0xCC, 0xCE, 0x47, 0x3, 0x0, 

0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 
0x0, 0x0, 0x0, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xF8, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xC0, 
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC0, 
0xC0, 0x0, 0x0, 0x0, 0xC0, 0xC0, 0x0, 0x0, 0x0, 0x0, 0xC0, 0xC0, 0x0, 0x0, 0x0, 0x80, 
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0xC0, 0xC0, 0x0, 0x0, 0x0, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 
0xC0, 0x80, 0x0, 0x0, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x0, 0x0, 0x0, 0xC0, 0xC0, 0x0, 
0x0, 0x0, 0xC0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC0, 0xC0, 0x0, 0x0, 0x0, 0x80, 0xC0, 
0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x80, 0x0, 0x0, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x0, 0x0, 

0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,};

// reduces how much is refreshed, which speeds it up!
// originally derived from Steve Evans/JCW's mod but cleaned up and
// optimized
#define enablePartialUpdate

#ifdef enablePartialUpdate
static uint8_t xUpdateMin, xUpdateMax, yUpdateMin, yUpdateMax;
#endif



static void updateBoundingBox(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax) {
#ifdef enablePartialUpdate
  if (xmin < xUpdateMin) xUpdateMin = xmin;
  if (xmax > xUpdateMax) xUpdateMax = xmax;
  if (ymin < yUpdateMin) yUpdateMin = ymin;
  if (ymax > yUpdateMax) yUpdateMax = ymax;
#endif
}

void ST7565::drawbitmap(uint8_t x, uint8_t y, 
const uint8_t *bitmap, uint8_t w, uint8_t h,
uint8_t color) {
  for (uint8_t j=0; j<h; j++) {
    for (uint8_t i=0; i<w; i++ ) {
      if (pgm_read_byte(bitmap + i + (j/8)*w) & _BV(j%8)) {
my_setpixel(x+i, y+j, color);
      }
    }
  }

  updateBoundingBox(x, y, x+w, y+h);
}

void ST7565::drawstring(uint8_t x, uint8_t line, char *c) {
  while (c[0] != 0) {
    drawchar(x, line, c[0]);
    c++;
    x += 6; // 6 pixels wide
    if (x + 6 >= LCDWIDTH) {
      x = 0;    // ran out of this line
      line++;
    }
    if (line >= (LCDHEIGHT/8))
      return;        // ran out of space :(
  }
}


void ST7565::drawstring_P(uint8_t x, uint8_t line, const char *str) {
  while (1) {
    char c = pgm_read_byte(str++);
    if (! c)
      return;
    drawchar(x, line, c);
    x += 6; // 6 pixels wide
    if (x + 6 >= LCDWIDTH) {
      x = 0;    // ran out of this line
      line++;
    }
    if (line >= (LCDHEIGHT/8))
      return;        // ran out of space :(
  }
}

void  ST7565::drawchar(uint8_t x, uint8_t line, char c) {
  for (uint8_t i =0; i<5; i++ ) {
    st7565_buffer[x + (line*128) ] = pgm_read_byte(font+(c*5)+i);
    x++;
  }

  updateBoundingBox(x, line*8, x+5, line*8 + 8);
}


// bresenham's algorithm - thx wikpedia
void ST7565::drawline(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, 
      uint8_t color) {
  uint8_t steep = abs(y1 - y0) > abs(x1 - x0);
  if (steep) {
    swap(x0, y0);
    swap(x1, y1);
  }

  if (x0 > x1) {
    swap(x0, x1);
    swap(y0, y1);
  }

  // much faster to put the test here, since we've already sorted the points
  updateBoundingBox(x0, y0, x1, y1);

  uint8_t dx, dy;
  dx = x1 - x0;
  dy = abs(y1 - y0);

  int8_t err = dx / 2;
  int8_t ystep;

  if (y0 < y1) {
    ystep = 1;
  } else {
    ystep = -1;}

  for (; x0<=x1; x0++) {
    if (steep) {
      my_setpixel(y0, x0, color);
    } else {
      my_setpixel(x0, y0, color);
    }
    err -= dy;
    if (err < 0) {
      y0 += ystep;
      err += dx;
    }
  }
}

// filled rectangle
void ST7565::fillrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, 
      uint8_t color) {

  // stupidest version - just pixels - but fast with internal buffer!
  for (uint8_t i=x; i<x+w; i++) {
    for (uint8_t j=y; j<y+h; j++) {
      my_setpixel(i, j, color);
    }
  }

  updateBoundingBox(x, y, x+w, y+h);
}

// draw a rectangle
void ST7565::drawrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, 
      uint8_t color) {
  // stupidest version - just pixels - but fast with internal buffer!
  for (uint8_t i=x; i<x+w; i++) {
    my_setpixel(i, y, color);
    my_setpixel(i, y+h-1, color);
  }
  for (uint8_t i=y; i<y+h; i++) {
    my_setpixel(x, i, color);
    my_setpixel(x+w-1, i, color);
  } 

  updateBoundingBox(x, y, x+w, y+h);
}

// draw a circle outline
void ST7565::drawcircle(uint8_t x0, uint8_t y0, uint8_t r, 
uint8_t color) {
  updateBoundingBox(x0-r, y0-r, x0+r, y0+r);

  int8_t f = 1 - r;
  int8_t ddF_x = 1;
  int8_t ddF_y = -2 * r;
  int8_t x = 0;
  int8_t y = r;

  my_setpixel(x0, y0+r, color);
  my_setpixel(x0, y0-r, color);
  my_setpixel(x0+r, y0, color);
  my_setpixel(x0-r, y0, color);

  while (x<y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
  
    my_setpixel(x0 + x, y0 + y, color);
    my_setpixel(x0 - x, y0 + y, color);
    my_setpixel(x0 + x, y0 - y, color);
    my_setpixel(x0 - x, y0 - y, color);
    
    my_setpixel(x0 + y, y0 + x, color);
    my_setpixel(x0 - y, y0 + x, color);
    my_setpixel(x0 + y, y0 - x, color);
    my_setpixel(x0 - y, y0 - x, color);
    
  }



}

void ST7565::fillcircle(uint8_t x0, uint8_t y0, uint8_t r, 
uint8_t color) {
  updateBoundingBox(x0-r, y0-r, x0+r, y0+r);

  int8_t f = 1 - r;
  int8_t ddF_x = 1;
  int8_t ddF_y = -2 * r;
  int8_t x = 0;
  int8_t y = r;

  for (uint8_t i=y0-r; i<=y0+r; i++) {
    my_setpixel(x0, i, color);
  }

  while (x<y) {
    if (f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x;
  
    for (uint8_t i=y0-y; i<=y0+y; i++) {
      my_setpixel(x0+x, i, color);
      my_setpixel(x0-x, i, color);
    } 
    for (uint8_t i=y0-x; i<=y0+x; i++) {
      my_setpixel(x0+y, i, color);
      my_setpixel(x0-y, i, color);
    }    
  }
}

void ST7565::my_setpixel(uint8_t x, uint8_t y, uint8_t color) {
  if ((x >= LCDWIDTH) || (y >= LCDHEIGHT))
    return;

  // x is which column
  if (color) 
    st7565_buffer[x+ (y/8)*128] |= _BV(7-(y%8));  
  else
    st7565_buffer[x+ (y/8)*128] &= ~_BV(7-(y%8)); 
}

// the most basic function, set a single pixel
void ST7565::setpixel(uint8_t x, uint8_t y, uint8_t color) {
  if ((x >= LCDWIDTH) || (y >= LCDHEIGHT))
    return;

  // x is which column
  if (color) 
    st7565_buffer[x+ (y/8)*128] |= _BV(7-(y%8));  
  else
    st7565_buffer[x+ (y/8)*128] &= ~_BV(7-(y%8)); 

  updateBoundingBox(x,y,x,y);
}


// the most basic function, get a single pixel
uint8_t ST7565::getpixel(uint8_t x, uint8_t y) {
  if ((x >= LCDWIDTH) || (y >= LCDHEIGHT))
    return 0;

  return (st7565_buffer[x+ (y/8)*128] >> (7-(y%8))) & 0x1;  
}

void ST7565::begin(uint8_t contrast) {
  st7565_init();
  st7565_command(CMD_DISPLAY_ON);
  st7565_command(CMD_SET_ALLPTS_NORMAL);
  st7565_set_brightness(contrast);
}

void ST7565::st7565_init(void) {
  // set pin directions
  pinMode(sid, OUTPUT);
  pinMode(sclk, OUTPUT);
  pinMode(a0, OUTPUT);
  pinMode(rst, OUTPUT);
  pinMode(cs, OUTPUT);

  // toggle RST low to reset; CS low so it'll listen to us
  if (cs > 0)
    digitalWrite(cs, LOW);

  digitalWrite(rst, LOW);
  _delay_ms(500);
  digitalWrite(rst, HIGH);

  // LCD bias select
  st7565_command(CMD_SET_BIAS_7);
  // ADC select
  st7565_command(CMD_SET_ADC_NORMAL);
  // SHL select
  st7565_command(CMD_SET_COM_NORMAL);
  // Initial display line
  st7565_command(CMD_SET_DISP_START_LINE);

  // turn on voltage converter (VC=1, VR=0, VF=0)
  st7565_command(CMD_SET_POWER_CONTROL | 0x4);
  // wait for 50% rising
  _delay_ms(50);

  // turn on voltage regulator (VC=1, VR=1, VF=0)
  st7565_command(CMD_SET_POWER_CONTROL | 0x6);
  // wait >=50ms
  _delay_ms(50);

  // turn on voltage follower (VC=1, VR=1, VF=1)
  st7565_command(CMD_SET_POWER_CONTROL | 0x7);
  // wait
  _delay_ms(10);

  // set lcd operating voltage (regulator resistor, ref voltage resistor)
  st7565_command(CMD_SET_RESISTOR_RATIO | 0x6);

  // initial display line
  // set page address
  // set column address
  // write display data

  // set up a bounding box for screen updates

  updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
}

inline void ST7565::spiwrite(uint8_t c) {
    
#if not defined (_VARIANT_ARDUINO_DUE_X_) && not defined (_VARIANT_ARDUINO_ZERO_)
    shiftOut(sid, sclk, MSBFIRST, c);
#else
    int8_t i;
    for (i=7; i>=0; i--) {
        digitalWrite(sclk, LOW);
        delayMicroseconds(5);      //need to slow down the data rate for Due and Zero
        if (c & _BV(i))
            digitalWrite(sid, HIGH);
        else
            digitalWrite(sid, LOW);
  //      delayMicroseconds(5);      //need to slow down the data rate for Due and Zero
        digitalWrite(sclk, HIGH);
    }
#endif
  /*
  int8_t i;
  for (i=7; i>=0; i--) {
    SCLK_PORT &= ~_BV(SCLK);
    if (c & _BV(i))
      SID_PORT |= _BV(SID);
    else
      SID_PORT &= ~_BV(SID);
    SCLK_PORT |= _BV(SCLK);
  }
  */

  /*
  // loop unwrapped! too fast doesnt work :(
  SCLK_PORT &= ~_BV(SCLK);
  if (c & _BV(7))
    SID_PORT |= _BV(SID);
  else
    SID_PORT &= ~_BV(SID);
  SCLK_PORT |= _BV(SCLK);

  SCLK_PORT &= ~_BV(SCLK);
  if (c & _BV(6))
    SID_PORT |= _BV(SID);
  else
    SID_PORT &= ~_BV(SID);
  SCLK_PORT |= _BV(SCLK);
  SCLK_PORT &= ~_BV(SCLK);
  if (c & _BV(5))
    SID_PORT |= _BV(SID);
  else
    SID_PORT &= ~_BV(SID);
  SCLK_PORT |= _BV(SCLK);

  SCLK_PORT &= ~_BV(SCLK);
  if (c & _BV(4))
    SID_PORT |= _BV(SID);
  else
    SID_PORT &= ~_BV(SID);
  SCLK_PORT |= _BV(SCLK);

  SCLK_PORT &= ~_BV(SCLK);
  if (c & _BV(3))
    SID_PORT |= _BV(SID);
  else
    SID_PORT &= ~_BV(SID);
  SCLK_PORT |= _BV(SCLK);

  SCLK_PORT &= ~_BV(SCLK);
  if (c & _BV(2))
    SID_PORT |= _BV(SID);
  else
    SID_PORT &= ~_BV(SID);
  SCLK_PORT |= _BV(SCLK);


  SCLK_PORT &= ~_BV(SCLK);
  if (c & _BV(1))
    SID_PORT |= _BV(SID);
  else
    SID_PORT &= ~_BV(SID);
  SCLK_PORT |= _BV(SCLK);

  SCLK_PORT &= ~_BV(SCLK);
  if (c & _BV(0))
    SID_PORT |= _BV(SID);
  else
    SID_PORT &= ~_BV(SID);
  SCLK_PORT |= _BV(SCLK);
*/

}
void ST7565::st7565_command(uint8_t c) {
  digitalWrite(a0, LOW);

  spiwrite(c);
}

void ST7565::st7565_data(uint8_t c) {
  digitalWrite(a0, HIGH);

  spiwrite(c);
}
void ST7565::st7565_set_brightness(uint8_t val) {
    st7565_command(CMD_SET_VOLUME_FIRST);
    st7565_command(CMD_SET_VOLUME_SECOND | (val & 0x3f));
}

/*2018-12-19 add  range 0x20~0x27*/
void ST7565::st7565_set_pre_contrast(uint8_t pval) {
    st7565_command(CMD_SET_PRE_CONTRAST);
}

void ST7565::display(void) {
  uint8_t col, maxcol, p;

  /*
  Serial.print("Refresh ("); Serial.print(xUpdateMin, DEC); 
  Serial.print(", "); Serial.print(xUpdateMax, DEC);
  Serial.print(","); Serial.print(yUpdateMin, DEC); 
  Serial.print(", "); Serial.print(yUpdateMax, DEC); Serial.println(")");
  */

  for(p = 0; p < 8; p++) {
    /*
      putstring("new page! ");
      uart_putw_dec(p);
      putstring_nl("");
    */
#ifdef enablePartialUpdate
    // check if this page is part of update
    if ( yUpdateMin >= ((p+1)*8) ) {
      continue;   // nope, skip it!
    }
    if (yUpdateMax < p*8) {
      break;
    }
#endif

    st7565_command(CMD_SET_PAGE | pagemap[p]);


#ifdef enablePartialUpdate
    col = xUpdateMin;
    maxcol = xUpdateMax;
#else
    // start at the beginning of the row
    col = 0;
    maxcol = LCDWIDTH-1;
#endif

    st7565_command(CMD_SET_COLUMN_LOWER | ((col+ST7565_STARTBYTES) & 0xf));
    st7565_command(CMD_SET_COLUMN_UPPER | (((col+ST7565_STARTBYTES) >> 4) & 0x0F));
    st7565_command(CMD_RMW);
    
    for(; col <= maxcol; col++) {
      //uart_putw_dec(col);
      //uart_putchar(' ');
      st7565_data(st7565_buffer[(128*p)+col]);
    }
  }

#ifdef enablePartialUpdate
  xUpdateMin = LCDWIDTH - 1;
  xUpdateMax = 0;
  yUpdateMin = LCDHEIGHT-1;
  yUpdateMax = 0;
#endif
}

// clear everything
void ST7565::clear(void) {
  memset(st7565_buffer, 0, 1024);
  updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1);
}


// this doesnt touch the buffer, just clears the display RAM - might be handy
void ST7565::clear_display(void) {
  uint8_t p, c;
  
  for(p = 0; p < 8; p++) {
    /*
      putstring("new page! ");
      uart_putw_dec(p);
      putstring_nl("");
    */

    st7565_command(CMD_SET_PAGE | p);
    for(c = 0; c < 129; c++) {
      //uart_putw_dec(c);
      //uart_putchar(' ');
      st7565_command(CMD_SET_COLUMN_LOWER | (c & 0xf));
      st7565_command(CMD_SET_COLUMN_UPPER | ((c >> 4) & 0xf));
      st7565_data(0x0);
    }     
  }
}





//============================================================
// othet test

//#include "./ST7565-LCD-master/ST7565.h"
#include "ST7565.h"
int ledPin =  13;    // LED connected to digital pin 13

// the LCD backlight is connected up to a pin so you can turn it on & off

// pin 9 - Serial data out (SID)
// pin 8 - Serial clock out (SCLK)
// pin 7 - Data/Command select (RS or A0)
// pin 6 - LCD reset (RST)
// pin 5 - LCD chip select (CS)
//ST7565 glcd(9, 8, 7, 6, 5);

//ST7565 glcd(SDA, SCK, RS/DC, RST, CS);
/*
  ST7565 glcd(5, 6, 4, 3, 2);
  #define Power_3v3 7
  #define Power_Gnd 8
  #define BACKLIGHT_LED 9
*/
ST7565 glcd(8, 9, 7, 6, 5);
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16

// a bitmap of a 16x16 fruit icon
const static unsigned char __attribute__ ((progmem)) logo16_glcd_bmp[] = {
  0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0xf8, 0xbe, 0x9f, 0xff, 0xf8, 0xc0, 0xc0, 0xc0, 0x80, 0x00,
  0x20, 0x3c, 0x3f, 0x3f, 0x1f, 0x19, 0x1f, 0x7b, 0xfb, 0xfe, 0xfe, 0x07, 0x07, 0x07, 0x03, 0x00,
};

// The setup() method runs once, when the sketch starts
void setup()   {
  Serial.begin(115200);

  // initialize and set the contrast to 0x18
  glcd.begin(0x08);
  delay(200);
  glcd.st7565_set_pre_contrast(0x20);/*0x20~0x27*/     // for ST7567 only
  //  glcd.st7565_set_brightness(0x00);
}


void loop() {
  glcd.drawstring(0, 0, "test");
  glcd.drawchar( 0, 1, 'a');   //a
  glcd.drawchar( 6, 1, 'b');   //b
  glcd.drawchar(12, 1, 'c');   //c

  //  glcd.drawstring(0, 6, 'a1');

  // ---------- show A0 ------------------
  String string1 =  String(analogRead(0), DEC);     // A0  to string串流  (使用 int 變數和指定的進位表示法) (十進位)
  char charString1[4];                              // 宣告字元陣列 4個字元
  string1.getBytes(charString1, 4);                 // 將string1串流  轉換成  charString字元陣列,4個字元
  //--------- 結構指標 -----------------            //  char *charString = "qazwsx"; //for test
  for (int i = 0; i < 4; i++) {
    glcd.drawchar(i * 6, 2, charString1[i]);
  }


  // ---------- show Sec ------------------
  String string2 =  String(millis() / 1000 );       // A0  to string串流  (使用 int 變數和指定的進位表示法) (十進位)
  char charString2[4];                              // 宣告字元陣列 4個字元
  string2.getBytes(charString2, 4);                 // 將string2串流  轉換成  charString2字元陣列,4個字元
  for (int i = 0; i < 4; i++) {
    glcd.drawchar(i * 6, 3, charString2[i]);
  }

  glcdVal(0, 5, 123, 4);
  glcdVal(6, 5, analogRead(7), 4);
  glcdVal_F(11, 5, millis() / 1000, 4);
  glcdVal_F(0, 6, millis() / 1000, 4);
  glcdVal_F(0, 7, millis() / 1000 * -1, 4);

  glcd.display();
  delay(100);
  glcd.clear();
}




void glcdVal_F(byte gx, byte gy, int val, byte cun) {   // 字元起始x,y,要顯示的值,顯示的位數
  String stringOne = String(val);                       // val  to string串流
  char charString[cun];                                 // 宣告字元陣列 4個字元
  stringOne.getBytes(charString, cun);                  // 將stringOne串流  轉換成  charString字元陣列,4個字元
  //--------- 結構指標 -----------------
  int i;   byte gx1;                                    //  char *charString = "qazwsx"; //for test
  for ( i = 0; i < cun; i++) {
    if (val >= 1000 && val <= 9999 )gx1 = cun - 4 ;
    if (val >= 100 && val <= 999 )gx1 = cun - 3 ;
    if (val >= 10 && val <= 99 )gx1 = cun - 2 ;
    if (val >= 0 && val <= 9 )gx1 = cun - 1 ;
    if (val >= -9 && val <= -1 )gx1 = cun - 2 ;
    if (val >= -99 && val <= -10 )gx1 = cun - 3 ;
    if (val >= -999 && val <= -100 )gx1 = cun - 4 ;
    if (val >= -9999 && val <= -1000 )gx1 = cun - 5 ;
    glcd.drawchar(((i + gx + gx1) * 6), gy, charString[i]);
  }
}


void glcdVal(byte gx, byte gy, int val, byte cun) {   // 字元起始x,y,要顯示的值,顯示的位數
  String stringOne = String(val);                     // val  to string串流
  char charString[cun];                               // 宣告字元陣列 4個字元
  stringOne.getBytes(charString, cun);                // 將stringOne串流  轉換成  charString字元陣列,4個字元
  //--------- 結構指標 -----------------
  int i;                                              //  char *charString = "qazwsx"; //for test
  for ( i = 0; i < cun; i++) {
    glcd.drawchar((i + gx) * 6, gy, charString[i]);
  }
}