Skip to content

Commit 7f30381

Browse files
plomi-netmarcelstoer
authored andcommitted
Add mcp23017 Lua module (#3197)
1 parent 29e5108 commit 7f30381

File tree

5 files changed

+496
-0
lines changed

5 files changed

+496
-0
lines changed

docs/lua-modules/mcp23017.md

+230
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# Lua MCP23017 Module for NodeMCU / ESP8266
2+
3+
| Since | Origin / Contributor | Maintainer | Source |
4+
| :----- | :-------------------- | :---------- | :------ |
5+
| 2020-04-10 | [Marcel P.](https://github.com/plomi-net) | [Marcel P.](https://github.com/plomi-net) | [mcp23017.lua](../../lua_modules/mcp23017/mcp23017.lua) |
6+
7+
8+
This Lua module provides access to the MCP23017 I²C I/O Expander.
9+
10+
The [MCP23017](http://ww1.microchip.com/downloads/en/devicedoc/20001952c.pdf) is a port expander and provides 16 channels for inputs and outputs.
11+
Up to 8 devices (128 channels) are possible by the configurable address (A0 - A2).
12+
13+
Due to the 16 channels, 2 bytes are required for switching outputs or reading input signals. These are A and B.
14+
A single pin can be set or a whole byte.
15+
16+
The numbering of the individual pins starts at 0 and ends with 7.
17+
The numbers are for each register GPIO A and GPIO B.
18+
19+
20+
!!! important
21+
The module requires `i2c` and `bit` C module built into firmware.
22+
23+
24+
### Require
25+
```lua
26+
mcp = require "mcp23017"
27+
```
28+
29+
## Example Script
30+
The example script can be found [here](../../lua_examples/mcp23017/mcp23017_example.lua)
31+
32+
## setup()
33+
Configures the address of the module and tests the connection to the i2c bus.
34+
The i2c id is required for an existing i2c interface, alternatively the sda and scl pins can be specified.
35+
Then this function will establish the connection.
36+
Automatically resets the device state (see `mcp23017:reset()`)
37+
38+
#### Syntax
39+
`mcp23017:setup(address, i2c_id)`
40+
41+
#### Parameter
42+
- `address` address for MCP23017, default: 0x20 (should be between 0x20 and 0x27)
43+
- `i2c_id` id for the i2c bus connection (remember to call i2c.setup before)
44+
45+
#### Return
46+
`true` if device found, otherwise `false`.
47+
48+
#### possible Errors
49+
- `MCP23017 device on address not found`
50+
- `MCP23017 address is out of range`
51+
52+
#### Example
53+
```lua
54+
local mcp23017 = require "mcp23017"
55+
56+
local address = 0x20
57+
local cSCL = 1
58+
local cSDA = 2
59+
local i2c_instance = 0
60+
61+
-- setup i2c bus and create instance for mcp23017 (assigned to mcp)
62+
i2c.setup(i2c_instance, cSDA, cSCL, i2c.SLOW)
63+
local mcp = mcp23017(address, i2c_instance)
64+
```
65+
66+
## setMode()
67+
Set the mode of a single channel. This can be OUTPUT or INPUT.
68+
69+
#### Syntax
70+
`mcp23017:setMode(register, pin, mode)`
71+
72+
#### Parameter
73+
- `register` the side of channels (GPA or GPB)
74+
- `pin` the number to be set for the channel (0-15)
75+
- `mode` the mode for the channel. This can be `mcp23017.INPUT` or `mcp23017.OUTPUT`
76+
77+
#### Return
78+
`true`, in case of error `nil`.
79+
80+
#### Example
81+
```lua
82+
-- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input
83+
mcp:setMode(mcp.GPA, 7, mcp.OUTPUT)
84+
mcp:setMode(mcp.GPB, 0, mcp.OUTPUT)
85+
mcp:setMode(mcp.GPB, 1, mcp.INPUT)
86+
```
87+
88+
## setPin()
89+
Set the state of a single channel. This can be HIGH or LOW.
90+
91+
#### Syntax
92+
`mcp23017:setMode(register, pin, state)`
93+
94+
#### Parameter
95+
- `register` the side of channels (GPA or GPB)
96+
- `pin` the number to be set for the channel (0-15)
97+
- `state` the state for the channel. This can be `mcp23017.HIGH` or `mcp23017.LOW`
98+
99+
#### Return
100+
`true`, in case of error `nil`.
101+
102+
#### Example
103+
```lua
104+
-- set pin 7 to high (GPA7)
105+
mcp:setPin(mcp.GPA, 7, mcp.HIGH)
106+
-- set pin 8 to low (GPB0)
107+
mcp:setPin(mcp.GPB, 0, mcp.LOW)
108+
```
109+
110+
## getPinState()
111+
get the state for a single channel. This can be HIGH or LOW.
112+
113+
#### Syntax
114+
`mcp23017:getPinState(register, pin)`
115+
116+
#### Parameter
117+
- `register` the side of channels (GPA or GPB)
118+
- `pin` the number for which a state is to be queried (0-15)
119+
120+
#### Return
121+
`true` for HIGH, `false` for LOW, in case of error `nil`.
122+
123+
#### Example
124+
```lua
125+
-- get the state for pin 9 (GPB1)
126+
print(mcp:getPinState(mcp.GPB, 1))
127+
```
128+
129+
## reset()
130+
By calling this function, a safe state is established.
131+
All channels are set to input.
132+
This function can be used for a panic program.
133+
134+
#### Syntax
135+
`mcp23017:reset()`
136+
137+
#### Parameter
138+
None
139+
140+
#### Return
141+
None
142+
143+
#### Example
144+
```lua
145+
-- reset the mcp23017 to startup defaults
146+
mcp:reset()
147+
```
148+
149+
## setInternalPullUp()
150+
Enable or disable the internal pullup resistors.
151+
152+
#### Syntax
153+
`mcp23017:setInternalPullUp(register, byte)`
154+
155+
#### Parameter
156+
- `register` the side of channels (GPA or GPB)
157+
- `byte` byte to set the pullup resistors
158+
159+
#### Return
160+
None
161+
162+
#### Example
163+
```lua
164+
-- enable all pullup resistors for GPA
165+
print(mcp:setInternalPullUp(mcp.GPA, 0xFF))
166+
-- disable all pullup resistors for GPA
167+
print(mcp:setInternalPullUp(mcp.GPA, 0x00))
168+
```
169+
170+
## writeIODIR()
171+
Setup the mode of the channels with a whole byte.
172+
173+
174+
#### Syntax
175+
`mcp23017:writeIODIR(register, byte)`
176+
177+
#### Parameter
178+
- `register` the side of channels (GPA or GPB)
179+
- `byte` byte to set the mode for all channels for this register
180+
181+
#### Return
182+
None
183+
184+
#### Example
185+
```lua
186+
-- set all GPA to input
187+
print(mcp:writeIODIR(mcp.GPA, 0xFF))
188+
-- set all GPA to output
189+
print(mcp:writeIODIR(mcp.GPA, 0x00))
190+
```
191+
192+
## writeGPIO()
193+
Setup the output state of the channels with a whole byte.
194+
195+
#### Syntax
196+
`mcp23017:writeGPIO(register, byte)`
197+
198+
#### Parameter
199+
- `register` the side of channels (GPA or GPB)
200+
- `byte` byte to set the state for all channels for this register
201+
202+
#### Return
203+
None
204+
205+
#### Example
206+
```lua
207+
-- set all GPA to HIGH
208+
print(mcp:writeGPIO(mcp.GPA, 0xFF))
209+
-- set all GPA to LOW
210+
print(mcp:writeGPIO(mcp.GPA, 0x00))
211+
```
212+
213+
## readGPIO()
214+
Read the input states of the channels with a whole byte.
215+
216+
#### Syntax
217+
`mcp23017:readGPIO(register)`
218+
219+
#### Parameter
220+
- `register` the side of channels (GPA or GPB)
221+
222+
#### Return
223+
byte with states
224+
225+
#### Example
226+
```lua
227+
-- get states for GPA
228+
print(mcp:readGPIO(mcp.GPA))
229+
```
230+
+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
--[[
2+
This example demonstrates how to use the different functions of the mcp23017 lua module.
3+
4+
@author Marcel P. | Plomi.net
5+
@github https://github.com/plomi-net
6+
@version 1.0.0
7+
]]
8+
9+
--[[
10+
initialize and setup
11+
]]
12+
-- initialize module
13+
local mcp23017 = require "mcp23017"
14+
local address = 0x20 -- the address for MCP23017 (between 0x20 and 0x27)
15+
local cSCL = 1 -- SCL pin = 1 = D1 / GPIO 5 (ESP8266)
16+
local cSDA = 2 -- SDA pin = 2 = D2 / GPIO4 (ESP8266)
17+
local i2cId = 0 -- i2c id
18+
-- setup i2c bus and create instance for mcp23017 (assigned to mcp)
19+
i2c.setup(i2cId, cSDA, cSCL, i2c.SLOW)
20+
local mcp = mcp23017(address, i2cId)
21+
22+
--[[
23+
set output and input channels
24+
]]
25+
-- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input
26+
mcp:setMode(mcp.GPA, 7, mcp.OUTPUT)
27+
mcp:setMode(mcp.GPB, 0, mcp.OUTPUT)
28+
mcp:setMode(mcp.GPB, 1, mcp.INPUT)
29+
30+
--[[
31+
set output channels to high and low
32+
]]
33+
-- set pin 7 to high (GPA7)
34+
mcp:setPin(mcp.GPA, 7, mcp.HIGH)
35+
-- set pin 8 to low (GPB0)
36+
mcp:setPin(mcp.GPB, 0, mcp.LOW)
37+
38+
--[[
39+
toggle pin 6 channel state every second (blinking)
40+
]]
41+
local currentPin = 6
42+
local currentReg = mcp.GPA
43+
local currentState = false
44+
45+
mcp:setMode(currentReg, currentPin, mcp.OUTPUT)
46+
tmr.create():alarm(1000, tmr.ALARM_AUTO, function()
47+
if currentState == true then
48+
-- print("set to low")
49+
mcp:setPin(currentReg, currentPin, mcp.LOW)
50+
currentState = false
51+
else
52+
-- print("set to high")
53+
mcp:setPin(currentReg, currentPin, mcp.HIGH)
54+
currentState = true
55+
end
56+
end)
57+
58+
--[[
59+
read input channels and display every 7 seconds
60+
]]
61+
-- read input register
62+
tmr.create():alarm(7000, tmr.ALARM_AUTO, function()
63+
local a = mcp:readGPIO(mcp.GPA)
64+
if a ~= nil then
65+
print("GPIO A input states: " .. a)
66+
else
67+
print("GPIO A unreadable, check device")
68+
end
69+
70+
local b = mcp:readGPIO(mcp.GPB)
71+
if b ~= nil then
72+
print("GPIO B input states: " .. b)
73+
else
74+
print("GPIO B unreadable, check device")
75+
end
76+
print(" ")
77+
end)

lua_modules/mcp23017/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# MCP23017 Module
2+
3+
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.

0 commit comments

Comments
 (0)