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
233 changed files with 9391 additions and 2739 deletions

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")]``