├── .gitignore ├── .travis.yml ├── .vscode └── settings.json ├── LICENSE.txt ├── Makefile ├── README.md ├── _locales ├── SSD1306_OLED-strings.json ├── pl │ └── SSD1306_OLED-strings.json ├── zh-TW │ └── SSD1306_OLED-strings.json └── zh │ └── SSD1306_OLED-strings.json ├── icon.png ├── main.ts ├── package.json ├── pxt.json ├── test.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | built 2 | node_modules 3 | yotta_modules 4 | yotta_targets 5 | pxt_modules 6 | *.db 7 | *.tgz 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | sudo: false 3 | 4 | node_js: 5 | - "7" 6 | 7 | python: 8 | - "2.7" 9 | 10 | addons: 11 | apt: 12 | sources: 13 | - george-edison55-precise-backports 14 | - sourceline: 'ppa:team-gcc-arm-embedded/ppa' 15 | packages: 16 | - ninja-build 17 | - cmake 18 | - cmake-data 19 | - gcc-arm-embedded 20 | - srecord 21 | 22 | install: 23 | - nvm install 7 24 | - pip install yotta 25 | - pip install pyopenssl 26 | - npm install 27 | - npm run pxt:init 28 | - npm run pxt:install 29 | 30 | script: 31 | - npm run test 32 | 33 | cache: 34 | directories: 35 | - node_modules 36 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "MicroPython.executeButton": [ 3 | { 4 | "text": "▶", 5 | "tooltip": "运行", 6 | "alignment": "left", 7 | "command": "extension.executeFile", 8 | "priority": 3.5 9 | } 10 | ], 11 | "MicroPython.syncButton": [ 12 | { 13 | "text": "$(sync)", 14 | "tooltip": "同步", 15 | "alignment": "left", 16 | "command": "extension.execute", 17 | "priority": 4 18 | } 19 | ], 20 | "files.exclude": { 21 | "**/.git": true, 22 | "**/.svn": true, 23 | "**/.hg": true, 24 | "**/CVS": true, 25 | "**/.DS_Store": true, 26 | "**/Thumbs.db": true 27 | }, 28 | "hide-files.files": [] 29 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Tinkertanker Pte Ltd 2 | 3 | All rights reserved. 4 | 5 | MIT License 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 8 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 9 | modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 15 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 16 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 17 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: deploy 2 | 3 | build: 4 | pxt build 5 | 6 | deploy: 7 | pxt deploy 8 | 9 | test: 10 | pxt test 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SSD1306 OLED MakeCode Package [![Build Status](https://travis-ci.org/Tinkertanker/pxt-oled-ssd1306.svg?branch=master)](https://travis-ci.org/Tinkertanker/pxt-oled-ssd1306) 2 | 3 | This is the MakeCode Package for SSD1306 OLED controller, based on the Adafruit Arduino library available [here](https://github.com/adafruit/Adafruit_SSD1306). 4 | 5 | ## Hardware Setup 6 | 1. Insert the OLED display into the I2C ports on the break out board. 7 | 8 | ## Blocks 9 | ### Initialize OLED Display 10 | Initializes the OLED display. 11 | 12 | Sets up the OLED display and prepares it for use by the micro:bit. 13 | 14 | ```sig 15 | OLED.init(64, 128); 16 | ``` 17 | 18 | This block must be placed before any of the ``show`` blocks. 19 | 20 | ### Show String Without Newline 21 | Displays a string on the OLED module without a newline. 22 | 23 | ```sig 24 | OLED.showString1("hello, micro:bit!") 25 | ``` 26 | 27 | The ``init`` block must be placed before this. 28 | 29 | ### Show String With Newline 30 | Displays a string on the OLED module with a newline. 31 | 32 | ```sig 33 | OLED.showString2("hello, micro:bit!") 34 | ``` 35 | 36 | The ``init`` block must be placed before this. 37 | 38 | 39 | ### Show Number Without newline 40 | Displays a number on the OLED module without a newline. 41 | 42 | ```sig 43 | OLED.showNumber1(123) 44 | ``` 45 | 46 | The ``init`` block must be placed before this. 47 | 48 | 49 | ### Show Number With Newline 50 | Displays a number on the OLED module with a newline. 51 | 52 | ```sig 53 | OLED.showNumber2(123) 54 | ``` 55 | 56 | The ``init`` block must be placed before this. 57 | 58 | 59 | ### Clear Display 60 | Clears the display. 61 | 62 | ```sig 63 | OLED.clear() 64 | ``` 65 | 66 | The ``init`` block must be placed before this. 67 | 68 | ### Draw Outlined Rectangle 69 | Displays an outline of a rectangle. 70 | 71 | ```sig 72 | OLED.drawRectangle(x,y,w,h) 73 | ``` 74 | 75 | The ``init`` block must be placed before this. 76 | 77 | 78 | ### Draw Outlined Circle 79 | Displays an outline of a circle. 80 | 81 | ```sig 82 | OLED.drawCircle(x,y,r) 83 | ``` 84 | 85 | The ``init`` block must be placed before this. 86 | 87 | 88 | ### Draw Line 89 | Displays a line. 90 | 91 | ```sig 92 | OLED.drawLine(x1,y1,x2,y2) 93 | ``` 94 | 95 | The ``init`` block must be placed before this. 96 | 97 | 98 | ### Progress bar 99 | Displays a progress bar with a specified percentage of progress. 100 | 101 | ```sig 102 | OLED.drawLoadingBar(percent) 103 | ``` 104 | 105 | The ``init`` block must be placed before this. 106 | 107 | 108 | ## Example: Counter 109 | The following code is a simple counter that displays an increasing number every second. 110 | 111 | ```blocks 112 | OLED.init(64, 128) 113 | let item = 0 114 | basic.forever(() => { 115 | basic.pause(1000) 116 | item += 1 117 | OLED.showNumber(item) 118 | }) 119 | ``` 120 | 121 | ## Supported targets 122 | 123 | * for PXT/microbit 124 | 125 | ## Footnotes 126 | 127 | 1. Datasheet https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf 128 | -------------------------------------------------------------------------------- /_locales/SSD1306_OLED-strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "OLED.clear|block": "clear OLED display", 3 | "OLED.drawLine|block": "draw line from:|x: $x0 y: $y0 to| x: $x1 y: $y1", 4 | "OLED.drawLoading|block": "draw loading bar at $percent percent", 5 | "OLED.drawRectangle|block": "draw rectangle from:|x: $x0 y: $y0 to| x: $x1 y: $y1", 6 | "OLED.init|block": "initialize OLED with width $width height $height", 7 | "OLED.newLine|block": "insert newline", 8 | "OLED.writeNumNewLine|block": "show number $n", 9 | "OLED.writeNum|block": "show (without newline) number $n", 10 | "OLED.writeStringNewLine|block": "show string $str", 11 | "OLED.writeString|block": "show (without newline) string $str", 12 | "{id:category}Math": "Math", 13 | "{id:category}OLED": "OLED" 14 | } 15 | -------------------------------------------------------------------------------- /_locales/pl/SSD1306_OLED-strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "OLED.clear|block": "wyczyść wyświetlacz OLED", 3 | "OLED.drawLoading|block": "zamaluj pasek ładowania do $percent procent", 4 | "OLED.writeString|block": "pokaż (bez przejścia do nowej linii) ciąg znaków $str", 5 | "OLED.writeNum|block": "pokaż (bez przejścia do nowej linii) liczbę $n", 6 | "OLED.writeStringNewLine|block": "pokaż ciąg znaków $str", 7 | "OLED.writeNumNewLine|block": "pokaż liczbę $n", 8 | "OLED.newLine|block": "wstaw nową linię", 9 | "OLED.drawLine|block": "narysuj linię od:|x: $x0 y: $y0 do| x: $x1 y: $y1", 10 | "OLED.drawRectangle|block": "narysuj prostokąt od:|x: $x0 y: $y0 do| x: $x1 y: $y1", 11 | "OLED.drawCircle|block": "narysuj okrąg w x: $x y: $y promień: $r", 12 | "OLED.drawFilledCircle|block": "narysuj wypełniony okrąg w x: $x y: $y promień: $r", 13 | "OLED.init|block": "zainicjuj OLED o szerokości $width i wysokości $height", 14 | "{id:category}Math": "Matematyka", 15 | "{id:category}OLED": "OLED" 16 | } -------------------------------------------------------------------------------- /_locales/zh-TW/SSD1306_OLED-strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "OLED.clear|block": "清空 OLED畫面", 3 | "OLED.drawLine|block": "繪製直線 起點:|x: $x0 y: $y0 終點| x: $x1 y: $y1", 4 | "OLED.drawLoading|block": "顯示進度條 $percent %", 5 | "OLED.drawRectangle|block": "繪製矩形 起點:|x: $x0 y: $y0 終點| x: $x1 y: $y1", 6 | "OLED.drawCircle|block": "繪製圆形 起點:|x: $x y: $y 半徑| $r", 7 | "OLED.drawFilledCircle|block": "繪製實心圆形 起點:|x: $x y: $y 半徑| $r", 8 | "OLED.init|block": "OLED初始化 寬 %width 高 %height", 9 | "OLED.newLine|block": "換行", 10 | "OLED.writeNumNewLine|block": "顯示數字 $n 後換行", 11 | "OLED.writeNum|block": "顯示數字 $n", 12 | "OLED.writeStringNewLine|block": "顯示字串 $str 後換行", 13 | "OLED.writeString|block": "顯示字串 $str", 14 | "{id:category}Math": "Math", 15 | "{id:category}OLED": "OLED" 16 | } 17 | -------------------------------------------------------------------------------- /_locales/zh/SSD1306_OLED-strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "OLED.clear|block": "清除显示", 3 | "OLED.drawLine|block": "画线条 起点:|x: $x0 y: $y0 终点| x: $x1 y: $y1", 4 | "OLED.drawLoading|block": "显示进度条 $percent %", 5 | "OLED.drawRectangle|block": "绘制矩形 起点:|x: $x0 y: $y0 终点| x: $x1 y: $y1", 6 | "OLED.drawCircle|block": "绘制圆形 起点:|x: $x y: $y 半径| $r", 7 | "OLED.drawFilledCircle|block": "绘制实心圆形 起点:|x: $x y: $y 半径| $r", 8 | "OLED.init|block": "OLED 初始化 宽 %width 高 %height", 9 | "OLED.newLine|block": "新行", 10 | "OLED.writeNumNewLine|block": "新行显示数字 $n", 11 | "OLED.writeNum|block": "显示数字 $n", 12 | "OLED.writeStringNewLine|block": "新行显示字符串 $str", 13 | "OLED.writeString|block": "显示字符串 $str", 14 | "{id:category}Math": "Math", 15 | "{id:category}OLED": "OLED" 16 | } 17 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkertanker/pxt-oled-ssd1306/54161a43172207fd424bfa9e140d54efe4971724/icon.png -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | declare interface Math { 2 | floor(x: number): number; 3 | } 4 | 5 | 6 | //% color=#27b0ba icon="\uf26c" 7 | namespace OLED { 8 | let font: Buffer; 9 | 10 | 11 | const SSD1306_SETCONTRAST = 0x81 12 | const SSD1306_SETCOLUMNADRESS = 0x21 13 | const SSD1306_SETPAGEADRESS = 0x22 14 | const SSD1306_DISPLAYALLON_RESUME = 0xA4 15 | const SSD1306_DISPLAYALLON = 0xA5 16 | const SSD1306_NORMALDISPLAY = 0xA6 17 | const SSD1306_INVERTDISPLAY = 0xA7 18 | const SSD1306_DISPLAYOFF = 0xAE 19 | const SSD1306_DISPLAYON = 0xAF 20 | const SSD1306_SETDISPLAYOFFSET = 0xD3 21 | const SSD1306_SETCOMPINS = 0xDA 22 | const SSD1306_SETVCOMDETECT = 0xDB 23 | const SSD1306_SETDISPLAYCLOCKDIV = 0xD5 24 | const SSD1306_SETPRECHARGE = 0xD9 25 | const SSD1306_SETMULTIPLEX = 0xA8 26 | const SSD1306_SETLOWCOLUMN = 0x00 27 | const SSD1306_SETHIGHCOLUMN = 0x10 28 | const SSD1306_SETSTARTLINE = 0x40 29 | const SSD1306_MEMORYMODE = 0x20 30 | const SSD1306_COMSCANINC = 0xC0 31 | const SSD1306_COMSCANDEC = 0xC8 32 | const SSD1306_SEGREMAP = 0xA0 33 | const SSD1306_CHARGEPUMP = 0x8D 34 | const chipAdress = 0x3C 35 | const xOffset = 0 36 | const yOffset = 0 37 | let charX = 0 38 | let charY = 0 39 | let displayWidth = 128 40 | let displayHeight = 64 / 8 41 | let screenSize = 0 42 | //let font: Array> 43 | let loadStarted: boolean; 44 | let loadPercent: number; 45 | function command(cmd: number) { 46 | let buf = pins.createBuffer(2) 47 | buf[0] = 0x00 48 | buf[1] = cmd 49 | pins.i2cWriteBuffer(chipAdress, buf, false) 50 | } 51 | //% block="clear OLED display" 52 | //% weight=3 53 | export function clear() { 54 | loadStarted = false 55 | loadPercent = 0 56 | command(SSD1306_SETCOLUMNADRESS) 57 | command(0x00) 58 | command(displayWidth - 1) 59 | command(SSD1306_SETPAGEADRESS) 60 | command(0x00) 61 | command(displayHeight - 1) 62 | let data = pins.createBuffer(17); 63 | data[0] = 0x40; // Data Mode 64 | for (let i = 1; i < 17; i++) { 65 | data[i] = 0x00 66 | } 67 | // send display buffer in 16 byte chunks 68 | for (let i = 0; i < screenSize; i += 16) { 69 | pins.i2cWriteBuffer(chipAdress, data, false) 70 | } 71 | charX = xOffset 72 | charY = yOffset 73 | } 74 | 75 | function drawLoadingFrame() { 76 | command(SSD1306_SETCOLUMNADRESS) 77 | command(0x00) 78 | command(displayWidth - 1) 79 | command(SSD1306_SETPAGEADRESS) 80 | command(0x00) 81 | command(displayHeight - 1) 82 | let col = 0 83 | let page = 0 84 | let data = pins.createBuffer(17); 85 | data[0] = 0x40; // Data Mode 86 | let i = 1 87 | for (let page = 0; page < displayHeight; page++) { 88 | for (let col = 0; col < displayWidth; col++) { 89 | if (page === 3 && col > 12 && col < displayWidth - 12) { 90 | data[i] = 0x60 91 | } else if (page === 5 && col > 12 && col < displayWidth - 12) { 92 | data[i] = 0x06 93 | } else if (page === 4 && (col === 12 || col === 13 || col === displayWidth - 12 || col === displayWidth - 13)) { 94 | data[i] = 0xFF 95 | } else { 96 | data[i] = 0x00 97 | } 98 | if (i === 16) { 99 | pins.i2cWriteBuffer(chipAdress, data, false) 100 | i = 1 101 | } else { 102 | i++ 103 | } 104 | 105 | } 106 | } 107 | charX = 30 108 | charY = 2 109 | writeString("Loading:") 110 | } 111 | function drawLoadingBar(percent: number) { 112 | charX = 78 113 | charY = 2 114 | let num = Math.floor(percent) 115 | writeNum(num) 116 | writeString("%") 117 | let width = displayWidth - 14 - 13 118 | let lastStart = width * (loadPercent / displayWidth) 119 | command(SSD1306_SETCOLUMNADRESS) 120 | command(14 + lastStart) 121 | command(displayWidth - 13) 122 | command(SSD1306_SETPAGEADRESS) 123 | command(4) 124 | command(5) 125 | let data = pins.createBuffer(2); 126 | data[0] = 0x40; // Data Mode 127 | data[1] = 0x7E 128 | for (let i = lastStart; i < width * (Math.floor(percent) / 100); i++) { 129 | pins.i2cWriteBuffer(chipAdress, data, false) 130 | } 131 | loadPercent = num 132 | } 133 | 134 | //% block="draw loading bar at $percent percent" 135 | //% percent.min=0 percent.max=100 136 | //% weight=2 137 | export function drawLoading(percent: number) { 138 | if (loadStarted) { 139 | drawLoadingBar(percent) 140 | } else { 141 | drawLoadingFrame() 142 | drawLoadingBar(percent) 143 | loadStarted = true 144 | } 145 | } 146 | 147 | 148 | //% block="show (without newline) string $str" 149 | //% weight=6 150 | export function writeString(str: string) { 151 | for (let i = 0; i < str.length; i++) { 152 | if (charX > displayWidth - 6) { 153 | newLine() 154 | } 155 | drawChar(charX, charY, str.charAt(i)) 156 | charX += 6 157 | } 158 | } 159 | //% block="show (without newline) number $n" 160 | //% weight=5 161 | export function writeNum(n: number) { 162 | let numString = n.toString() 163 | writeString(numString) 164 | } 165 | //% block="show string $str" 166 | //% weight=8 167 | export function writeStringNewLine(str: string) { 168 | writeString(str) 169 | newLine() 170 | } 171 | //% block="show number $n" 172 | //% weight=7 173 | export function writeNumNewLine(n: number) { 174 | writeNum(n) 175 | newLine() 176 | } 177 | //% block="insert newline" 178 | //% weight=4 179 | export function newLine() { 180 | charY++ 181 | charX = xOffset 182 | } 183 | function drawChar(x: number, y: number, c: string) { 184 | command(SSD1306_SETCOLUMNADRESS) 185 | command(x) 186 | command(x + 5) 187 | command(SSD1306_SETPAGEADRESS) 188 | command(y) 189 | command(y + 1) 190 | let line = pins.createBuffer(2) 191 | line[0] = 0x40 192 | for (let i = 0; i < 6; i++) { 193 | if (i === 5) { 194 | line[1] = 0x00 195 | } else { 196 | let charIndex = c.charCodeAt(0) 197 | let charNumber = font.getNumber(NumberFormat.UInt8BE, 5 * charIndex + i) 198 | line[1] = charNumber 199 | 200 | } 201 | pins.i2cWriteBuffer(chipAdress, line, false) 202 | } 203 | 204 | } 205 | function drawShape(pixels: Array>) { 206 | let x1 = displayWidth 207 | let y1 = displayHeight * 8 208 | let x2 = 0 209 | let y2 = 0 210 | for (let i = 0; i < pixels.length; i++) { 211 | if (pixels[i][0] < x1) { 212 | x1 = pixels[i][0] 213 | } 214 | if (pixels[i][0] > x2) { 215 | x2 = pixels[i][0] 216 | } 217 | if (pixels[i][1] < y1) { 218 | y1 = pixels[i][1] 219 | } 220 | if (pixels[i][1] > y2) { 221 | y2 = pixels[i][1] 222 | } 223 | } 224 | let page1 = Math.floor(y1 / 8) 225 | let page2 = Math.floor(y2 / 8) 226 | let line = pins.createBuffer(2) 227 | line[0] = 0x40 228 | for (let x = x1; x <= x2; x++) { 229 | for (let page = page1; page <= page2; page++) { 230 | line[1] = 0x00 231 | for (let i = 0; i < pixels.length; i++) { 232 | if (pixels[i][0] === x) { 233 | if (Math.floor(pixels[i][1] / 8) === page) { 234 | line[1] |= Math.pow(2, (pixels[i][1] % 8)) 235 | } 236 | } 237 | } 238 | if (line[1] !== 0x00) { 239 | command(SSD1306_SETCOLUMNADRESS) 240 | command(x) 241 | command(x + 1) 242 | command(SSD1306_SETPAGEADRESS) 243 | command(page) 244 | command(page + 1) 245 | //line[1] |= pins.i2cReadBuffer(chipAdress, 2)[1] 246 | pins.i2cWriteBuffer(chipAdress, line, false) 247 | } 248 | } 249 | } 250 | } 251 | 252 | //% block="draw line from:|x: $x0 y: $y0 to| x: $x1 y: $y1" 253 | //% x0.defl=0 254 | //% y0.defl=0 255 | //% x1.defl=20 256 | //% y1.defl=20 257 | //% weight=1 258 | export function drawLine(x0: number, y0: number, x1: number, y1: number) { 259 | let pixels: Array> = [] 260 | let kx: number, ky: number, c: number, i: number, xx: number, yy: number, dx: number, dy: number; 261 | let targetX = x1 262 | let targetY = y1 263 | x1 -= x0; kx = 0; if (x1 > 0) kx = +1; if (x1 < 0) { kx = -1; x1 = -x1; } x1++; 264 | y1 -= y0; ky = 0; if (y1 > 0) ky = +1; if (y1 < 0) { ky = -1; y1 = -y1; } y1++; 265 | if (x1 >= y1) { 266 | c = x1 267 | for (i = 0; i < x1; i++ , x0 += kx) { 268 | pixels.push([x0, y0]) 269 | c -= y1; if (c <= 0) { if (i != x1 - 1) pixels.push([x0 + kx, y0]); c += x1; y0 += ky; if (i != x1 - 1) pixels.push([x0, y0]); } 270 | if (pixels.length > 20) { 271 | drawShape(pixels) 272 | pixels = [] 273 | drawLine(x0, y0, targetX, targetY) 274 | return 275 | } 276 | } 277 | } else { 278 | c = y1 279 | for (i = 0; i < y1; i++ , y0 += ky) { 280 | pixels.push([x0, y0]) 281 | c -= x1; if (c <= 0) { if (i != y1 - 1) pixels.push([x0, y0 + ky]); c += y1; x0 += kx; if (i != y1 - 1) pixels.push([x0, y0]); } 282 | if (pixels.length > 20) { 283 | drawShape(pixels) 284 | pixels = [] 285 | drawLine(x0, y0, targetX, targetY) 286 | return 287 | } 288 | } 289 | } 290 | drawShape(pixels) 291 | } 292 | 293 | //% block="draw rectangle from:|x: $x0 y: $y0 to| x: $x1 y: $y1" 294 | //% x0.defl=0 295 | //% y0.defl=0 296 | //% x1.defl=20 297 | //% y1.defl=20 298 | //% weight=0 299 | export function drawRectangle(x0: number, y0: number, x1: number, y1: number) { 300 | drawLine(x0, y0, x1, y0) 301 | drawLine(x0, y1, x1, y1) 302 | drawLine(x0, y0, x0, y1) 303 | drawLine(x1, y0, x1, y1) 304 | } 305 | //% block="draw circle at x: $x y: $y radius: $r" 306 | //% x.defl=64 307 | //% y.defl=32 308 | //% r.defl=10 309 | //% weight=0 310 | export function drawCircle(x: number, y: number, r: number) { 311 | let theta = 0; 312 | let step = Math.PI / 90; // Adjust step for smoothness 313 | let pixels: Array> = []; 314 | 315 | while (theta < 2 * Math.PI) { 316 | let xPos = Math.floor(x + r * Math.cos(theta)); 317 | let yPos = Math.floor(y + r * Math.sin(theta)); 318 | pixels.push([xPos, yPos]); 319 | theta += step; 320 | } 321 | 322 | drawShape(pixels); 323 | } 324 | 325 | //% block="draw filled circle at x: $x y: $y radius: $r" 326 | //% x.defl=64 327 | //% y.defl=32 328 | //% r.defl=10 329 | //% weight=0 330 | export function drawFilledCircle(x: number, y: number, r: number) { 331 | for (let dx = -r; dx <= r; dx++) { 332 | let height = Math.floor(Math.sqrt(r * r - dx * dx)); 333 | drawLine(x + dx, y - height, x + dx, y + height); 334 | } 335 | } 336 | //% block="initialize OLED with width $width height $height" 337 | //% width.defl=128 338 | //% height.defl=64 339 | //% weight=9 340 | export function init(width: number, height: number) { 341 | command(SSD1306_DISPLAYOFF); 342 | command(SSD1306_SETDISPLAYCLOCKDIV); 343 | command(0x80); // the suggested ratio 0x80 344 | command(SSD1306_SETMULTIPLEX); 345 | command(0x3F); 346 | command(SSD1306_SETDISPLAYOFFSET); 347 | command(0x0); // no offset 348 | command(SSD1306_SETSTARTLINE | 0x0); // line #0 349 | command(SSD1306_CHARGEPUMP); 350 | command(0x14); 351 | command(SSD1306_MEMORYMODE); 352 | command(0x00); // 0x0 act like ks0108 353 | command(SSD1306_SEGREMAP | 0x1); 354 | command(SSD1306_COMSCANDEC); 355 | command(SSD1306_SETCOMPINS); 356 | command(0x12); 357 | command(SSD1306_SETCONTRAST); 358 | command(0xCF); 359 | command(SSD1306_SETPRECHARGE); 360 | command(0xF1); 361 | command(SSD1306_SETVCOMDETECT); 362 | command(0x40); 363 | command(SSD1306_DISPLAYALLON_RESUME); 364 | command(SSD1306_NORMALDISPLAY); 365 | command(SSD1306_DISPLAYON); 366 | displayWidth = width 367 | displayHeight = height / 8 368 | screenSize = displayWidth * displayHeight 369 | charX = xOffset 370 | charY = yOffset 371 | font = hex` 372 | 0000000000 373 | 3E5B4F5B3E 374 | 3E6B4F6B3E 375 | 1C3E7C3E1C 376 | 183C7E3C18 377 | 1C577D571C 378 | 1C5E7F5E1C 379 | 00183C1800 380 | FFE7C3E7FF 381 | 0018241800 382 | FFE7DBE7FF 383 | 30483A060E 384 | 2629792926 385 | 407F050507 386 | 407F05253F 387 | 5A3CE73C5A 388 | 7F3E1C1C08 389 | 081C1C3E7F 390 | 14227F2214 391 | 5F5F005F5F 392 | 06097F017F 393 | 006689956A 394 | 6060606060 395 | 94A2FFA294 396 | 08047E0408 397 | 10207E2010 398 | 08082A1C08 399 | 081C2A0808 400 | 1E10101010 401 | 0C1E0C1E0C 402 | 30383E3830 403 | 060E3E0E06 404 | 0000000000 405 | 00005F0000 406 | 0007000700 407 | 147F147F14 408 | 242A7F2A12 409 | 2313086462 410 | 3649562050 411 | 0008070300 412 | 001C224100 413 | 0041221C00 414 | 2A1C7F1C2A 415 | 08083E0808 416 | 0080703000 417 | 0808080808 418 | 0000606000 419 | 2010080402 420 | 3E5149453E 421 | 00427F4000 422 | 7249494946 423 | 2141494D33 424 | 1814127F10 425 | 2745454539 426 | 3C4A494931 427 | 4121110907 428 | 3649494936 429 | 464949291E 430 | 0000140000 431 | 0040340000 432 | 0008142241 433 | 1414141414 434 | 0041221408 435 | 0201590906 436 | 3E415D594E 437 | 7C1211127C 438 | 7F49494936 439 | 3E41414122 440 | 7F4141413E 441 | 7F49494941 442 | 7F09090901 443 | 3E41415173 444 | 7F0808087F 445 | 00417F4100 446 | 2040413F01 447 | 7F08142241 448 | 7F40404040 449 | 7F021C027F 450 | 7F0408107F 451 | 3E4141413E 452 | 7F09090906 453 | 3E4151215E 454 | 7F09192946 455 | 2649494932 456 | 03017F0103 457 | 3F4040403F 458 | 1F2040201F 459 | 3F4038403F 460 | 6314081463 461 | 0304780403 462 | 6159494D43 463 | 007F414141 464 | 0204081020 465 | 004141417F 466 | 0402010204 467 | 4040404040 468 | 0003070800 469 | 2054547840 470 | 7F28444438 471 | 3844444428 472 | 384444287F 473 | 3854545418 474 | 00087E0902 475 | 18A4A49C78 476 | 7F08040478 477 | 00447D4000 478 | 2040403D00 479 | 7F10284400 480 | 00417F4000 481 | 7C04780478 482 | 7C08040478 483 | 3844444438 484 | FC18242418 485 | 18242418FC 486 | 7C08040408 487 | 4854545424 488 | 04043F4424 489 | 3C4040207C 490 | 1C2040201C 491 | 3C4030403C 492 | 4428102844 493 | 4C9090907C 494 | 4464544C44 495 | 0008364100 496 | 0000770000 497 | 0041360800 498 | 0201020402 499 | 3C2623263C 500 | 1EA1A16112 501 | 3A4040207A 502 | 3854545559 503 | 2155557941 504 | 2154547841 505 | 2155547840 506 | 2054557940 507 | 0C1E527212 508 | 3955555559 509 | 3954545459 510 | 3955545458 511 | 0000457C41 512 | 0002457D42 513 | 0001457C40 514 | F0292429F0 515 | F0282528F0 516 | 7C54554500 517 | 2054547C54 518 | 7C0A097F49 519 | 3249494932 520 | 3248484832 521 | 324A484830 522 | 3A4141217A 523 | 3A42402078 524 | 009DA0A07D 525 | 3944444439 526 | 3D4040403D 527 | 3C24FF2424 528 | 487E494366 529 | 2B2FFC2F2B 530 | FF0929F620 531 | C0887E0903 532 | 2054547941 533 | 0000447D41 534 | 3048484A32 535 | 384040227A 536 | 007A0A0A72 537 | 7D0D19317D 538 | 2629292F28 539 | 2629292926 540 | 30484D4020 541 | 3808080808 542 | 0808080838 543 | 2F10C8ACBA 544 | 2F102834FA 545 | 00007B0000 546 | 08142A1422 547 | 22142A1408 548 | AA005500AA 549 | AA55AA55AA 550 | 000000FF00 551 | 101010FF00 552 | 141414FF00 553 | 1010FF00FF 554 | 1010F010F0 555 | 141414FC00 556 | 1414F700FF 557 | 0000FF00FF 558 | 1414F404FC 559 | 141417101F 560 | 10101F101F 561 | 1414141F00 562 | 101010F000 563 | 0000001F10 564 | 1010101F10 565 | 101010F010 566 | 000000FF10 567 | 1010101010 568 | 101010FF10 569 | 000000FF14 570 | 0000FF00FF 571 | 00001F1017 572 | 0000FC04F4 573 | 1414171017 574 | 1414F404F4 575 | 0000FF00F7 576 | 1414141414 577 | 1414F700F7 578 | 1414141714 579 | 10101F101F 580 | 141414F414 581 | 1010F010F0 582 | 00001F101F 583 | 0000001F14 584 | 000000FC14 585 | 0000F010F0 586 | 1010FF10FF 587 | 141414FF14 588 | 1010101F00 589 | 000000F010 590 | FFFFFFFFFF 591 | F0F0F0F0F0 592 | FFFFFF0000 593 | 000000FFFF 594 | 0F0F0F0F0F 595 | 3844443844 596 | 7C2A2A3E14 597 | 7E02020606 598 | 027E027E02 599 | 6355494163 600 | 3844443C04 601 | 407E201E20 602 | 06027E0202 603 | 99A5E7A599 604 | 1C2A492A1C 605 | 4C7201724C 606 | 304A4D4D30 607 | 3048784830 608 | BC625A463D 609 | 3E49494900 610 | 7E0101017E 611 | 2A2A2A2A2A 612 | 44445F4444 613 | 40514A4440 614 | 40444A5140 615 | 0000FF0103 616 | E080FF0000 617 | 08086B6B08 618 | 3612362436 619 | 060F090F06 620 | 0000181800 621 | 0000101000 622 | 3040FF0101 623 | 001F01011E 624 | 00191D1712 625 | 003C3C3C3C 626 | 0000000000` 627 | loadStarted = false 628 | loadPercent = 0 629 | clear() 630 | } 631 | } 632 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pxt-oled-ssd1306", 3 | "version": "2.0.4", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "pxt": "^0.3.0", 7 | "pxt-microbit": "^0.9.76" 8 | }, 9 | "scripts": { 10 | "pxt:init": "pxt target microbit", 11 | "pxt:install": "pxt install", 12 | "test": "pxt test" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /pxt.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SSD1306_OLED", 3 | "version": "2.0.17", 4 | "description": "Tinkercademy package for SSD1306 OLED controller", 5 | "license": "MIT", 6 | "dependencies": { 7 | "core": "*" 8 | }, 9 | "files": [ 10 | "README.md", 11 | "main.ts", 12 | "_locales/zh/SSD1306_OLED-strings.json", 13 | "_locales/pl/SSD1306_OLED-strings.json", 14 | "_locales/zh-TW/SSD1306_OLED-strings.json" 15 | ], 16 | "testFiles": [ 17 | "test.ts" 18 | ], 19 | "public": true, 20 | "targetVersions": { 21 | "target": "7.0.51", 22 | "targetId": "microbit" 23 | }, 24 | "supportedTargets": [ 25 | "microbit" 26 | ], 27 | "preferredEditor": "tsprj" 28 | } 29 | -------------------------------------------------------------------------------- /test.ts: -------------------------------------------------------------------------------- 1 | OLED.init(128, 64); 2 | OLED.writeStringNewLine("the quick brown fox jumped over the lazy dog?"); 3 | OLED.writeStringNewLine("THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG!"); 4 | basic.pause(1000); 5 | OLED.clear(); 6 | OLED.writeString("Your magic number is "); 7 | OLED.writeNum(23 * 3); 8 | OLED.writeStringNewLine("!"); 9 | OLED.writeNumNewLine(1); 10 | basic.pause(100); 11 | OLED.writeNumNewLine(2); 12 | basic.pause(100); 13 | OLED.writeNumNewLine(3); 14 | basic.pause(1000); 15 | for (let i = 0; i < 100; i++) { 16 | OLED.drawLoading(i); 17 | } 18 | basic.pause(1000); 19 | OLED.clear(); 20 | OLED.drawRectangle(10, 10, 60, 60); 21 | OLED.drawLine(0, 0, 128, 64); 22 | OLED.drawLine(0, 64, 128, 0); 23 | basic.pause(1000); 24 | OLED.clear(); 25 | OLED.drawCircle(20, 32, 10); 26 | OLED.drawFilledCircle(100, 32, 10); 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "noImplicitAny": true, 5 | "outDir": "built", 6 | "rootDir": "." 7 | }, 8 | "exclude": ["pxt_modules/**/*test.ts"] 9 | } 10 | --------------------------------------------------------------------------------