Bump V3.0.22 (#110)

* change simulator svg

* change radio image

* Remove google fonts cdn

* change color of 'advanced' button

* font fix

* font fix 2

* display fix

* change fullsceen simulator bg

* Continuous servo

* handle continuous state

* adding shims

* update rendering for continuous servos

* fixing sim

* fix sig

* typo

* fix sim

* bump pxt

* bump pxt

* rerun travis

* Input blocks revision

- add Button and Pin event types
- merge onPinPressed & onPinReleased in new onPinEvent function
- create new onButtonEvent function

* update input blocks in docs and tests

* remove device_pin_release block

* Hide DAL.x behind Enum

* bring back deprecated blocks, but hide them

* shims and locales files

* fix input.input. typing

* remove buildpr

* bump V3

* update simulator aspect ratio

* add Loudness Block

* revoke loudness block

* Adds soundLevel

To be replaced by pxt-common-packages when DAL is updated.

* Remove P0 & P3 from AnalogPin

Co-authored-by: Juri <gitkraken@juriwolf.de>
This commit is contained in:
Amerlander 2020-09-08 11:04:25 +02:00 committed by GitHub
parent 98d8b2977b
commit 918af4f3ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
233 changed files with 9391 additions and 2739 deletions

8
.github/lock.yml vendored
View File

@ -30,7 +30,13 @@ lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: false
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.

View File

@ -0,0 +1,12 @@
name: Compress images
on: pull_request
jobs:
build:
name: calibreapp/image-actions
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: calibreapp/image-actions
uses: calibreapp/image-actions@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,31 +0,0 @@
name: pxt-buildpr
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [8.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install
run: |
sudo apt-get install xvfb
sudo npm install -g pxt
npm install
- name: pxt ci
run: |
pxt ci
env:
CHROME_BIN: chromium-browser
DISPLAY: :99.0
CI: true

View File

@ -1,39 +0,0 @@
name: pxt-buildtarget
on:
push:
branches:
- master
create:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [8.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install
run: |
sudo apt-get install xvfb
sudo npm install -g pxt
npm install
- name: pxt ci
run: |
pxt ci
env:
CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }}
PXT_ACCESS_TOKEN: ${{ secrets.PXT_ACCESS_TOKEN }}
PXT_RELEASE_REPO: ${{ secrets.PXT_RELEASE_REPO }}
NPM_ACCESS_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
CHROME_BIN: chromium-browser
DISPLAY: :99.0
CI: true

50
.github/workflows/testghpkgs.yml vendored Normal file
View File

@ -0,0 +1,50 @@
name: pxt-testghpkgs
on:
schedule:
- cron: '0 0 * * 6'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [8.x]
steps:
- uses: actions/checkout@v1
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: npm install
run: |
sudo npm install -g pxt
npm install
- name: pxt buildtarget
run: pxt buildtarget
- name: cache build output
uses: actions/cache@v1
env:
cache-name: cache-testghpkgs
with:
path: temp/ghpkgs
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: pxt testghpkgs
run: pxt testghpkgs
env:
PXT_FORCE_GITHUB_PROXY: 1
PXT_ACCESS_TOKEN: ${{ secrets.PXT_ACCESS_TOKEN }}
GITHUB_TOKEN: ${{ secrets.TRAVIS_GITHUB_ACCESS_TOKEN }}
- name: upload build log
uses: actions/upload-artifact@v2
if: ${{ always() }}
with:
name: logs
path: temp/ghpkgs/*.txt

4
.gitignore vendored
View File

@ -27,10 +27,6 @@ crowdinstats.csv
*.db
*.suo
*.log
.DS_Store
.idea
*.iml
.vscode/.BROWSE.VC.DB-shm
.vscode/.BROWSE.VC.DB-wal
package-lock.json

138
README.md
View File

@ -1,79 +1,149 @@
# Calliope target for Microsoft MakeCode
# micro:bit target for PXT
This editor is hosted at https://makecode.calliope.cc.
* Got a question? Try the forum at https://forum.calliope.cc/
### BUILD COMMENTS
pxt-calliope is a [Microsoft Programming Experience Toolkit (PXT)](https://github.com/Microsoft/pxt) target that allows you to program a [BBC micro:bit](https://microbit.org/).
- build libs/core/dal.d.ts new requires some meddling, as the `#define` parser does not parse `#ifdef` and thus
has some conflicts with double defines constants
![](http://calliope.cc/content/1-ueber-mini/mini_board.png)
* [Try it live](https://makecode.calliope.cc/)
## Local server
## Issue tracking
The local server allows to run the editor and the documentation from your computer.
Please add an issue if you discover an (unreported) bug.
### Setup
## Developing new extensions
The following commands are a 1-time setup after synching the repo on your machine.
Authoring and testing of new extensions can be done directly from the web editor. See [our documentation](https://makecode.com/blog/github-packages) on how to get started. If you want to run the editor locally, keep reading.
* See requirements for [pxt](https://github.com/Microsoft/pxt)
* [clone this repo](https://help.github.com/articles/cloning-a-repository/) to your computer and go in the project folder
## Local server setup
The local server lets you to run the editor and serve the documentation from your own computer. It is meant for a single developer used and not designed to serve the editor to a large amount of users.
1. Install [Node.js](https://nodejs.org/) 8.9.4 or higher.
2. Clone this repository.
```
git clone https://github.com/microsoft/pxt-calliope
cd pxt-calliope
```
* install the PXT command line (add ``sudo`` for Mac/Linux shells).
3. Install the PXT command line (add `sudo` for Mac/Linux shells).
```
npm install -g pxt
```
* install the dependencies
4. Install the pxt-calliope dependencies.
```
npm install
```
Go to the **Running** section.
### Developer Setup
This is the typical setup used by the MakeCode team to work on the microbit.
1. Install [Node.js](https://nodejs.org/) 8.9.4 or higher.
2. Install [Docker](https://www.docker.com/get-started) if you plan to build ``.cpp`` files.
3. Clone the pxt repository.
```
git clone https://github.com/microsoft/pxt
cd pxt
```
4. Install the dependencies of pxt and build it
```
npm install
npm run build
cd ..
```
5. Clone the pxt-common-packages repository
```
git clone https://github.com/microsoft/pxt-common-packages
cd pxt-common-packages
npm install
cd ..
```
6. Clone this repository.
```
git clone https://github.com/microsoft/pxt-calliope
cd pxt-calliope
```
7. Install the PXT command line (add `sudo` for Mac/Linux shells).
```
npm install -g pxt
```
8. Install the pxt-calliope dependencies.
```
npm install
```
8. Link pxt-calliope back to base pxt repo (add `sudo` for Mac/Linux shells).
This step is only required if you intend to make changes to pxt and/or
pxt-common-packages repos. If all you want is serve a local Makecode, you can skip
this step.
```
pxt link ../pxt
pxt link ../pxt-common-packages
```
Note the above command assumes the folder structure of
```
makecode
|
----------------------------------
| | |
pxt pxt-common-packages pxt-calliope
```
### Running
Run this command to open a local web server (add ``sudo`` for Mac/Linux shells).
Run this command from inside pxt-calliope to open a local web server
```
pxt serve
```
If the local server opens in the wrong browser, make sure to copy the URL containing the local token.
Otherwise, the editor will not be able to load the projects.
If you need modify the `.cpp` files, turn on yotta compilation with the ``-yt`` flag (add ``sudo`` for Mac/Linux shells). On Windows, you must be running
from the ``Run Yotta`` command prompt.
If you need to modify the `.cpp` files (and have installed yotta), enable yotta compilation using the `--localbuild` flag:
```
pxt serve -yt
pxt serve --local
```
## Updates
To update your PXT version and make sure you're running the latest tools, run (add ``sudo`` for Mac/Linux shells)
If you want to speed up the build, you can use the ``rebundle`` option, which skips building and simply refreshes the target information
```
pxt update
pxt serve --rebundle
```
More instructions at https://github.com/Microsoft/pxt#running-a-target-from-localhost
### Cleaning
## Testing
Sometimes, your built folder might be in a bad state, clean it and try again.
```
pxt clean
```
The build automatically runs the following:
### Updates
* make sure the built-in packages compile
* `pxt run` in `libs/lang-test*` - this will run the test in command line runner;
there is a number of asserts in both of these
* `pxt testdir` in `tests` - this makes sure all the files compile and generates .hex files
Make sure to pull changes from all repos regularly. More instructions are at https://github.com/Microsoft/pxt#running-a-target-from-localhost
To test something on the device:
## Update playlists in markdown
* do a `pxt deploy` in `libs/lang-test*` - they should show `1` or `2` on the screen (and not unhappy face)
* run `pxt testdir` in `tests` and deploy some of the hex files from `tests/built`
Get a Google API key and store it in the ``GOOGLE_API_KEY`` environment variables (turn on data from the app).
The `lang-test0` source comes from the `pxt-core` package. It's also tested with `pxt run` there.
```
pxt downloadplaylists
```
## Repos
The pxt-calliope target depends on several other repos. The main ones are:
- https://github.com/Microsoft/pxt, the PXT framework
- https://github.com/Microsoft/pxt-common-packages, common APIs accross various MakeCode editors
- https://github.com/lancaster-university/microbit, basic wrapper around the DAL
- https://github.com/lancaster-university/microbit-dal
## History
See the [MakeCode blog](https://makecode.com/blog).
## Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
## Trademarks
MICROSOFT, the Microsoft Logo, and MAKECODE are registered trademarks of Microsoft Corporation. They can only be used for the purposes described in and in accordance with Microsofts Trademark and Brand guidelines published at https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general.aspx. If the use is not covered in Microsofts published guidelines or you are not sure, please consult your legal counsel or MakeCode team (makecode@microsoft.com).

View File

@ -1,13 +0,0 @@
{
"folders": [
{
"path": "../pxt"
},
{
"path": "../pxt-common-packages"
},
{
"path": "."
}
]
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

View File

@ -0,0 +1,30 @@
# @extends
## #examples
## Example: ``AND`` operator
This example turns on LED `3 , 3`, if LEDs `1 , 1` and `2 , 2` are both on:
```blocks
if (led.point(1,1) && led.point(2,2)) {
led.plot(3,3)
}
```
## Example: Comparisons of numbers and strings
When you compare two Numbers, you get a Boolean value, such as the comparison `x < 5` in the code below:
```blocks
input.onButtonPressed(Button.A, () => {
let x = randint(0, 5)
if(x < 5) {
basic.showString("low");
} else {
basic.showString("high");
}
})
```
See the documentation on [Numbers](/types/number) for more information on comparing two Numbers.

15
docs/blocks/logic/if.md Normal file
View File

@ -0,0 +1,15 @@
# @extends
## #examples
## Example: adjusting screen brightness
If the [light level](/reference/input/light-level) is `< 100`, this code sets the brightness to `255` when the button A is pressed:
```blocks
input.onButtonPressed(Button.A, () => {
if(input.lightLevel()<100){
led.setBrightness(255);
}
})
```

3
docs/blocks/loops.md Normal file
View File

@ -0,0 +1,3 @@
# @extends
## #specific

View File

@ -0,0 +1,20 @@
# @extends
## #examples
## Example: Find the highest number
Find the highest number in a list of numbers. Display the highest number on the screen.
```blocks
let list: number[] = []
let highest = 0
highest = 0
list = [5, 8, 6, 2, 4, 3, 7, 1]
for (let value of list) {
if (value > highest) {
highest = value
}
}
basic.showNumber(highest)
```

15
docs/blocks/loops/for.md Normal file
View File

@ -0,0 +1,15 @@
# @extends
## #examples
## Example: Count to 4
This program will show the numbers 0, 1, 2, 3, and 4 one after another on the LED screen.
```blocks
input.onButtonPressed(Button.A, () => {
for(let i = 0; i < 5; ++i) {
basic.showNumber(i)
}
})
```

View File

@ -0,0 +1,16 @@
# @extends
## #examples
## Example: Blinking heart
Flash the ``heart`` icon on the screen `4` times.
```blocks
for (let i = 0; i < 4; i++) {
basic.showIcon(IconNames.Heart)
basic.pause(300)
basic.clearScreen()
basic.pause(300)
}
```

View File

@ -0,0 +1,17 @@
# @extends
## #examples
## Example: diagonal line
The following example uses a while loop to make a diagonal line on the LED screen (points `0, 0`, `1, 1`, `2, 2`, `3, 3`, `4, 4`).
```blocks
input.onButtonPressed(Button.A, () => {
let index = 4;
while(index >= 0) {
led.plot(index, index);
index--;
}
})
```

View File

@ -0,0 +1,29 @@
# random Boolean
Returns a pseudo-random boolean value that is either `true` or `false`.
```sig
Math.randomBoolean()
```
## Returns
* a pseudo-random [boolean](types/boolean) that is either `true` or `false`.
## Example
Make your @boardname@ do a coin toss when it's dropped softly. Have the LEDs show 'heads' or 'tails' as the result of the toss.
```blocks
input.onGesture(Gesture.FreeFall, () => {
if (Math.randomBoolean()) {
basic.showIcon(IconNames.Happy)
} else {
basic.showIcon(IconNames.Sword)
}
})
```
## See Also
[random](/reference/math/random)

12
docs/blocks/on-start.md Normal file
View File

@ -0,0 +1,12 @@
# @extends
## #exstart
In this example, ``on start`` sets a dimmer brightness on the screen and the button handler shows a string.
```blocks
input.onButtonPressed(Button.A, () => {
basic.showString("Hello!")
})
led.setBrightness(50)
```

View File

@ -0,0 +1,36 @@
# Assignment Operator
Use an equals sign to make a [variable](/blocks/variables/var) store the [number](/types/number)
or [string](/types/string) you say.
When you use the equals sign to store something in a variable, the equals sign is called
an *assignment operator*, and what you store is called a *value*.
## Storing numbers in variables
This program makes the variable `item` equal `5` and then shows it on the [LED screen](/device/screen).
````blocks
let item = 5
basic.showNumber(item)
````
## Storing strings in variables
This program makes the variable `name` equal `Joe` and then shows it on the [LED screen](/device/screen).
````blocks
let name = "Joe"
basic.showString(name);
````
## Notes
You can use the assignment operator with variables of
every [type](/types). A *type* is which kind of thing
a variable can store, like a number or string.
## See also
[variable](/blocks/variables/var), [types](/types)

View File

@ -0,0 +1,13 @@
# @extends
## #examples
## Example: show the value of a variable
Use the assignment operator to set the value of a [variable](/blocks/variables/var). Change the value of a variable from 0 to 1 using the change item block. Then display the new value of the variable on the LED screen. Like this:
```blocks
let x = 0;
x += 1;
basic.showNumber(x);
```

View File

@ -0,0 +1,87 @@
# Local Variables
How to define and use local variables.
## @parent language
A variable is a place where you can store and retrieve data. Variables have a name, a [type](/types), and value:
* *name* is how you'll refer to the variable
* *type* refers to the kind of data a variable can store
* *value* refers to what's stored in the variable
## Var statement
Use the Block Editor variable statement to create a variable
and the [assignment operator](/blocks/variables/assign)
to store something in the variable.
For example, this code stores the number `2` in the `x` variable:
```blocks
let x = 2;
```
Here's how to define a variable in the Block Editor:
1. Click `variables`.
2. Change the default variable name if you like.
3. Drag a block type on the right-side of the [assignment operator](/blocks/variables/assign) and click the down arrow to change the variable name.
A variable is created for the number returned by the [brightness](/reference/led/brightness) function.
```blocks
let b = led.brightness();
```
## Using variables
Once you've defined a variable, just use the variable's name whenever you need what's stored in the variable. For example, the following code shows the value stored in `counter` on the LED screen:
```blocks
let counter = 1;
basic.showNumber(counter);
```
To change the contents of a variable use the assignment operator. The following code sets `counter` to 1 and then increments `counter` by 10:
```blocks
let counter = 1;
counter = counter + 10;
basic.showNumber(counter);
```
## Why use variables?
If you want to remember and modify data, you'll need a variable.
A counter is a great example:
```blocks
let counter = 0;
input.onButtonPressed(Button.A, () => {
counter = counter + 1;
basic.showNumber(counter);
});
```
## Local variables
Local variables exist only within the function or block of code where they're defined. For example:
```blocks
// x does NOT exist here.
if (led.brightness() > 128) {
// x exists here
let x = 0;
}
```
### Notes
* You can use the default variable names if you'd like, however, it's best to use descriptive variable names. To change a variable name in the editor, select the down arrow next to the variable and then click "new variable".
## See also
[types](/types), [assignment operator](/blocks/variables/assign)

74
docs/coding-cards.md Normal file
View File

@ -0,0 +1,74 @@
# Coding Cards
## Math
```codecard
[
{
"name": "Make a Digital Balance",
"description": "Use the accelerometer to find the balance point",
"url": "https://drive.google.com/open?id=1Tl80unLA5_Zwkymh1flSbwuZbCIqSOxQ",
"imageUrl": "/static/coding-cards/balance-card.jpg"
},
{
"name": "Make a Digital Dice",
"description": "Create a shakeable dice that uses the accelerometer",
"url": "https://drive.google.com/open?id=1iW75z-7maJ3qixwv9Yuj6rA5U387qVpg",
"imageUrl": "/static/coding-cards/dice-card.jpg"
},
{
"name": "Make a Trundle Wheel",
"description": "Build trundle wheel that measures a distance travelled",
"url": "https://drive.google.com/open?id=1hzpBN5aqzYMvm7s_W6RQr9u4eFx1f6LK",
"imageUrl": "/static/coding-cards/trundlewheel-card.jpg"
}
]
```
## Games
```codecard
[
{
"name": "Nervous",
"description": "Carefully move the ring but don't touch the wire!",
"url": "https://drive.google.com/open?id=1BJCkrdMoojU-ojQcOluawecw5W6kcdnZ",
"imageUrl": "/static/coding-cards/games-nervous.jpg"
},
{
"name": "Reaction",
"description": "Which player has the fastest reaction time?",
"url": "https://drive.google.com/open?id=1kfZKLflUrPoeveboo1LpubgaJSsFkDgY",
"imageUrl": "/static/coding-cards/games-reaction.jpg"
},
{
"name": "Shake the Bottle",
"description": "Shake the bottle until the fizz inside pops the lid",
"url": "https://drive.google.com/open?id=1lTZbrVP5UDG7IZeY1Kod8gw4VNcldzzZ",
"imageUrl": "/static/coding-cards/games-shake.jpg"
},
{
"name": "Sprite Based Games",
"description": "Try this game to see how to make sprite based games",
"url": "https://drive.google.com/open?id=1p1fm9SlFVr8NQ9ctQvhZ7H-okfxXhabW",
"imageUrl": "/static/coding-cards/games-sprite.jpg"
},
{
"name": "Zen",
"description": "Strike a pose but keep very still, wiggle too much and your out!",
"url": "https://drive.google.com/open?id=14JBWsx-K489GjSgvMX4kslxaHKYfdBtj",
"imageUrl": "/static/coding-cards/games-zen.jpg"
}
]
```
## See Also
[Make a Digital Balance](https://drive.google.com/open?id=1Tl80unLA5_Zwkymh1flSbwuZbCIqSOxQ),
[Make a Digital Dice](https://drive.google.com/open?id=1iW75z-7maJ3qixwv9Yuj6rA5U387qVpg),
[Make a Trundle Wheel](https://drive.google.com/open?id=1hzpBN5aqzYMvm7s_W6RQr9u4eFx1f6LK),
[Nervous](https://drive.google.com/open?id=1BJCkrdMoojU-ojQcOluawecw5W6kcdnZ),
[Reaction](https://drive.google.com/open?id=1kfZKLflUrPoeveboo1LpubgaJSsFkDgY),
[Shake the Bottle](https://drive.google.com/open?id=1lTZbrVP5UDG7IZeY1Kod8gw4VNcldzzZ),
[Sprite Based Games](https://drive.google.com/open?id=1p1fm9SlFVr8NQ9ctQvhZ7H-okfxXhabW),
[Zen](https://drive.google.com/open?id=14JBWsx-K489GjSgvMX4kslxaHKYfdBtj)

View File

@ -0,0 +1,8 @@
# [Blocks to JavaScript](/courses/blocks-to-javascript)
* [Blocks to JavaScript](/courses/blocks-to-javascript)
* [Hello JavaScript](/courses/blocks-to-javascript/hello-javascript)
* [Starter Blocks](/courses/blocks-to-javascript/starter-blocks)
* [Writing Code](/courses/blocks-to-javascript/writing-code)
* [Conditional Loops](/courses/blocks-to-javascript/conditional-loops)
* [Writing Functions](/courses/blocks-to-javascript/writing-functions)

15
docs/courses/logic-lab.md Normal file
View File

@ -0,0 +1,15 @@
# Logic Lab
![Logic lab header image](/static/courses/logic-lab/logic-lab-header.jpg)
A basic aspect of knowledge and understanding is whether something is true or not. Considering conditions around you and making a conclusion about something being true or false means that you are using logic. Computers and, in fact, all of digital electronics rely on this idea of logic to process information and give results in terms of conditions being true or false. Logic is used almost everywhere in the programs you write in places where you want decide to do one task or another.
## Logic topics
These topic sections teach you about applying logic to conditions and using Boolean algebra to express them. Also, you will see how logical operators work and how they combine to form more complex logic structures.
* [Logic and Expressions](/courses/logic-lab/expressions)
* [Boolean Elements](/courses/logic-lab/elements)
* [Logic Explorer](/courses/logic-lab/explorer)
* [Logic Gates](/courses/logic-lab/logic-gates)
* [Programmable Logic](/courses/logic-lab/programmable)

View File

@ -0,0 +1,8 @@
# [Logic Lab](/courses/logic-lab)
* [Logic Lab](/courses/logic-lab)
* [Logic and Expressions](/courses/logic-lab/expressions)
* [Boolean Elements](/courses/logic-lab/elements)
* [Logic Explorer](/courses/logic-lab/explorer)
* [Logic Gates](/courses/logic-lab/logic-gates)
* [Programmable Logic](/courses/logic-lab/programmable)

View File

@ -0,0 +1,207 @@
# Boolean elements
Whether creating equations in Boolean algebra or using them in your programs, you'll form both simple and complex logical expressions that use basic operations to combine the logical conditions.
## Notation
Boolean (logical) equations are expressed in a way similar to mathmatical equations. Variables in Boolean expressions though, have only two possible values, ``true`` or ``false``. For an equation using a logical expression, the equivalant sides of the equal sign ,``=``, will be only ``true`` or ``false`` too.
The following list shows the basic notation elements for Boolean expressions.
* ``~A``: the inverse (**NOT**) of ``A``, when ``A`` is ``true``, ``~A`` is ``false``
* ``A + B``: the value of ``A`` **OR** ``B``
* ``A · B``: the value of ``A`` **AND** ``B``
* ``A ⊕ B``: the value of the exclusive OR (**XOR**) of ``A`` with ``B``
* ``Q``: equivalent result (OUTPUT) value of a logical expression
A resulting value, ``Q``, from a logical expression in is shown like:
``Q`` = ``A + B``
An equation to show logically equivalent expressions (where both sides have the same resulting value) can look like this:
``~(A + B)`` = ``~A · ~B``
## Logical operators
All Boolean expressions result from a combination of conditions and operators. These operators join individual conditons together and evaluate into a single ``true`` or ``false`` condition. The following are the basic logical operators. Their use in both Boolean algebra and in code is shown along with their truth table.
### Identity
Identity means that a result value is the same as the condition itself.
``Q = A``
```block
let A = false
let Q = A
```
#### Example - Blink LEDs on press
```blocks
let A = false
basic.forever(function () {
A = input.buttonIsPressed(Button.A)
if (A) {
basic.showIcon(IconNames.Chessboard)
} else {
basic.clearScreen()
}
basic.pause(100)
})
```
#### Truth table
A | A
-|-
F | F
T | T
### NOT (Negation)
The NOT operator is called negation or the inverse. It takes a single logical value and makes it have the opposite value, ``true`` goes to ``false`` and ``false`` goes to ``true``.
``Q = ~A``
```block
let A = false
let Q = !(A)
```
#### Example - Blink LEDs on not pressed
```blocks
let A = false
basic.forever(function () {
A = input.buttonIsPressed(Button.A)
if (!(A)) {
basic.showIcon(IconNames.Chessboard)
} else {
basic.clearScreen()
}
basic.pause(100)
})
```
#### Truth table
A | ~A
-|-
F | T
T | F
### OR (Disjunction)
The OR operator results in ``true`` when one or more conditions are ``true``.
``Q = A + B``
```block
let A = false
let B = false
let Q = A || B
```
#### Example - Blink on any press
```blocks
let A = false
let B = false
basic.forever(function () {
A = input.buttonIsPressed(Button.A)
B = input.buttonIsPressed(Button.B)
if (A || B) {
basic.showIcon(IconNames.Chessboard)
} else {
basic.clearScreen()
}
basic.pause(100)
})
```
#### Truth table
A | B | A + B
-|-|-
F | F | F
T | F | T
F | T | T
T | T | T
### AND (Conjunction)
The AND operator requires that all conditions are ``true`` for the result to be ``true``.
``Q = A · B``
```block
let A = false
let B = false
let Q = A && B
```
#### Example - Blink on double press only
```blocks
let A = false
let B = false
basic.forever(function () {
A = input.buttonIsPressed(Button.A)
B = input.buttonIsPressed(Button.B)
if (A && B) {
basic.showIcon(IconNames.Chessboard)
} else {
basic.clearScreen()
}
basic.pause(100)
})
```
#### Truth table
A | B | A · B
-|-|-
F | F | F
T | F | F
F | T | F
T | T | T
### XOR (Exclusive OR) #xor
Exclusive OR (XOR) means that only one or the other condition is true. Both conditions can't be true at the same time. XOR is common in Boolean algebra but it has no operator in JavaScript. Its operation can be made from combining a few simple expressions.
``Q = A ⊕ B``
```block
let A = false
let B = false
let Q = (A || B) && !(A && B)
```
#### Example - Blink on one press or the other
```blocks
let A = false
let B = false
basic.forever(function () {
A = input.buttonIsPressed(Button.A)
B = input.buttonIsPressed(Button.B)
if ((A || B) && !(A && B)) {
basic.showIcon(IconNames.Chessboard)
} else {
basic.clearScreen()
}
basic.pause(100)
})
```
#### Truth table
A | B | A ⊕ B
-|-|-
F | F | F
T | F | T
F | T | T
T | T | F

View File

@ -0,0 +1,162 @@
# Logic explorer
As a way to see how the basic logical operators work, we'll make a program to test them with all their possible input values.
## Inputs and output
Make an array called ``||variables:inputs||`` with two values, ``false`` and ``true``, as logical inputs. Add another variable ``||variables:Q||`` to receive the resulting value of a logical expression as output.
```blocks
let inputs = [false, true]
let Q = false
```
## Single input loop
To start with, we'll make a single input test for the variable ``||variables:A||``. The output, in variable ``||variables:Q||``, for the logical operator test will display an icon on the LEDs. A ``true`` value shows a ``t-shirt`` and ``false`` will show a ``small diamond``.
1. Get a ``||loops:for element||`` loop and put it in the ``||loops:on start||``. Rename the ``||variables:index||`` variable to ``||variables:A||`` and switch the ``||variables:list||`` variable to ``||variables:inputs||``.
2. Pull a ``||variables:set Q to||`` block into the ``||loops:for element||`` loop and set the value to ``||logic:false||``.
3. Go find the ``||logic:if then else||`` and put in below the ``||variables:set Q to||``. Pick up a ``||variables:Q||`` in ``||variables:VARIABLE||`` and drop it onto the ``||logic:false||`` to replace it.
4. Move a ``||basic:show icon||`` inside the ``||logic:if then||`` section and change the image to a ``t-shirt``. This is our image for a ``true`` output.
5. Move a ``||basic:show icon||`` inside the ``||logic:else||`` section and change the image to a ``small diamond``. This is our image for a ``false`` output.
6. Just below the ``||logic:if then else||``, put in a ``||loops:pause||``, a ``||basic:clear screen||``, and another ``||basic:pause||`` block. Set the time for each ``||basic:pause||`` to ``500``.
```blocks
let inputs = [false, true]
let Q = false
for (let A of inputs) {
Q = false
if (Q) {
basic.showIcon(IconNames.TShirt)
} else {
basic.showIcon(IconNames.SmallDiamond)
}
basic.pause(500)
basic.clearScreen()
basic.pause(500)
}
```
## Identity test
The identity test is simple. It just makes the output have the same logical value as the input. Set the ``||variables:Q||`` output variable to the ``||variables:A||`` variable.
```block
let A = false
let Q = A
```
### Identity truth table
For the Identity test, these output values will show for the inputs:
A | Q = A
-|-
**false** | ``[basic.showIcon(IconNames.SmallDiamond)]``
**true** | ``[basic.showIcon(IconNames.TShirt)]``
## NOT test
Negation, or inversion, makes the output have the opposite value of the input. So, the output value is NOT the same as the input. Since there are only two possible values, the output is the other value that is NOT the input.
Replace the ``||logic:false||`` in the ``||variables:Q||`` equation with a ``||logic:not||`` operator. Pull the ``||variables:A||`` variable down from the ``||loops:for element||`` loop and drop it inside the ``||logic:not||`` operator.
```block
let A = false
let Q = !A
```
### NOT truth table
For the NOT test, these output values will show for the inputs:
A | ~A
-|-
**false** | ``[basic.showIcon(IconNames.TShirt)]``
**true** | ``[basic.showIcon(IconNames.SmallDiamond)]``
## Two input loop
For the rest of the operator tests, we need to have another input variable. This variable comes from a second ``||loops:for element||`` loop. With one input variable there was just two possible input values. Adding a second input variable increases the number of possible input combinations by two times. Now there will be 4 different input possibilities. This will result in the truth tables having 4 rows for the operator tests.
Go get another ``||loops:for element||`` loop and put it in so that it surrounds all the inside the first loop. Rename the ``||variables:index||`` variable to ``||variables:B||`` and switch the ``||variables:list||`` variable to ``||variables:inputs||``.
```blocks
let inputs = [false, true]
let Q = false
for (let A of inputs) {
for (let B of inputs) {
Q = !A
if (Q) {
basic.showIcon(IconNames.TShirt)
} else {
basic.showIcon(IconNames.SmallDiamond)
}
basic.pause(500)
basic.clearScreen()
basic.pause(500)
}
}
```
## OR test
Now, grab an ``||logic:or||`` operator and replace the ``||logic:not||`` in the ``||variables:Q||`` equation with it. Pull the ``||variables:A||`` variable down from the outside ``||loops:for element||`` loop and drop it in on the left side the ``||logic:or||`` operator. Drag down the ``||variables:B||`` variable down from the inside ``||loops:for element||`` loop and drop it in on the right side the ``||logic:or||`` operator.
```block
let A = false
let B = false
let Q = A || B
```
### OR truth table
For the OR test, these output values will show for the inputs:
A | B | A + B
-|-|-
**false** | **false** | ``[basic.showIcon(IconNames.SmallDiamond)]``
**false** | **true** | ``[basic.showIcon(IconNames.TShirt)]``
**true** | **false** | ``[basic.showIcon(IconNames.TShirt)]``
**true** | **true** | ``[basic.showIcon(IconNames.TShirt)]``
## AND test
Now, switch the ``||logic:or||`` operator type in the ``||variables:Q||`` equation to the ``||logic:and||`` operator type:
```block
let A = false
let B = false
let Q = A && B
```
### AND truth table
For the AND test, these output values will show for the inputs:
A | B | A · B
-|-|-
**false** | **false** | ``[basic.showIcon(IconNames.SmallDiamond)]``
**false** | **true** | ``[basic.showIcon(IconNames.SmallDiamond)]``
**true** | **false** | ``[basic.showIcon(IconNames.SmallDiamond)]``
**true** | **true** | ``[basic.showIcon(IconNames.TShirt)]``
## XOR test
To test XOR, we'll use the XOR expression from [Boolean elements](/courses/logic-lab/elements#xor). Drag and place the ``||logic:LOGIC||`` blocks to make the ``||variables:Q||`` equation to look like this:
```block
let A = false
let B = false
let Q = (A || B) && !(A && B)
```
### XOR truth table
For the XOR test, these output values will show for the inputs:
A | B | A ⊕ B
-|-|-
**false** | **false** | ``[basic.showIcon(IconNames.SmallDiamond)]``
**false** | **true** | ``[basic.showIcon(IconNames.TShirt)]``
**true** | **false** | ``[basic.showIcon(IconNames.TShirt)]``
**true** | **true** | ``[basic.showIcon(IconNames.SmallDiamond)]``

View File

@ -0,0 +1,142 @@
# Logic and expressions
The use and study of _logic_ involves finding a new fact by analyzing whether some other facts together can prove to be true. Some facts, or conditions, when looked at together may prove another fact to be true, or maybe false.
If the temperature outside is below freezing and you don't have a coat, you will feel cold. If you're not sick, then you will feel well. If you can swim or ride in a boat in water, you will stay afloat. These are statements of fact that result from some condition being true.
## Truth statements
By taking some facts and putting them into a logical form, we can make an arithmetic that helps us analyze them and make a conclusion. Using the examples just mentioned, let's turn them into some logical word equations:
* ``Outside temperature is freezing`` **AND** ``I have no coat`` **=** ``I feel cold``
* **NOT** ``sick`` **=** ``I feel well``
* ``I can swim`` **OR** ``I'm in a boat`` **=** ``I'm floating``
You see the AND, NOT, and OR in the example word equations? These are our logical _operators_. Every day we make decisions when we think about one or more facts together using these operators. Sometimes, it's necessary for all facts to be true in order for the conclusion to be true. This is the case when the AND operator is used. When analyzing facts with the OR operator, only on fact needs to be true for the conclusion to be true also.
Making a decision may require more than just one or two facts. When this happens, another operator is needed to combine the facts together to make a conclusion. In the last example word equation, you actually might not be floating if just those two condtions are true. To correctly prove that you're actually floating, you need to state that you're in water too.
* **(**``I can swim`` **OR** ``I'm in a boat``**) AND** ``I'm in water`` **=** ``I'm floating``
To prove that you're floating, the two facts that you can swim or you are in a boat must be made into a single fact that is combined with the other fact that you are also in water. Otherwise, if you're able to swim but still on land, or in a boat that is on the beach, you're not not floating.
## Boolean algebra
As a way to reduce the conditions, or facts as we've called them, into a form that is more compact, an algebra was invented. George Boole made a type of arithmetic (Boolean algebra) that uses symbols for the conditions, the operators, and the result. The conditions are considered as variables that have the value of either ``true`` or ``false``. the operators like AND, OR, and NOT are single character symbols. If we want to change the statement "I'm happy when it's sunny or when I'm eating a donut" into a Boolean equation, we could start by making the conditions into variables.
* Variable ``A`` = ``"It's sunny"``
* Variable ``B`` = ``"I've eaten a donut"``
The result then, is a variable called ``Q`` that is true when you're happy and is a value of an operation of ``A`` with ``B``. This operation is OR which is represented by the ``+`` symbol.
``Q`` = ``A + B``
The result of ``Q`` is ``true`` when either it's sunny or you've had a donut. If other things make you happy, like being on vacation, you could add that to the equation.
* Variable ``C`` = ``"I'm on vacation"``
``Q`` = ``A + B + C``
It could be that you're easy to please and you just have to feel well to be happy. So, you're happy when your NOT sick. We'll use the ``~`` to mean NOT in our equation.
* Variable ``A`` = ``"I'm sick"``
``Q`` = ``~A``
In the situation where all conditions must be true for the result to be true, the conditions use the AND operation. For the sun to shine on you, the sky must be clear and it has to be daytime. We put these two facts together with the AND symbol ``·``.
* Variable ``A`` = ``"The sky is clear"``
* Variable ``B`` = ``"It's daytime"``
* Result ``Q`` = ``"The sun is shining"``
``Q`` = ``A · B``
## Expressions
Sometimes different operations on the same conditions can make equivalent results. If we take the opposite case of the last example where the sun is not shining, the variables for that are:
* Variable ``A`` = ``"The sky is clear"``
* Variable ``B`` = ``"It's daytime"``
* Result ``Q`` = ``"The sun is shining"``
* Result ``~Q`` = ``"The sun is NOT shining"``
To make the opposite of ``"the sun is shining"`` we negate, use the NOT symbol, on both sides of the equation.
``~Q`` = ``~(A · B)``
Now, let's think of the sun NOT shining due to negative conditions. If the sky isn't clear OR it's not daytime, then the sun isn't shining. So, the NOT symbol is put in before the variables for each condition so that ``"the sun is NOT shining"`` has another equation like this:
``~Q`` = ``~A + ~B``
We see that the side with the ``A`` and ``B`` variables in both equations are equivalent to each other since they both equate to ``~Q``:
``~(A · B)`` = ``~A + ~B``
The logic equation now doesn't include the result variable ``Q`` but instead there are two _expressions_ that are logically equivalent on each side.
### ~ hint
#### De Morgan's Thereom
That last equation, ``~(A · B)`` = ``~A + ~B``, demonstrates an inportant property in Boolean algebra. It's called De Morgan's Thereom which says that the inverse (NOT) of a conjunction (AND) is logically equivalent to the disjunction (OR) of two inverses (NOT). Also, the inverse (NOT) of a disjunction (OR) is logically equivalent to the conjunction (AND) of two inverses (NOT).
This easier understood by seeing the Boolean equations for both cases:
``~(A · B)`` = ``~A + ~B``
>-- AND --
``~(A + B)`` = ``~A · ~B``
### ~
## Truth tables
A truth table is a way to see all possible condtions for the variables in a logical expression and to chart the results. Using the truth statement about when it's freezing outside and you have no coat, here's the truth table showing the possible conditions and their results:
It's freezing | I have no coat | I feel cold
-|-|-
false | false | false
false | true | false
true | false | false
true | true | true
<br/>
Because you feel cold only when both conditions are true, the statement becomes an AND expression in Boolean algebra.
* Variable ``A`` = ``"it's freezing"``
* Variable ``B`` = ``"I don't have a coat"``
``A · B`` = ``Q``
A truth table for the variables in the expression have the same values as the table for the truth statement (``true`` and ``false`` are abbreviated to just ``T`` and ``F``).
A | B | Q
-|-|-
F | F | F
F | T | F
T | F | F
T | F | T
<br/>
What would happen if we changed the condition of ``"I have no coat"`` to ``"I have a coat"``? How does that affect truth table about how cold you feel?
It's freezing | I have a coat | I feel cold
-|-|-
false | false | false
false | true | false
true | false | true
true | true | false
<br/>
A | B | Q
-|-|-
F | F | F
F | T | F
T | F | T
T | F | F
<br/>
To write a Boolean equation for when you feel cold, we find the condtions in the table where ``Q`` is ``true``. Here we see that you will feel cold only in one row, when condition ``A`` is ``true`` and condtion ``B`` is ``false``. The Boolean equation for these conditions is this:
``A · ~B`` = ``Q``

View File

@ -0,0 +1,87 @@
# Logic Gates
![OR gate symbol](/static/courses/logic-lab/logic-gates/full-adder.png)
In the real world digital devices aren't the abstract logical expressions of Boolean algebra, but they are implementations of these expressions in hardware. The logical expressions are translated into device structures called _logic gates_. A logic gate is both a symbolic representation of a logical operation and, when used in digital electronics, it can is an actual circuit in hardware. A single logic gate is usually made of several transistors an shares space with many others in an integrated circuit.
Each of the basic operators we learned about in the [expressions](/courses/logic-lab/expressions) section have a gate symbol. The symbol takes the place of the operator and the variables are the inputs to the gate. The resulting value from the expression equation is the output of the gate. The output of a gate can be a final result or it can be connected as an input to yet another gate.
## Gate symbols
Logic gates are symbols that can directly replace an expression in Boolean arithmetic. Each one has a different shape to show its particular function. The inputs (Boolean variables) enter at the left of the symbol and the output leaves from the right. When combined together, several gates can make a complex logical evaluation system that has many inputs and outputs. Digital computers are designed by connecting thousands, or millions, of these gates to together.
### NOT gate
The NOT gate is a forward arrow with a small circle at the output. The circle part of the symbol is what says that the output is negating the input.
![NOT gate symbol](/static/courses/logic-lab/logic-gates/not-gate.png)
### OR gate
Th OR gate has a curved input side and a sharp pointed output.
![OR gate symbol](/static/courses/logic-lab/logic-gates/or-gate.png)
### AND gate
The AND gate has a flat input side and round output side.
![AND gate symbol](/static/courses/logic-lab/logic-gates/and-gate.png)
### Exclusive OR (XOR) gate
The exclusive or gate symbol is just like the OR gate but it has an additonal curved line crossing the inputs.
![XOR gate symbol](/static/courses/logic-lab/logic-gates/xor-gate.png)
## Combined logic
When you connect multiple gates together you have a combined logic system or _combinatorial logic_. To design a combined logic system we can use a truth tables to match logical outputs for out various input conditions. Boolean expressions are written from the conditions in the table. Then, we can directly convert the expression into a diagram of logic gates.
You might remember that back in [Boolean elements](/courses/logic-lab/elements#xor) we saw that there was no operator to use in code for XOR. It was was made up using a combination of AND, OR, and NOT operators:
```block
let A = false
let B = false
let Q = (A || B) && !(A && B)
```
Let's map the input and output conditions in a truth table for a combined logic system for XOR. We'll find all the conditions that cause a ``true`` result and create a Boolean expression for them.
A | B | A ⊕ B
-|-|-
F | F | F
F| T | T
T| F | T
T | T | F
<br/>
There are two conditions where the result column has ``true`` values. The first conditon is when ``A`` is ``false`` and ``B`` is ``true`` which is expressed as ``~A · B``. The second conditon is when ``A`` is ``true`` and ``B`` is ``false`` which is expressed as ``A · ~B``. Our XOR expression is ``true`` when one of these conditions are ``true`` which is written like:
``A ⊕ B`` = ``(~A · B) + (A · ~B)``
In code this expression is formed with these logic blocks:
```block
let A = false
let B = false
let Q = (!A && B) || (A && !B)
```
Coverting the equation to logic gates makes the following diagram. Notice how each gate "connects" the variables together just like the logic blocks in the code above.
![Combinatorial XOR first version](/static/courses/logic-lab/logic-gates/combinatorial1-xor.png)
However, if we take the other two unused conditions from the truth table that make the XOR operation ``false``, can make the negative equation for XOR, called a NXOR:
``~(A ⊕ B)`` = ``(~A · ~B) + (A · B)``
To get back to ``A ⊕ B`` we have to negate this negative equation. Then, with the help of [De Morgan's Thereom](/courses/logic-lab/expressions#de-morgan-s-thereom), we get a different equation for XOR but it's still logically equivalent to the original one.
``A ⊕ B`` = ``(A + B) · ~(A · B)``
When this equation is converted to logic gates, there's one fewer gate than in the first diagram.
![Combinatorial XOR second version](/static/courses/logic-lab/logic-gates/combinatorial2-xor.png)
This diagram has less complexity than the first one. Reduction in the number of gates to accomplish the same logical result is one of the primary goals for digital logic design. For electronic devices, this allows more gates to use the limited amount of space on an integrated circuit.

View File

@ -0,0 +1,231 @@
# Programmable logic
Logic gates are formed by connecting transistors together on a semiconductor material to make an integrated circuit. The wafers, or chips, of semiconductor contain lots of logic gates that make up different types of devices which work together to read, store, calculate, and transmit digital information.
Most integrated circuits contain a specific arrangement logic gates at the time they are manufactured. Because of their physical and chemical properties, some semiconductors can let you change connections between the gates after the device is manufactured. By applying special voltages at programming pins, a custom arrangement of gates can be "programmed" into the integrated circuit. These types of semiconductors are part of a category of electronics called _Programmable Logic Devices (PLD)_. There are many different kinds. Some of them you program only once and others you can erase the original gate arrangement and program in new ones multiple times.
We can use the @boardname@ to create our own PLD. The digital pins are the inputs for the logic circuits. The logic gates we program are logical expressions in code that combine the digital inputs we read from the pins. The result of the expression is written to a digital output pin.
## Board PLD
The physical idea of using your board as a PLD looks like this:
![Board with to logic inputs and one output](/static/courses/logic-lab/pld/mbit-pld.png)
The logic inputs for `A` and `B` are connected to digital input pins. The resulting output `Q` is connected to a digital output pin. We can make a general representation of your board as a PLD by selecting some digital pins to use as inputs and outputs for our programmable logic.
![Generic PLD representation](/static/courses/logic-lab/pld/generic-pld.png)
By "connecting" the pins together with code, we can program virtual logic gates and make the board act like a PLD. With multiple pins and some more code, we can even create a combined logic circuit.
![Gates inside the PLD diagram](/static/courses/logic-lab/pld/not-and-or.png)
## Programmable NOT gate
The **NOT** gate takes the logic value of the input and inverts it at the output. This is a single input gate using just the **P0** pin for input.
![NOT gate with pin assignments](/static/courses/logic-lab/pld/not-gate-pins.png)
The **NOT** gate is wired using alligator test clips as shown in the following diagram. The output clip is connected to pin **P2**.
![NOT gate wiring diagram](/static/courses/logic-lab/pld/not-gate-pld.png)
The script to program the **NOT** gate is simply a logical inverse of ``||pins:digital read pin||`` written to an output pin with ``||pins:digital write pin||``.
```block
if (pins.digitalReadPin(DigitalPin.P0) > 0) {
pins.digitalWritePin(DigitalPin.P2, 0)
} else {
pins.digitalWritePin(DigitalPin.P2, 1)
}
```
## Programmable OR gate
The **OR** gate takes two inputs and makes the output ``true`` if any input is ``true``. The **P0** and **P1** pins are the inputs.
![OR gate with pin assignments](/static/courses/logic-lab/pld/or-gate-pins.png)
The **OR** gate is wired using alligator test clips as shown in this diagram. The output clip is connected to pin **P2**.
![OR gate wiring diagram](/static/courses/logic-lab/pld/or-gate-pld.png)
The script to program an **OR** gate is two ``||pins:digital read pin||`` blocks, evaluated with an ``||logic:or||``, and the result is written to an output pin with ``||pins:digital write pin||``.
```block
if ((pins.digitalReadPin(DigitalPin.P0) > 0) || pins.digitalReadPin(DigitalPin.P1) > 0) {
pins.digitalWritePin(DigitalPin.P2, 1)
} else {
pins.digitalWritePin(DigitalPin.P2, 0)
}
```
## Programmable AND gate
The **AND** gate takes two inputs and makes the output ``true`` if both inputs are ``true``. The **P0** and **P1** pins are the inputs.
![AND gate with pin assignments](/static/courses/logic-lab/pld/and-gate-pins.png)
The **AND** gate is wired using alligator test clips as shown in the next diagram. The output pin is connected to pin **A2**.
![AND gate wiring diagram](/static/courses/logic-lab/pld/and-gate-pld.png)
The script for an **AND** gate is two ``||pins:digital read pin||`` blocks, evaluated with an ``||logic:and||``, and the result is written to an output pin with ``||pins:digital write pin||``.
```block
if ((pins.digitalReadPin(DigitalPin.P0) > 0) && pins.digitalReadPin(DigitalPin.P1) > 0) {
pins.digitalWritePin(DigitalPin.P2, 1)
} else {
pins.digitalWritePin(DigitalPin.P2, 0)
}
```
## Combined logic
You can program your board to have multiple logic gates that operate on the two inputs. Just combine the three logic gate scripts from above into one ``||loops:forever||`` loop. If you have an expansion connector for your @boardname@, you could program multiple outputs for your logic system. You could also use one extra input pin as an observer pin to test the outputs of your combined logic. The different outputs feedback to the observer pin so it will see what their logic levels are. Here's a schematic for a multiple gate system.
![micro:bit NOT, AND, OR gate PLD](/static/courses/logic-lab/pld/not-and-or-pld.png)
The combined logic for our multiple gate PLD is programmed like this:
```blocks
let A = false
let B = false
basic.forever(function () {
A = pins.digitalReadPin(DigitalPin.P0) > 0
B = pins.digitalReadPin(DigitalPin.P1) > 0
if (A) {
pins.digitalWritePin(DigitalPin.P2, 0)
} else {
pins.digitalWritePin(DigitalPin.P2, 1)
}
if (A || B) {
pins.digitalWritePin(DigitalPin.P3, 1)
} else {
pins.digitalWritePin(DigitalPin.P3, 0)
}
if (A && B) {
pins.digitalWritePin(DigitalPin.C4, 1)
} else {
pins.digitalWritePin(DigitalPin.C4, 0)
}
basic.pause(100)
})
```
### Logic observer
As easy way to see what the outputs of our PLD are, you can use the **P6** pin as a logic observer input and display the letter ``T`` for a ``true`` output value and the letter ``F`` for ``false``.
```blocks
basic.forever(function () {
if (pins.digitalReadPin(DigitalPin.C6) > 0) {
basic.showString("T")
} else {
basic.showString("F")
}
basic.pause(100)
})
```
### Input tests
You can test different input combinations by connecting the other ends of alligator clip leads on pins **P0** and **P1** to either **GND** or **3V**. The **GND** pin will make a ``false`` input value and **3V** will make a ``true`` input value.
If you have an expansion connector for your @boardname@, you can use the combined logic script and the logic observer code to check each ouptput. Move the other end alligator clip lead connected to the observer pin **P6** to each of the outputs **P2**, **P3**, and **P4** to see the result of the logic operation programmed for those pins.
If you just have the @boardname@ by itself, you can test each logic function using only the scripts for each logic gate. Just put the script inside a ``||loops:forever||`` and place a ``||basic:show string||`` block with the logic letter after each ``||pins:digital write pin||``.
This is the code for the **NOT** gate:
```blocks
basic.forever(function() {
if (pins.digitalReadPin(DigitalPin.P0) > 0) {
pins.digitalWritePin(DigitalPin.P2, 0)
basic.showString("F")
} else {
pins.digitalWritePin(DigitalPin.P2, 1)
basic.showString("T")
}
basic.pause(100)
})
```
#### NOT truth table
As an example, here's the truth table with pin voltages for the **NOT** operation:
P0 | P2 | Display
-|-|-
GND | 3V | ``[basic.showString("T")]``
3V | GND | ``[basic.showString("F")]``
<br/>
Do test connections for the inputs and check the results for the **OR** and **AND** outputs.
#### OR truth table
P0 | P1 | P3 | Display
-|-|-|-
GND | GND | ? | ?
GND | 3V | ? | ?
3V | GND | ? | ?
3V | 3V | ? | ?
#### AND truth table
P0 | P1 | P4 | Display
-|-|-|-
GND | GND | ? | ?
GND | 3V | ? | ?
3V | GND | ? | ?
3V | 3V | ? | ?
### XOR device
As we learned earlier, the **XOR** gate operation is made up from several other gates. The result `Q` was made from this expression in code:
```block
let A = false
let B = false
let Q = (!A && B) || (A && !B)
```
We'll make an **XOR** gate by programming a combined logic device for it. This time let's say that the whole @boardname@ is a programmed **XOR** gate.
![XOR symbol with board image](/static/courses/logic-lab/pld/xor-mbit.png)
Let's use the same wiring diagram as we did for the **OR** gate using **P0** and **P1** as input pins with **P2** as the output pin.
![XOR gate wiring diagram](/static/courses/logic-lab/pld/xor-gate-pld.png)
Our logic gate script is a bit different this time. To simplify forming the expression for **XOR**, we'll assign variables to the input and output values.
```blocks
let A = false
let B = false
basic.forever(function () {
A = pins.digitalReadPin(DigitalPin.P0) > 0
B = pins.digitalReadPin(DigitalPin.P1) > 0
if (!(A) && B || A && !(B)) {
pins.digitalWritePin(DigitalPin.P2, 1)
basic.showString("T")
} else {
pins.digitalWritePin(DigitalPin.P2, 0)
basic.showString("F")
}
basic.pause(100)
})
```
Connect the inputs for **P0** and **P1** according to the **XOR** truth table and see if the outputs in the table match your results.
P0 | P1 | P2 | Display
-|-|-|-
GND | GND | GND | ``[basic.showString("F")]``
GND | 3V | 3V | ``[basic.showString("T")]``
3V | GND | 3V | ``[basic.showString("T")]``
3V | 3V | GND | ``[basic.showString("F")]``

View File

@ -0,0 +1,19 @@
# Bluetooth HF2
The Bluetooth HF2 service implements a subset of [HF2](https://github.com/Microsoft/uf2/blob/master/hf2.md), namely the serial message logging.
## Service
### HF2 service
* UUID: ``b112f5e6-2679-30da-a26e-0273b6043849``
### TX Characteristic
* Optional
* UUDI: ``b112f5e6-2679-30da-a26e-0273b604384a``
* NOTIFY only
This characteristic mostly emits HF2 serial messages. The first byte contains the type of message and length in the lower 6 bits. The message contains up to 19 bytes.
This service is supported by the MakeCode editor to receive messages.

View File

@ -0,0 +1,48 @@
# Crocodile clips
The large holes at the bottom of the board are designed to attach alligator/crocodile clips
to create electrical circuit with other components.
# ~hint
**No crocodile clips!?!?!** Use [wires or aluminium foil](/device/foil-circuits)!
# ~
## Connecting crocodile clips
The hole for ``P0`` and ``GND`` allow to grab the board on the side which makes for a great grip.
![](/static/mb/device/croc-clips/crocclipsclamped.jpg)
Pass one jaw in the hole and grab the side of the board with the other jaw.
![](/static/mb/device/croc-clips/sideclamp.jpg)
For the center holes, ``P1`` and ``P2``, you can also grab the bottom of the board but they are a bit harder to grip.
You can also grip the board between the jaws. In which case, you will want to make sure to avoid overlapping the jaws
with the other pins as it will create short-circuit in the board.
![](/static/mb/device/croc-clips/badclamp.jpg)
Adding a little tape helps keeping the crocodile clips in place.
![](/static/mb/device/croc-clips/frontclamp.jpg)
## Example: on pin pressed with random numbers
This example displays a random number every time the crocodile clip holds `GND` then connects and disconnects the `P0` pin.
Each time the crocodile clip is firmly connected and disconnected from pin `P0`,
the @boardname@ will return a random Number between 0 and the parameter limit.
```blocks
input.onPinPressed(TouchPin.P0, () => {
basic.showNumber(randint(0, 10))
})
```
## See also
[micro:bit pins](/device/pins)

View File

@ -0,0 +1,16 @@
# Data Analysis
In addition to learning programming, the @boardname@ is a fantastic tool for observing and measuring things that happen in the natural world. The sciences rely on methods of observation, information gathering, and analysis. Using the @boardname@ with MakeCode, you can use the sensors and inputs to measure and capture physical events that occur. Measurement data can then be sent for recording by other devices like another @boardname@ or a personal computer.
![Data graph logo](/static/mb/device/data-analysis/data-analysis.jpg)
The Data Viewer in the MakeCode editor allows you to stream and log data from your programs. It will do this when you write data values using the **[serial](/reference/serial)** write functions. When you try your code in the simulator or connect with USB, each value you write is saved and collected as a log for you to analyze later if you want.
These topics describe how to analyze your data using MakeCode with the @boardname@:
* [Plotting with LEDs](./data-analysis/led-plotting)
* [Viewing your data](./data-analysis/viewing)
* [Writing data](./data-analysis/writing)
* [Generating data](./data-analysis/generating)
* [Analyze](./data-analysis/analyze)
* [Remote data collection](./data-analysis/remote)

View File

@ -0,0 +1,110 @@
# Analyze
When it recognizes that data in the console has a format it can show in a chart, the Data Viewer will display it along with any new values that arrive. It also creates multiple charts if it notices more than one value stream in the incoming data.
If you want to keep the data and work with it later, you can download it and save it to your computer or mobile device.
## Charting value streams
As an example, let's generate some data for two values. The first value `x` makes a line on the chart. The second value is the square of the first value `x**2`shifted by `5`. This second value will show a chart of a parabola.
```blocks
for (let x = 0; x <= 10; x++) {
serial.writeValue("x", x)
serial.writeValue("y", (x - 5)**2)
basic.pause(1000)
}
```
![Charts of line and parabola](/static/mb/device/data-analysis/line-parabola.jpg)
Since we used ``||serial:serial write value||`` for each value, there are two charts, one for the `x` stream and the other for the `y` stream. Also, the values shown in the console window are formatted as name value pairs:
```
x:0
y:25
x:1
y:16
...
```
## Charting by data lines
Instead of writing multiple values separately, we can combine them in an array and write them together at once. Using the last example, let's combine each line and parabola value into an array.
```blocks
for (let x = 0; x <= 10; x++) {
serial.writeNumbers([x, (x - 5) ** 2])
basic.pause(1000)
}
```
![One chart of both line and parabola](/static/mb/device/data-analysis/line-parabola2.jpg)
This time both values are shown on the same chart. We used ``||serial:serial write numbers||`` to send both values at the same time. Instead of being written as name value pairs, the values are combined into one line of comma separated values (CSV). The Data Viewer recognizes the values as one stream and puts multiple data lines on the same chart. The console shows the data in CSV format:
```
0,25
1,16
2,9
3,4
...
```
## Raw data
The data in the console window appears exactly like it's written by your program. The data your program writes is called "raw" data. The Data Viewer reads the data and "cooks" it by deciding how to display it in a way that's useful to you.
You can select and copy the raw data from the console and paste it into another program if you want to work with it outside of the MakeCode editor. Also, there is a copy button next to the console window that let's you easily copy the raw data with one click.
![Copy button for console data](/static/mb/device/data-analysis/copy-button.gif)
## Downloading your data
You can download your data to save it to view in another program. Click the **Download** button above the chart view.
![Download button highlighted](/static/mb/device/data-analysis/download-button.jpg)
The data is formatted again and saved in file with a name like:
``microbit-data-13-20-2018-14-18-15-0700.csv``
The filename contains the date and time when the data was downloaded. If you open the file in an editor you can see how the Data Viewer reformatted it from how it was in the console.
### Download format
The download file will contain your data as lines of CSV. The downloaded data from the first example will look something like this:
```
sep=
time (source1) x time (source1) y
0 0 0 25
1.018 1 1.026 16
2.049 2 2.045 9
3.062 3 3.059 4
4.064 4 4.074 1
5.078 5 5.078 0
6.115 6 6.112 1
7.097 7 7.112 4
8.131 8 8.128 9
9.145 9 9.145 16
10.148 10 10.16 25
```
The first line says what character is used as the value separator. Characters other than a comma can be used as separators. The Data Viewer choose to use a `TAB` character. The next line contains the headings for the values. These are the names of each value when name value pairs are written to the console. Also, a time value (timestamp) is included for each value. The timestamp is the amount of time since the start of the program when the value was written.
The remaining lines contain the data values and their timestamps. Each line has one occurrence of each value. So, for the example data above, each new `x` and `y` value is put together on the same line.
### Loading into a spreadsheet
Each line of data is placed into a row in the spreadsheet. The separators tell the spreadsheet which column the values go into.
![CSV data in spreadsheet](/static/mb/device/data-analysis/spreadsheet-data.jpg)
### Analyze in the spreadsheet
Spreadsheets are powerful tools for analyzing and looking at relationships in your data. Most spreadsheet programs can do advanced charting too. Here's a chart of our example data. You'll notice that it looks similar to the chart displayed by the MakeCode editor.
![Spreadsheet with chart](/static/mb/device/data-analysis/spreadsheet-chart.jpg)
The spreadsheet knows how to take the headings from the download file and use them as labels for the individual data lines.

View File

@ -0,0 +1,111 @@
# Generating data
## Sensor values
Most of the data you want to record probably comes from values measured by the sensors. The sensor values are read using ``||input:Input||`` blocks. They return to your program the current value measured by the sensor.
```block
serial.writeValue("accelX", input.acceleration(Dimension.X))
```
```block
serial.writeValue("heading", input.compassHeading())
```
```block
serial.writeValue("light", input.lightLevel())
```
```block
serial.writeValue("forceX", input.magneticForce(Dimension.X))
```
## Pin data
External sensors and devices connected to the board are read using the ``||pins:Pins||`` blocks. Here are some examples of reading the pins and reporting measurements from devices:
### Soil moisture
```block
let moisture = pins.analogReadPin(AnalogPin.P0)
serial.writeValue("moisture", moisture)
```
### Closed door detector
```block
pins.onPulsed(DigitalPin.P0, PulseValue.Low, () => {
serial.writeValue("DoorClosed", 1)
})
```
### I2C humidity sensor
```block
let humidity = pins.i2cReadNumber(61, NumberFormat.Int8LE)
serial.writeValue("humidity", humidity)
```
## Human events
Sometimes we want to track human interactions with a device. These events might be button presses, gestures, or pin touches.
### Example: Button tracker
Run this example in the editor and switch to the Data Viewer. Watch it plot your button presses like pulse events in the chart.
```blocks
let buttonValue = 0
basic.forever(() => {
if (input.buttonIsPressed(Button.A)) {
buttonValue = 1
} else {
buttonValue = 0;
}
serial.writeValue("ButtonA", buttonValue)
basic.pause(200)
})
```
Writing an additional value creates another stream that will appear in a separate chart. Adding and event for another button press, we can plot pulses on a second chart.
```blocks
let buttonValue = 0
basic.forever(() => {
if (input.buttonIsPressed(Button.A)) {
buttonValue = 1
} else {
buttonValue = 0;
}
serial.writeValue("ButtonA", buttonValue)
if (input.buttonIsPressed(Button.B)) {
buttonValue = 1
} else {
buttonValue = 0;
}
serial.writeValue("ButtonB", buttonValue)
basic.pause(200)
})
```
## Time and timestamps
A timestamp marks when you read a value or detect that an event happens. These are commonly written along with other data values as an additional data item. The data viewer will create timestamps for values it sees when you write them. If you are downloading and saving data from the Data Viewer, it creates the timestamps for you and you don't need to add them.
If you need your own time values, you can make them from the **running time** of the board.
```block
input.onGesture(Gesture.Shake, () => {
serial.writeValue("shaken", input.runningTime())
})
```
Also, you can write your own custom CSV with your own timestamp:
```blocks
serial.writeLine("timestamp,temp,light")
basic.forever(() => {
serial.writeNumbers([input.runningTime(), input.temperature(), input.lightLevel()])
basic.pause(30000)
})
```

View File

@ -0,0 +1,97 @@
# Plotting data with LEDs
To quickly see and record your data values, use the ``||led:plot bar graph||`` block. It will plot a value on the LED screen and write a number to console at the same time.
```blocks
basic.forever(() => {
let i = 0
while (i < 25) {
led.plotBarGraph(i, 25)
i += 2
basic.pause(1000)
}
})
```
Here's a plot of values from `1` to `25`:
```sim
basic.forever(() => {
let i = 0
while (i < 25) {
led.plotBarGraph(i, 25)
i += 2
basic.pause(1000)
}
})
```
## Plot range
A number of LEDs will light up to show how much the value is related to the _high_ number in the second argument. The high number sets the _range_ of values to show. If the high number is set to `16` and you want to plot the value of `8`, then that value is half of the range.
```block
led.plotBarGraph(8, 16)
```
So, about half of the LEDs will light up to represent that number.
```sim
basic.forever(() => {
basic.clearScreen()
basic.showString("8 up to 16")
basic.clearScreen()
basic.pause(500)
led.plotBarGraph(8, 16)
basic.pause(2000)
})
```
## Autoranging
If you don't know what the largest number to plot will be, then you can set the high number to `0`. This lets the largest value plotted be the range value. This is called _autoranging_. To see how it works, make an array of numbers and plot them. Put a large value in the middle of the array with smaller values before and after it. Watch as the same values are plotted with fewer lights after the largest number is plotted.
```blocks
let values = [4,8,12,16,50,4,8,12,16]
for (let i = 0; i < values.length; i++) {
led.plotBarGraph(values[i], 0)
basic.pause(1000)
}
```
## Recording plotted values
The ``||led:plot bar graph||`` also sends the number value it's plotting to the console. You can see the output in the Data Viewer. It charts the values and they appear as individual numbers in console.
```blocks
input.onButtonPressed(Button.B, () => {
for (let i = 0; i < 25; i++) {
if (i % 2 > 0) {
led.plotBarGraph(0, 0)
} else {
led.plotBarGraph(i, 24)
}
basic.pause(500)
}
})
```
The chart for the the plotted values from the example above:
![Plot LEDs chart result](/static/mb/device/data-analysis/plot-bar-graph.jpg)
The values appear in the console as just one number per line:
```
0
2
0
4
0
6
...
```
## See also
[plot bar graph](/reference/led/plot-bar-graph)

View File

@ -0,0 +1,161 @@
# Remote data collection
If you have more than one @boardname@ you can setup one of them to receive data sent by radio from other @boardname@s. Remote @boardname@s can take measurements and send them to a board that's connected by USB to a computer. The @boardname@ connected to the computer is the data recorder and writes the received data to the serial port.
![Remote micro:bit sending](/static/mb/device/data-analysis/radio-zap.jpg)
## Receiver @boardname@
Connect the @boardname@ to a computer with a USB cable. The data received over radio is sent to the computer with this connection using writes to the serial port. If you have the [Windows 10 MakeCode](https://www.microsoft.com/store/apps/9PJC7SV48LCX) app, you can view the received data with the [Data Viewer](./viewing) in the editor. Otherwise, you need a _serial terminal_ app or some other program that can read from the computer's serial port.
The receiving @boardname@ sets a radio group number on which to listen for incoming messages.
```block
radio.setGroup(99)
```
The receiver then waits to receive a packet (radio message) from the sender which contains the data to record. This happens inside an ``||radio:on received number||`` block. If the sending @boardname@ is measuring temperature at a remote location (somewhere else in the room maybe), the receiver will write the value received as a temperature measurement to the serial port.
```blocks
radio.setGroup(99)
radio.onReceivedNumber(function (receivedNumber) {
basic.showNumber(receivedNumber)
serial.writeValue("TempCelsius", receivedNumber)
})
```
## Remote sender @boardname@
A remote @boardname@ reads its measurement values and sends them to the same radio group as the receiver.
```block
radio.setGroup(99)
```
A typical measurement program might read a sensor value continuously. Depending on how much the values change, the measurement program could contain the read operation in a loop with a delay interval. In the example here, the delay is one minute between each read of a temperature value. The value is sent on the current radio group with ``||radio:radio send number||``.
```blocks
let temperature = 0
radio.setGroup(99)
basic.forever(() => {
temperature = input.temperature()
basic.showNumber(temperature)
radio.sendNumber(temperature)
basic.pause(60000)
})
```
## Sending multiple values
The remote @boardname@ in the previous example sent a single value which was temperature. The receiver understands that the incoming value is a temperature measurement. If you want the remote to also send the current amount of light measured, the receiver won't know that this other value isn't a temperature reading.
The sender code is modified to use a value packet instead of just a number message. Here's the sender program sending both temperature and light values with ``||radio:radio send value||``.
```blocks
let temperature = 0
let lightLevel = 0
radio.setGroup(99)
basic.forever(() => {
temperature = input.temperature()
radio.sendValue("temperature", temperature)
lightLevel = input.lightLevel()
radio.sendValue("light", lightLevel)
basic.pause(60000)
})
```
Here's the program for the receiver to record both temperature and light:
```blocks
radio.setGroup(99)
radio.onReceivedValue(function (name: string, value: number) {
basic.showString(name + ":")
basic.showNumber(value)
serial.writeValue(name, value)
})
```
The receiver program uses just one ``||radio:on received number||`` event to record the values. The ``name`` and the ``value`` are parameters for the event block so both temperature and light values are received here.
## Multiple remote stations
For more complex data recording situations, you might need to measure sensor values from multiple locations at the same time. This means that there is more than one remote @boardname@ (station) measuring data.
### Separate radio groups
You could add another receiver @boardname@ and set it to a different radio group. This way you can copy the same programs to each sender and receiver and just change the radio group number for the matched boards. This solution, though, means you need an extra receiver board and another computer to record the data from the second station.
### Station identifiers
A different solution from using more than one radio group is to still have just one receiver on one group but make the different stations send identifiers with their values.
This is done with ``||radio:radio set transmit serial number||`` which tells the radio to add the board's serial number to the packet it sends. The serial number is included with the ``name`` and ``value`` so the receiver can know what station it comes from.
```block
radio.setTransmitSerialNumber(true)
```
The sender's program with the identifier added:
```blocks
let temperature = 0
radio.setGroup(99)
radio.setTransmitSerialNumber(true)
basic.forever(() => {
temperature = input.temperature()
basic.showNumber(temperature)
radio.sendValue("temperature", temperature)
basic.pause(60000)
})
```
The program on the receiver board can use the serial number to make a name value pair that the [Data Viewer](./writing#name-value-pairs) can recognize:
```blocks
let id = 0;
radio.setGroup(99)
radio.onReceivedValue(function (name: string, value: number) {
id = radio.receivedPacket(RadioPacketProperty.SerialNumber)
basic.showString(name + ":")
basic.showNumber(value)
serial.writeValue(id + "_" + name, value)
})
```
The serial number, ``id``, is used as a _prefix_ for the ``name`` to identify which station the ``value`` came from.
### Extended data recording
If you're recording data to save on a computer for analysis or other uses outside of the MakeCode editor, you can use the ``||radio:radio write received packet to serial||`` block to format it for you. This function will format the data from the received packet into a [JSON](https://en.wikipedia.org/wiki/JSON) string and write it to the serial port, all in one operation. It's used just like this:
```blocks
radio.onReceivedNumber(function (receivedNumber) {
radio.writeReceivedPacketToSerial();
});
```
The output to the serial port is a line of text with these name value pairs:
* **t** - time: the time when the packet was sent
* **s** - serial: the serial number of the board that sent the packet (if enabled)
* **n** - name: the name for the data value from the string part of the packet
* **v** - value: the data from the number part of the packet
It's sent in this format to the serial port:
```json
{"t":3504,"s":1951284846,"n":"temperature","v":19}
{"t":3823,"s":1951284846,"n":"temperature","v":20}
{"t":4143,"s":1951284846,"n":"temperature","v":20}
{"t":4463,"s":1951284846,"n":"temperature","v":18}
{"t":4781,"s":1951284846,"n":"temperature","v":21}
{"t":5102,"s":1951284846,"n":"temperature","v":17}
```
## See also
[radio](/reference/radio), [serial write value](/reference/serial/write-value),
[write received packet to serial](/reference/radio/write-received-packet-to-serial)
```package
radio
```

View File

@ -0,0 +1,50 @@
# Viewing your data
## Recording data
When your code is writing data, and the editor is recording it, the **Show data** button is displayed in the simulator under the board and simulation controls.
![Show data button](/static/mb/device/data-analysis/show-data.jpg)
## Data view window
If you press the **Show data** button, the editor will switch from the **Blocks** or **JavaScript** view to display a charting window and a text console.
![Data chart and console](/static/mb/device/data-analysis/data-view.jpg)
The console window under the graph will show the data in the format it was written. The chart is the visual representation of the values appearing on the console.
## Time scroll
The chart will display new data as it arrives. The chart will scroll with time to continue to display new values.
![Data chart time scroll](/static/mb/device/data-analysis/time-scroll.gif)
## Data view controls
The chart window shows the data view controls on top of the chart.
![Data view controls](/static/mb/device/data-analysis/data-view-controls.jpg)
Here's what the controls do:
**Return**: The return button switches the view back to previous code window (either Blocks or JavaScript).
![Return button](/static/mb/device/data-analysis/return-button.jpg)
**Source**: Tells you where the data is coming from. If the code writing the data is running in the simulator, then the source is **Simulator**. If your code is running on the @boardname@ and connected by USB, the source is **@boardname@**.
![Source label](/static/mb/device/data-analysis/source-label.jpg)
**Pause**: The pause button will stop the display of new values and stop scrolling. When you resume, the chart starts again with the current value written.
![Pause button](/static/mb/device/data-analysis/pause-button.jpg)
**Resume**: The resume button will start displaying new values after the **Pause** button was pressed.
![Resume button](/static/mb/device/data-analysis/resume-button.jpg)
**Download**: The download button collects the data your code has written and downloads it to your computer as a file called something like _data-11-2018-23-00-0700.csv_. The numbers in the filename are the date and time when the file is created. The file may automatically open in an editor or spreadsheet if one of those programs is associated with _csv_ files.
![Download button](/static/mb/device/data-analysis/download-button.jpg)

View File

@ -0,0 +1,187 @@
# Writing data
While you're using MakeCode, all data written by the [serial](/reference/serial) functions is recorded by the MakeCode editor. This happens when you try your code in the simulator and also when the @boardname@ is connected to a computer running the MakeCode app with USB.
## Data formats
The Data Viewer recognizes the format of your output and decides how to display it. If your data is a _stream_ of values it will plot them in the chart window and show them as text in the console. If your data is just text information, it appears only in the console window.
You can write data in these format types:
* Text ([string](/types/string)): `"Hello there!"`
* [Numbers](/types/number): `"354"`
* [Number arrays](/types/array): `"11,3,45,76"`
* Name value pairs: `"accelY:956"`
## Text output
Text is formed by simply using string data. The text data is not recorded in the console until a complete "line" of text is written. A line is just a string with some special characters (ones you don't actually see printed) at the end. You can write several strings, say:
```block
serial.writeString("Hello ");
serial.writeString("from ")
serial.writeString("micro:bit")
```
This text, though, won't appear in the editor console until it becomes a complete line. If you follow the string writes with a line in your code, then the line will show up:
```block
serial.writeString("Hello ")
serial.writeString("from ")
serial.writeString("micro:bit")
serial.writeLine("")
```
Text output is used mostly for messages since number formats have meaning when used for data analysis.
The blank ``||serial:serial write line||`` adds the special line ending characters and turns the previous strings into a complete line of text. The whole line could simply be written out with just one function:
```block
serial.writeLine("Hello from micro:bit")
```
When you're writing only text, it appears only in the console view and not in the chart window. This example writes four messages of text:
```block
for (let i = 0; i < 4; i++) {
serial.writeLine("Hello from micro:bit " + i)
}
```
The four messages appear in the console window:
![Console output](/static/mb/device/data-analysis/console-output.jpg)
## Writing numbers
In order for the Data Viewer to recognize a number as value and show in the chart, it has to be in a line by itself. So, numbers written individually won't be charted:
```block
serial.writeNumber(1)
serial.writeNumber(2)
serial.writeNumber(3)
```
The numbers don't show up as single values because they appear in the output as a string: `"123"`. Also, the string doesn't form a complete line so it doesn't show up in the console window either. You could add a blank line to the numbers already written. If you did this, you would have just one value charted which is `123`:
```block
serial.writeNumber(1)
serial.writeNumber(2)
serial.writeNumber(3)
serial.writeLine("")
```
Here's a way to chart the numbers individually:
```block
for (let i = 0; i < 4; i++) {
serial.writeNumber(i)
serial.writeLine("")
}
```
It's much better though to use a value stream by writing the numbers as [name value pairs](#name-value-pairs).
## Number arrays
Numbers in arrays are displayed on separate data lines on the same chart. You can use ``||serial:serial write numbers||`` to write several values at once. The numbers are written to the output as _comma separated values_ (CSV). The array of numbers:
```block
let values = [0,1,2,3,4];
```
is written to the output in the form of a CSV string as: `"0,1,2,3,4"`.
The Data Viewer recognizes this as an array of numbers and charts them on separate data lines:
```block
let values = [0, 1, 2, 3, 4]
basic.forever(() => {
serial.writeNumbers(values)
})
```
Data lines are shown for each value in the array:
![Data lines on chart](/static/mb/device/data-analysis/data-lines.jpg)
Give this example a try and watch the chart make a diamond pattern from two triangle waves:
```blocks
let diamond: number[] = []
basic.forever(() => {
for (let i = 0; i <= 10 - 1; i++) {
if (i < 5) {
diamond[0] = i
diamond[1] = 5 - i
} else {
diamond[0] = 10 - i
diamond[1] = i - 5
}
serial.writeNumbers(diamond)
basic.pause(500)
}
})
```
It will look like this:
![Data pattern on chart](/static/mb/device/data-analysis/diamond-chart.jpg)
## Name value pairs
A very common way to report and record data is to use a _name value pair_ (NVP). A value is given a name so you know what it's for or where it came from. The name value pair is written with the format of _name:value_. There is a name, a colon character, and the value all together on one line. The line is written to the output and the Data Viewer recognizes it as a value and charts it as part of a value stream. The value stream is based on the name so any new values received with the same name are displayed on the chart that's showing values for that name. If more than one type of name value pair is found, the Data Viewer makes another value stream and shows those values on a different chart.
If you want to report the values for both temperature and light, you can make separate name value pairs for them. The name value pairs are written using ``||serial:serial write value||``. This function writes the values to the output as lines in a format like this:
```
temp:17
light:118
temp:18
light:117
```
```blocks
basic.forever(() => {
serial.writeValue("temp", input.temperature())
serial.writeValue("light", input.lightLevel())
basic.pause(5000)
})
```
Two charts display each value stream:
![Two charts for each value type](/static/mb/device/data-analysis/two-value-chart.jpg)
The console output shows the different name value pairs too:
![Two values in console output](/static/mb/device/data-analysis/two-value-console.jpg)
### Writing subvalues
Similar to number arrays, different name value pairs are shown on one chart by using _subvalues_. You make a subvalue by combining a first-level name and a second-level name with a `'.'`:
``"firstLevel.secondLevel"``
The first-level name is value name for the chart. The second-level name is the name for the actual value displayed.
If you want to show all three values of acceleration on a single chart, then use each axis as a second-level (subvalue) name, ``"acceleration.x"``.
```block
serial.writeValue("acceleration.x", input.acceleration(Dimension.X))
```
To show the values for each axis together:
```blocks
basic.forever(() => {
serial.writeValue("acceleration.x", input.acceleration(Dimension.X))
serial.writeValue("acceleration.y", input.acceleration(Dimension.Y))
serial.writeValue("acceleration.z", input.acceleration(Dimension.Z))
basic.pause(500)
})
```
Each subvalue ``'x'``, ``'y'``, and ``'z'`` is displayed on the chart named ``"acceleration"`` in the Data Viewer.
![Three subvalues of acceleration in one chart](/static/mb/device/data-analysis/combined-values.jpg)

View File

@ -0,0 +1,86 @@
# Error codes
Your @boardname@ may encounter a situation that prevents it from running your code. When this happens, a frowny face will appear on your @boardname@ screen (see picture) followed by an error number. These are called _panic_ codes.
```sim
basic.forever(function() {
basic.showLeds(`
# . . . #
# # . # #
. . . . .
. # # # .
# . . . #
`)
basic.pause(1000)
basic.clearScreen()
basic.showString("020")
})
```
## Board system errors
The @boardname@ system errors range between **01** - **99**. For a full list of these codes, what they mean and what you can do to resolve them, visit the [micro:bit guide to error codes](https://support.microbit.org/en/support/solutions/articles/19000016969).
* **10** (`MICROBIT_I2C_LOCKUP`): the @boardname@'s I2C bus is not working
* **20** (`MICROBIT_OOM`): there is no free memory on the @boardname@
* **30** (`MICROBIT_HEAP_ERROR`): a problem in the heap space
* **40** (`MICROBIT_NULL_DEREFERENCE `): there was a NULL dereference, the @boardname@ tried to manage a invalid object pointer
* **42** (`MICROBIT_SYSTEM_ERROR`): there's an error condition in the @boardname@ system software
* **43** (`MICROBIT_NO_RADIO`): the @boardname@ can't enable the radio
* **50** (`MICROBIT_HARDWARE_UNAVAILABLE_ACC`): an error occurred with the micro:bit's accelerometer component
* **51** (`MICROBIT_HARDWARE_UNAVAILABLE_MAG`): an error occurred with the micro:bit's magnetometer component
* **90** (`MICROBIT_HARDWARE_CONFIGURATION_ERROR`): actual board hardware doesn't match the configuration description
* **98** (`MICROBIT_ASSERTION_FAILED`): assertion failed, the condition in an [assert](/reference/control/assert) was false
## Memory errors
Memory error codes range from **800** - **909**.
### ~alert
#### Report errors!
If you ever see an error within the range of **800** - **909**, please report an issue at [GitHub](https://github.com/microsoft/pxt-microbit/issues) or on the [support](https://support.microbit.org/) page.
### ~
### Garbage collector errors
Error codes generated from the garbage collector.
* **840**: Allocation pointer is null or invalid
* **841**: Garbage collection work queue error
* **843**: VTable entry is not free
* **844**: GC allocation failed for requested number of bytes
* **846**: Invalid allocation thread
* **848**: Allocation pointer beyond allocation header
* **849**: Allocation pointer is null
### Program access errors
* **901** (`PANIC_INVALID_BINARY_HEADER`): the type header for the object is not valid
* **902** (`PANIC_OUT_OF_BOUNDS`): the object data portion is greater than the length defined for it
* **903** (`PANIC_REF_DELETED`): an object reference was deleted and the object is no longer valid
* **904** (`PANIC_SIZE`): the object size doesn't match the size defined for the type
* **905** (`PANIC_INVALID_VTABLE`): an object vtable is invalid or not initialized
* **906** (`PANIC_INTERNAL_ERROR`): an internal resource error
* **907** (`PANIC_NO_SUCH_CONFIG`): the specified device resource is not present
* **909** (`PANIC_INVALID_ARGUMENT`): the argument value is out of range or the type or format is invalid
## JavaScript runtime codes
### Invalid cast codes
When the static type of ``x`` is a class ``C``, the dynamic type of ``x`` isnt ``C``, and you try to access a field on ``x`` or call a method on ``x``, you will get one of the following codes, depending on dynamic type of ``x``.
* **980** (`PANIC_CAST_FROM_UNDEFINED`): when value of ``x`` is ``undefined``
* **981** (`PANIC_CAST_FROM_BOOLEAN`): when value of ``x`` is ``true`` or ``false``
* **982** (`PANIC_CAST_FROM_NUMBER`): when ``x`` is a ``number``
* **983** (`PANIC_CAST_FROM_STRING`): when ``x`` is a ``string``
* **984** (`PANIC_CAST_FROM_OBJECT`): when ``x`` is object of some type
* **985** (`PANIC_CAST_FROM_FUNCTION`): when ``x`` is a function
* **989** (`PANIC_CAST_FROM_NULL`): when ``x`` is ``null``
## See also
[panic](/reference/control/panic), [assert](/reference/control/assert)

11
docs/device/firmware.md Normal file
View File

@ -0,0 +1,11 @@
# Firmware
Occasionally, changes and improvements to the system software (firmware) on the @boardname@ are needed. Updates to the firmware are made by the [micro:bit Education Foundation](http://microbit.org/about).
## Do I need an update?
Changes to the firmware don't happen very often. You probably don't need to update it for your @boardname@ if everything is working alright. Sometimes there's a problem with a certain part of the board not working right or it has trouble connecting to your computer or other device. In those cases, a firmware update may include a fix for the problem.
## Getting a firmware update
Instructions for updating the firmware are shown on the **[firmware upgrade](https://microbit.org/guide/firmware/)** support page at microbit.org.

View File

@ -0,0 +1,52 @@
# foil circuits
The large holes at the bottom of the board are designed to attach alligator/crocodile clips
to create electrical circuit with other components.
If you do not have crocodile clips at hand, you can use wires or even Aluminium foil to achieve the same result.
We will show you how to connect the @boardname@ to headphones using Aluminium foil and tape.
https://youtu.be/mhXYyPuvpz0
## Materials
* @boardname@ and battery pack (you can also power it via USB)
* a small piece of cardboard
* Aluminium foil
* tape
## Assembly instructions
Tape the @boardname@ and battery pack to the card board. Make sure to remove the batteries while you are building your circuit.
![](/static/mb/device/croc-clips/microbitattached.jpg)
Cut the thinnest strip of foil possible and roll it into a cable. You can also try to fold, whatever works for you.
Build two of those wires.
![](/static/mb/device/croc-clips/foilcut.jpg)
Place the foil wire on the ``GND`` pin and attach with a piece of tape. Press hard to get the best connection between
the foil and the pin board. Make sure the foil is not overlapping with the other pins!
![](/static/mb/device/croc-clips/groundconnected.jpg)
Place the second wire on the ``P0`` pin the same way. Make sure the wire does not overlap with the other pins!
![](/static/mb/device/croc-clips/microbitconnect.jpg)
Tape the headphone jack connector to the cardboard and roll the wire coming from ``GND`` around the metal base.
Make sure the wire does not touch the other metal rings on the jack.
![](/static/mb/device/croc-clips/jackground.jpg)
Tape the second wire on the head of the jack connector.
![](/static/mb/device/croc-clips/jackconnect.jpg)
![](/static/mb/device/croc-clips/foilcircuit.jpg)
## See also
[@boardname@ pins](/device/pins)

145
docs/device/mes-events.md Normal file
View File

@ -0,0 +1,145 @@
# MES events
Events and event values are generated in the Message Event Service (MES). Using MES events allows orderly interactions between the @boardname@ and external devices. These events are sent to and received from other wireless devices paired with the @boardname@ (phone, game pad, etc.).
The event source IDs represent a device feature category. The event values are actions for, or notifications about a device feature.
### ~hint
**MES system sources**
The MES events are defined in this source file of the **[microbit-dal](https://github.com/lancaster-university/microbit-dal)**:
* [MESEvents.h](https://github.com/lancaster-university/microbit-dal/blob/master/inc/bluetooth/MESEvents.h)
Also, you can see how the message bus works in the DAL core files:
* [MemberFunctionCallback.cpp](https://github.com/lancaster-university/microbit-dal/blob/master/source/core/MemberFunctionCallback.cpp)
* [MicroBitListener.cpp](https://github.com/lancaster-university/microbit-dal/blob/master/source/core/MicroBitListener.cpp)
### ~
## Raised events
Events are generated, or _raised_, for by the @boardname@ for a paired device. These are raised using the [raise event](/reference/control/raise-event) function.
```typescript-ignore
control.raiseEvent(
control.eventSourceId(EventBusSource.MES_REMOTE_CONTROL_ID),
control.eventValueId(EventBusValue.MES_REMOTE_CONTROL_EVT_VOLUMEUP)
);
```
### Remote control
Events for using the @boardname@ as a remote control for audio play.
#### MES_REMOTE_CONTROL_ID
* `MES_REMOTE_CONTROL_EVT_PLAY`: Play the current track
* `MES_REMOTE_CONTROL_EVT_PAUSE`: Pause the current play in progress
* `MES_REMOTE_CONTROL_EVT_STOP`: Stop playing and reset to the beginning of the current track
* `MES_REMOTE_CONTROL_EVT_NEXTTRACK`: Skip to the next track
* `MES_REMOTE_CONTROL_EVT_PREVTRACK`: Skip to the previous track
* `MES_REMOTE_CONTROL_EVT_FORWARD`: Move forward in the current track
* `MES_REMOTE_CONTROL_EVT_REWIND`: Move backward in the current track
* `MES_REMOTE_CONTROL_EVT_VOLUMEUP`: Increase the play volume (audio)
* `MES_REMOTE_CONTROL_EVT_VOLUMEDOWN`: Decrease the play volume (audio)
### Camera
Control camera actions on a paired device.
#### MES_CAMERA_ID
* `MES_CAMERA_EVT_LAUNCH_PHOTO_MODE`: Turn on or set the camera to _photo_ mode.
* `MES_CAMERA_EVT_LAUNCH_VIDEO_MODE`: Turn on or set the camera to _video_ mode.
* `MES_CAMERA_EVT_TAKE_PHOTO`: Capture the picture in the camera view.
* `MES_CAMERA_EVT_START_VIDEO_CAPTURE`: Begin capturing video (start record)
* `MES_CAMERA_EVT_STOP_VIDEO_CAPTURE`: End capturing video (stop record)
* `MES_CAMERA_EVT_STOP_PHOTO_MODE`: Stop photo mode and return to the default mode
* `MES_CAMERA_EVT_STOP_VIDEO_MODE`: Stop video mode and return to the default mode
* `MES_CAMERA_EVT_TOGGLE_FRONT_REAR`: Switch from the front camera to rear camera or rear to front
### Alerts
Trigger standard alert notifications on a device.
#### MES_ALERTS_ID
* `MES_ALERT_EVT_DISPLAY_TOAST`
* `MES_ALERT_EVT_VIBRATE`
* `MES_ALERT_EVT_PLAY_SOUND`
* `MES_ALERT_EVT_PLAY_RINGTONE`
* `MES_ALERT_EVT_FIND_MY_PHONE`
* `MES_ALERT_EVT_ALARM1`
* `MES_ALERT_EVT_ALARM2`
* `MES_ALERT_EVT_ALARM3`
* `MES_ALERT_EVT_ALARM4`
* `MES_ALERT_EVT_ALARM5`
* `MES_ALERT_EVT_ALARM6`
## Received events
Events are received by the @boardname@ from a paired device. You capture these in an [on event](/reference/control/on-event) function.
```typescript-ignore
control.onEvent(EventBusSource.MES_DEVICE_INFO_ID, EventBusValue.MES_DEVICE_INCOMING_CALL, () => {
})
```
### Carrier signal strength
Signal strength to the subscribed carrier service.
#### MES_SIGNAL_STRENGTH_ID
* `MES_SIGNAL_STRENGTH_EVT_NO_BAR`: No service available or very low signal strength
* `MES_SIGNAL_STRENGTH_EVT_ONE_BAR`: Low signal strength
* `MES_SIGNAL_STRENGTH_EVT_TWO_BAR`: Medium signal strength
* `MES_SIGNAL_STRENGTH_EVT_THREE_BAR`: High signal strength
* `MES_SIGNAL_STRENGTH_EVT_FOUR_BAR`: Full signal strength
### Device information
Information about the current status of the device
#### MES_DEVICE_INFO_ID
* `MES_DEVICE_ORIENTATION_LANDSCAPE`: Display orientation is now in landscape
* `MES_DEVICE_ORIENTATION_PORTRAIT`: Display orientation is now in portrait
* `MES_DEVICE_GESTURE_NONE`: No gesture detected for device activation
* `MES_DEVICE_GESTURE_DEVICE_SHAKEN`: The device was shaken
* `MES_DEVICE_DISPLAY_OFF`: Device display is now turned off
* `MES_DEVICE_DISPLAY_ON`: Device display is now turned on
* `MES_DEVICE_INCOMING_CALL`: Currently receiving an incoming call
* `MES_DEVICE_INCOMING_MESSAGE`: A message was received (SMS or other messaging app)
### Game pad controller
Button events from a paired game pad.
#### MES_DPAD_CONTROLLER_ID
* `MES_DPAD_BUTTON_A_DOWN`: Button **A** pressed
* `MES_DPAD_BUTTON_A_UP`: Button **A** released
* `MES_DPAD_BUTTON_B_DOWN`: Button **B** pressed
* `MES_DPAD_BUTTON_B_UP`: Button **B** released
* `MES_DPAD_BUTTON_C_DOWN`: Button **C** pressed
* `MES_DPAD_BUTTON_C_UP`: Button **C** released
* `MES_DPAD_BUTTON_D_DOWN`: Button **D** pressed
* `MES_DPAD_BUTTON_D_UP`: Button **D** released
* `MES_DPAD_BUTTON_1_DOWN`: Button **1** pressed
* `MES_DPAD_BUTTON_1_UP`: Button **1** released
* `MES_DPAD_BUTTON_2_DOWN`: Button **2** pressed
* `MES_DPAD_BUTTON_2_UP`: Button **2** released
* `MES_DPAD_BUTTON_3_DOWN`: Button **3** pressed
* `MES_DPAD_BUTTON_3_UP`: Button **3** released
* `MES_DPAD_BUTTON_4_DOWN`: Button **4** pressed
* `MES_DPAD_BUTTON_4_UP`: Button **4** released
## See also
[raise event](/reference/control/raise-event), [on event](/reference/control/on-event),
[event value](/reference/control/event-value)

64
docs/device/pins.md Normal file
View File

@ -0,0 +1,64 @@
# micro:bit pins
The micro:bit pins
![](/static/mb/device/pins-0.png)
The micro:bit has 25 external connections on the edge connector of the board, which we refer to as pins. The edge connector is the grey area on the right side of the figure above.
There are five large pins, that are also connected to holes in the board labelled: 0, 1, 2, 3V, and GND. And along the same edge, there are 20 small pins that you can use when plugging the micro:bit into an edge connector.
## Large pins
You can easily attach crocodile clips or 4mm banana plugs to the five large pins.
The first three, labelled 0, 1 and 2 are flexible and can be used for many different things - which means they are often called general purpose input and output (shortened to GPIO). These three pins also have the ability to read analogue voltages using something called an analogue-to-digital converter (ADC). They all have the same function:
* **0**: GPIO (general purpose digital input and output) with analogue to digital convertor (ADC).
* **1**: GPIO with ADC
* **2**: GPIO with ADC
The other two large pins (3V and GND) are very different!
## ~hint
Watch out! The pins labelled 3V and GND relate to the power supply of the board, and they should NEVER be connected together.
For details on the power, current and voltage limitations of the board, see [Power Supply](https://tech.microbit.org/hardware/powersupply/)
## ~
*power input*: If the micro:bit is powered by USB or a battery, then you can use the 3V pin as a *power output* to power peripherals with.
* **3V**: *3 volt power output* or *power input*. (1) *power output*: If the micro:bit is powered by USB or a battery, then you can use the 3V pin as a power output to power peripherals with; (2) *power input*: If the micro:bit is not being powered by USB or battery, you can use the 3V pin as a power input to power the micro:bit
* **GND**: attaches to ground in order to complete a circuit (required when using the 3V pin)
If you hold the GND pin with one hand, you can program the microbit to detect yourself touching the 0,1 or 2 pins with your other hand, giving you three more buttons to experiment with (you just used your body to complete an electrical circuit).
## Small pins
There are 20 small pins numbered sequentially from 3-22 (these pins are not labeled on the micro:bit, however, they are labelled in the picture above).
Unlike the three large pins that are dedicated to being used for external connections, some of the small pins are shared with other components on the micro:bit board. For example, pin 3 is shared with some of the LEDs on the screen of the micro:bit, so if you are using the screen to scroll messages, you cant use this pin as well.
* **pin 3**: GPIO shared with LED Col 1 of the LED screen; can be used for ADC and digital I/O when the LED screen is turned off.
* **pin 4**: GPIO shared with LED Col 2 of the LED screen; can be used for ADC and digital I/O when the LED screen is turned off.
* **pin 5**: GPIO shared with Button A. This lets you trigger or detect a button "A" click externally. This pin has a pull-up resistor, which means that by default it is at voltage of 3V. To replace button A on the micro:bit with an external button, connect one end of the external button to pin 5 and the other end to GND. When the button is pressed, the voltage on pin 5 is pulled down to 0, which generates a button click event.
* **pin 6**: GPIO shared with LED Col 9 of the LED screen; can be used for digital I/O when the LED screen is turned off.
* **pin 7**: GPIO shared with LED Col 8 of the LED screen; can be used for digital I/O when the LED screen is turned off.
* **pin 8**: Dedicated GPIO, for sending and sensing digital signals.
* **pin 9**: GPIO shared with LED Col 7 of the LED screen; can be used for digital I/O when the LED screen is turned off.
* **pin 10**: GPIO shared with LED Col 3 of the LED screen; can be used for ADC and digital I/O when the LED screen is turned off.
* **pin 11**: GPIO shared with Button B. This lets you trigger or detect a button “B” click externally.
* **pin 12**: this GPIO pin has been reserved to provide support for accessibility.
* **pin 13**: GPIO that is conventionally used for the serial clock (SCK) signal of the 3-wire Serial Peripheral Interface (SPI) bus.
* **pin 14**: GPIO that is conventionally used for the Master In Slave Out (MISO) signal of the SPI bus.
* **pin 15**: GPIO that is conventionally used for the Master Out Slave In (MOSI) signal of the SPI bus.
* **pin 16**: Dedicated GPIO (conventionally also used for SPI Chip Select function).
* **pins 17 and 18**: these pins are wired to the 3V supply, like the large 3V pad.
* **pins 19 and 20**: implement the clock signal (SCL) and data line (SDA) of the I2C bus communication protocol. With I2C, several devices can be connected on the same bus and send/read messages to and from the CPU. Internally, the accelerometer and the compass are connected to i2c.
* **pins 21 and 22**: these pins are wired to the GND pin and serve no other function
## Connecting to the small pins
It is recommended that an edge connector be acquired to connect to the small pins. More information on compatible edge connectors will be available later.

172
docs/device/reactive.md Normal file
View File

@ -0,0 +1,172 @@
# The micro:bit - a reactive system
## Computing systems
What sort of a *computing system* is the micro:bit?
## ~hint
There are different types of computing systems, to address different kinds of problems that arise in practice: *transaction processing systems* are used by banks to handle huge numbers of financial transactions by their customers; *distributed systems* make a set of networked computers appear as one big computer (like Googles search engine); there are also *parallel systems*, such as graphic cards, which perform a huge number of primitive operations simultaneously, using a great number of small processing cores.
## ~
The micro:bit is a *reactive system* it reacts continuously to external events, such as a person pressing the **A** button of the micro:bit or shaking the device. The reaction to an event may be to perform a computation, update variables, and change the display. After the device reacts to an event, it is ready to react to the next one. If this sounds like a computer game, thats because most computer games are reactive systems too!
## Responsiveness
We want reactive systems to be responsive, which means to react in a timely manner to events. For example, when you play a computer game, its frustrating if you press a button to make a character jump, but it doesnt immediately jump. A delay in reacting, or lack of responsiveness, can be the difference between life and death, both in the real and virtual worlds.
Lets consider a simple example: you want to program your micro:bit to accurately count the number of times the **A** button has been pressed and continuously display the current count on the 5x5 [LED screen](/device/screen). Because the LED screen is small, we can only display one digit of a number at a time on it. The [show number](/reference/basic/show-number) function will scroll the digits of a number across the screen so you can read it.
Lets say that the current count is 42 and the number 42 is scrolling across the LED screen. This means there is some code executing to perform the scroll. So, what should happen if you press the **A** button during the scroll? It would be a bad idea to ignore the button press, so some code should record the occurrence of the button press. But we just said there already is code running in order to scroll the number 42! If we wait until the code scrolling the 42 has finished to look for a button press, we will miss the button press. We want to avoid this sort of unresponsiveness.
## Concurrency
To be responsive, a reactive system needs to be able to do several things at the same time (concurrently), just like you can. But the micro:bit only has one CPU for executing your program, which means it can only execute one program instruction at a time. It can, however, execute millions of instructions in a single second. This points the way to a solution.
Think about how a motion picture projector works - it projects only 24 frames per second, yet this is good enough to provide the illusion of fluid motion on the screen. The micro:bit can execute millions of instructions per second, so it seems quite possible for the device to both to smoothly scroll the number 42 across the LED screen while looking for button presses and counting them.
Lets think about three sequences of instructions:
* Sequence **S1**: contains the instructions (lets say several hundred thousand or so) that scroll the number 42 across the LED screen.
* Sequence **S2**: contains a few instructions to check if button **A** is pressed.
* Sequence **S3**: contains a few instructions to increment a counter.
In order to be responsive, we would like to *interrupt* the execution of sequence **S1** *periodically* to execute the sequence **S2**, which will check if button **A** is pressed, which looks like:
![Execution sequence diagram: S1 and S2](/static/mb/device/reactive-0.png)
The result is that it takes sequence **S1** a little longer to complete, due to the interruptions to execute sequence **S2**, but we are checking often enough to detect a press of button **A** . When **S2** detects a press of button **A**, then the sequence **S3** can be executed before **S1** resumes:
![Execution sequence diagram: S1 and S2 with interrupt and one S3 slice](/static/mb/device/reactive-1.png)
As well soon see, there are other choices for how the sequences can be ordered to achieve the desired result.
## The micro:bit scheduler and queuing up subprograms
The micro:bits *scheduler* provides the capability to concurrently execute different code sequences, relieving us of a lot of low-level programming. In fact, scheduling is so useful that it is a part of every *operating system*!
The first job of the scheduler is to allow multiple *subprograms* to be queued up for later execution. For our purposes, a subprogram is just a statement or sequence of statements in the context of a larger program. Consider the program below for counting button presses.
```typescript
let count = 0
input.onButtonPressed(Button.A, () => {
count++;
})
basic.forever(() => {
basic.showNumber(count)
})
```
The program above contains three statements that execute in order from top to bottom.
The first statement initializes the global variable `count` to zero.
```typescript
// statement 1
let count = 0
```
The second statement informs the scheduler that on each and every event of the **A** button being pressed, a subprogram (called the event handler) should be queued for execution. The event handler code is contained within the braces `{...}`; it increments the global variable `count` by one.
```typescript
// statement 1
let count = 0
// statement 2
input.onButtonPressed(Button.A, () => {
count++;
})
```
The third statement queues a `forever` loop for later execution by the scheduler; the body of this loop (also inside the braces `{...}`) displays the current value of global variable `count` on the LED screen.
```typescript
// statement 1
let count = 0
// statement 2
input.onButtonPressed(Button.A, () => {
count++;
})
// statement 3
basic.forever(() => {
basic.showNumber(count)
})
```
There are no more statements after the execution of these three statements, but this is not the end of program execution! Thats because the program queued the `forever` loop for execution by the scheduler (and registered an event handler for presses of button A).
The second job of the scheduler is to periodically interrupt execution to read (poll) the various inputs to the micro:bit (the buttons, pins, etc.) and fire off events (such as “button A pressed”). Recall that the firing of an event causes the event handler subprogram associated with that event to be queued for later execution. The scheduler uses a timer built into the micro:bit hardware to interrupt execution every 6 milliseconds and poll the inputs, which is more than fast enough to catch the quickest press of a button.
## Cooperative passing of control
How does the `forever` loop get to start execution? Furthermore, once the `forever` loop is running, how does any other subprogram (like the event handler that increments the count) ever get a chance to execute?
The answer is “cooperation” and “passing”. Think of a football team doing a drill there is one ball and each footballer gets to dribble the ball for a certain number of touches, after which they pass to another footballer. A footballer who never passes prevents all other footballers from dribbling. A cooperative footballer always passes to some other footballer after taking a few touches.
If you hadnt guessed already, a footballer represents subprogram and dribbling the ball corresponds to that subprogram executing. Only one subprogram gets to execute at a time, as there is only one ball (processor). Footballer Alice passing the ball to footballer Bob corresponds to stopping execution of Alices subprogram (and remembering where it stopped) and starting/resuming execution of Bobs subprogram.
We will call this “passing control of execution” rather than “passing the ball”. However, in the world of the micro:bit, the concurrently executing subprograms are not aware of each other, so they dont actually pass control directly to one another. Rather they pass control of execution back to the scheduler and the scheduler determines the subprogram to pass control to next. The programmer inserts a call to the `pause` function to indicate a point in the subprogram where control of execution passes to the scheduler. Also, when a subprogram ends execution, control passes to the scheduler.
Lets take a look at the implementation of the `basic.forever` function to see an example of cooperative scheduling:
```typescript
function forever_(body: () => void) {
control.inBackground(() => {
while(true) {
body()
basic.pause(20)
}
})
}
```
The `forever` loop actually is a function that takes a subprogram (another function) as a parameter. The function uses the `control.inBackground` function of the micro:bit runtime to queue a `while true` loop for execution by the scheduler. The while loop has two statements. The first statement runs the subprogram represented by the `body` parameter. The second statement passes control to the scheduler (requesting to “sleep” for 20 milliseconds).
Though the `while true` loop will repeatedly execute the body subprogram, between each execution of the body it will permit the scheduler to execute other subprograms. If the while loop did not contain the call to `pause`, then once control passed into the while loop, it would never pass back to the scheduler and no other subprogram would be able to execute (unless the body subprogram contained a call to `pause` itself).
## Round-robin scheduling
Now, we come to the third and final job of the scheduler, which is to determine which subprogram to pass control to next. The scheduler uses two queues to perform this task, the sleep queue and the run queue. The sleep queue contains the subprograms that have called the pause function and still have time left to sleep. The run queue contains all the non-sleeping subprograms, such as the event handlers queued by the firing of an event.
The scheduler moves the subprogram that has just paused into the sleep queue and then removes the subprogram at the head of the run queue and resumes its execution. Once a subprograms sleep period is over, the scheduler moves it from the sleep queue to the back of the run queue.
The property of such round-robin scheduling is that under the assumption that every subprogram periodically enters the sleep queue, then every subprogram will periodically get a chance to execute.
## Putting it all together
Lets go back to the `count button presses` program and revisit its execution based on what we have learned about the micro:bit scheduler. As detailed before, the program executes three steps to:
1. Initialize the global variable `count` to zero
2. Set up the event handler for each press of button **A**
3. Queue the forever loop to the run queue
The program then ends execution and control passes back to the scheduler. Lets assume the user has not pressed any buttons . The scheduler finds the `forever` loop in the run queue and passes control to it. The loop first calls `basic.showNumber(0)`. In the diagram below, we use “Show 0” to refer to the execution of this function:
![Execution sequence diagram: display loop with increment and interrupt](/static/mb/device/reactive-3.png)
While "Show 0" (the blue sequence) is running, periodic interrupts by the scheduler (every 6 milliseconds) poll for button presses and queue an event handler for each press of button **A**. Lets say that one button press takes place during this time, as shown above. This will cause an event handler (labelled “inc”) to be queued for later execution by the scheduler. Once the "Show 0" has completed, the loop then calls `basic.pause(20)` to put the forever loop to sleep for 20 milliseconds and give the scheduler an opportunity to run any newly queued event handler. Control passes to the “inc” event handler which will increment the global variable `count` from 0 to 1 and then complete, returning control to the scheduler. At some point, the `forever` loop moves from the sleep queue to the run queue; the `forever` loop then will resume and call `basic.showNumber(1)`.
## Final thoughts
Through this example, we have seen that the micro:bit scheduler enables you to create a program that is composed of concurrent subprograms. In essence, the programmer needs to only think about the concurrent subprograms cooperatively passing control back to the scheduler, making sure no subprogram hogs control (or “dribbles the ball without passing”) for too long. While a subprogram runs, the scheduler polls the buttons and other IO peripherals at a high frequency in order to fire off events and queue event handlers for later execution, but this is invisible to the programmer.
As a result, you can easily add a new capability to the micro:bit by just adding a new subprogram. For example, if you want to add a reset feature to the counter program, all you need to do is add a new event handler for a press of button **B** that sets the global variable "count" to zero, as shown below:
```typescript
let count = 0
input.onButtonPressed(Button.A, () => {
count = count + 1
})
basic.forever(() => {
basic.showNumber(count)
})
input.onButtonPressed(Button.B, () => {
count = 0
})
```

97
docs/device/screen.md Normal file
View File

@ -0,0 +1,97 @@
# LED screen
```sim
basic.showLeds(`
# . # . #
. # . # .
# . # . #
. # . # .
# . # . #
`);
```
The micro:bit LED screen has 25 red LED lights arranged in a 5X5 grid (5 LEDs across by 5 LEDs down).
In the screen above, we created a checkerboard pattern using the LEDs.
## Which LED?
You use `(x ,y)` coordinates to specify a particular LED in the grid;
where `x` is the horizontal position (0,1,2,3,4) and `y` is the vertical position
(0, 1, 2, 3, 4).
To figure out the ``x``, ``y`` coordinates, position your micro:bit horizontally, like a credit card (see picture above).
Here are the x, y coordinates for the LEDs in the 5X5 grid:
`(0,0)` `(1,0)` `(2,0)` `(3,0)` `(4,0)`
`(0,1)` `(1,1)` `(2,1)` `(3,1)` `(4,1)`
`(0,2)` `(1,2)` `(2,2)` `(3,2)` `(4,2)`
`(0,3)` `(1,3)` `(2,3)` `(3,3)` `(4,3)`
`(0,4)` `(1,4)` `(2,4)` `(3,4)` `(4,4)`
The x, y coordinates for the LED in the center of the grid are `(2,2)`. Starting from `(0,0)` count over 2 columns and then down 2 rows.
## Check your understanding
Which LEDs are turned on in the checkboard pattern above?
## Row, column - 1
Since the row and column numbers start at 0, an easy way to figure out the (x,y) coordinates
is to subtract 1 from the row and column number (when counting from 1).
In other words, to specify the LED in the 4th column 5th row, subtract 1 from each number to get coordinates `(3,4)`.
## Turn a LED on/off
Use [plot](/reference/led/plot) and [unplot](/reference/led/unplot) to turn a LED on or off
```blocks
led.plot(0,0);
led.plot(1,1);
basic.pause(1000);
led.unplot(0,0);
basic.pause(1000);
led.unplot(1,1);
```
## Is a LED on/off?
Use the [point](/reference/led/point) function to find out if a LED is on or off.
```blocks
if(led.point(0,0)) {
}
```
## Display images, strings and numbers
Instead of turning individual LEDs on or off, as above, you can display an [image](/reference/images/image) directly to the screen or show text and numbers on screen using the [show number](/reference/basic/show-number) and [show string](/reference/basic/show-string) functions.
## The display buffer
The micro:bit runtime keeps a representation of the state of all 25 LEDS in memory. This state is known as the "display buffer" and controls which LEDs are on and which are off. The plot, unplot, and point functions access the display buffer directly. On the other hand, the functions that show an image, number, or string overwrite the buffer completely. To illustrate this, first try running this code sequence
```blocks
basic.showString("d")
led.plot(0, 0)
```
You will see the letter "d" displayed as well as the LED in position `0,0` lit up. Now try reversing the order of the two statements above:
```blocks
led.plot(0, 0)
basic.showString("d")
```
You will not see the LED at position `0,0` lit up because the `show string` function overwrites the whole display buffer.
## Pins: P3, P4, P6, P7, P9, P10
These pins are coupled to the LED matrix display and also to the display's associated ambient light sensing mode.
To disable the display driver feature (which will automatically disable the light sensing feature) use the function [led.enable](/reference/led/enable).
More information at http://tech.microbit.org/hardware/edgeconnector_ds/ .

81
docs/device/serial.md Normal file
View File

@ -0,0 +1,81 @@
# Serial
The [serial](/reference/serial) supports [serial communication](https://en.wikipedia.org/wiki/Serial_port) between the BBC micro:bit and another computer. Basically, this allows you to send data from the micro:bit to your own computer. This is very useful for debugging purposes: you can add `write line` statements in your code and see them display on your computer as the program executes.
The code below shows a simple script that sends a line when the BBC micro:bit starts and another line each time the button ``A`` is pressed.
```blocks
serial.writeLine("started...")
input.onButtonPressed(Button.A, () => {
serial.writeLine("A pressed")
})
```
Data is also automatically streamed to serial by the ** bar graph** block
and picked up by the editor. This data can be streamed to the cloud as well.
```blocks
basic.forever(() => {
led.plotBarGraph(input.acceleration(Dimension.X), 0);
});
```
## How to read the micro:bit's serial output from your computer
Unfortunately, using the serial library requires quite a bit of a setup.
### ~ hint
**Windows earlier than 10**
If you are running a Windows version earlier than 10, you must [install a device driver](https://os.mbed.com/docs/latest/tutorials/windows-serial-driver.html) (for the computer to recognize the serial interface of the micro:bit).
## ~
Also, if you don't see the serial port as one of your computer's devices, you might need to [update the firmware](/device/firmware) on the @boardname@. Find the device name for the attached serial port in the following instructions for your operating system.
### Windows > Tera Term
* Install the terminal emulator [Tera Term](https://ttssh2.osdn.jp/index.html.en). At the time of this writing, the latest version is 4.88 and can be downloaded [from here](http://en.osdn.jp/frs/redir.php?m=jaist&f=%2Fttssh2%2F63767%2Fteraterm-4.88.exe). Follow the instructions from the installer.
Once both the driver and the terminal emulator are installed, plug in the micro:bit and wait until the device is fully setup. Then, open TeraTerm.
* Hit `File` > `New Connection`
* Check "Serial"; in the dropdown menu, pick the COM port that says "mbed Serial Port". Hit `Ok`.
* In the menus, hit `Setup` > `Serial Port` and set the baud rate to `115200`.
You should be good. Feel free to hit `Setup` > `Save Setup` in the menus to erase the default configuration file with a new one so that you don't have to type in the settings again.
Please note that Windows will assign you a different COM port if you plug in another micro:bit. If you're juggling between micro:bits, you'll have to change the COM port every time.
### Windows > Putty
If you prefer another terminal emulator (such as [PuTTY](http://www.putty.org/)), here are some instructions.
* Open Windows's [Device Manager](https://windows.microsoft.com/en-us/windows/open-device-manager); expand the section called "Ports (COM & LPT)"; write down the com number for "mbed Serial Port" (e.g. COM14)
* Open PuTTY; on the main screen, use the following settings: Serial / COM14 / 115200. Replace COM14 with the COM port number you wrote down previously. Feel free to type in a name and hit "Save" to remember this configuration.
![](/static/mb/serial-library-0.png)
* (optional): in the "Terminal" section, check "implicit cr in every lf"
![](/static/mb/serial-library-1.png)
## Linux
* Install the program `screen` if it is not already installed.
* Plug in the micro:bit.
* Open a terminal.
* Find which device node the micro:bit was assigned to with the command `ls /dev/ttyACM*`.
* If it was `/dev/ttyACM0`, type the command `screen /dev/ttyACM0 115200`. If it was some other device node,
use that one in the command instead. **Note:** You may need root access to run `screen`
successfully. You can probably use the command `sudo` like this: `sudo screen /dev/ttyACM0 115200`.
* To exit `screen`, type `Ctrl-A` `Ctrl-D`.
Alternative programs include `minicom` and so on.
## Mac OS
* Plug in the micro:bit
* Open a terminal
* `ls /dev/cu.*` will return to you a list of serial devices; one of them will look like `/dev/cu.usbmodem1422` (the exact number depends on your computer)
* `screen /dev/cu.usbmodem1422 115200` will open up the micro:bit's serial output. To exit, hit `Ctrl-A` `Ctrl-D`.

144
docs/device/servo.md Normal file
View File

@ -0,0 +1,144 @@
# Equipping a microservo with Crocodile clips
## ~ hint
If you are conducting a class or group activity, you should consider preparing all servos ahead of time.
## ~
## Using a microservo with the @boardname@
The @boardname@ provides just enough current to operate the SG90 microservo. This servo requires 3 connections: **GND**, **3V** and a logic **pin**. In this tutorial, we will equip the servo with crocodile clips to make it easier to use. However, you could also use a shield or crocodile clips with a male connector on one end to achieve the same result.
### ~ hint
To better understand how servos work and how they are controlled, take a few minutes to read this [Brief Guide to Servos](https://www.kitronik.co.uk/pdf/a-brief-guide-to-servos.pdf).
### ~
## The easy way: Alligator/Crocodile Clip to Male Jumpers #hintconnection
The easiest way to connect a servo to the @boardname@ is to use cables with an **Alligator/Crocodile clip** on one end
and a **Male jumper (pig tail)** on the other end. You can purchase bundles these cables from various electronic resellers or easily build some as shown here.
https://youtu.be/XtzsydSTXEg
### Materials
* 1 Crocodile clip cable
* 1 male (pig tail) cable
* Cutting pliers or wire cutter
* 1 piece of heat shrink tubing and a lighter
Simply cut the cables, strip them, twist the bare wires together, and cover the connection with some heat shrink tubing.
### ~ hint
It is very **important** to ensure a good connection between the 2 cables. If the connection is weak, the microservo will not receive enough current and it will not work. **If you have access to a soldering iron, we strongly recommend that you solder this connection.**
### ~
## Direct connection
You can also connect your crocodile clips directly to the servo.
### Materials
* Cutting pliers or wire cutter
* Tape (masking, duct tape, and/or packing tape)
* 3 crocodile clips, yellow, red and black.
* 1 micro servo 9g (SG90)
### Step 1: Cut off the connector
With the cutting pliers, cut off the dark plastic connector.
![Cutting of the plastic connector from the servo cable](/static/mb/projects/inchworm/servo1.jpg)
### Step 2: Strip the ends of the cables
Using the pliers or a wire stripper, strip the plastic insulation from the cables.
![Stripping the servo cable insulation](/static/mb/projects/inchworm/servotrim.jpg)
### Step 3: Twist the wire strands together
Twist the strands of bare wire at the ends of the servo cables together.
![Strands of the servo wires twisted together](/static/mb/projects/inchworm/servo3.jpg)
### Step 4: Crocodile clip
Cut a crocodile cable in two and strip off the insulation. If it's possible, try to use cables with colors that match the cables on the servo!
![Stripping insulation of a croc cable with cutting pliers](/static/mb/projects/inchworm/servo4.jpg)
### Step 5: Thread the cable ends together
Place the cables next to each other...
![Bare wires place together before threading](/static/mb/projects/inchworm/servo5.jpg)
... and thread them together.
![Bare wires threaded together](/static/mb/projects/inchworm/servo6.jpg)
### ~ hint
It is very **important** to ensure that there is a good connection between the 2 cables. If the connection is weak, the microservo will not receive enough current and it will not work. **If you have access to a soldering iron, we strongly recommend soldering this connection.**
### ~
### Step 6: Protect the connection
Protect the connection with heat shrink tubing, electrical tape, or duct tape.
![Wire connection protected with electrical tape](/static/mb/projects/inchworm/servo7.jpg)
### Step 7: Repeat for all cables
Repeat the same process until all cables are connected.
![All three cables connected and taped](/static/mb/projects/inchworm/servo8.jpg)
### Step 8: Testing!
It's time to test and find out if your connections are all secure and that the servo will function **when the @boardname@ is powered by battery**.
* Connect the microservo cables to these pins on the @boardname@: black to **GND**, red to **3V**, and the remaining cable to pin **0**.
![Connect to the pins on the board](/static/mb/projects/inchworm/circuit1.jpg)
## ~ hint
When attaching the crocodile clips to the pins, don't be afraid to clamp on to the edge of the board with the clips.
![Clippiing the cables to the edge of the board](/static/mb/projects/inchworm/circuit2.jpg)
## ~
* Download the following code to your @boardname@.
```blocks
basic.forever(() => {
pins.servoWritePin(AnalogPin.P0, pins.map(
input.acceleration(Dimension.X),
-512,
512,
0,
180
))
})
```
* Test with both power sources and make sure that the servo moves when you tilt the board:
>* Connected with USB.
>* Powered by batteries **only** and not connected with USB.
## Calibrating
Use the [servo calibrator](/projects/servo-calibrator) program to determine the best angles to use for your make.
## Troubleshooting
If your servo seems to stutter and remain stuck at a particular position, it means that it's not receiving enough power. This is probably due to a weak connection or low battery level. Make sure that each connection is good and check your batteries.

25
docs/device/simulator.md Normal file
View File

@ -0,0 +1,25 @@
# Simulator
The JavaScript simulator allows you to test and execute most BBC micro:bit programs in the browser.
It allows you to emulate sensor data or user interactions.
```sim
input.onButtonPressed(Button.A, () => {
basic.showString("A");
});
input.onButtonPressed(Button.B, () => {
basic.showString("B");
});
input.onPinPressed(TouchPin.P0, () => {
basic.showString("0");
});
input.onPinPressed(TouchPin.P1, () => {
basic.showString("1");
});
input.onPinPressed(TouchPin.P2, () => {
basic.showString("2");
});
input.temperature()
input.compassHeading()
input.lightLevel()
```

36
docs/device/usb.md Normal file
View File

@ -0,0 +1,36 @@
# Uploading programs to your @boardname@
Most of the time you'll be writing and testing your programs in the [simulator](/device/simulator). Once you've finished your program though, you can **compile** it and run it on your @boardname@. Transferring your program to the @boardname@ is as simple as saving a file to a drive on your computer.
When you plug your @boardname@ into USB, a new drive is created with the **@drivename@** label. This is where you'll save your program.
![](/static/mb/device/usb-thin.jpg)
The basic steps are:
1. Connect your @boardname@ to your computer with a USB cable.
2. Click **Download** to download the `.hex` file.
3. Move the `.hex` file from your computer onto the **@drivename@** drive. The next section has instructions for the browser that you're using.
## How to transfer the program with your browser
Here are instructions for different browsers on Windows and Mac computers. Choose the one you're using:
### Windows browsers
* [Microsoft Edge](/device/usb/windows-edge)
* [Internet Explorer](/device/usb/windows-ie)
* [Chrome](/device/usb/windows-chrome)
* [Firefox](/device/usb/windows-firefox)
### Mac browsers
* [Safari](/device/usb/mac-safari)
* [Chrome](/device/usb/mac-chrome)
* [Firefox](/device/usb/mac-firefox)
## ~hint
Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot).
## ~

View File

@ -0,0 +1,69 @@
# Uploading from Chrome for Mac
While you're writing and testing your programs, you'll mostly be [running them
in the simulator](/device/simulator), but once you've finished your program you
can **compile** it and run it on your micro:bit.
The basic steps are:
1. Connect your micro:bit to your computer via USB
2. Click **Download** and download the `.hex` file
3. Copy the `.hex` file from your computer onto the micro:bit drive
## Requirements
You need the following things to transfer and run a script on your micro:bit:
* A-Male to Micro USB cable to connect your computer to your micro:bit. This is
the same cable that is commonly used to connect a smart phone to a computer.
* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later
## Step 1: Connect your micro:bit to your computer
First, connect the micro:bit:
1. Connect the small end of the USB cable to the micro USB port on your micro:bit.
2. Connect the other end of the USB cable to a USB port on your computer.
Your computer should recognise your micro:bit as a new drive. On computers
running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac
it appears as a new drive under Devices.
![](/static/mb/device/usb-osx-device.png)
## Step 2: Download your program
1. Open your project on @homeurl@
2. Click **Download**
3. When prompted, choose to **save** the compiled file onto your computer. The
prompt will be different depending on which browser you are using, or
whether you are using a Windows computer or a Mac
When you select **Download** in Chrome, the file will appear at the bottom of
the browser. Click on the small arrow and select **Show in Finder**. This will
show the file in your download folder. Drag and drop the file onto your
`MICROBIT` drive.
![](/static/mb/device/usb-osx-chrome.png)
## Step 3: Transfer the file to your micro:bit
* Once you've found the folder containing your `.hex` file, drag and drop it
onto your `MICROBIT` drive
* The LED on the back of your micro:bit flashes during the transfer (which
should only take a few seconds).
* Once transferred, the code will run automatically on your micro:bit. To rerun
your program, press the reset button on the back of your micro:bit. The reset
button automatically runs the newest file on the micro:bit.
By copying the script onto the `MICROBIT` drive, you have programmed it into the
flash memory on the micro:bit, which means even after you unplug the micro:bit,
your program will still run if the micro:bit is powered by battery.
## ~hint
Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot).
## ~

View File

@ -0,0 +1,71 @@
# Uploading from Firefox for Mac
While you're writing and testing your programs, you'll mostly be [running them
in the simulator](/device/simulator), but once you've finished your program you
can **compile** it and run it on your micro:bit.
The basic steps are:
1. Connect your micro:bit to your computer via USB
2. Click **Download** and download the `.hex` file
3. Copy the `.hex` file from your computer onto the micro:bit drive
## Requirements
You need the following things to transfer and run a script on your micro:bit:
* A-Male to Micro USB cable to connect your computer to your micro:bit. This is
the same cable that is commonly used to connect a smart phone to a computer.
* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later
## Step 1: Connect your micro:bit to your computer
First, connect the micro:bit:
1. Connect the small end of the USB cable to the micro USB port on your micro:bit.
2. Connect the other end of the USB cable to a USB port on your computer.
Your computer should recognise your micro:bit as a new drive. On computers
running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac
it appears as a new drive under Devices.
![](/static/mb/device/usb-osx-device.png)
## Step 2: Download your program
1. Open your project on @homeurl@
2. Click **Download**
3. When prompted, choose to **save** the compiled file onto your computer. The
prompt will be different depending on which browser you are using, or
whether you are using a Windows computer or a Mac
A dialogue box will appear, asking whether you would like to open or save your
hex file. Select **Save file** and click **OK** and the file will then appear in
your downloads in the top right of your browser. Right click on the file and
click on **Show in Finder** and the file will appear in your downloads folder.
Select the file and drag and drop it onto your `MICROBIT` drive.
![](/static/mb/device/usb-osx-firefox-1.jpg)
![](/static/mb/device/usb-osx-firefox-2.png)
## Step 3: Transfer the file to your micro:bit
* Once you've found the folder containing your `.hex` file, drag and drop it
onto your `MICROBIT` drive
* The LED on the back of your micro:bit flashes during the transfer (which
should only take a few seconds).
* Once transferred, the code will run automatically on your micro:bit. To rerun
your program, press the reset button on the back of your micro:bit. The reset
button automatically runs the newest file on the micro:bit.
By copying the script onto the `MICROBIT` drive, you have programmed it into the
flash memory on the micro:bit, which means even after you unplug the micro:bit,
your program will still run if the micro:bit is powered by battery.
## ~hint
Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot).
## ~

View File

@ -0,0 +1,68 @@
# Uploading from Safari for Mac
While you're writing and testing your programs, you'll mostly be [running them
in the simulator](/device/simulator), but once you've finished your program you
can **compile** it and run it on your micro:bit.
The basic steps are:
1. Connect your micro:bit to your computer via USB
2. Click **Download** and download the `.hex` file
3. Copy the `.hex` file from your computer onto the micro:bit drive
## Requirements
You need the following things to transfer and run a script on your micro:bit:
* A-Male to Micro USB cable to connect your computer to your micro:bit. This is
the same cable that is commonly used to connect a smart phone to a computer.
* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later
## Step 1: Connect your micro:bit to your computer
First, connect the micro:bit:
1. Connect the small end of the USB cable to the micro USB port on your micro:bit.
2. Connect the other end of the USB cable to a USB port on your computer.
Your computer should recognise your micro:bit as a new drive. On computers
running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac
it appears as a new drive under Devices.
![](/static/mb/device/usb-osx-device.png)
## Step 2: Download your program
1. Open your project on @homeurl@
2. Click **Download**
3. When prompted, choose to **save** the compiled file onto your computer. The
prompt will be different depending on which browser you are using, or
whether you are using a Windows computer or a Mac
When you select **Download** in Safari a file called `Unknown` will be
downloaded into your Downloads folder. Open your Downloads folder and drag and
drop the file onto your `MICROBIT` drive, under Devices:
![](/static/mb/device/usb-osx-dnd.png)
## Step 3: Transfer the file to your micro:bit
* Once you've found the folder containing your `.hex` file, drag and drop it
onto your `MICROBIT` drive
* The LED on the back of your micro:bit flashes during the transfer (which
should only take a few seconds).
* Once transferred, the code will run automatically on your micro:bit. To rerun
your program, press the reset button on the back of your micro:bit. The reset
button automatically runs the newest file on the micro:bit.
By copying the script onto the `MICROBIT` drive, you have programmed it into the
flash memory on the micro:bit, which means even after you unplug the micro:bit,
your program will still run if the micro:bit is powered by battery.
## ~hint
Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot).
## ~

View File

@ -0,0 +1,24 @@
# Troubleshooting Transfer
You cant drag and drop more than one hex file at once onto your micro:bit. If
you try to drag and drop a second hex file onto your micro:bit before the first
file has finished downloading, then the second file may fail in different ways.
When the first program has been written to the micro:bit, the drive will
disengage. If you drag and drop a second file at this point it may not find the
drive and the second write will fail.
The errors may look like this:
**Windows**
![](/static/mb/device/usb-windows-copy-file-error.jpg)
**Mac**
![](/static/mb/device/usb-osx-copy-file-error.png)
Or it may appear that there are two hex files on your micro:bit so the micro:bit
wont be able to run multiple files. To rectify this, unplug your micro:bit and
plug it in again. Make sure that your micro:bit appears as `MICROBIT` and not
`MAINTENANCE`.

44
docs/device/usb/webusb.md Normal file
View File

@ -0,0 +1,44 @@
# WebUSB
[WebUSB](https://wicg.github.io/webusb/) is an emerging web standard that allows to access @boardname@ from web pages.
It allows for a **one-click download** without installing any additional app or software! It also allows to receive data from the @boardname@.
## Support
* Chrome 79+ browser for Android, Chrome OS, Linux, macOS and Windows 10.
* Microsoft Edge 79+ browser for Android, Chrome OS, Linux, macOS and Windows 10.
## Prepare your @boardname@
Make sure that your @boardname@ is running version **0249** or above of the firmware. Upgrading is as easy as dragging a file and it takes a few seconds to get it done.
* [Check out the instructions to check and upgrade your @boardname@.](/device/usb/webusb/troubleshoot)
## Pair your @boardname@
Here are the steps on the supported browsers:
* connect your @boardname@ to your computer with the microUSB cable
* open a project
* click the triple dot icon on the **Download** button and click **Pair device**
* click on the **Pair device** button and select **Calliope mini** or **DAPLink CMSIS-DAP** from the list.
If you don't see any devices in the list and @boardname@ has the right firmware (**0249** or above), you can create a [support ticket](https://support.microbit.org/support/tickets/new) to notify the Micro:bit Foundation of the problem. Skip the rest of these steps.
## Unpair your @boardname@ #unpair
You will need to unpair your device from the editor to disable WebUSB.
* Click on the **lock** icon in the address bar
* Uncheck each **Calliope mini** or **DAPLink CMSIS-DAP** device
* Reload the page
![](/static/webusb/unpair.gif)
## One-click Download
Once your @boardname@ is paired, MakeCode will use WebUSB to transfer the code without having to drag and drop. Happy coding!
## Console output
MakeCode will be able to "listen" to your @boardname@ and display the console output.

View File

@ -0,0 +1,69 @@
# Troubleshooting downloads with WebUSB
### ~ avatar
Having issues pairing your @boardname@ with [WebUSB](/device/usb/webusb)? Let's try to figure out why!
### ~
## Step 1: Check your cable
Make sure that your @boardname@ is connected to your computer with a micro USB cable. You should see a **MICROBIT** drive appear in Windows Explorer when it's connected.
![MICROBIT drive](/static/mb/device/windows-microbit-drive.png)
**If you can see the MICROBIT drive go to step 2**.
If you can't see the drive:
* Make sure that the USB cable is working.
>Does the cable work on another computer? If not, find a different cable to use. Some cables may only provide a power connection and don't actually transfer data.
* Try another USB port on your computer.
Is the cable good but you still can't see the **MICROBIT** drive? Hmm, you might have a problem with your @boardname@. Try the additional steps described in the [fault finding](https://support.microbit.org/support/solutions/articles/19000024000-fault-finding-with-a-micro-bit) page at microbit.org. If this doesn't help, you can create a [support ticket](https://support.microbit.org/support/tickets/new) to notify the Micro:bit Foundation of the problem. **Skip the rest of these steps**.
## Step 2: Check your firmware version
It's possible that the firmware version on the @boardname@ needs an update. Let's check:
1. Go to the **MICROBIT** drive.
2. Open the **DETAILS.TXT** file.<br/>
![](/static/mb/device/mb-drive-contents.jpg)<br/>
3. Look for a line in the file that says the version number. It should say **Version: \.\.\.**
![](/static/mb/device/details-txt.jpg)
or **Interface Version: \.\.\.**
![](/static/mb/device/details-243.png)
<br/>
If the version is **0234**, **0241**, **0243** you **NEED** to update the [firmware](/device/firmware) on your @boardname@. Go to **Step 3** and follow the upgrade instructions.
If the version is **0249**, **0250** or higher, **you have the right firmware** go to step **4**.
## Step 3: Upgrade the firmware
1. Put your @boardname@ into **MAINTENANCE Mode**. To do this, unplug the USB cable from the @boardname@ and then re-connect the USB cable while you hold down the reset button. Once you insert the cable, you can release the reset button. You should now see a **MAINTENANCE** drive instead of the **MICROBIT** drive like before. Also, a yellow LED light will stay on next to the reset button.
![MAINTENANCE gesture](/static/mb/device/maintenance.gif)
2. **[Download the firmware .hex file](https://microbit.org/guide/firmware/)**
3. Drag and drop that file onto the **MAINTENANCE** drive.
4. The yellow LED will flash while the `HEX` file is copying. When the copy finishes, the LED will go off and the @boardname@ resets. The **MAINTENANCE** drive now changes back to **MICROBIT**.
5. The upgrade is complete! You can open the **DETAILS.TXT** file to check and see that the firmware version changed to the match the version of the `HEX` file you copied.
### ~hint
If you want to know more about connecting the board, MAINTENANCE Mode, and upgrading the firmware, read about it in the [Firmware guide](https://microbit.org/guide/firmware/).
### ~
## Step 4: Check your browser version
WebUSB is a fairly new feature and may require you to update your browser. Check that your browser version matches one of these:
* Chrome 65+ for Android, Chrome OS, Linux, macOS and Windows 10.
## Step 5: Pair device
Once you've updated the firmware, open the **Chrome Browser**, go to the editor and click on **Pair Device** in the gearwheel menu.
See [WebUSB](/device/usb/webusb) for pairing instructions.
Enjoy fast downloads!

View File

@ -0,0 +1,92 @@
# Uploading from Chrome for Windows
## ~ hint
Starting with Chrome 65 on Windows 10,
you can use **WebUSB** to download with one-click.
[Learn more about WebUSB...](/device/usb/webusb).
## ~
While you're writing and testing your programs, you'll mostly be [running them
in the simulator](/device/simulator), but once you've finished your program you
can **compile** it and run it on your micro:bit.
The basic steps are:
1. Connect your micro:bit to your computer via USB
2. Click **Download** and download the `.hex` file
3. Copy the `.hex` file from your computer onto the micro:bit drive
## Requirements
You need the following things to transfer and run a script on your micro:bit:
* A-Male to Micro USB cable to connect your computer to your micro:bit. This is
the same cable that is commonly used to connect a smart phone to a computer.
* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later
## Step 1: Connect your micro:bit to your computer
First, connect the micro:bit:
1. Connect the small end of the USB cable to the micro USB port on your micro:bit.
2. Connect the other end of the USB cable to a USB port on your computer.
Your computer should recognise your micro:bit as a new drive. On computers
running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac
it appears as a new drive under Devices.
![](/static/mb/device/usb-windows-device.jpg)
## Step 2 (optional): Configure Chrome to ask where to save the file
You only need to do this once.
1. Open the **Settings** for Chrome.
2. Click **Advanced** at the bottom of the page.
3. Find the **Downloads** settings.
4. Enable the setting **Ask where to save each file before downloading**.
## Step 3: Download your program
1. Open your project on @homeurl@
2. Click **Download**
3. If you did Step 2 above, Chrome will ask where to save the `.hex` file,
so save it into the `MICROBIT` drive.
Otherwise, continue with one of the options in Step 4 below.
## Step 4: Transfer the file to your micro:bit
If the file was saved onto your computer, you will need to transfer it to the micro:bit.
## Manual transfer
Your `.hex` file (created in Step 3 above) appears as a download at the bottom of the browser.
Click on the arrow next to the name of the file and then click **Show in folder**.
![](/static/mb/device/usb-windows-chrome.png)
In File Explorer, drag and drop the `.hex` file from the download folder onto the `MICROBIT` drive.
Alternatively, right-click on the hex file, choose **Send to**, and then **MICROBIT**.
![](/static/mb/device/usb-windows-sendto.jpg)
## Step 5: After transferring the file
* The LED on the back of your micro:bit flashes during the transfer (which
should only take a few seconds).
* Once transferred, the code will run automatically on your micro:bit. To rerun
your program, press the reset button on the back of your micro:bit. The reset
button automatically runs the newest file on the micro:bit.
* By copying the script onto the `MICROBIT` drive, you have programmed it into the
flash memory on the micro:bit, which means even after you unplug the micro:bit,
your program will still run if the micro:bit is powered by battery.
## ~hint
Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot).
## ~

View File

@ -0,0 +1,72 @@
# Uploading from Microsoft Edge on Windows
How to compile, transfer, and run a program on your micro:bit on **Microsoft Edge**.
While you're writing and testing your programs, you'll mostly be [running them
in the simulator](/device/simulator), but once you've finished your program you
can **compile** it and run it on your micro:bit.
The basic steps are:
1. Connect your @boardname@ to your computer via USB
2. Click **Download** to download the `.hex` file
3. Click the **Save As** button in the bottom bar and save the `.hex` file into the MICROBIT drive
## Requirements
You need the following things to transfer and run a script on your micro:bit:
* A-Male to Micro USB cable to connect your computer to your micro:bit. This is
the same cable that is commonly used to connect a smart phone to a computer.
* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later
## Step 1: Connect your micro:bit to your computer
First, connect the micro:bit:
1. Connect the small end of the USB cable to the micro USB port on your micro:bit.
2. Connect the other end of the USB cable to a USB port on your computer.
Your computer should recognise your micro:bit as a new drive. On computers
running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac
it appears as a new drive under Devices.
![](/static/mb/device/usb-windows-device.jpg)
## Step 2: Download your program
1. Open your project on @homeurl@
2. Click **Download**
3. When prompted, choose to **save** the compiled file onto your computer. The
prompt will be different depending on which browser you are using, or
whether you are using a Windows computer or a Mac
A message will appear at the bottom of the browser asking what you want to do
with the file.
4. Click **Save As**
![Save download file dialog](/static/mb/device/usb/save-as-edge.gif)
5. Save the ``.hex`` file into the **MICROBIT** drive
![Save hex file to MICROBIT drive](/static/mb/device/usb/save-as-windows.png)
## Step 3: Transfer the file to your micro:bit
* The LED on the back of your micro:bit flashes during the transfer (which
should only take a few seconds).
* Once transferred, the code will run automatically on your @boardname@. To rerun
your program, press the reset button on the back of your @boardname@. The reset
button automatically runs the newest file on the micro:bit.
By copying the script onto the `MICROBIT` drive, you have programmed it into the
flash memory on the micro:bit, which means even after you unplug the micro:bit,
your program will still run if the micro:bit is powered by battery.
## ~hint
Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot).
## ~

View File

@ -0,0 +1,71 @@
# Uploading from Firefox on Windows
How to compile, transfer, and run a program on your micro:bit on **Firefox for Windows**.
While you're writing and testing your programs, you'll mostly be [running them
in the simulator](/device/simulator), but once you've finished your program you
can **compile** it and run it on your micro:bit.
The basic steps are:
1. Connect your micro:bit to your computer via USB
2. Click **Download** and download the `.hex` file
3. Click the **Save As** button and save the `.hex` file into the MICROBIT drive
## Requirements
You need the following things to transfer and run a script on your micro:bit:
* A-Male to Micro USB cable to connect your computer to your micro:bit. This is
the same cable that is commonly used to connect a smart phone to a computer.
* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later
## Step 1: Connect your micro:bit to your computer
First, connect the micro:bit:
1. Connect the small end of the USB cable to the micro USB port on your micro:bit.
2. Connect the other end of the USB cable to a USB port on your computer.
Your computer should recognise your micro:bit as a new drive. On computers
running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac
it appears as a new drive under Devices.
![](/static/mb/device/usb-windows-device.jpg)
## Step 2: Download your program
1. Open your project on @homeurl@.
2. Click **Download**.
3. When prompted, choose to **save** the compiled file onto your computer. The
prompt will be different depending on which browser you are using, or
whether you are using a Windows computer or a Mac.
![Save download file dialog](/static/mb/device/usb/save-file-firefox.gif)
A window may appear asking whether you want to save or open the `.hex` file. If it doesn't, go click on the downloads icon at the top of the browser.
![Save file prompt](/static/mb/device/usb/open-file-firefox.png)
Click the folder icon and copy the file from the list of downloads to the **MICROBIT** drive.
![Move hex file to MICROBIT drive](/static/mb/device/usb/move-hex-file-firefox.png)
## Step 3: Transfer the file to your micro:bit
* The LED on the back of your micro:bit flashes during the transfer (which
should only take a few seconds).
* Once transferred, the code will run automatically on your @boardname@. To rerun
your program, press the reset button on the back of your @boardname@. The reset
button automatically runs the newest file on the micro:bit.
By copying the script onto the `MICROBIT` drive, you have programmed it into the
flash memory on the micro:bit, which means even after you unplug the micro:bit,
your program will still run if the micro:bit is powered by battery.
## ~hint
Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot).
## ~

View File

@ -0,0 +1,70 @@
# Uploading from Internet Explorer on Windows
While you're writing and testing your programs, you'll mostly be [running them
in the simulator](/device/simulator), but once you've finished your program you
can **compile** it and run it on your micro:bit.
The basic steps are:
1. Connect your micro:bit to your computer via USB
2. Click **Download** and download the `.hex` file
3. **Click the down arrow next to Save** in the bottom bar and select **Save As**.
4. In the save dialog, save the `.hex` file into the MICROBIT drive
## Requirements
You need the following things to transfer and run a script on your micro:bit:
* A-Male to Micro USB cable to connect your computer to your micro:bit. This is
the same cable that is commonly used to connect a smart phone to a computer.
* A PC running Windows 7 or later, or a Mac running OS X 10.6 or later
## Step 1: Connect your micro:bit to your computer
First, connect the micro:bit:
1. Connect the small end of the USB cable to the micro USB port on your micro:bit.
2. Connect the other end of the USB cable to a USB port on your computer.
Your computer should recognise your micro:bit as a new drive. On computers
running Windows, `MICROBIT` appears as a drive under Devices and drives. On a Mac
it appears as a new drive under Devices.
![](/static/mb/device/usb-windows-device.jpg)
## Step 2: Download your program
1. Open your project on @homeurl@
2. Click **Download**
3. When prompted, choose to **save** the compiled file onto your computer. The
prompt will be different depending on which browser you are using, or
whether you are using a Windows computer or a Mac
A message will appear at the bottom of the browser asking what you want to do
with the file. Click **on the arrow next to Save** and click **Save As**
![Save download file dialog](/static/mb/device/usb/save-as-ie.gif)
In the save dialog, save as the ``.hex`` file to the MICROBIT drive.
![Save hex file to MICROBIT drive](/static/mb/device/usb/save-as-windows.png)
## Step 3: Transfer the file to your micro:bit
* The LED on the back of your micro:bit flashes during the transfer (which
should only take a few seconds).
* Once transferred, the code will run automatically on your @boardname@. To rerun
your program, press the reset button on the back of your @boardname@. The reset
button automatically runs the newest file on the micro:bit.
By copying the script onto the `MICROBIT` drive, you have programmed it into the
flash memory on the micro:bit, which means even after you unplug the micro:bit,
your program will still run if the micro:bit is powered by battery.
## ~hint
Transfer not working? See some [troubleshooting tips](/device/usb/troubleshoot).
## ~

View File

@ -0,0 +1,65 @@
# Troubleshooting downloads from the Windows 10 App
### ~ avatar
Is the [Windows App](https://www.microsoft.com/store/apps/9pjc7sv48lcx) not downloading your program properly? Let's try to figure out why!
### ~
## Step 1: Check your cable
Make sure that your @boardname@ is connected to your computer with a micro USB cable. You should see a **MICROBIT** drive appear in Windows Explorer when it's connected.
![MICROBIT drive](/static/mb/device/windows-microbit-drive.png)
**If you can see the MICROBIT drive go to step 2**.
If you can't see the drive:
* Make sure that the USB cable is working.
>Does the cable work on another computer? If not, find a different cable to use. Some cables may only provide a power connection and don't actually transfer data.
* Try another USB port on your computer.
Is the cable good but you still can't see the **MICROBIT** drive? Hmm, you might have a problem with your @boardname@. Try the additional steps described in the [fault finding](https://support.microbit.org/support/solutions/articles/19000024000-fault-finding-with-a-micro-bit) page at microbit.org. If this doesn't help, you can create a [support ticket](https://support.microbit.org/support/tickets/new) to notify the Micro:bit Foundation of the problem. **Skip the rest of these steps**.
## Step 2: Check your firmware version
It's possible that the firmware version on the @boardname@ needs an update. Let's check:
1. Go to the **MICROBIT** drive.
2. Open the **DETAILS.TXT** file.<br/>
![](/static/mb/device/mb-drive-contents.jpg)<br/>
3. Look for a line in the file that says the version number. It should say **Version: \.\.\.**
![](/static/mb/device/details-txt.jpg)<br/>
If the version is **0234**, you **NEED** to update the [firmware](/device/firmware) on your @boardname@. Go to **Step 3** and follow the upgrade instructions.
If the version is **0241**, **0243** or higher, **you have the right firmware**. You can create a [support ticket](https://support.microbit.org/support/tickets/new) to notify the Micro:bit Foundation of the problem. **Skip the rest of these steps**.
## Step 3: Upgrade the firmware
1. Put your @boardname@ into **MAINTENANCE Mode**. To do this, unplug the USB cable from the @boardname@ and then re-connect the USB cable while you hold down the reset button. Once you insert the cable, you can release the reset button. You should now see a **MAINTENANCE** drive instead of the **MICROBIT** drive like before. Also, a yellow LED light will stay on next to the reset button.
![MAINTENANCE gesture](/static/mb/device/maintenance.gif)
2. **[Download the firmware .hex file](https://microbit.org/guide/firmware/#update-firmware)**
3. Drag and drop that file onto the **MAINTENANCE** drive.
4. The yellow LED will flash while the `HEX` file is copying. When the copy finishes, the LED will go off and the @boardname@ resets. The **MAINTENANCE** drive now changes back to **MICROBIT**.
5. The upgrade is complete! You can open the **DETAILS.TXT** file to check and see that the firmware version changed to the match the version of the `HEX` file you copied.
### ~hint
If you want to know more about connecting the board, MAINTENANCE Mode, and upgrading the firmware, read about it in the [micro:bit firmware guide](https://microbit.org/guide/firmware).
### ~
## Step 4: Wait for the driver updates
Once you've updated the firmware, Windows will detect the updated device and install the drivers necessary to enable communication with the @boardname@. This step happens in the background and may take a minute or two.
## Step 5: Drag and drop a fresh .hex file
If different editors were used with this board, it may need a reset to bring it back to a known-good state. Do this by dragging a ``.hex`` file containing a simple program onto the drive. You can use the one here. Click on the **Download** icon below the blocks, then drag and drop the file onto the @drivename@ drive.
```blocks
basic.forever(function() {
basic.showString("OK")
})
```

47
docs/examples.md Normal file
View File

@ -0,0 +1,47 @@
# Examples
Here are some fun programs for your @boardname@!
## Fun stuff
```codecard
[{
"name": "Rando",
"description": "Randomly blinking LEDs",
"url": "/examples/rando",
"cardType": "example"
},
{
"name": "Game of Life",
"description": "A Game of Life simulation in LEDs",
"url": "/examples/gameofLife",
"cardType": "example"
},
{
"name": "Pi Monte Carlo",
"description": "Approximate the number Pi",
"url": "/examples/pi-montecarlo",
"cardType": "example"
}]
```
## Sensors
```codecard
[{
"name": "Egg & Spoon Race",
"description": "Balance a micro:bit like an egg and spoon race",
"url": "/examples/egg-and-spoon",
"cardType": "example"
},{
"name": "Plot Acceleration",
"description": "Chart acceleration on the LED screen",
"url": "/examples/plot-acceleration",
"cardType": "example"
}, {
"name": "Radio Dashboard",
"description": "A dashboard for radio clients",
"url": "/examples/radio-dashboard",
"cardType": "example"
}]
```

View File

@ -73,8 +73,8 @@ basic.forever(() => {
inside = 0
for (let i = 0; i < n; i++) {
// generate a point within the square
x = Math.randomRange(0, r + 1)
y = Math.randomRange(0, r + 1)
x = randint(0, r + 1)
y = randint(0, r + 1)
// test if the point is within the circle
// sqrt(x**2 + y**2) < r ==> x**2 + y**2 < r**2
if (x * x + y * y < r2) {

View File

@ -4,6 +4,6 @@ Generate a random coordinate and display it on the LED screen.
```blocks
basic.forever(() => {
led.toggle(Math.randomRange(0, 4), Math.randomRange(0, 4))
led.toggle(randint(0, 4), randint(0, 4))
})
```

63
docs/live-coding.md Normal file
View File

@ -0,0 +1,63 @@
# Live coding sessions
Here are some videos of live tutorial sessions with the @boardname@!
## Fun stuff
```codecard
[
{
"name": "Daily Coding Lessons!",
"description": "Subscribe to our mixer.com stream. Live coding Monday through Friday at 9AM PST / Noon EST / 4PM GMT",
"url": "https://mixer.com/MakeCode",
"imageUrl": "/static/live-coding/live.png"
},
{
"name": "Flashing Heart",
"description": "Demonstrating the Flashing Heart tutorial, live.",
"youTubeId": "NvEOKZ8wh9s",
"imageUrl": "/static/live-coding/showleds.jpg"
},
{
"name": "Name Tag",
"description": "A live illustration of the Name tag tutorial",
"youTubeId": "xpRI5jjQ31E",
"imageUrl": "/static/live-coding/showstring.jpg"
},
{
"name": "Smiley Button",
"description": "Step by step live coding of the Smiley Button tutorial.",
"youTubeId": "BgDxz3M7JIM"
},
{
"name": "Dice",
"description": "Step by step live coding of the Dice tutorial.",
"youTubeId": "OmrmjtOm_sQ"
},
{
"name": "Love Meter",
"description": "Steps by step live coding of the Love Meter tutorial",
"youTubeId": "1IYsy0_9n8g"
},
{
"name": "Micro Chat",
"description": "Steps by step live coding of the Micro Chat tutorial",
"youTubeId": "5XqsGROG2fI"
},
{
"name": "Rock Paper Scissor",
"description": "Steps by step live coding of the Rock Paper Scissor tutorial",
"youTubeId": "94lLBB3b1kU"
},
{
"name": "Playlist",
"description": "See all the previous live stream sessions",
"url": "https://www.youtube.com/watch?v=NvEOKZ8wh9s&list=PLMMBk9hE-SepocOwueEtTDyOPI_TBE9yC",
"imageUrl": "/static/live-coding/playlist.png"
}
]
```
## See Also
[YouTube Playlist](https://www.youtube.com/watch?v=NvEOKZ8wh9s&list=PLMMBk9hE-SepocOwueEtTDyOPI_TBE9yC)

View File

@ -35,7 +35,7 @@ Put a ``||Math:pick random||`` block in the ``||basic:show number||`` block to p
```blocks
input.onGesture(Gesture.Shake, () => {
basic.showNumber(Math.randomRange(0, 10))
basic.showNumber(randint(0, 10))
})
```
@ -45,7 +45,7 @@ A typical dice shows values from `1` to `6`. So, in ``||Math:pick random||``, do
```blocks
input.onGesture(Gesture.Shake, () => {
basic.showNumber(Math.randomRange(1, 6))
basic.showNumber(randint(1, 6))
})
```

View File

@ -0,0 +1,18 @@
# Escape Room
Projects used to create escape room experiences.
## Radio
```codecard
[{
"name": "Rotary Dial Radio",
"url":"/projects/rotary-dial-radio",
"description": "Turn an antique rotary dial phone into a radio transmitter",
"imageUrl":"/static/mb/projects/rotary-dial-radio.png"
}]
```
## Acknowledgments
Escape room ideas are gathered from a great discussion with [Pauline Maas](https://twitter.com/4pip) and [Peter Heldens](https://twitter.com/PeterHeldens) at https://microbit101.nl/.

View File

@ -21,7 +21,7 @@ Using ``||basic:show number||`` and ``||Math:pick random||`` blocks, show a rand
```blocks
input.onPinPressed(TouchPin.P0, () => {
basic.showNumber(Math.randomRange(0, 100));
basic.showNumber(randint(0, 100));
});
```
## Step 3
@ -35,7 +35,7 @@ Show ``"LOVE METER"`` on the screen when the @boardname@ starts.
```blocks
basic.showString("LOVE METER");
input.onPinPressed(TouchPin.P0, () => {
basic.showNumber(Math.randomRange(0, 100));
basic.showNumber(randint(0, 100));
});
```

View File

@ -0,0 +1,98 @@
# Name Badge
![Name badge project](/static/mb/projects/name-badge/header.png)
Make yourself known with a fancy name badge powered by your @boardname@!
## Code
First, let's get your name to display on the screen.
### Button press
From the ``||input:Input||`` Toolbox drawer, drag an ``||input:on button A pressed||`` block onto the Workspace.
```blocks
input.onButtonPressed(Button.A, function () {
})
```
### Show a string
From the ``||basic:Basic||`` Toolbox drawer drag a ``||basic:show string||`` block into the ``||input:on button A pressed||`` block.
```blocks
input.onButtonPressed(Button.A, function () {
basic.showString("Hello!")
})
```
### Show my name
In the ``||basic:show string||`` block, type your name.
```blocks
input.onButtonPressed(Button.A, function () {
basic.showString("My Name")
})
```
### Test the badge
Go to the simulator and test your name badge by pressing button **A**.
```sim
input.onButtonPressed(Button.A, function () {
basic.showString("My Name")
})
```
### Download
Download the program to your @boardname@:
1. Make sure your @boardname@ is plugged into the computer.
2. Click the `|Download|` button.
## Make
Now that you have your name showing on the @boardname@, let's make a proper badge to wear and display it on.
Cut out a badge shape from a piece of colored construction paper.
![Construction paper and scisssors](/static/mb/projects/name-badge/picture1.png)
Loop a piece of duct tape and stick it on the back of your @boardname@.
![Roll of tape with the other materials](/static/mb/projects/name-badge/picture2.png)
Stick your @boardname@ onto the front of your badge.
![Board attached to the paper](/static/mb/projects/name-badge/picture3.png)
Using a hole-punch, punch out 2 holes in the top of your badge.
![Holes punched in the paper](/static/mb/projects/name-badge/picture4.png)
Attach the battery pack to the @boardname@.
![Battery pack connected to the board](/static/mb/projects/name-badge/picture5.png)
Tape battery pack onto the back of the badge.
![Battery pack taped on](/static/mb/projects/name-badge/picture6.png)
Thread a shoelace through the top 2 holes of your badge.
![Shoelace threaded through a hole](/static/mb/projects/name-badge/picture7.png)
Tie a knot at the end of your shoelace
![Ends of shoelace tied together](/static/mb/projects/name-badge/picture8.png)
Decorate your badge with colored paper, markers, stickers, glitter.
![Completed name badge](/static/mb/projects/name-badge/picture9.png)
It's now finished! your badge is ready let others know who you are.

View File

@ -0,0 +1,200 @@
# Robot Unicorn
## by [Helen Leigh](https://twitter.com/helenleigh)
Hey, I made a herd of very silly gesture controlled robot unicorns I did this because I was bored with those personality-free robots that only move in a straight line. This is a cheap, unreliable, hilarious robot unicorn project suitable for total beginners. You'll learn about LEDs, gesture control, radio, and servo control.
On this project page, I've written up what you'll need to make your own Robot Unicorn, with all the steps you'll need to follow and the code you'll need to write. I've even have videos for each of the steps to help guide you through this project. Happy making and have fun!
![Robot Unicorn](/static/mb/projects/robot-unicorn/robotunicorn.jpg)
## Ingredients
Here's what you'll need. The links telling where to get parts are just examples - with a bit of searching you will be able to find any of these parts cheaper in whatever shop you normally use to get parts like this: eBay, Amazon, Rapid, Digikey, Kitronik, etc.
- Two @boardname@s plus a AAA battery pack for each of them.
- Two 360 continuous rotation servos with wheels (I used FS90R servos with wheels [like this](https://www.kitronik.co.uk/2574-wheel-for-fs90r-60mmx8mm.html)). 360 servos are super cheap, super unreliable and super easy to hook up, which is exactly why I chose them. Remember, the unicorn not going exactly where you expect it to go is kind of the point.
- One small swivelling castor wheel plus the nuts and bolts to fix it to the base (something [like this](https://www.amazon.co.uk/dp/B074WP1QJN/)). You can use a marble like castor wheel designed for robots but if you use the cheaper ones designed for furniture you can figure out a special way to get your robot unicorn to rear up like She Ra's flying unicorn Swift Wind. Or sometimes it will just fall over. Either way, it's funny.
- One 3XAA battery pack with on off switch and leads (something [like this](https://www.amazon.com/x1-5V-Battery-Holder-Switch-Wires/dp/B01C5J4K3Q/)).
- Three crocodile clips, or alligator clips as Americans apparently call them. Cute.
- One unicorn horn. Obviously. I modified an old ``stl`` from Adafruit at [Thingverse](https://www.thingiverse.com/thing:956359) to make it smaller and give it a solid base so it stuck securely onto my unicorn's head. I've included my revised ``stl`` file in the project files at the bottom of this project page if you want to 3D print your own, or you can make a horn from whatever kind of material you like!
- Something shiny for the tail. I used tinsel for some and tiny disco balls for some others.
- Three sheets of A4 card, the sparklier the better. I've made pdf templates for the shape of the body and head which you can either use as a printed template or as a lasercutting file. You'll find the pdfs in the project files at the bottom of this project page. If you want to experiment with using other materials for your Robot Unicorn, go for it! I've used a card base and a furry body, my friend made a leather version and I've also lasercut semi transparent polypropylene for the head, putting LEDs, jelly beans, copper tape and glitter inside. (The glitter was a total pain. 0/10 do not recommend.)
- Some wire strippers and some electrical tape.
- Some double sided sticky tape, some sellotape and/or some decent glue. Those double sided sticky pads work really well for fixing the servos to the cardboard chassis.
![micro:bits and Unicorn Horn](/static/mb/projects/robot-unicorn/microbitsunicorn.jpg)
### Instructions
**1. Make the unicorn body!** I've made the video below to show how to put your unicorn together using the templates in the project files at the bottom of this project page. Not feeling crafty? That's okay! You can experiment with cutting wheel holes in a small box instead.
https://www.youtube.com/watch?v=CKqrMxuZ6gQ
<br/>
**2. Add in the electronics!** Put on the wheels, then wire up the servos and the battery and the first @boardname@. Just watch my video to see how.
https://youtu.be/CKqrMxuZ6gQ?t=178
<br/>
**3. Code it!** I've supplied my code below, but I'd recommend that you watch the videos I've made so that you understand what is going on. The first video gets you started with one @boardname@, and the second helps you take the next step: gesture controlling your robot unicorn with two @boardname@s. **Pro tip**: there are lots of ways to get the same results using different code, so it's totaslly fine if your code works but doesn't match mine.
**Getting started with @boardname@**
https://www.youtube.com/watch?v=OBcVMPdAIoE
<br/>
**Using gesture control and radio to control your Robot Unicorn with @boardname@**
https://www.youtube.com/watch?v=qAakgfNouOI
<br/>
**4. Play!** Make an obstacle course! Make another one and have a race or a dance off with a friend! Once you've mastered the basics of making your unicorn move around you might want to think about how to make improvements.
**5. Tell me about it!** It brings me joy to know other people make my silly inventions. You can say hi [on Twitter](https://twitter.com/helenleigh), follow me [on Insta](https://www.instagram.com/helenleigh_makes/) or [subscribe to my channel on YouTube](https://youtube.com/c/HelenLeigh).
## Code
**MakeCode blocks for the body of the Robot Unicorn**
```blocks
radio.onReceivedNumberDeprecated(function (receivedNumber) {
received = receivedNumber
})
let received = 0
radio.setGroup(1)
received = 4
basic.forever(function () {
if (received == 0) {
basic.showLeds(`
. . # . .
. # # # .
# . # . #
. . # . .
. . # . .
`)
pins.analogWritePin(AnalogPin.P0, 100)
pins.analogWritePin(AnalogPin.P1, 10)
} else if (received == 1) {
basic.showLeds(`
. . # . .
. . # . .
# . # . #
. # # # .
. . # . .
`)
pins.analogWritePin(AnalogPin.P0, 10)
pins.analogWritePin(AnalogPin.P1, 100)
} else if (received == 2) {
pins.analogWritePin(AnalogPin.P0, 20)
pins.analogWritePin(AnalogPin.P1, 20)
basic.showLeds(`
. . # . .
. # . . .
# # # # #
. # . . .
. . # . .
`)
} else if (received == 3) {
pins.analogWritePin(AnalogPin.P0, 80)
pins.analogWritePin(AnalogPin.P1, 80)
basic.showLeds(`
. . # . .
. . . # .
# # # # #
. . . # .
. . # . .
`)
} else if (received == 4) {
pins.analogWritePin(AnalogPin.P0, 0)
pins.analogWritePin(AnalogPin.P1, 0)
basic.showLeds(`
# . . . #
. # . # .
. . # . .
. # . # .
# . . . #
`)
}
})
```
**MakeCode blocks for the Robot Unicorn controller**
```blocks
input.onButtonPressed(Button.AB, function () {
radio.sendNumber(4)
basic.showLeds(`
# . . . #
. # . # .
. . # . .
. # . # .
# . . . #
`)
})
input.onGesture(Gesture.Shake, function () {
radio.sendNumber(1)
basic.showLeds(`
. . # . .
. . # . .
# . # . #
. # # # .
. . # . .
`)
})
input.onGesture(Gesture.LogoDown, function () {
radio.sendNumber(0)
basic.showLeds(`
. . # . .
. # # # .
# . # . #
. . # . .
. . # . .
`)
})
input.onGesture(Gesture.TiltRight, function () {
radio.sendNumber(2)
basic.showLeds(`
. . # . .
. . . # .
# # # # #
. . . # .
. . # . .
`)
})
input.onGesture(Gesture.TiltLeft, function () {
radio.sendNumber(3)
basic.showLeds(`
. . # . .
. # . . .
# # # # #
. # . . .
. . # . .
`)
})
radio.setGroup(1)
radio.setTransmitPower(7)
basic.showLeds(`
. . # . .
. # # # .
# # # # #
# # # # #
. # . # .
`)
```
## Everythin Else
Here's where you can find all the templates you need to make the Robot Unicorn.
- Template for the main part of the body: [pdf file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20chassis%20A4.pdf) and [ai file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20chassis%20A4.ai).
- Template for the top part of the body: [pdf file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20lid%20a4.pdf) and [ai file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20lid%20a4.ai).
- Template for the head: [pdf file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20head%20A4.pdf) and [ai file here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20head%20A4.ai).
- STL file for 3D printing your Robot Unicorn horn [is here](https://github.com/helenleigh/robot-unicorn/blob/master/unicorn%20horn%20solid%20base.stl).
![Robot Unicorn Tail](/static/mb/projects/robot-unicorn/robotunicorntail.jpg)
```package
radio
```

View File

@ -0,0 +1,232 @@
# Rotary Dial Radio
Rotary dial phones may not be one of the latest tech fashions but they've still got some wings if you pair them with a @boardname@. If you are lucky enough to still own one of these antiques, follow this guide and you can bring it into the 21st century.
![A rotary dial phone connected to a @boardname@](/static/mb/projects/rotary-dial-radio/final.jpg)
This guide is mainly a journal of notes and techniques used to convert a 1945 rotary dial into a @boardname@ radio encoder. This is an example of **reverse engineering**, a treasure hunt for engineers if you wish.
### ~ hint
### Stay safe
Opening and handling any electrical device can be very dangerous. Make sure to unplug all sources of power. Unless you know what you are doing, stay away from wall power outlets (AC).
### ~
## What is Pulse dialing?
The phone below is a Belgium rotary dial phone from 1945. It's really heavy and the dial makes a wonderful clicking noise when it turns.
![Antique rotary dial phone](/static/mb/projects/rotary-dial-radio/oldphone.jpg)
If you skim through the WikiPedia on "rotary dial phones", you'll quickly learn that they operated by using something called **pulse dialing** (https://en.wikipedia.org/wiki/Pulse_dialing). In a nutshell, the dialing mechanism opens and closes a circuit while it rotates which sends a series of electrical pulses on the phone line. One pulse for number 1, two pulses for number 2, and so on. (Hey, what about 0?)
## Digging into the phone
Fortunately for us, the bottom of the phone is easily removed by pressing lever. It reveals the internals of the phone. One can see the two massive bells to ring the phone and some other capacitors and circuitery.
![Inside of a rotary phone](/static/mb/projects/rotary-dial-radio/guts.jpg)
Most interestingly, there are 8 terminals near the 2 holes in the case for wires.
* The 2 terminals on each side are connected by a black wire. This is most likely the ground wire.
* The phone line was missing but there is still a hole for it. Since phone lines carry a bit of electrical current, we'll inject electricity on those terminals.
* Three (3) terminals seem to be used by the handset so they must be carrying some kind of microphone/speaker signal. We'll try each of them.
At this point, we have enough information to start "scoping" the lines and hopefully get lucky and see the pulses. (Did I mention treasure hunting?)
## Scoping the lines
Electrical engineers use tools called "scopes" to "see" the eletrical signals on the line. In our case, we'd like to see the pulses generated when the phone is dialing. We don't have a scope so we'll use the @boardname@ instead.
We connect the @boardname@ to the phone using 3 croc clips:
* **GND** pin goes to the ground terminal
* **3v** pin connects at the positive terminal on the phone line
* **P0** is attacned to one of the headset lines (not **GND**)
![Wiring](/static/mb/projects/rotary-dial-radio/wired.jpg)
In the MakeCode, we upload a program that reads the analog input on **P0** and plots it on the screen. If you pair your @boardname@, you can also see the data in the console view.
```blocks
basic.forever(function () {
led.plotBarGraph(
pins.analogReadPin(AnalogPin.P0),
1023
)
})
```
Try moving the dial slowly...click, click and you should see the pulses, e.g. the signal going high and low. If you don't see anything, keep trying other cables. Be patient, don't give up.
https://youtu.be/po9o77IEDaI
## Detecting the pulses
The @boardname@ can raise an event when an electrical signal on **P0** goes low or high. This is the most important step as it allows us to precisely detect and count pulses. Try the following program with the phone. When you move the dial, you see the first LED turn on and off as the line goes high and low.
```blocks
pins.onPulsed(DigitalPin.P0, PulseValue.High, function () {
led.plot(0, 0)
})
pins.onPulsed(DigitalPin.P0, PulseValue.Low, function () {
led.unplot(0, 0)
})
```
## Counting the pulses
Now that we are detecting pulses, we can use a variable to count them too. In this test program, we increment the **pulseCount** variable by one on each high pulse and we display the number when pressing the **A** button. Try dialing a number; then press A.
```blocks
let pulseCount = 0
input.onButtonPressed(Button.A, function () {
basic.showNumber(pulseCount)
pulseCount = 0
})
pins.onPulsed(DigitalPin.P0, PulseValue.High, function () {
led.plot(0, 0)
})
pins.onPulsed(DigitalPin.P0, PulseValue.Low, function () {
led.unplot(0, 0)
pulseCount += 1
})
```
## Digits and Numbers
Our next task is to detect that the pulses for a digit have finished and we should then record the final number. The phone generates a train of pulses (typically 10 per second) per digit; the user might then move the dial back to start the next digit. This leaves a window of time when nothing happens on the line. If our decoder detects that nothing happens on the line for a long time, say 200ms, we assume that the train is done and save the digit.
Instead of using button **A**, we add a **forever** loop that monitors the elapsed time since the last pulse.
If we have had a pulse (``pulseCount > 0``) **and** the last pulse was more than 200ms ago, we have a digit and we can send it.
```blocks
let pulseCount = 0
let lastPulseMs = 0
pins.onPulsed(DigitalPin.P0, PulseValue.High, function () {
led.plot(0, 0)
})
pins.onPulsed(DigitalPin.P0, PulseValue.Low, function () {
led.unplot(0, 0)
pulseCount += 1
lastPulseMs = input.runningTime()
})
basic.forever(function () {
if (pulseCount > 0 && lastPulseMs - input.runningTime() > 200) {
radio.sendNumber(pulseCount)
basic.showNumber(pulseCount)
pulseCount = 0
}
})
```
## What about 0?
Great question! ``0`` is a special case and is represented by 10 pulses, so we need to update our decoder to take this into account.
```blocks
let pulseCount = 0
let lastPulseMs = 0
pins.onPulsed(DigitalPin.P0, PulseValue.High, function () {
led.plot(0, 0)
})
pins.onPulsed(DigitalPin.P0, PulseValue.Low, function () {
led.unplot(0, 0)
pulseCount += 1
lastPulseMs = input.runningTime()
})
basic.forever(function () {
if (pulseCount > 0 && lastPulseMs - input.runningTime() > 200) {
if(pulseCount == 10) {
pulseCount = 0
}
radio.sendNumber(pulseCount)
basic.showNumber(pulseCount)
pulseCount = 0
}
})
```
## Numbers and more
Improving the program is left as a challenge for you (treasure hunt). The following program was the result of the initial investigation; it waits 3 seconds between digits to send the entire number over radio and uses the screen to display how many digits were entered. This is just an example, you can come up with your own twist on this too!
https://youtu.be/gW6rLH7qH5Q
```blocks
pins.onPulsed(DigitalPin.P0, PulseValue.High, function () {
led.plot(0, 0)
})
function plotIndex (i: number, on: boolean) {
row = Math.idiv(i, 5)
col = i % 5
if (on) {
led.plot(col, row)
} else {
led.unplot(col, row)
}
}
function codeDots () {
for (let index = 0; index <= 4; index++) {
led.plot(index, 2)
}
for (let index2 = 0; index2 <= 9; index2++) {
plotIndex(15 + index2, index2 < code.length)
}
}
pins.onPulsed(DigitalPin.P0, PulseValue.Low, function () {
led.unplot(0, 0)
if (lastPulseMs == 0) {
pulseCount = 0
lastPulseMs = input.runningTime()
} else if (input.runningTime() - lastPulseMs > 85) {
pulseCount += 1
lastPulseMs = input.runningTime()
}
})
let codeNumber = 0
let lastDigitMs = 0
let col = 0
let row = 0
let pulseCount = 0
let code = ""
let lastPulseMs = 0
radio.setGroup(1)
lastPulseMs = 0
code = ""
pulseCount = 0
basic.forever(function () {
if (lastPulseMs > 0 && input.runningTime() - lastPulseMs >= 250) {
led.plot(1, 0)
if (pulseCount == 10) {
pulseCount = 0
}
code = "" + code + convertToText(pulseCount)
lastPulseMs = 0
lastDigitMs = input.runningTime()
} else if (lastPulseMs == 0 && (code.length > 0 && (code.length == 10 || input.runningTime() - lastDigitMs >= 3000))) {
led.plot(2, 0)
codeNumber = parseFloat(code)
for (let index = 0; index < 1; index++) {
radio.sendNumber(codeNumber)
basic.pause(10)
}
basic.clearScreen()
basic.showNumber(codeNumber)
basic.clearScreen()
code = ""
lastPulseMs = 0
} else {
led.unplot(1, 0)
led.unplot(2, 0)
}
codeDots()
})
```
```package
radio
```

View File

@ -0,0 +1,25 @@
# millis
Get the number of milliseconds of time passed since the board was turned on.
```sig
control.millis()
```
## Returns
* the [number](/types/number) of milliseconds of time since the board was turned on.
## Example #example
Find how many days, hours, minutes, and seconds the @boardname@ has been running.
```blocks
let msecs = control.millis()
let seconds = msecs / 1000
let mins = seconds / 60
let hours = mins / 60
let days = hours / 24
```
## #seealso

View File

@ -0,0 +1,67 @@
# wait For Event
Stop running the current code and wait for an event.
```sig
control.waitForEvent(0, 0)
```
You might want your code to stop for a while until some event you're expecting happens.
If you want your code to pause until a known event happens, use a ``||control:wait for event||`` block.
A known event is something you identify that happens on the board or in your program.
An event has both a source and a cause. The source is where the event comes from, like a sensor or
some condition in your program. The cause is what made the event happen at the source.
You assign numbers for your event sources and causes. These numbers are used by [``||control:raise event||``](/reference/control/raise-event) to announce to your program that an event just happened.
As an example, you could make a timer that always causes an event every 100 milliseconds. The source
number for the timer is `6` and the cause value is `1`. The program could wait for one of the time
events like this:
```blocks
const myTimer = 6;
const timerTimeout = 1;
control.runInParallel(function() {
while (true) {
control.waitMicros(100000)
control.raiseEvent(myTimer, timerTimeout)
}
})
control.waitForEvent(myTimer, timerTimeout)
```
## Parameters
* **id**: the identification [number](/types/number) (the source) of this event, such as: `10`.
* **value**: a [number](/types/number) tells what the cause of the event is, like: `4`.
## Example #example
Make a timeout timer to signal every 2 seconds. Wait two times and write to the
console each time.
```blocks
const myTimer = 6;
const timerTimeout = 1;
control.runInParallel(function() {
while (true) {
pause(2000)
control.raiseEvent(myTimer, timerTimeout)
}
})
control.waitForEvent(myTimer, timerTimeout)
console.log("Timer timeout")
control.waitForEvent(myTimer, timerTimeout)
console.log("Timer timeout")
```
**This is an advanced API.** For more information, see the
[@boardname@ runtime messageBus documentation](https://lancaster-university.github.io/microbit-docs/ubit/messageBus/).
## See also #seealso
[raise event](/reference/control/raise-event), [on event](/reference/control/on-event)

View File

@ -17,7 +17,7 @@ This program shows a number from `2` to `9` when you shake the @boardname@.
```blocks
forever(function() {
if (input.isGesture(Gesture.Shake)) {
let x = Math.randomRange(2, 9)
let x = randint(2, 9)
basic.showNumber(x)
}
})

View File

@ -1,6 +1,6 @@
# On Button Pressed
Start an [event handler](/reference/event-handler) (part of the program that will run when something happens, like when a button is pressed).
Start an [event handler](/reference/event-handler) (part of the program that will run when something happens, like when a button is pressed).
This handler works when button `A` or `B` is pressed, or `A` and `B` together.
When you are using this function in a web browser, click the buttons on the screen instead of the ones
on the @boardname@.
@ -18,7 +18,7 @@ https://www.youtube.com/watch?v=t_Qujjd_38o
## Example: count button clicks
This example counts how many times you press the `A` button.
This example counts how many times you press the `A` button.
Each time you press the button, the [LED screen](/device/screen) shows the `count` variable getting bigger.
```blocks
@ -36,7 +36,7 @@ This example shows a number from 1 to 6 when you press the `B` button.
```blocks
input.onButtonPressed(Button.B, () => {
let dice = Math.randomRange(0, 5) + 1
let dice = randint(0, 5) + 1
basic.showNumber(dice)
})
```

View File

@ -19,7 +19,7 @@ This program shows a number from `2` to `9` when you shake the @boardname@.
```blocks
input.onGesture(Gesture.Shake,() => {
let x = Math.randomRange(2, 9)
let x = randint(2, 9)
basic.showNumber(x)
})
```

View File

@ -0,0 +1,46 @@
# Point Brightness
Read the brightness of a LED on the [LED screen](/device/screen).
```sig
led.pointBrightness(0,0);
```
## Parameters
* ``x`` is a [number](/types/number) that means the
horizontal spot on the LED screen (from left to right: 0, 1, 2, 3,
or 4)
* ``y`` is a [number](/types/number) that means the vertical
spot on the LED screen (from top to bottom: 0, 1, 2, 3, or 4)
If a parameter is [out of bounds](/reference/out-of-bounds) (a value
other than 0 to 4), this function will return `false`.
## Returns
* a [number](/blocks/logic/number). If it is `true`, that means the LED is on. If it is `false`, that means the LED is off.
## ~hint
The LED screen is a solid square of LEDs with five LEDs on each side.
To learn more about how you number the LEDs with ``x`` and ``y``
coordinates, see [LED screen](/device/screen).
## ~
## Example: Toggle off
This program turns the center LED (2, 2) off it is not bright enough. (If
it is already off, this program leaves it off.)
```blocks
if (led.pointBrightness(2, 2) < 100) {
led.unplot(2, 2)
}
```
## See also
[unplot](/reference/led/unplot), [plot](/reference/led/plot), [LED screen](/device/screen)

View File

@ -3,22 +3,25 @@
Generation of music tones through pin ``P0``.
```cards
music.playTone(0, 0);
music.ringTone(0);
music.rest(0);
music.beginMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once);
music.stopMelody(MelodyStopOptions.All);
music.onEvent(MusicEvent.MelodyNotePlayed, () => {});
music.beat(BeatFraction.Whole);
music.tempo();
music.changeTempoBy(20);
music.setTempo(120);
music.playTone(0, 0)
music.ringTone(0)
music.rest(0)
music.startMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once)
music.stopMelody(MelodyStopOptions.All)
music.onEvent(MusicEvent.MelodyNotePlayed, () => {})
music.beat(BeatFraction.Whole)
music.tempo()
music.changeTempoBy(20)
music.setTempo(120)
music.setVolume(0)
music.volume()
```
## See Also
[playTone](/reference/music/play-tone), [ringTone](/reference/music/ring-tone), [rest](/reference/music/rest),
[beginMelody](/reference/music/begin-melody),
[stopMelody](/reference/music/stop-melody),
[onEvent](/reference/music/on-event),
[beat](/reference/music/beat), [tempo](/reference/music/tempo), [changeTempoBy](/reference/music/change-tempo-by), [setTempo](/reference/music/set-tempo),
[playTone](/reference/music/play-tone), [ringTone](/reference/music/ring-tone),
[rest](/reference/music/rest), [startMelody](/reference/music/start-melody),
[stopMelody](/reference/music/stop-melody), [onEvent](/reference/music/on-event),
[beat](/reference/music/beat), [tempo](/reference/music/tempo),
[changeTempoBy](/reference/music/change-tempo-by), [setTempo](/reference/music/set-tempo),
[setVolume](/reference/music/set-volume), [volume](/reference/music/volume)

View File

@ -6,9 +6,11 @@ Composing some sound, or maybe some music, is done by putting tones to together,
A _note_ is a tone that is recognized as part of music. A note has a name like '**C**'. A note is played for an amount of time called its _duration_.
On your @boardname@, a note is played on the speaker by sending a signal to a it with a certain _frequency_ called [Hertz](http://wikipedia.org/Hertz). Frequency is how fast something vibrates during one second. If you ring a bell that was made to play an '**A**' note, the bell will vibrate at 440 Hertz (440 times per second). So, notes are just certain frequencies that have special names.
On your @boardname@, a note is played on the speaker by sending a signal to it with a certain _frequency_ called [Hertz](http://wikipedia.org/Hertz). Frequency is how fast something vibrates during one second. If you ring a bell that was made to play an '**A**' note, the bell will vibrate at 440 Hertz (440 times per second). So, notes are just certain frequencies that have special names.
## ~ hint
### ~ hint
#### Listen to music with headphones
Watch this video to see how speakers and headphones make sound when connected to your @boardname@.
@ -24,7 +26,7 @@ Basic notes have names that use one of the first nine letters of the alphabet. T
``|A|``, ``|B|``, ``|C|``, ``|D|``, ``|E|``, ``|F|``, ``|G|``
Ther are other notes named like the basic notes but have extra parts to the name called _sharp_ and _flat_. These other notes are just a bit different from the basic notes and have frequencies a little higher or lower than the basic note. This makes music a little more complicated but much more interesting!
There are other notes named like the basic notes but have extra parts to the name called _sharp_ and _flat_. These other notes are just a bit different from the basic notes and have frequencies a little higher or lower than the basic note. This makes music a little more complicated but much more interesting!
Some of these other notes look like:
@ -32,6 +34,14 @@ Some of these other notes look like:
When a small amount music or even a song is written down it is called [sheet music](https://wikipedia.org/wiki/Sheet_music).
### ~ hint
#### Note names in different languages
Many languages other than English use different names for some or all of the musical notes. MakeCode uses English for names in code.
### ~
## Sounds and music in code
Of course, we can't use written music in our code. We can make music another way. The way to do it is to put names of notes in [strings](/types/string). We make our notes using letters, symbols, and numbers. The notes of a melody are put together in an array like:
@ -51,13 +61,13 @@ What you see here is not some alien language but a bunch of notes with their dur
You might notice that the sound string has an ``'R:1'`` in it. The '**R**` means _rest_ and to rest for one beat. A rest is a pause, or a time of silence, in the sound.
#### ~ hint
### ~ hint
**Duration**
#### Duration
The amount of time a note is played (duration) is measured as _beats_. The standard number _beats per minute_ (bpm) in music is 120 bpm which is one-half of a second of time. A _whole_ note lasts for 4 beats and a _quarter_ note takes just one beat.
#### ~
### ~
## Example

View File

@ -56,7 +56,7 @@ The events related to background melody get triggered by a melody that is played
```
control.inBackground(function () {
basic.pause(Math.randomRange(0, 5000))
basic.pause(randint(0, 5000))
music.beginMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once)
})
music.onEvent(MusicEvent.BackgroundMelodyStarted, function () {

View File

@ -0,0 +1,35 @@
# set Volume
Set the volume for the sound synthesizer.
```sig
music.setVolume(128)
```
### ~hint
#### Simulator
``||music:set volume||`` works on the @boardname@. It might not work in the simulator on every browser.
### ~
## Parameters
* ``volume``: the volume of of the sounds played to the sound output. The volume [number](/types/number) can be between `0` for silent and `255` for the loudest sound.
## Example #example
Set the synthesizer volume to something quieter.
```blocks
music.setVolume(50)
```
## See also
[volume](/reference/music/volume)
```package
music
```

View File

@ -0,0 +1,64 @@
# start Melody
Start playing a musical melody through pin ``P0`` of the @boardname@.
```sig
music.startMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once)
```
## ~ hint
**Simulator**: This function only works on the @boardname@ and in some browsers.
## ~
There are built-in melodies that you can choose from the ``||start melody||`` block. These are already composed for you and are easy to use by just selecting the one you want. If you want to play your own melody, you can [compose](/reference/music/making-melodies) one and use it instead of one of the built-in ones.
Melodies are a sequence of notes, each played for some small amount time, one after the other. The notes in a melody are held in an [array](/types/array) of [strings](/types/string). Each string in the array is a note of the melody. You make a melody by assembling the notes along with the _duration_ that the note plays for. The melody is [formed](/reference/music/making-melodies) like this:
``NOTE[octave][:duration] eg: ['g5:1']``
```block
music.startMelody(['g4:1', 'c5', 'e', 'g:2', 'e:1', 'g:3'], MelodyOptions.Once)
```
Melodies are played either in the _foreground_ or _background_. This allows more than one melody to be active at once. If a melody is set to play in the background, it can be interrupeted, or paused, temporarily while a melody set for the foreground is played. If the foreground melody is not set to play ``forever``, then the background melody resumes when the foreground melody is finished.
You can set options for how you want the melody to play. You can ask that the melody plays just one time, ``once``, or have it keep repeating, ``forever``. With these options the melody will play in the foreground either once or continue to repeat. Of course, if you set ``forever``, any melody that was started in background will never play unless you [stop](/reference/music/stop-melody) the foreground melody. To make a background melody, set the option to ``once in background`` or ``forever in background``.
## Parameters
* **melody**: A built-in melody or an [array](/types/array) representation of a [melody](reference/music/making-melodies) you wish to play.
* **options**: the play option for the melody:
>* ``once``: play the melody in the foreground one time
>* ``forever``: play the melody in the foreground and keep repeating it
>* ``once in background``: play the melody in the background one time
>* ``forever in background``: play the melody in the background and keep repeating it
## Examples
### Play the "Entertainer"
This example plays the ``Entertainer`` built-in melody.
```blocks
music.startMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once)
```
### Play a composed melody forever
Play a made-up melody in the background forever.
```blocks
music.startMelody(['g4:1', 'c5', 'e', 'g:2', 'e:1', 'g:3'], MelodyOptions.ForeverInBackground)
```
## See also
[stop melody](/reference/music/stop-melody), [play tone](/reference/music/play-tone),
[rest](/reference/music/rest), [ring tone](/reference/music/ring-tone),
[tempo](/reference/music/tempo), [set tempo](/reference/music/set-tempo),
[change tempo by](/reference/music/change-tempo-by)
[Making Melodies](/reference/music/making-melodies)

View File

@ -0,0 +1,27 @@
# volume
Get the current volume level of the sound synthesizer.
```sig
music.volume()
```
### ~hint
#### Simulator
Using ``||music:volume||`` works on the @boardname@. It might not work in the simulator on every browser.
### ~
## Returns
* a [number](/types/number) that is the current volume level of output from the sound synthesizer. The value can be between `0` for silent and `255` for the loudest sound.
## See also
[set volume](/reference/music/set-volume)
```package
music
```

View File

@ -11,7 +11,7 @@ is connected to ``GND`` (0 volts), then when you press the button,
button press.
```sig
pins.setPull(DigitalPin.P9, PinPullMode.PullDown);
pins.setPull(DigitalPin.C9, PinPullMode.PullDown);
```
The pull-up and -down resistors are about 13kOhm.

View File

@ -30,7 +30,7 @@ The default number of bits is `8` and the default mode value is `3`.
Set the pins and format for the SPI connection.
```blocks
pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13);
pins.spiPins(DigitalPin.C15, DigitalPin.C14, DigitalPin.C13);
pins.spiFormat(8, 3);
```

View File

@ -26,7 +26,7 @@ Read the value of the _WHOAMI_ register from the device connected to the SPI bus
```blocks
pins.digitalWritePin(DigitalPin.P0, 1);
pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13);
pins.spiPins(DigitalPin.C15, DigitalPin.C14, DigitalPin.C13);
pins.spiFormat(8, 3);
pins.spiFrequency(1000000);
pins.digitalWritePin(DigitalPin.P0, 0);

View File

@ -31,7 +31,7 @@ If you don't set the pins for the SPI connection, the default pin assignments ar
Set the pin assignments for a SPI connection to the default pins.
```blocks
pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13);
pins.spiPins(DigitalPin.C15, DigitalPin.C14, DigitalPin.C13);
```
## See also

View File

@ -28,7 +28,7 @@ Send the command to read the value of the _WHOAMI_ register from the device conn
```blocks
pins.digitalWritePin(DigitalPin.P0, 1);
pins.spiPins(DigitalPin.P15, DigitalPin.P14, DigitalPin.P13);
pins.spiPins(DigitalPin.C15, DigitalPin.C14, DigitalPin.C13);
pins.spiFormat(8, 3);
pins.spiFrequency(1000000);
pins.digitalWritePin(DigitalPin.P0, 0);

View File

@ -8,9 +8,12 @@ serial.readLine();
### ~hint
This function expects the line it reads to be terminated with the `\r`
This function expects the line it reads to be terminated with the `\n`
character. If your terminal software does not terminate lines with
`\r`, this function will probably never return a value.
`\n`, this function will probably never return a value.
You can override the ``serial.NEW_LINE_DELIMITER`` field to change the newline delimiter.
### ~

View File

@ -0,0 +1,58 @@
# Science Experiments
* [Watch Playlist on Youtube](https://www.youtube.com/playlist?list=PLMMBk9hE-SepXDy_290SeRmEpGA2u1pwW)
## Videos
```codecard
[
{
"name": "Data Collection",
"description": "Collect, view, and analyze the data from your experiments.",
"youTubeId": "tZy9Ev21B4c",
"imageUrl": "/static/mb/science-experiments/data-collection.jpg"
},
{
"name": "Population Trait Counter",
"description": "Observe population traits by collecting survey data from people, analyze and track the genetic traits.",
"youTubeId": "NNZEMiJHY2o",
"imageUrl": "/static/mb/science-experiments/population-trait.jpg"
},
{
"name": "Temperature Sensor",
"description": "Chart temperature data in and out of direct sunlight using a sun shield, see if using a windshield sun shade in your car really makes it cooler.",
"youTubeId": "pHDYsy6xyE4",
"imageUrl": "/static/mb/science-experiments/temperature-sensor.jpg"
},
{
"name": "Soil Moisture Sensor",
"description": "Watch this video to find out how you can create a soil moisture sensor to measure the health of your plants!",
"youTubeId": "n0WRQf11Pzo",
"imageUrl": "/static/mb/science-experiments/soil-moisture.jpg"
},
{
"name": "EMG Muscle Sensor",
"description": "Monitor the movement of your muscles and measure the signals to them",
"youTubeId": "vxlPQZIwYRc",
"imageUrl": "/static/mb/science-experiments/emg-muscle-sensor.jpg"
},
{
"name": "Egg Drop",
"description": "Can the egg survive a drop, test the drop force on an egg to find out when it might crack",
"youTubeId": "tnDJFdC3Nd4",
"imageUrl": "/static/mb/science-experiments/egg-drop.jpg"
},
{
"name": "Battery Tester",
"description": "See if your batteries still have their voltage with this battery tester",
"youTubeId": "gdlc34nhjK4",
"imageUrl": "/static/mb/science-experiments/battery-tester.jpg"
},
{
"name": "Rocket Acceleration",
"description": "Have a blast building, launching, and tracking your own rocket!",
"youTubeId": "m9ntqxh8FvQ",
"imageUrl": "/static/mb/science-experiments/rocket-acceleration.jpg"
}
]
```

BIN
docs/static/bluetooth/Bluetooth_SIG.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
docs/static/bluetooth/gatt_hierarchy.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/static/courses/logic-lab.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Some files were not shown because too many files have changed in this diff Show More