mBlock が生成した「Hello World」のソースは、こういう感じでした。
#include <Arduino.h> #include <Wire.h> #include <SoftwareSerial.h> #include "watchX.h" #include <SPI.h> double angle_rad = PI/180.0; double angle_deg = 180.0/PI; unsigned char animation_offsetY=0; bool needClear = false; void writeText(int oledPosX, int oledPosY, String oledText){ drawString(oledPosX,oledPosY,oledText.c_str() ,smallFont);} void setup(){ SPI.begin(); ssd1306_configure(); clearAll(); writeText(0, 0, ((String)"Hello World!").c_str()); needClear = true; } void loop(){ _loop(); } void _delay(float seconds){ long endTime = millis() + seconds * 1000; while(millis() < endTime)_loop(); } void _loop(){ if(needClear){ ssd1306_drawBuffer(0, 0, 128,64, mbuf); clearAll(); needClear = false; } }
内容を確認してみます。
#include <Arduino.h> #include <Wire.h> #include <SoftwareSerial.h> #include "watchX.h" #include <SPI.h>
通常の Arduino 系 include に加えて、”watchX.h”ヘッダーがあります。
watchX.h
#include "Adafruit_Sensor.h" #include "Adafruit_BMP280.h" #include "SparkFun_MAG3110.h" #include "RTClib.h" #include "MPU6050.h" #include "oled.h" #include "resources.h" #include "Adafruit_BLE.h" #include "Adafruit_BluefruitLE_SPI.h" #include "Adafruit_BluefruitLE_UART.h" #include "BluefruitConfig.h"
ライブラリ関連のincludeをまとめて行ってますね。
setup() の処理を見ると、
ssd1306_configure();
で watchX 表示関連の初期化を行っているみたいです。ssd1306_configure() は、oled.cpp にあります。
void ssd1306_configure(){ const uint8_t s_oled128x64_initData[] = { SSD1306_DISPLAYOFF, // display off SSD1306_MEMORYMODE, HORIZONTAL_ADDRESSING_MODE, // Page Addressing mode SSD1306_COMSCANDEC, // Scan from 127 to 0 (Reverse scan) SSD1306_SETSTARTLINE | 0x00, // First line to start scanning from SSD1306_SETCONTRAST, 0xFF, // contast value to 0x7F according to datasheet SSD1306_SEGREMAP | 0x01, // Use reverse mapping. 0x00 - is normal mapping SSD1306_NORMALDISPLAY, SSD1306_SETMULTIPLEX, 63, // Reset to default MUX. See datasheet // SSD1306_SETDISPLAYOFFSET, 0x00, // no offset // SSD1306_SETDISPLAYCLOCKDIV, 0x80,// set to default ratio/osc frequency // SSD1306_SETPRECHARGE, 0xF1, // switch precharge to 0x22 // 0xF1 // SSD1306_SETCOMPINS, 0x12, // set divide ratio SSD1306_SETVCOMDETECT, 0x40, // vcom deselect to 0x20 // 0x40 SSD1306_CHARGEPUMP, 0x14, // Enable charge pump // 0X20,0X80, // SSD1306_DISPLAYALLON_RESUME, SSD1306_DISPLAYON }; pinMode(rstPin, OUTPUT); pinMode(cesPin, OUTPUT); pinMode(dcPin, OUTPUT); digitalWrite(rstPin, HIGH); digitalWrite(dcPin, HIGH); digitalWrite(cesPin, HIGH); for( uint8_t i=0; i<sizeof(s_oled128x64_initData); i++) { ssd1306_sendCommand(s_oled128x64_initData[i]); } }
ピンの状態を設定して、初期設定のコマンドを順に ssd1306_sendCommand で送ってます。
次が clearAll();
void clearAll(){ //if(animation_offsetY==0) memset(mbuf, 0x00, 1024); //for(uint16_t i=0;i<1024;i++) mbuf[i]=0; }
mbuf[1024]が、画面表示のバッファです。0クリアしてます。
次の
writeText(0, 0, ((String)"Hello World!").c_str());
が、”Hello World!” を バッファに書き込んでいるところです。
drawString(oledPosX,oledPosY,oledText.c_str() ,smallFont);
を(フォントの指定を追加して)呼び出してます。実際の処理は oled.cpp 内のdrawString。
void drawString(uint8_t x,uint8_t y,const char*s,const char* font,char startindex=-32); void drawString(uint8_t x,uint8_t y,const char*s,const char* font,char startindex){ char a=0; if(!s)return; while(s[a]!=0){ // strtmpbuf[a]= pgm_read_byte_near(months[month]+a); // draw_bitmap( 0, 32, font_mid, 19, 24, false, 0); draw_bitmap( x+(a*6), y, font+((s[a]+startindex)*5), 5, 8, false, 0); a++; } }
位置(x,y)から、文字列char* s それぞれ順番に、フォント char*font を用いて描きます。
startIndexはフォント文字コードとフォントデータの開始位置調整です。なにもなければデフォルトで指定されている「-32」が使われてます。文字コードの制御文字コードの部分を飛ばすためですね。
1文字描くごとに、x 位置を 6 ずつずらしています。(完全にフォントサイズ固定な処理ですね。)
font+((s[a]+startindex)*5)で、フォントデータの開始位置。これも1フォントのデータ5バイト固定想定での実装です。
フォントデータは,resources.h の CHARACTER_SET 経由で、english.h にありました。
#define CHARACTER_SET \ 0x00,0x00,0x00,0x00,0x00,/* space */ \ 0x00,0x5F,0x00,0x00,0x00,/* ! */ \ 0x00,0x07,0x00,0x07,0x00,/* " */ \ 0x14,0x7F,0x14,0x7F,0x14,/* # */ \ 0x24,0x2A,0x7F,0x2A,0x12,/* $ */ \ 0x23,0x13,0x08,0x64,0x62,/* % */ \ 0x36,0x49,0x55,0x22,0x50,/* & */ \ 0x00,0x05,0x03,0x00,0x00,/* ' */ \ 0x1C,0x22,0x41,0x00,0x00,/* ( */ \ 0x41,0x22,0x1C,0x00,0x00,/* ) */ \ : 0x3E,0x51,0x49,0x45,0x3E,/* 0 */ \ 0x00,0x42,0x7F,0x40,0x00,/* 1 */ \ 0x62,0x51,0x49,0x49,0x46,/* 2 */ \ 0x22,0x41,0x49,0x49,0x36,/* 3 */ \ 0x18,0x14,0x12,0x7F,0x10,/* 4 */ \ 0x27,0x45,0x45,0x45,0x39,/* 5 */ \ 0x3C,0x4A,0x49,0x49,0x30,/* 6 */ \ 0x01,0x71,0x09,0x05,0x03,/* 7 */ \ 0x36,0x49,0x49,0x49,0x36,/* 8 */ \ 0x06,0x49,0x49,0x29,0x1E,/* 9 */ \ : 0x7E,0x09,0x09,0x09,0x7E,/* A */ \ 0x7F,0x49,0x49,0x49,0x36,/* B */ \ 0x3E,0x41,0x41,0x41,0x22,/* C */ \ 0x7F,0x41,0x41,0x22,0x1C,/* D */ \ 0x7F,0x49,0x49,0x49,0x41,/* E */ \ 0x7F,0x09,0x09,0x09,0x01,/* F */ \ 0x3E,0x41,0x41,0x51,0x72,/* G */ \ :
という感じ。例えば
0x7E,0x09,0x09,0x09,0x7E,/* A */ \
を16進→2進 変換してみると…
7E : 01111110 09 : 00001001 09 : 00001001 09 : 00001001 7E : 01111110
んんんー?「A」の形にならない…。と思ったら、縦向きに描かれるらしい。
漢字表示グラフィック液晶表示ライブラリ
http://www.picfun.com/PIC32MX/PIC32MXAp05.html
こういうことか!
このデータを
void draw_bitmap(byte x, byte yy, const char* bitmap, byte w, byte h, bool invert=false, byte offsetY=0);
で画面表示バッファmbuf に設定してます。中身の処理は追っかけないですけども、x , yy + offsetY の位置に、bitmap で指定したフォントデータを、幅 w 高さ h でセットするようですね。invert = true にすると、白黒反転すると思われます。
その後、loop() の中で、
ssd1306_drawBuffer(0, 0, 128,64, mbuf);
実際の画面に mbuf 内容を描画して、
clearAll();
で描画が終了した mbuf をクリアして、終了な感じですね。(実際は loop()を回ってますけども。)
フォントは縦横回転してしまうフォーマットなので、M5Stack の時に作ったデータはそのままでは使えないなあー。