├── README.md ├── _locales ├── de │ └── IR-strings.json └── zh │ └── IR-strings.json ├── images ├── blocks.jpg ├── rec_sample1_en.jpg ├── rec_sample2_en.jpg └── sample3_en.jpg ├── main.ts └── pxt.json /README.md: -------------------------------------------------------------------------------- 1 | # InfraRed 2 | 3 | 這是專為micro:bit提供的紅外線積木\ 4 | This is the infrared blocks for microbit 5 | 6 | ## Author 7 | Liou Zheng-Ji\ 8 | 劉正吉\ 9 | [my page, https://sites.google.com/jes.mlc.edu.tw/ljj/](https://sites.google.com/jes.mlc.edu.tw/ljj/) 10 | 11 | ## Video 12 | [![click here to see the sample video](https://img.youtube.com/vi/4JWbFmI6djI/0.jpg)](https://www.youtube.com/watch?v=4JWbFmI6djI) 13 | 14 | ## Blocks 15 | ![image](images/blocks.jpg) 16 | 17 | ## Sample1 18 | [![click here to see the sample video](https://img.youtube.com/vi/Id3h4RjNyXw/0.jpg)](https://www.youtube.com/watch?v=Id3h4RjNyXw)\ 19 | \ 20 | The code of how to receive IR message.\ 21 | For now, the blocks can send and receive IR message using the encoding of NEC and SONY. You can emit IR to your IR receiver attached on microbit from the normal IR remote control, then the blocks will decode the IR message to Hex. You can record the IR message then send the same IR message when you want to emit the same IR message by microbit. 22 | ![image](images/rec_sample1_en.jpg) 23 | 24 | ## Sample2 25 | [![click here to see the sample video](https://img.youtube.com/vi/WI193AyCgbA/0.jpg)](https://www.youtube.com/watch?v=WI193AyCgbA)\ 26 | \ 27 | I use the TV remote controller to control the micro:bit. 28 | ![image](images/sample3_en.jpg) 29 | 30 | ## Sample3 31 | The code of how to send IR message 32 | ![image](images/rec_sample2_en.jpg) 33 | 34 | ## License 35 | 36 | * MIT 37 | 38 | ## Supported targets 39 | 40 | * for PXT/microbit 41 | (The metadata above is needed for package search.) 42 | 43 | ```package 44 | IR=github:lioujj/pxt-IR 45 | ``` 46 | -------------------------------------------------------------------------------- /_locales/de/IR-strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IR|block": "Infrarot IR", 3 | "IR.setIR_pin|block": "Infrarot Empfänger an Pin: %myPin", 4 | "IR.setREC_pin|block": "Infrarot Sender an Pin: %myPin", 5 | "IR.sendMyMessage1|block": "Sende IR-Code: %msg| ,: %times| mal, Codierung:%myType", 6 | "IR.sendMyMessage2|block": "Sende IR-Code: %msg| ,: %times| mal, Codierung:%myType", 7 | "IR.onReceivedIR|block": "Wenn IR-Code empfangen", 8 | "IR.getRecType|block": "die empfangene IR-Verschlüsselung", 9 | "IR.getMessage|block": "empfangener IR-Code" 10 | } 11 | -------------------------------------------------------------------------------- /_locales/zh/IR-strings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IR|block": "紅外線", 3 | "IR.setIR_pin|block": "設定紅外線發射腳位: %myPin", 4 | "IR.setREC_pin|block": "設定紅外線接收腳位: %myPin", 5 | "IR.sendMyMessage1|block": "發射紅外線訊息: %msg| ,發射次數: %times| 次, 訊息編碼:%myType", 6 | "IR.sendMyMessage2|block": "發射紅外線訊息: %msg| ,發射次數: %times| 次, 訊息編碼:%myType", 7 | "IR.onReceivedIR|block": "當接收到紅外線訊息", 8 | "IR.getRecType|block": "接收到的紅外線訊息編碼方式", 9 | "IR.getMessage|block": "接收到的紅外線訊息" 10 | } 11 | -------------------------------------------------------------------------------- /images/blocks.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lioujj/pxt-IR/54b42abb1556601b772b3c0f6cd20fd19f39e527/images/blocks.jpg -------------------------------------------------------------------------------- /images/rec_sample1_en.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lioujj/pxt-IR/54b42abb1556601b772b3c0f6cd20fd19f39e527/images/rec_sample1_en.jpg -------------------------------------------------------------------------------- /images/rec_sample2_en.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lioujj/pxt-IR/54b42abb1556601b772b3c0f6cd20fd19f39e527/images/rec_sample2_en.jpg -------------------------------------------------------------------------------- /images/sample3_en.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lioujj/pxt-IR/54b42abb1556601b772b3c0f6cd20fd19f39e527/images/sample3_en.jpg -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | //% weight=0 color=#87bc4b icon="\uf1eb" block="InfraRed" 2 | namespace IR { 3 | export enum encodingType { 4 | //% block="NEC" 5 | NEC, 6 | //% block="SONY" 7 | SONY 8 | } 9 | let tempHandler: Action; 10 | let irLed = AnalogPin.P16; 11 | const pwmPeriod = 26; 12 | pins.analogWritePin(irLed, 0); 13 | pins.analogSetPeriod(irLed, pwmPeriod); 14 | let send_init = false; 15 | let rec_init = false; 16 | let arr: number[] = [] 17 | let received = false 18 | let first = true 19 | let rec_Type = "" 20 | let messageStr = "" 21 | let recPin = DigitalPin.P8 22 | let thereIsHandler = false 23 | arr = [] 24 | 25 | function transmitBit(highTime: number, lowTime: number): void { 26 | pins.analogWritePin(irLed, 512); 27 | control.waitMicros(highTime); 28 | pins.analogWritePin(irLed, 0); 29 | control.waitMicros(lowTime); 30 | } 31 | 32 | /** 33 | * set the infrared LED pin. 34 | */ 35 | //% blockId=setIR_pin block="set IR LED pin: %myPin" blockExternalInputs=false 36 | //% weight=90 blockGap=10 37 | //% myPin.fieldEditor="gridpicker" myPin.fieldOptions.columns=4 38 | //% myPin.fieldOptions.tooltips="false" myPin.fieldOptions.width="300" 39 | export function setIR_pin(myPin: AnalogPin) { 40 | irLed = myPin; 41 | pins.analogWritePin(irLed, 0); 42 | pins.analogSetPeriod(irLed, pwmPeriod); 43 | send_init = true; 44 | } 45 | 46 | /** 47 | * set the IR receiver pin. 48 | */ 49 | //% blockId=setREC_pin block="set IR receiver pin: %myPin" blockExternalInputs=false 50 | //% weight=85 blockGap=10 51 | //% myPin.fieldEditor="gridpicker" myPin.fieldOptions.columns=4 52 | //% myPin.fieldOptions.tooltips="false" myPin.fieldOptions.width="300" 53 | export function setREC_pin(myPin: DigitalPin) { 54 | recPin = myPin; 55 | pins.setEvents(recPin, PinEventType.Pulse) 56 | pins.setPull(recPin, PinPullMode.PullUp) 57 | pins.onPulsed(recPin, PulseValue.Low, function () { 58 | arr.push(input.runningTimeMicros()) 59 | }) 60 | pins.onPulsed(recPin, PulseValue.High, function () { 61 | arr.push(input.runningTimeMicros()) 62 | }) 63 | control.onEvent(recPin, DAL.MICROBIT_PIN_EVENT_ON_TOUCH, tempHandler); 64 | rec_init = true; 65 | } 66 | 67 | /** 68 | * send message from IR LED. You must set the message encoding type, send how many times, and the message. 69 | */ 70 | //% blockId=sendMyMessage1 block="send message: %msg| ,%times| times, encoding type:%myType" 71 | //% weight=80 blockGap=10 72 | export function sendMyMessage1(msg: string, times: number, myType: encodingType): void { 73 | if (send_init) { 74 | //control.inBackground(() => { 75 | sendMessage(convertHexStrToNum(msg), times, myType); 76 | //}) 77 | } 78 | } 79 | /** 80 | * send message from IR LED. You must set the message encoding type, send how many times, and the message. 81 | */ 82 | //% blockId=sendMyMessage2 block="send message: %msg| ,%times| times, encoding type:%myType" 83 | //% weight=75 blockGap=10 84 | export function sendMyMessage2(msg: string, times: number, myType: string): void { 85 | if (send_init) { 86 | if (myType == "NEC") { 87 | sendMessage(convertHexStrToNum(msg), times, encodingType.NEC); 88 | } else if (myType == "SONY") { 89 | sendMessage(convertHexStrToNum(msg), times, encodingType.SONY); 90 | } 91 | } 92 | } 93 | 94 | 95 | function encode(myCode: number, bits: number, trueHigh: number, trueLow: number, falseHigh: number, falseLow: number): void { 96 | const MESSAGE_BITS = bits; 97 | for (let mask = 1 << (MESSAGE_BITS - 1); mask > 0; mask >>= 1) { 98 | if (myCode & mask) { 99 | transmitBit(trueHigh, trueLow); 100 | } else { 101 | transmitBit(falseHigh, falseLow); 102 | } 103 | } 104 | } 105 | 106 | function sendNEC(message: number, times: number): void { 107 | const enum NEC { 108 | startHigh = 9000, 109 | startLow = 4500, 110 | stopHigh = 560, 111 | stopLow = 0, 112 | trueHigh = 560, 113 | trueLow = 1690, 114 | falseHigh = 560, 115 | falseLow = 560, 116 | interval = 110000 117 | } 118 | let address = message >> 16; 119 | let command = message % 0x010000; 120 | const MESSAGE_BITS = 16; 121 | let startTime = 0; 122 | let betweenTime = 0; 123 | for (let sendCount = 0; sendCount < times; sendCount++) { 124 | startTime = input.runningTimeMicros(); 125 | transmitBit(NEC.startHigh, NEC.startLow); 126 | encode(address, 16, NEC.trueHigh, NEC.trueLow, NEC.falseHigh, NEC.falseLow); 127 | encode(command, 16, NEC.trueHigh, NEC.trueLow, NEC.falseHigh, NEC.falseLow); 128 | transmitBit(NEC.stopHigh, NEC.stopLow); 129 | betweenTime = input.runningTimeMicros() - startTime 130 | if (times > 0) 131 | control.waitMicros(NEC.interval - betweenTime); 132 | } 133 | } 134 | 135 | function sendSONY(message: number, times: number): void { 136 | const enum SONY { 137 | startHigh = 2300, 138 | startLow = 500, 139 | trueHigh = 1100, 140 | trueLow = 500, 141 | falseHigh = 500, 142 | falseLow = 500, 143 | interval = 45000 144 | } 145 | const MESSAGE_BITS = 12; 146 | let startTime = 0; 147 | let betweenTime = 0; 148 | for (let sendCount = 0; sendCount < times; sendCount++) { 149 | startTime = input.runningTimeMicros(); 150 | transmitBit(SONY.startHigh, SONY.startLow); 151 | encode(message, 12, SONY.trueHigh, SONY.trueLow, SONY.falseHigh, SONY.falseLow); 152 | betweenTime = input.runningTimeMicros() - startTime 153 | if (times > 0) 154 | control.waitMicros(SONY.interval - betweenTime); 155 | } 156 | } 157 | 158 | export function sendMessage(message: number, times: number, myType: encodingType): void { 159 | switch (myType) { 160 | case encodingType.NEC: sendNEC(message, times); 161 | case encodingType.SONY: sendSONY(message, times); 162 | default: sendNEC(message, times); 163 | } 164 | } 165 | 166 | function convertHexStrToNum(myMsg: string): number { 167 | let myNum = 0 168 | for (let i = 0; i < myMsg.length; i++) { 169 | if ((myMsg.charCodeAt(i) > 47) && (myMsg.charCodeAt(i) < 58)) { 170 | myNum += (myMsg.charCodeAt(i) - 48) * (16 ** (myMsg.length - 1 - i)) 171 | } else if ((myMsg.charCodeAt(i) > 96) && (myMsg.charCodeAt(i) < 103)) { 172 | myNum += (myMsg.charCodeAt(i) - 87) * (16 ** (myMsg.length - 1 - i)) 173 | } else if ((myMsg.charCodeAt(i) > 64) && (myMsg.charCodeAt(i) < 71)) { 174 | myNum += (myMsg.charCodeAt(i) - 55) * (16 ** (myMsg.length - 1 - i)) 175 | } else { 176 | myNum = 0 177 | break 178 | } 179 | } 180 | return myNum 181 | } 182 | 183 | //------------------receiver------------- 184 | 185 | function resetReceiver() { 186 | arr = [] 187 | received = false 188 | } 189 | 190 | control.inBackground(function () { 191 | basic.forever(function () { 192 | if ((!received) && (rec_init)) { 193 | if (arr.length > 20) { 194 | if ((input.runningTimeMicros() - arr[arr.length - 1]) > 120000) { 195 | if (first) { 196 | resetReceiver() 197 | first = false 198 | } else { 199 | received = true 200 | decodeIR(); 201 | } 202 | } 203 | } 204 | } 205 | }) 206 | }) 207 | 208 | function decodeIR() { 209 | let addr = 0 210 | let command = 0 211 | messageStr = "" 212 | rec_Type = "" 213 | for (let i = 0; i <= arr.length - 1 - 1; i++) { 214 | arr[i] = arr[i + 1] - arr[i] 215 | } 216 | if (((arr[0] + arr[1]) > 13000) && ((arr[0] + arr[1]) < 14000)) { 217 | rec_Type = "NEC" 218 | arr.removeAt(1) 219 | arr.removeAt(0) 220 | addr = pulseToDigit(0, 15, 1600) 221 | command = pulseToDigit(16, 31, 1600) 222 | messageStr = convertNumToHexStr(addr, 4) + convertNumToHexStr(command, 4) 223 | arr = []; 224 | if (thereIsHandler) { 225 | tempHandler(); 226 | } 227 | } else if (((arr[0] + arr[1]) > 2600) && ((arr[0] + arr[1]) < 3200)) { 228 | rec_Type = "SONY" 229 | arr.removeAt(1) 230 | arr.removeAt(0) 231 | command = pulseToDigit(0, 11, 1300) 232 | messageStr = convertNumToHexStr(command, 3) 233 | arr = []; 234 | if (thereIsHandler) { 235 | tempHandler(); 236 | } 237 | } 238 | resetReceiver(); 239 | } 240 | 241 | function pulseToDigit(beginBit: number, endBit: number, duration: number): number { 242 | let myNum = 0 243 | for (let i = beginBit; i <= endBit; i++) { 244 | myNum <<= 1 245 | if ((arr[i * 2] + arr[i * 2 + 1]) < duration) { 246 | myNum += 0 247 | } else { 248 | myNum += 1 249 | } 250 | } 251 | return myNum 252 | } 253 | 254 | function convertNumToHexStr(myNum: number, digits: number): string { 255 | let tempDiv = 0 256 | let tempMod = 0 257 | let myStr = "" 258 | tempDiv = myNum 259 | while (tempDiv > 0) { 260 | tempMod = tempDiv % 16 261 | if (tempMod > 9) { 262 | myStr = String.fromCharCode(tempMod - 10 + 97) + myStr 263 | } else { 264 | myStr = tempMod + myStr 265 | } 266 | tempDiv = Math.idiv(tempDiv, 16) 267 | } 268 | while (myStr.length != digits) { 269 | myStr = "0" + myStr 270 | } 271 | return myStr 272 | } 273 | 274 | /** 275 | * Do something when a receive IR 276 | */ 277 | //% blockId=onReceivedIR block="on IR message received" blockInlineInputs=true 278 | //% weight=70 blockGap=10 279 | export function onReceivedIR(handler: Action): void { 280 | tempHandler = handler 281 | thereIsHandler = true 282 | } 283 | 284 | /** 285 | * return the encoding type of the received IR 286 | */ 287 | //% blockId=getRecType block="the received IR encoding type" 288 | //% weight=60 blockGap=10 289 | export function getRecType(): string { 290 | return rec_Type 291 | } 292 | 293 | /** 294 | * return the message of the received IR 295 | */ 296 | //% blockId=getMessage block="the received IR message" 297 | //% weight=60 blockGap=10 298 | export function getMessage(): string { 299 | return messageStr 300 | } 301 | 302 | } 303 | -------------------------------------------------------------------------------- /pxt.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "IR", 3 | "version": "0.0.3", 4 | "description": "這是專為micro:bit提供的紅外線積木(This is the infrared blocks for microbit)", 5 | "license": "MIT", 6 | "dependencies": { 7 | "core": "*" 8 | }, 9 | "files": [ 10 | "README.md", 11 | "main.ts", 12 | "_locales/zh/IR-strings.json", 13 | "_locales/de/IR-strings.json" 14 | ], 15 | "public": true 16 | } 17 | --------------------------------------------------------------------------------