Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
Nodemcu Firmware
Commits
7f303813
Commit
7f303813
authored
Oct 25, 2020
by
Marcel P
Committed by
Marcel Stör
Nov 07, 2020
Browse files
Add mcp23017 Lua module (#3197)
parent
29e51088
Changes
5
Show whitespace changes
Inline
Side-by-side
docs/lua-modules/mcp23017.md
0 → 100644
View file @
7f303813
# Lua MCP23017 Module for NodeMCU / ESP8266
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2020-04-10 |
[
Marcel P.
](
https://github.com/plomi-net
)
|
[
Marcel P.
](
https://github.com/plomi-net
)
|
[
mcp23017.lua
](
../../lua_modules/mcp23017/mcp23017.lua
)
|
This Lua module provides access to the MCP23017 I²C I/O Expander.
The
[
MCP23017
](
http://ww1.microchip.com/downloads/en/devicedoc/20001952c.pdf
)
is a port expander and provides 16 channels for inputs and outputs.
Up to 8 devices (128 channels) are possible by the configurable address (A0 - A2).
Due to the 16 channels, 2 bytes are required for switching outputs or reading input signals. These are A and B.
A single pin can be set or a whole byte.
The numbering of the individual pins starts at 0 and ends with 7.
The numbers are for each register GPIO A and GPIO B.
!!! important
The module requires
`i2c`
and
`bit`
C module built into firmware.
### Require
```
lua
mcp
=
require
"mcp23017"
```
## Example Script
The example script can be found
[
here
](
../../lua_examples/mcp23017/mcp23017_example.lua
)
## setup()
Configures the address of the module and tests the connection to the i2c bus.
The i2c id is required for an existing i2c interface, alternatively the sda and scl pins can be specified.
Then this function will establish the connection.
Automatically resets the device state (see
`mcp23017:reset()`
)
#### Syntax
`mcp23017:setup(address, i2c_id)`
#### Parameter
-
`address`
address for MCP23017, default: 0x20 (should be between 0x20 and 0x27)
-
`i2c_id`
id for the i2c bus connection (remember to call i2c.setup before)
#### Return
`true`
if device found, otherwise
`false`
.
#### possible Errors
-
`MCP23017 device on address not found`
-
`MCP23017 address is out of range`
#### Example
```
lua
local
mcp23017
=
require
"mcp23017"
local
address
=
0x20
local
cSCL
=
1
local
cSDA
=
2
local
i2c_instance
=
0
-- setup i2c bus and create instance for mcp23017 (assigned to mcp)
i2c
.
setup
(
i2c_instance
,
cSDA
,
cSCL
,
i2c
.
SLOW
)
local
mcp
=
mcp23017
(
address
,
i2c_instance
)
```
## setMode()
Set the mode of a single channel. This can be OUTPUT or INPUT.
#### Syntax
`mcp23017:setMode(register, pin, mode)`
#### Parameter
-
`register`
the side of channels (GPA or GPB)
-
`pin`
the number to be set for the channel (0-15)
-
`mode`
the mode for the channel. This can be
`mcp23017.INPUT`
or
`mcp23017.OUTPUT`
#### Return
`true`
, in case of error
`nil`
.
#### Example
```
lua
-- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input
mcp
:
setMode
(
mcp
.
GPA
,
7
,
mcp
.
OUTPUT
)
mcp
:
setMode
(
mcp
.
GPB
,
0
,
mcp
.
OUTPUT
)
mcp
:
setMode
(
mcp
.
GPB
,
1
,
mcp
.
INPUT
)
```
## setPin()
Set the state of a single channel. This can be HIGH or LOW.
#### Syntax
`mcp23017:setMode(register, pin, state)`
#### Parameter
-
`register`
the side of channels (GPA or GPB)
-
`pin`
the number to be set for the channel (0-15)
-
`state`
the state for the channel. This can be
`mcp23017.HIGH`
or
`mcp23017.LOW`
#### Return
`true`
, in case of error
`nil`
.
#### Example
```
lua
-- set pin 7 to high (GPA7)
mcp
:
setPin
(
mcp
.
GPA
,
7
,
mcp
.
HIGH
)
-- set pin 8 to low (GPB0)
mcp
:
setPin
(
mcp
.
GPB
,
0
,
mcp
.
LOW
)
```
## getPinState()
get the state for a single channel. This can be HIGH or LOW.
#### Syntax
`mcp23017:getPinState(register, pin)`
#### Parameter
-
`register`
the side of channels (GPA or GPB)
-
`pin`
the number for which a state is to be queried (0-15)
#### Return
`true`
for HIGH,
`false`
for LOW, in case of error
`nil`
.
#### Example
```
lua
-- get the state for pin 9 (GPB1)
print
(
mcp
:
getPinState
(
mcp
.
GPB
,
1
))
```
## reset()
By calling this function, a safe state is established.
All channels are set to input.
This function can be used for a panic program.
#### Syntax
`mcp23017:reset()`
#### Parameter
None
#### Return
None
#### Example
```
lua
-- reset the mcp23017 to startup defaults
mcp
:
reset
()
```
## setInternalPullUp()
Enable or disable the internal pullup resistors.
#### Syntax
`mcp23017:setInternalPullUp(register, byte)`
#### Parameter
-
`register`
the side of channels (GPA or GPB)
-
`byte`
byte to set the pullup resistors
#### Return
None
#### Example
```
lua
-- enable all pullup resistors for GPA
print
(
mcp
:
setInternalPullUp
(
mcp
.
GPA
,
0xFF
))
-- disable all pullup resistors for GPA
print
(
mcp
:
setInternalPullUp
(
mcp
.
GPA
,
0x00
))
```
## writeIODIR()
Setup the mode of the channels with a whole byte.
#### Syntax
`mcp23017:writeIODIR(register, byte)`
#### Parameter
-
`register`
the side of channels (GPA or GPB)
-
`byte`
byte to set the mode for all channels for this register
#### Return
None
#### Example
```
lua
-- set all GPA to input
print
(
mcp
:
writeIODIR
(
mcp
.
GPA
,
0xFF
))
-- set all GPA to output
print
(
mcp
:
writeIODIR
(
mcp
.
GPA
,
0x00
))
```
## writeGPIO()
Setup the output state of the channels with a whole byte.
#### Syntax
`mcp23017:writeGPIO(register, byte)`
#### Parameter
-
`register`
the side of channels (GPA or GPB)
-
`byte`
byte to set the state for all channels for this register
#### Return
None
#### Example
```
lua
-- set all GPA to HIGH
print
(
mcp
:
writeGPIO
(
mcp
.
GPA
,
0xFF
))
-- set all GPA to LOW
print
(
mcp
:
writeGPIO
(
mcp
.
GPA
,
0x00
))
```
## readGPIO()
Read the input states of the channels with a whole byte.
#### Syntax
`mcp23017:readGPIO(register)`
#### Parameter
-
`register`
the side of channels (GPA or GPB)
#### Return
byte with states
#### Example
```
lua
-- get states for GPA
print
(
mcp
:
readGPIO
(
mcp
.
GPA
))
```
lua_examples/mcp23017/mcp23017_example.lua
0 → 100644
View file @
7f303813
--[[
This example demonstrates how to use the different functions of the mcp23017 lua module.
@author Marcel P. | Plomi.net
@github https://github.com/plomi-net
@version 1.0.0
]]
--[[
initialize and setup
]]
-- initialize module
local
mcp23017
=
require
"mcp23017"
local
address
=
0x20
-- the address for MCP23017 (between 0x20 and 0x27)
local
cSCL
=
1
-- SCL pin = 1 = D1 / GPIO 5 (ESP8266)
local
cSDA
=
2
-- SDA pin = 2 = D2 / GPIO4 (ESP8266)
local
i2cId
=
0
-- i2c id
-- setup i2c bus and create instance for mcp23017 (assigned to mcp)
i2c
.
setup
(
i2cId
,
cSDA
,
cSCL
,
i2c
.
SLOW
)
local
mcp
=
mcp23017
(
address
,
i2cId
)
--[[
set output and input channels
]]
-- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input
mcp
:
setMode
(
mcp
.
GPA
,
7
,
mcp
.
OUTPUT
)
mcp
:
setMode
(
mcp
.
GPB
,
0
,
mcp
.
OUTPUT
)
mcp
:
setMode
(
mcp
.
GPB
,
1
,
mcp
.
INPUT
)
--[[
set output channels to high and low
]]
-- set pin 7 to high (GPA7)
mcp
:
setPin
(
mcp
.
GPA
,
7
,
mcp
.
HIGH
)
-- set pin 8 to low (GPB0)
mcp
:
setPin
(
mcp
.
GPB
,
0
,
mcp
.
LOW
)
--[[
toggle pin 6 channel state every second (blinking)
]]
local
currentPin
=
6
local
currentReg
=
mcp
.
GPA
local
currentState
=
false
mcp
:
setMode
(
currentReg
,
currentPin
,
mcp
.
OUTPUT
)
tmr
.
create
():
alarm
(
1000
,
tmr
.
ALARM_AUTO
,
function
()
if
currentState
==
true
then
-- print("set to low")
mcp
:
setPin
(
currentReg
,
currentPin
,
mcp
.
LOW
)
currentState
=
false
else
-- print("set to high")
mcp
:
setPin
(
currentReg
,
currentPin
,
mcp
.
HIGH
)
currentState
=
true
end
end
)
--[[
read input channels and display every 7 seconds
]]
-- read input register
tmr
.
create
():
alarm
(
7000
,
tmr
.
ALARM_AUTO
,
function
()
local
a
=
mcp
:
readGPIO
(
mcp
.
GPA
)
if
a
~=
nil
then
print
(
"GPIO A input states: "
..
a
)
else
print
(
"GPIO A unreadable, check device"
)
end
local
b
=
mcp
:
readGPIO
(
mcp
.
GPB
)
if
b
~=
nil
then
print
(
"GPIO B input states: "
..
b
)
else
print
(
"GPIO B unreadable, check device"
)
end
print
(
" "
)
end
)
lua_modules/mcp23017/README.md
0 → 100644
View file @
7f303813
# MCP23017 Module
Documentation for this Lua module is available in the
[
mcp23017.md
](
../../docs/lua-modules/mcp23017.md
)
file and in the
[
Official NodeMCU Documentation
](
https://nodemcu.readthedocs.io/
)
in
`Lua Modules`
section.
lua_modules/mcp23017/mcp23017.lua
0 → 100644
View file @
7f303813
--[[
This Lua module provides access to the MCP23017 module.
The MCP23017 is a port expander and provides 16 channels for inputs and outputs.
Up to 8 devices (128 channels) are possible by the configurable address (A0 - A2 Pins).
Due to the 16 channels, 2 bytes are required for switching outputs or reading input signals. These are A and B.
A single pin can be set or a whole byte.
The numbering of the individual pins starts at 0 and ends with 7.
The numbers are for each register GPIO A and GPIO B.
The module requires `i2c` and `bit` C module built into firmware.
@author Marcel P. | Plomi.net
@github https://github.com/plomi-net
@version 1.0.0
]]
local
i2c
,
string
,
issetBit
,
setBit
,
clearBit
,
error
=
i2c
,
string
,
bit
.
isset
,
bit
.
set
,
bit
.
clear
,
error
local
isINPUT
,
isGPB
,
isHIGH
=
true
,
true
,
true
-- registers (not used registers are commented out)
local
MCP23017_IODIRA
=
0x00
local
MCP23017_IODIRB
=
0x01
local
MCP23017_DEFVALA
=
0x06
local
MCP23017_DEFVALB
=
0x07
local
MCP23017_GPIOA
=
0x12
local
MCP23017_GPIOB
=
0x13
--[[
local MCP23017_IPOLA = 0x02
local MCP23017_IPOLB = 0x03
local MCP23017_GPINTENA = 0x04
local MCP23017_GPINTENB = 0x05
local MCP23017_DEFVALA = 0x06
local MCP23017_DEFVALB = 0x07
local MCP23017_INTCONA = 0x08
local MCP23017_INTCONB = 0x09
local MCP23017_IOCON = 0x0A
local MCP23017_IOCON2 = 0x0B
local MCP23017_GPPUA = 0x0C
local MCP23017_GPPUB = 0x0D
local MCP23017_INTFA = 0x0E
local MCP23017_INTFB = 0x0F
local MCP23017_INTCAPA = 0x10
local MCP23017_INTCAPB = 0x11
local MCP23017_OLATA = 0x14
local MCP23017_OLATB = 0x15
]]
-- metatable
local
mcp23017
=
{
INPUT
=
isINPUT
,
OUTPUT
=
not
isINPUT
,
GPA
=
not
isGPB
,
GPB
=
isGPB
,
HIGH
=
isHIGH
,
LOW
=
not
isHIGH
}
mcp23017
.
__index
=
mcp23017
-- check device is available on address
local
function
checkDevice
(
address
,
i2cId
)
i2c
.
start
(
i2cId
)
local
response
=
i2c
.
address
(
i2cId
,
address
,
i2c
.
TRANSMITTER
)
i2c
.
stop
(
i2cId
)
return
response
end
-- write byte
local
function
writeByte
(
address
,
i2cId
,
registerAddr
,
val
)
i2c
.
start
(
i2cId
)
i2c
.
address
(
i2cId
,
address
,
i2c
.
TRANSMITTER
)
i2c
.
write
(
i2cId
,
registerAddr
)
i2c
.
write
(
i2cId
,
val
)
i2c
.
stop
(
i2cId
)
end
-- read byte
local
function
readByte
(
address
,
i2cId
,
registerAddr
)
i2c
.
start
(
i2cId
)
i2c
.
address
(
i2cId
,
address
,
i2c
.
TRANSMITTER
)
i2c
.
write
(
i2cId
,
registerAddr
)
i2c
.
stop
(
i2cId
)
i2c
.
start
(
i2cId
)
i2c
.
address
(
i2cId
,
address
,
i2c
.
RECEIVER
)
local
data
=
i2c
.
read
(
i2cId
,
1
)
i2c
.
stop
(
i2cId
)
return
string.byte
(
data
)
end
-- check pin is in range
local
function
checkPinIsInRange
(
pin
)
if
pin
>
7
or
pin
<
0
then
error
(
"MCP23017 the pin must be between 0 and 7"
)
end
return
pin
end
local
function
reset
(
address
,
i2cId
)
writeByte
(
address
,
i2cId
,
MCP23017_IODIRA
,
0xFF
)
writeByte
(
address
,
i2cId
,
MCP23017_IODIRB
,
0xFF
)
end
-- setup device
local
function
setup
(
address
,
i2cId
)
-- check device address (0x20 to 0x27)
if
(
address
<
32
or
address
>
39
)
then
error
(
"MCP23017 address is out of range"
)
end
if
(
checkDevice
(
address
,
i2cId
)
~=
true
)
then
error
(
"MCP23017 device on "
..
string.format
(
'0x%02X'
,
address
)
..
" not found"
)
else
reset
(
address
,
i2cId
)
return
1
end
end
return
function
(
address
,
i2cId
)
local
self
=
setmetatable
({},
mcp23017
)
if
setup
(
address
,
i2cId
)
then
self
.
writeIODIR
=
function
(
sf
,
bReg
,
newByte
)
-- luacheck: no unused
writeByte
(
address
,
i2cId
,
bReg
==
isGPB
and
MCP23017_IODIRB
or
MCP23017_IODIRA
,
newByte
)
end
self
.
writeGPIO
=
function
(
sf
,
bReg
,
newByte
)
-- luacheck: no unused
writeByte
(
address
,
i2cId
,
bReg
==
isGPB
and
MCP23017_GPIOB
or
MCP23017_GPIOA
,
newByte
)
end
self
.
readGPIO
=
function
(
sf
,
bReg
)
-- luacheck: no unused
return
readByte
(
address
,
i2cId
,
-- upvals
bReg
==
isGPB
and
MCP23017_GPIOB
or
MCP23017_GPIOA
)
end
-- read pin input
self
.
getPinState
=
function
(
sf
,
bReg
,
pin
)
-- luacheck: no unused
return
issetBit
(
readByte
(
address
,
i2cId
,
bReg
==
isGPB
and
MCP23017_GPIOB
or
MCP23017_GPIOA
),
checkPinIsInRange
(
pin
))
end
-- set pin to low or high
self
.
setPin
=
function
(
sf
,
bReg
,
pin
,
state
)
-- luacheck: no unused
local
inReq
=
bReg
==
isGPB
and
MCP23017_GPIOB
or
MCP23017_GPIOA
local
inPin
=
checkPinIsInRange
(
pin
)
local
response
=
readByte
(
address
,
i2cId
,
inReq
)
writeByte
(
address
,
i2cId
,
inReq
,
state
==
isHIGH
and
setBit
(
response
,
inPin
)
or
clearBit
(
response
,
inPin
))
return
true
end
-- set mode for a pin
self
.
setMode
=
function
(
sf
,
bReg
,
pin
,
mode
)
-- luacheck: no unused
local
inReq
=
bReg
==
isGPB
and
MCP23017_IODIRB
or
MCP23017_IODIRA
local
inPin
=
checkPinIsInRange
(
pin
)
local
response
=
readByte
(
address
,
i2cId
,
inReq
)
writeByte
(
address
,
i2cId
,
inReq
,
mode
==
isINPUT
and
setBit
(
response
,
inPin
)
or
clearBit
(
response
,
inPin
))
return
true
end
-- reset gpio mode
self
.
reset
=
function
(
sf
)
-- luacheck: no unused
reset
(
address
,
i2cId
)
end
-- setup internal pullup
self
.
setInternalPullUp
=
function
(
sf
,
bReg
,
iByte
)
-- luacheck: no unused
writeByte
(
address
,
i2cId
,
bReg
==
isGPB
and
MCP23017_DEFVALB
or
MCP23017_DEFVALA
,
iByte
)
end
return
self
end
return
nil
end
mkdocs.yml
View file @
7f303813
...
...
@@ -62,6 +62,7 @@ pages:
-
'
liquidcrystal'
:
'
lua-modules/liquidcrystal.md'
-
'
lm92'
:
'
lua-modules/lm92.md'
-
'
mcp23008'
:
'
lua-modules/mcp23008.md'
-
'
mcp23017'
:
'
lua-modules/mcp23017.md'
-
'
redis'
:
'
lua-modules/redis.md'
-
'
telnet'
:
'
lua-modules/telnet.md'
-
'
yeelink'
:
'
lua-modules/yeelink.md'
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment