1 本节介绍
📝本节您将学习如何通过控制开发板的GPIO引脚,实现对RGB灯和按键的控制。
🏆学习目标
1️⃣如何将GPIO引脚配置为输出模式,通过引脚电平来控制RGB灯的颜色变化。
2️⃣如何将GPIO引脚配置为输入模式,来检测按键是否按下或松开,去改变RGB灯的亮灭。
2 名词解释
名词 | 说明 |
---|---|
GPIO | General Purpose Input Output (通用输入/输出) |
FPIOA | Field Programmable Input and Output Array(现场可编程 IO 阵列) |
iomux | Pin multiplexing(管脚功能选择) |
Pin 模块 | 在MicroPython 中用于控制设备的GPIO 引脚。 |
INFO
- GPIO就是我们常说的IO引脚,它直接从芯片上引出,可以被设置为输入或输出信号。没有额外功能的GPIO主要用来控制简单的设备,比如点亮LED灯或者读取按键的状态。
- FPIOA是一种灵活的输入输出阵列,允许芯片对IO功能进行重新配置,类似用STM32上的复用引脚,也就是说不同的引脚可以根据需求重新定义。
- iomux就是引脚复用了,主要是配置物理PAD(管脚)的功能,由于soc功能多管脚(pads)少,多个功能共享同一个I/O管脚(pads),但是一个pads同一时间只能使用其中一个功能,所以需要IOMUX进行功能选择。IOMUX也叫FPIOA,Pin multiplexing,管脚功能选择等,在K230中,FPIOA就是iomux。
- 我们使用 MicroPython 语法来控制K230的引脚,
machine.Pin
模块用于控制微控制器的 GPIO 引脚。Pin
类提供了访问和控制硬件引脚的功能,主要包括配置引脚模式,读写引脚状态等。
3 开发板引脚介绍
3.1 兼容树莓派40Pin排针引脚
【TODO】更换正式版图片
排针处的GPIO还可复用为IIC,SPI,PWM,PDM,IIS等功能,这些IO电平都是3.3V的。
上方的I2C0
和I2C1
并没有标明实际的IO引脚,而且由于也要驱动摄像头,都已经有了内部上拉电阻了,大家在做外部扩展板或连接外部模块时,就可以不用再加上拉电阻了。这里为了方便大家,不用再去查看原理图,也进行一下GPIO号说明。
I2C0:
I2C0_SCL
:BANK3_GPIO48I2C0_SDA
:BANK3_GPIO49I2C1:
I2C1_SCL
:BANK3_GPIO40I2C1_SDA
:BANK3_GPIO41
需要注意的是,这里的排针都没有ADC功能,也就是没有模拟功能,这里主要有两个考虑点:
- 考虑到K230的ADC仅支持最高1.8V的输入电压。为了避免用户在使用过程中意外将超过1.8V的电压输入ADC,从而导致芯片损坏,这里并未将ADC接口直接引出到标准的GPIO排针上
- K230的ADC引脚只能作为模拟输入,不能当做普通GPIO来使用。
结合以上两点本开发板采用了FPC排线座来引出ADC引脚,需要用到的时候用一个fpc转出来就可以了,这里印出来4个ADC通道,可以连接两个摇杆。
3.2 GH1.25座和大焊盘触点引出
【TODO】更换正式版图片
左边是立创·庐山派-K230-CanMV开发板的正面图,右边是立创·庐山派-K230-CanMV开发板的背面图,分别用3个GH1.25-4P带锁接口和3组2.54mm间距的大触点焊盘接口对GPIO进行了引出。它们既可以被当做普通GPIO来控制,也可以被复用为串口(UART)来和外部设备进行通讯,其中串口2还可以被复用为IIC2。
串口0:
UART0_TXD
:BANK3_GPIO38UART0_RXD
:BANK3_GPIO39串口2:
UART2_TXD
:BANK0_GPIO11UART2_RXD
:BANK0_GPIO12串口3:
UART3_TXD
:BANK4_GPIO50UART3_RXD
:BANK4_GPIO51
⚠️注意!
串口0默认被系统大核RT-Smart占用,作为调试串口使用,所以以上三个串口我们在运行CanMV固件时能用的只有串口2和串口3
3.3 各引脚可复用功能
使用以下程序即可打印出各GPIO的复用功能,把程序复制到CanMV IDE K230里面然后执行就可以从串行终端中得到所有引脚的复用信息了,为了方便大家查阅,这里也一并以表格的形式放出来。
from machine import FPIOA
# 实例化FPIOA
fpioa = FPIOA()
# 打印所有引脚配置
fpioa.help()
2
3
4
5
查看全部引脚的可复用功能
pin | cur func | can be func |
---|---|---|
0 | GPIO0 | GPIO0/BOOT0/RESV/ |
1 | GPIO1 | GPIO1/BOOT1/RESV/ |
2 | JTAG_TCK | GPIO2/JTAG_TCK/PULSE_CNTR0/RESV/ |
3 | JTAG_TDI | GPIO3/JTAG_TDI/PULSE_CNTR1/UART1_TXD/RESV/ |
4 | JTAG_TDO | GPIO4/JTAG_TDO/PULSE_CNTR2/UART1_RXD/RESV/ |
5 | UART2_TXD | GPIO5/JTAG_TMS/PULSE_CNTR3/UART2_TXD/RESV/ |
6 | UART2_RXD | GPIO6/JTAG_RST/PULSE_CNTR4/UART2_RXD/RESV/ |
7 | PWM2 | GPIO7/PWM2/IIC4_SCL/RESV/RESV/ |
8 | PWM3 | GPIO8/PWM3/IIC4_SDA/RESV/RESV/ |
9 | PWM4 | GPIO9/PWM4/UART1_TXD/IIC1_SCL/RESV/ |
10 | CTRL_IN_3D | GPIO10/CTRL_IN_3D/UART1_RXD/IIC1_SDA/RESV/ |
11 | CTRL_O1_3D | GPIO11/CTRL_O1_3D/UART2_TXD/IIC2_SCL/RESV/ |
12 | CTRL_O2_3D | GPIO12/CTRL_O2_3D/UART2_RXD/IIC2_SDA/RESV/ |
13 | M_CLK1 | GPIO13/M_CLK1/RESV/ |
14 | OSPI_CS | GPIO14/OSPI_CS/RESV/QSPI0_CS0/RESV/ |
15 | OSPI_CLK | GPIO15/OSPI_CLK/RESV/QSPI0_CLK/RESV/ |
16 | OSPI_D0 | GPIO16/OSPI_D0/QSPI1_CS4/QSPI0_D0/RESV/ |
17 | OSPI_D1 | GPIO17/OSPI_D1/QSPI1_CS3/QSPI0_D1/RESV/ |
18 | OSPI_D2 | GPIO18/OSPI_D2/QSPI1_CS2/QSPI0_D2/RESV/ |
19 | OSPI_D3 | GPIO19/OSPI_D3/QSPI1_CS1/QSPI0_D3/RESV/ |
20 | GPIO20 | GPIO20/OSPI_D4/QSPI1_CS0/PULSE_CNTR0/RESV/ |
21 | OSPI_D5 | GPIO21/OSPI_D5/QSPI1_CLK/PULSE_CNTR1/RESV/ |
22 | OSPI_D6 | GPIO22/OSPI_D6/QSPI1_D0/PULSE_CNTR2/RESV/ |
23 | GPIO23 | GPIO23/OSPI_D7/QSPI1_D1/PULSE_CNTR3/RESV/ |
24 | GPIO24 | GPIO24/OSPI_DQS/QSPI1_D2/PULSE_CNTR4/RESV/ |
25 | GPIO25 | GPIO25/PWM5/QSPI1_D3/PULSE_CNTR5/RESV/ |
26 | PDM_CLK | GPIO26/MMC1_CLK/RESV/PDM_CLK/ |
27 | GPIO27 | GPIO27/MMC1_CMD/PULSE_CNTR5/PDM_IN0/RESV/ |
28 | GPIO28 | GPIO28/MMC1_D0/UART3_TXD/PDM_IN1/RESV/ |
29 | GPIO29 | GPIO29/MMC1_D1/UART3_RXD/CTRL_IN_3D/RESV/ |
30 | GPIO30 | GPIO30/MMC1_D2/UART3_RTS/CTRL_O1_3D/RESV/ |
31 | GPIO31 | GPIO31/MMC1_D3/UART3_CTS/CTRL_O2_3D/RESV/ |
32 | IIS_CLK | GPIO32/IIC0_SCL/IIS_CLK/UART3_TXD/RESV/ |
33 | IIS_WS | GPIO33/IIC0_SDA/IIS_WS/UART3_RXD/RESV/ |
34 | IIS_D_IN0 | GPIO34/IIC1_SCL/IIS_D_IN0/PDM_IN3/UART3_RTS/ |
35 | IIS_D_OUT0 | GPIO35/IIC1_SDA/IIS_D_OUT0/PDM_IN1/UART3_CTS/ |
36 | GPIO36 | GPIO36/IIC3_SCL/IIS_D_IN1/PDM_IN2/UART4_TXD/ |
37 | GPIO37 | GPIO37/IIC3_SDA/IIS_D_OUT1/PDM_IN0/UART4_RXD/ |
38 | UART0_TXD | GPIO38/UART0_TXD/RESV/QSPI1_CS0/HSYNC0/ |
39 | UART0_RXD | GPIO39/UART0_RXD/RESV/QSPI1_CLK/VSYNC0/ |
40 | IIC1_SCL | GPIO40/UART1_TXD/IIC1_SCL/QSPI1_D0/RESV/ |
41 | IIC1_SDA | GPIO41/UART1_RXD/IIC1_SDA/QSPI1_D1/RESV/ |
42 | GPIO42 | GPIO42/UART1_RTS/PWM0/QSPI1_D2/RESV/ |
43 | GPIO43 | GPIO43/UART1_CTS/PWM1/QSPI1_D3/RESV/ |
44 | IIC3_SCL | GPIO44/UART2_TXD/IIC3_SCL/RESV/SPI2AXI_CK/ |
45 | IIC3_SDA | GPIO45/UART2_RXD/IIC3_SDA/RESV/SPI2AXI_CS/ |
46 | IIC4_SCL | GPIO46/UART2_RTS/PWM2/IIC4_SCL/RESV/ |
47 | IIC4_SDA | GPIO47/UART2_CTS/PWM3/IIC4_SDA/RESV/ |
48 | IIC0_SCL | GPIO48/UART4_TXD/RESV/IIC0_SCL/SPI2AXI_DI/ |
49 | IIC0_SDA | GPIO49/UART4_RXD/RESV/IIC0_SDA/SPI2AXI_DO/ |
50 | UART3_TXD | GPIO50/UART3_TXD/IIC2_SCL/QSPI0_CS4/RESV/ |
51 | UART3_RXD | GPIO51/UART3_RXD/IIC2_SDA/QSPI0_CS3/RESV/ |
52 | GPIO52 | GPIO52/UART3_RTS/PWM4/IIC3_SCL/RESV/ |
53 | GPIO53 | GPIO53/UART3_CTS/PWM5/IIC3_SDA/ |
54 | MMC1_CMD | GPIO54/QSPI0_CS0/MMC1_CMD/PWM0/RESV/ |
55 | MMC1_CLK | GPIO55/QSPI0_CLK/MMC1_CLK/PWM1/RESV/ |
56 | MMC1_D0 | GPIO56/QSPI0_D0/MMC1_D0/PWM2/RESV/ |
57 | MMC1_D1 | GPIO57/QSPI0_D1/MMC1_D1/PWM3/RESV/ |
58 | MMC1_D2 | GPIO58/QSPI0_D2/MMC1_D2/PWM4/RESV/ |
59 | MMC1_D3 | GPIO59/QSPI0_D3/MMC1_D3/PWM5/ |
60 | GPIO60 | GPIO60/PWM0/IIC0_SCL/QSPI0_CS2/HSYNC1/ |
61 | GPIO61 | GPIO61/PWM1/IIC0_SDA/QSPI0_CS1/VSYNC1/ |
62 | M_CLK2 | GPIO62/M_CLK2/UART3_DE/RESV/ |
63 | M_CLK3 | GPIO63/M_CLK3/UART3_RE/RESV/ |
4 GPIO 使用指南
4.1 使用FPIOA
FPIOA(灵活外设输入/输出阵列)是 K230 CanMV 系列微处理器提供的功能,允许用户灵活配置引脚来连接不同的外设。通过这个模块,我们可以轻松管理各种硬件接口。FPIOA 可以允许用户根据需要,将特定的引脚分配给不同的功能(比如 SPI、I2C、UART 等),每个引脚在同一时刻只能激活一种功能。使用 FPIOA,可以简化引脚管理,提升芯片的灵活性。
TIP
FPIOA 类位于 machine
模块中,可以像使用其他 Python 模块一样进行操作。如from machine import FPIOA
。
4.1.1 构造函数
fpioa = FPIOA()
4.1.2 设置引脚功能
fpioa.set_function(pin, func, ie=-1, oe=-1, pu=-1, pd=-1, st=-1, sl=-1, ds=-1)
参数:
pin
: 要配置的引脚编号,范围:[0, 63]func
: 要分配给引脚的功能代码- 普通GPIO:
FPIOA.GPIO0
,FPIOA.GPIO1
,FPIOA.GPIO2
等,范围【0,63】 - 串口:
FPIOA.UART0_TXD
,FPIOA.UART0_RXD
,FPIOA.UART1_RXD
等。 - IIC:
FPIOA.IIC0_SCL
,FPIOA.IIC0_SDA
,FPIOA.IIC1_SCL
,FPIOA.IIC1_SDA
等。 - PWM:
FPIOA.PWM0
,FPIOA.PWM1
,FPIOA.PWM2
等。 - 以及其他功能,更多详情请参考上方3.3章的 各引脚可复用功能。
- 普通GPIO:
set_function
其他可选参数
ie
: 输入使能,可选参数(-1为默认值,0为不使能,1为使能)oe
: 输出使能,可选参数(-1为默认值,0为不使能,1为使能)pu
: 上拉使能,可选参数(-1为默认值,0为不使能,1为使能)pd
: 下拉使能,可选参数(-1为默认值,0为不使能,1为使能)st
: st 使能,可选参数(-1为默认值,0为不使能,1为使能)- 输入施密特触发器控制使能,使能后提高信号的干扰抵抗能力和改善信号的完整性,简单来说,施密特触发器是一种具有滞回特性的电子电路,其输出只在输入信号超过设定的正向或负向阈值时改变,提高了对噪声的抗干扰能力。
sl
: sl 使能,可选参数(-1为默认值,0为不使能,1为使能)- 目前已经不再使用,建议直接设置为-1.
ds
: 驱动电流能力,可选参数(-1为默认值)- 默认值为
7
,范围0-15
,数值越大IO的驱动能力越强,除了boot 0 1其他引脚都可以设置最大15。
- 默认值为
更多关于K230 IO引脚的信息,设计最大电压,施密特触发器高低阈值,上下拉电阻阻值,各IO驱动电流能力。
4.1.3 引脚功能读取获取
fpioa.get_pin_func(pin)
参数:
pin
: 要配置的引脚编号,范围:[0, 63]。
返回值:
返回引脚当前的功能号。
示例
当前返回的功能号还不是字符串,是标号,大家根据获取到的序号来比对下方的序号确定。 例如以下代码,获取38
号引脚的当前功能:
from machine import FPIOA
print(fpioa.get_pin_func(38))
2
3
其运行结果打印出来的数值为166
,结合下方表格,可知166
代表当前38
号引脚的功能为 UART0_TXD,串口0被RT SMART占用,主要用来调试。
序号 | 功能名 |
---|---|
0 | GPIO0 |
1 | GPIO1 |
2 | GPIO2 |
3 | GPIO3 |
4 | GPIO4 |
5 | GPIO5 |
6 | GPIO6 |
7 | GPIO7 |
8 | GPIO8 |
9 | GPIO9 |
10 | GPIO10 |
11 | GPIO11 |
12 | GPIO12 |
13 | GPIO13 |
14 | GPIO14 |
15 | GPIO15 |
16 | GPIO16 |
17 | GPIO17 |
18 | GPIO18 |
19 | GPIO19 |
20 | GPIO20 |
21 | GPIO21 |
22 | GPIO22 |
23 | GPIO23 |
24 | GPIO24 |
25 | GPIO25 |
26 | GPIO26 |
27 | GPIO27 |
28 | GPIO28 |
29 | GPIO29 |
30 | GPIO30 |
31 | GPIO31 |
32 | GPIO32 |
33 | GPIO33 |
34 | GPIO34 |
35 | GPIO35 |
36 | GPIO36 |
37 | GPIO37 |
38 | GPIO38 |
39 | GPIO39 |
40 | GPIO40 |
41 | GPIO41 |
42 | GPIO42 |
43 | GPIO43 |
44 | GPIO44 |
45 | GPIO45 |
46 | GPIO46 |
47 | GPIO47 |
48 | GPIO48 |
49 | GPIO49 |
50 | GPIO50 |
51 | GPIO51 |
52 | GPIO52 |
53 | GPIO53 |
54 | GPIO54 |
55 | GPIO55 |
56 | GPIO56 |
57 | GPIO57 |
58 | GPIO58 |
59 | GPIO59 |
60 | GPIO60 |
61 | GPIO61 |
62 | GPIO62 |
63 | GPIO63 |
64 | BOOT0 |
65 | BOOT1 |
66 | CI0 |
67 | CI1 |
68 | CI2 |
69 | CI3 |
70 | CO0 |
71 | CO1 |
72 | CO2 |
73 | CO3 |
74 | DI0 |
75 | DI1 |
76 | DI2 |
77 | DI3 |
78 | DO0 |
79 | DO1 |
80 | DO2 |
81 | DO3 |
82 | HSYNC0 |
83 | HSYNC1 |
84 | IIC0_SCL |
85 | IIC0_SDA |
86 | IIC1_SCL |
87 | IIC1_SDA |
88 | IIC2_SCL |
89 | IIC2_SDA |
90 | IIC3_SCL |
91 | IIC3_SDA |
92 | IIC4_SCL |
93 | IIC4_SDA |
94 | IIS_CLK |
95 | IIS_D_IN0_PDM_IN3 |
96 | IIS_D_IN1_PDM_IN2 |
97 | IIS_D_OUT0_PDM_IN1 |
98 | IIS_D_OUT1_PDM_IN0 |
99 | IIS_WS |
100 | JTAG_RST |
101 | JTAG_TCK |
102 | JTAG_TDI |
103 | JTAG_TDO |
104 | JTAG_TMS |
105 | M_CLK1 |
106 | M_CLK2 |
107 | M_CLK3 |
108 | MMC1_CLK |
109 | MMC1_CMD |
110 | MMC1_D0 |
111 | MMC1_D1 |
112 | MMC1_D2 |
113 | MMC1_D3 |
114 | OSPI_CLK |
115 | OSPI_CS |
116 | OSPI_D0 |
117 | OSPI_D1 |
118 | OSPI_D2 |
119 | OSPI_D3 |
120 | OSPI_D4 |
121 | OSPI_D5 |
122 | OSPI_D6 |
123 | OSPI_D7 |
124 | OSPI_DQS |
125 | PDM_IN0 |
126 | PDM_IN1 |
127 | PDM_IN2 |
128 | PDM_IN3 |
129 | PULSE_CNTR0 |
130 | PULSE_CNTR1 |
131 | PULSE_CNTR2 |
132 | PULSE_CNTR3 |
133 | PULSE_CNTR4 |
134 | PULSE_CNTR5 |
135 | PWM0 |
136 | PWM1 |
137 | PWM2 |
138 | PWM3 |
139 | PWM4 |
140 | PWM5 |
141 | QSPI0_CLK |
142 | QSPI0_CS0 |
143 | QSPI0_CS1 |
144 | QSPI0_CS2 |
145 | QSPI0_CS3 |
146 | QSPI0_CS4 |
147 | QSPI0_D0 |
148 | QSPI0_D1 |
149 | QSPI0_D2 |
150 | QSPI0_D3 |
151 | QSPI1_CLK |
152 | QSPI1_CS0 |
153 | QSPI1_CS1 |
154 | QSPI1_CS2 |
155 | QSPI1_CS3 |
156 | QSPI1_CS4 |
157 | QSPI1_D0 |
158 | QSPI1_D1 |
159 | QSPI1_D2 |
160 | QSPI1_D3 |
161 | SPI2AXI_CK |
162 | SPI2AXI_CS |
163 | SPI2AXI_DI |
164 | SPI2AXI_DO |
165 | UART0_RXD |
166 | UART0_TXD |
167 | UART1_CTS |
168 | UART1_RTS |
169 | UART1_RXD |
170 | UART1_TXD |
171 | UART2_CTS |
172 | UART2_RTS |
173 | UART2_RXD |
174 | UART2_TXD |
175 | UART3_CTS |
176 | UART3_DE |
177 | UART3_RE |
178 | UART3_RTS |
179 | UART3_RXD |
180 | UART3_TXD |
181 | UART4_RXD |
182 | UART4_TXD |
183 | PDM_CLK |
184 | VSYNC0 |
185 | VSYNC1 |
186 | CTRL_IN_3D |
187 | CTRL_O1_3D |
188 | CTRL_O2_3D |
189 | TEST_PIN0 |
190 | TEST_PIN1 |
191 | TEST_PIN2 |
192 | TEST_PIN3 |
193 | TEST_PIN4 |
194 | TEST_PIN5 |
195 | TEST_PIN6 |
196 | TEST_PIN7 |
197 | TEST_PIN8 |
198 | TEST_PIN9 |
199 | TEST_PIN10 |
200 | TEST_PIN11 |
201 | TEST_PIN12 |
202 | TEST_PIN13 |
203 | TEST_PIN14 |
204 | TEST_PIN15 |
205 | TEST_PIN16 |
206 | TEST_PIN17 |
207 | TEST_PIN18 |
208 | TEST_PIN19 |
209 | TEST_PIN20 |
210 | TEST_PIN21 |
211 | TEST_PIN22 |
212 | TEST_PIN23 |
213 | TEST_PIN24 |
214 | TEST_PIN25 |
215 | TEST_PIN26 |
216 | TEST_PIN27 |
217 | TEST_PIN28 |
218 | TEST_PIN29 |
219 | TEST_PIN30 |
220 | TEST_PIN31 |
221 | FUNC_MAX |
TIP
使用以上函数可以查询指定引脚的当前功能。
fpioa.get_pin_num(func)
获取指定功能当前所在的引脚。
参数
func
: 功能号
返回值
返回引脚号,如果未找到相应功能则返回None
。
示例
例如以下代码,获取38
号引脚的当前功能:
from machine import FPIOA
print(fpioa.get_pin_num(FPIOA.UART0_TXD))
2
3
其运行结果打印出来为38
,标明当前UART0_TXD
功能正在被38
引脚使用。
TIP
使用以上函数可以查找想要功能的当前引脚。
4.1.4 帮助方法
fpioa.help([number, func=False])
打印引脚配置提示信息。
参数
number
: 引脚号或功能号, 可选参数func
: 是否启用功能号查询,默认为False
返回值
可能为以下三种:
- 所有引脚的配置信息(未设置
number
) - 指定引脚的详细配置信息(设置了
number
,未设置func
或设置为False
) - 指定功能的所有可配置引脚号(设置了
number
,并将func
设置为True
)
示例
例如以下代码,获取38
号引脚的当前功能:
from machine import FPIOA
print("---run fpioa.help(38) result:")
fpioa.help(38)
print("---run fpioa.help(38) result:")
fpioa.help(FPIOA.UART0_TXD,func=True)
2
3
4
5
6
其运行结果打印如下:
---run fpioa.help(38) result:
|pin num |38 |
|current config |UART0_TXD,ie:0,oe:1,pd:0,pu:0,msc:0-3.3v,ds:7,st:1,sl:0,di:0|
|can be function |GPIO38/UART0_TXD/RESV/QSPI1_CS0/HSYNC0/ |
---run fpioa.help(FPIOA.UART0_TXD,func=True) result:
UART0_TXD function can be set to PIN38
2
3
4
5
6
4.2 使用machine.Pin
machine.Pin
类是 MicroPython 中用于控制输入/输出引脚的核心模块。通过该模块,我们可以轻松地管理微控制器上的 GPIO 引脚,进行基础的输入输出操作。
要使用 machine.Pin
,首先需要导入该模块:
from machine import Pin
4.2.1 构造函数
pin = Pin(index, mode, pull=Pin.PULL_NONE, drive=7)
用于构造pin对象,可同时对引脚进行初始化。
参数
index
: 引脚编号,范围为 [0, 63]。mode
: 引脚的模式,支持输入模式或输出模式。Pin.OUT
Pin.IN
pull
: 上下拉配置(可选),默认为Pin.PULL_NONE
。Pin.PULL_NONE
Pin.PULL_UP
Pin.PULL_DOWN
drive
: 驱动能力配置(可选),默认值为 7。- 默认值为
7
,范围0-15
,数值越大IO的驱动能力越强,除了boot 0 1其他引脚都可以设置最大15。
- 默认值为
⚠️注意!
K230的普通IO无法被配置为模拟输入输出功能,ADC功能有固定的引脚且最高只能输入1.8V,在板子上的物理引出形式为一个6P的FPC座子。
更多关于K230 IO引脚的信息,设计最大电压,施密特触发器高低阈值,上下拉电阻阻值,各IO驱动电流能力等。
示例:
# 实例化Pin2为输出
pin = Pin(2, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
2
4.2.2 初始化引脚
pin.init(mode, pull=Pin.PULL_NONE, drive=7)
用于初始化引脚的模式、上下拉配置及驱动能力。
参数
mode
: 引脚的模式(输入或输出)。Pin.OUT
Pin.IN
pull
: 上下拉配置(可选),默认值为Pin.PULL_NONE
。Pin.PULL_NONE
Pin.PULL_UP
Pin.PULL_DOWN
drive
: 驱动能力(可选),默认值为 7。- 默认值为
7
,范围0-15
,数值越大IO的驱动能力越强,除了boot 0 1其他引脚都可以设置最大15。
- 默认值为
示例:
# 初始化pin为输入
pin.init(Pin.IN, pull=Pin.PULL_UP, drive=7)
2
4.2.3 控制PIN
value
方法
pin.value([value])
获取引脚的输入电平值或设置引脚的输出电平。
参数
value
: 输出值(可选),如果传递该参数则设置引脚输出为指定值。如果不传参则返回引脚的当前输入电平值。- 0:输出低电平。
- 1:输出高电平。
返回值
返回空或当前引脚的输入电平值。
- 0:当前引脚输入为低电平
- 1:当前引脚输入为高电平
示例:
# 设置输出为高
pin.value(1)
# 设置输出为低
pin.value(0)
# 获取引脚输入电平
print(pin.value())
2
3
4
5
6
mode
方法
pin.mode([mode])
主要用来获取或设置引脚的模式。
参数
mode
: 引脚模式(输入或输出),如果不传参则返回当前引脚的模式。Pin.OUT
Pin.IN
返回值
返回空或当前引脚模式。
示例:
# 设置引脚为输入模式
pin.mode(Pin.IN)
# 设置引脚为输出模式
pin.mode(Pin.OUT)
2
3
4
pull
方法
pin.pull([pull])
获取或设置引脚的上下拉配置。
参数
pull
: 上下拉配置(可选),如果不传参则返回当前上下拉配置。
返回值
返回空或当前引脚的上下拉配置。
drive
方法
pin.drive([drive])
获取或设置引脚的驱动能力。
参数
drive
: 驱动能力(可选),如果不传参则返回当前驱动能力。
返回值
返回空或当前引脚的驱动能力。
on
方法
pin.on()
将引脚输出设置为高电平。
off
方法
pin.off()
将引脚输出设置为低电平。
high
方法
pin.high()
将引脚输出设置为高电平。
low
方法
pin.low()
将引脚输出设置为低电平。
4.2.4 中断模式
⚠️注意!
当前的CanMV固件还不支持将引脚配置为中断模式,请等待后续更新。
PIN综合示例
from machine import Pin
from machine import FPIOA
# 实例化FPIOA
fpioa = FPIOA()
# 设置Pin2为GPIO2
fpioa.set_function(2, FPIOA.GPIO2)
# 实例化Pin2为输出
pin = Pin(2, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
# 设置输出为高
pin.value(1)
# pin.on()
# pin.high()
# 设置输出为低
pin.value(0)
# pin.off()
# pin.low()
# 初始化Pin2为输入
pin.init(Pin.IN, pull=Pin.PULL_UP, drive=7)
# 获取输入
print(pin.value())
# 设置模式
pin.mode(Pin.IN)
# 获取模式
print(pin.mode())
# 设置上下拉
pin.pull(Pin.PULL_NONE)
# 获取上下拉
print(pin.pull())
# 设置驱动能力
pin.drive(7)
# 获取驱动能力
print(pin.drive())
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
5 点亮板载RGB灯
如果说学C语言的第一个程序是Hello world!,那么我们学习嵌入式板子的第一个程序就应该是点亮一个LED灯。RGB灯其实就是一种由三个LED灯组成的灯,由三个基本颜色的 LED 组成:红色、绿色和蓝色。通过调整这三种颜色的亮度,我们可以混合出几乎任何颜色,不过庐山派CanMV开发板的这个RGB灯为了节约多功能的IO,并没有连接到具有PWM功能的IO上,所以只能控制个LED灯的亮灭而改变不了亮度。初学时我们可以只点亮其中的一个灯。
5.1 LED 灯结构组成
LED 灯(发光二极管)是一种半导体光源,主要结构包括以下部分:
- 外壳:通常由塑料或玻璃制成,用于保护内部元件。
- 发光材料:LED 最核心的部分,由特殊半导体材料制成,例如:常见的 InGaN(氮化铟镓)或 AlInGaP(铝铟镓磷)。
- 芯片:用于产生光的发光二极管芯片。
- 引线:提供电连接的金属引线。
- 焊点:将LED 芯片与引线连接在一起的焊接点。
- 电极:负责连接半导体材料与外部电路,通常由金属制成。
- 反射腔:用于增强发光效果的一个结构,将发出的光反射到正面。
5.2 LED 灯发光原理
LED(发光二极管)发光原理基于半导体特性。在半导体中,存在着两类载流子:电子(n型半导体)和空穴(p型半导体)。当n型与p型半导体材料接触时,会在交界处形成一个层结。当施加适当的电压时,层结中空穴和电子可重组并释放能量。这个能量以光子的形式释放出来,产生光。
5.3 LED 灯驱动原理
LED 驱动指的是通过稳定的电源为 LED 提供合适的电流和电压,使其正常工作点亮。LED 驱动方式主要有恒流和恒压两种。限定电流的恒流驱动是最常见的方式,因为 LED 灯对电流敏感,电流大于其额定值可能导致损坏。恒流驱动保证了稳定的电流,从而确保了 LED 安全。 LED 灯的驱动比较简单,只需要给将对应的正负极接到单片机的正负极即可驱动。LED的接法也分有两种,灌入电流和输出电流。
TIP
在庐山派开发板中,我们使用的为共阳级的RGB灯,详情请看后面的原理图。
- 灌入电流指的是LED的供电电流是由外部提供电流,将电流灌入我们的MCU。
- 输出电流指的是由MCU提供电压电流,将电流输出给LED;如果使用 MCU的GPIO 直接驱动 LED,则驱动能力较弱,可能无法提供足够的电流驱动 LED。
- 需要注意的 是 LED 灯的颜色不同,对应的电压也不同。电流不可过大,通常需要接入220欧姆到10K欧姆左右的限流电阻,限流电阻的阻值越大,LED的亮度越暗。
5.4 RGB灯原理图
结合之前介绍,我们已经知道了LED(发光二极管)灯通常只有一个发光二极管,它能产生单一颜色的光。比如,一个红色 LED 只会发出红光,而一个蓝色 LED 只会发出蓝光。而本庐山派开发板和泰山派一样,板载了一个RGB灯,他是红色、绿色和蓝色 LED 灯的组合,可以单独控制每个 LED 的亮灭。
那么我们先来看一下开发板上的RGB灯分别连接的是哪些引脚,看一下原理图:
这里的LED1
就是我们需要控制的用户指示灯,结合左上角的短接符我们可以了解到以下信息:
- 这是一个共阳级的RGB灯,当对应颜色引脚为低电平时对应引脚就会亮。
- 这个RGB灯内部有三个不同颜色的灯珠,红灯,绿灯,蓝灯分别接到了GPIO62,GPIO20和GPIO63上面。
5.5 基础点灯试验
接下来我们实现一个让RGB灯里面的红灯每1秒闪烁一次的程序:
# 立创·庐山派-K230-CanMV开发板资料与相关扩展板软硬件资料官网全部开源
# 开发板官网:www.lckfb.com
# 技术支持常驻论坛,任何技术问题欢迎随时交流学习
# 立创论坛:www.jlc-bbs.com/lckfb
# 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
# 不靠卖板赚钱,以培养中国工程师为己任
from machine import Pin
from machine import FPIOA
import time
# 创建FPIOA对象,用于初始化引脚功能配置
fpioa = FPIOA()
# 设置引脚功能,将指定的引脚配置为普通GPIO功能,
fpioa.set_function(62,FPIOA.GPIO62)
fpioa.set_function(20,FPIOA.GPIO20)
fpioa.set_function(63,FPIOA.GPIO63)
# 实例化Pin62, Pin20, Pin63为输出,分别用于控制红、绿、蓝三个LED灯
LED_R = Pin(62, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 红灯
LED_G = Pin(20, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 绿灯
LED_B = Pin(63, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 蓝灯
# 板载RGB灯是共阳结构,设置引脚为高电平时关闭灯,低电平时点亮灯
# 初始化时先关闭所有LED灯
LED_R.high() # 关闭红灯
LED_G.high() # 关闭绿灯
LED_B.high() # 关闭蓝灯
# 基础点灯试验:选择一个LED灯并让其闪烁
# 默认选择红色LED灯,后续可以通过变量改变需要控制的灯
LED = LED_R # 当前控制的LED为红色LED
while True:
LED.low() # 点亮当前选择的LED
time.sleep(0.5) # 等待0.5秒
LED.high() # 熄灭当前选择的LED
time.sleep(0.5) # 等待0.5秒from machine import Pin
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
在上述程序中,首先从machine
导入了 Pin
和FPIOA
模块,用来初始化和控制K230的GPIO引脚,也导入了 time
模块,来调用时间延迟函数。
将对应LED灯的GPIO初始化为普通GPIO后实例化了这三个GPIO引脚,分别用于控制RGB灯的红、绿和蓝三种颜色的LED灯,都指定了对应的引脚号,输出模式,不使用上下拉,输出能力。
接下来初始化了LED灯的状态,通过让每个灯的控制引脚变为高电平来熄灭所有LED灯。
然后定义了一个变量 LED
,初始设置为控制红色LED。这个小细节在后面可以轻松改变 LED
变量为其他颜色的灯(比如如 LED_G
或 LED_B
),就可以控制不同的RGB颜色来闪烁了。
比如这里改成LED_G,那点亮的就是绿色LED灯了:
LED = LED_G # 那当前控制的LED为绿色LED
改成LED_G,那点亮的就是蓝色LED了:
LED = LED_B # 那当前控制的LED为蓝色LED
最后就是一段无限循环的代码,来控制LED
变量所选RGB颜色的闪烁效果。首先用LED.low()
方法点亮,然后使用time.sleep(0.5)
延时0.5秒,再通过 LED.high()
熄灭LED,再次等待0.5秒后继续循环。
5.6 点亮7种不同颜色的RGB灯
接下来我们实现一个让RGB灯组合成七种不同的颜色然后每1秒闪烁一次的程序:
# 立创·庐山派-K230-CanMV开发板资料与相关扩展板软硬件资料官网全部开源
# 开发板官网:www.lckfb.com
# 技术支持常驻论坛,任何技术问题欢迎随时交流学习
# 立创论坛:www.jlc-bbs.com/lckfb
# 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
# 不靠卖板赚钱,以培养中国工程师为己任
from machine import Pin
from machine import FPIOA
import time
# 创建FPIOA对象,用于初始化引脚功能配置
fpioa = FPIOA()
# 设置引脚功能,将指定的引脚配置为普通GPIO功能,
fpioa.set_function(62,FPIOA.GPIO62)
fpioa.set_function(20,FPIOA.GPIO20)
fpioa.set_function(63,FPIOA.GPIO63)
# 实例化Pin62, Pin20, Pin63为输出,分别控制红、绿、蓝灯
LED_R = Pin(62, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
LED_G = Pin(20, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
LED_B = Pin(63, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
def set_color(r, g, b):
"""设置RGB灯的颜色,使用Pin.high()和Pin.low()控制"""
if r == 0:
LED_R.low() # 红灯亮
else:
LED_R.high() # 红灯灭
if g == 0:
LED_G.low() # 绿灯亮
else:
LED_G.high() # 绿灯灭
if b == 0:
LED_B.low() # 蓝灯亮
else:
LED_B.high() # 蓝灯灭
def blink_color(r, g, b, delay):
"""设置颜色并让灯亮一段时间后熄灭"""
set_color(r, g, b) # 设置颜色
time.sleep(delay) # 保持该颜色一段时间
set_color(1, 1, 1) # 熄灭所有灯(共阳:1为熄灭)
time.sleep(delay) # 熄灭后等待一段时间
while True:
# 红色
blink_color(0, 1, 1, 0.5)
# 绿色
blink_color(1, 0, 1, 0.5)
# 蓝色
blink_color(1, 1, 0, 0.5)
# 黄色(红+绿)
blink_color(0, 0, 1, 0.5)
# 紫色(红+蓝)
blink_color(0, 1, 0, 0.5)
# 青色(绿+蓝)
blink_color(1, 0, 0, 0.5)
# 白色(红+绿+蓝)
blink_color(0, 0, 0, 0.5)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
前面和基础点灯试验重复的地方就不再赘述,不同的是这里实现了一个设置颜色的函数set_color(r, g, b)
,它用于设置 RGB 灯内部的三个LED的颜色。接受三个参数 r
、g
和 b
,分别代表红、绿、蓝灯的状态(0 为亮,1 为灭)。函数内部通过判断每个参数的值来控制对应 LED 灯的状态。使用 Pin.low()
让对应的灯亮,用 Pin.high()
使对应的灯灭,实现了三种颜色的灵活配置。
然后定义了一个让对应RGB颜色闪烁的函数blink_color(r, g, b, delay)
,它先设置所需的颜色,然后让 LED 灯保持亮起一段设定时间(通过 delay
参数调整)。然后,调用 set_color
函数将所有灯熄灭(因为我们庐山派板子上的RGB灯为共阳结构,熄灭时三个灯都设置为高电平),防止影响下一个颜色,再在熄灭状态下等待一段时间。
接下来就到无限循环了,依次调用blink_color
函数,使 板载RGB 灯以不同的颜色闪烁。
6 使用用户按键
TODO:待更新实际开发板的照片,标识出用户按键的位置
6.1 独立按键是什么
独立按键是一种简单的输入设备,广泛应用于各种电子设备中,用于实现基本的用户交互。它们的工作原理通常基于一个简单的机械开关,当按下按键时触发某些操作。独立按键可以有多种尺寸、形状和颜色,便于用户辨识和使用。常见按键展示:
4.2 独立按键结构组成
独立按键的主要结构组成包括:按钮、外壳、弹簧、触点、导电片和引脚。由一个弹性体(如弹簧或金属片)和一个按键帽组成。当按键被用户按下时,弹性体会缩短,使按键帽压缩,使按钮顶部变得接近或触摸基底。当用户松开按钮时,弹性体恢复原状,按键返回初始位置。所以当按键未被按下时,通常触点是分开的,电路是断开的。当按下按键时,导电片触碰到触点,从而形成一个闭合电路。常见按键原理图示意如下:
6.3 独立按键驱动原理
独立按键驱动是为了让微控制器能识别按键的状态,而微控制器正好可以识别高电平和低电平,所以大多数的按键都是通过给按键的一端接入高电平,一端接入GPIO;或者是给按键的一端接入低电平,一端接入GPIO。通过检测连接按键的引脚有没有发生电平变化,就可以知道按键是否按下。
6.4 消抖措施
我们通常用的按键内部都是机械弹性开关,当它按下或者弹起的时候,机械触点会因为弹性作用而在闭合和断开的瞬间伴随着一连串的抖动。这种抖动会导致输入信号在高低电位之间弹跳,产生不正确的输入。这就是按键抖动现象。消抖措施主要分为软件消抖和硬件消抖:
- 软件消抖:主要是通过编程的方法,设定一个延迟或计时器,确保不读取按键在抖动状态时的电平,避免抖动对程序的影响。
- 硬件RC消抖:在按键电路中加入元器件如电阻、电容组成的RC滤波器,对按键信号进行平滑处理,降低抖动的影响。注意硬件消抖只能改善而不能消除抖动(除非你用比较大的电容,但那样会导致上升沿太缓,也会造成按钮反应时间太长)。同时,如果你只用一个电容直接并联在按键两端,当按键按下时,按键相当于短路了这个电容,但是按钮的电阻又很小,就会有很大的放电电流,造成按钮机械接触点加速老化,从而导致按钮寿命极具减少。所以这个电路的设计需要下一些功夫,一般来说即使你的硬件电路中做了硬件消抖,也是需要软件消抖来配合的。
- 硬件RS触发器消抖:成本极高,每个按钮都需要单独的RS电路,这里不过多介绍,想详细理解请从逻辑门电路开始。
TIP
在本庐山派开发板中,按键部分的电路很简单(如下面的原理图所示),没有使用硬件消抖,所以在需要使用按钮来进行状态切换功能时需要进行软件消抖处理。
6.5 板载独立按键原理图
开发板原理图中,将按键一端(1号引脚)通过电阻R78接到3.3V的高电平上,另一端(2号引脚)接到K230芯片的引脚GPIO53上,2号引脚和4号引脚是我们板载侧按按钮的固定角,没有电气作用,只是用来固定按键的。这样当按键按下时,1号引脚和2号引脚就会导通,GPIO53的电平就会变为3.3V。
这里面电阻(R78)的作用是限流(害怕初学者不小心给设置成推挽输出了)。
在这里要注意的是要在芯片内部将该GPIO(GPIO53)设置为下拉输入模式,这样当按钮没被按下时,引脚为默认的低电平状态。
6.6 按键控制板载RGB灯亮灭
当用户按下用户按键时关闭对应的LED灯
# 立创·庐山派-K230-CanMV开发板资料与相关扩展板软硬件资料官网全部开源
# 开发板官网:www.lckfb.com
# 技术支持常驻论坛,任何技术问题欢迎随时交流学习
# 立创论坛:www.jlc-bbs.com/lckfb
# 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
# 不靠卖板赚钱,以培养中国工程师为己任
from machine import Pin
from machine import FPIOA
import time
# 创建FPIOA对象,用于初始化引脚功能配置
fpioa = FPIOA()
# 设置引脚功能,将指定的引脚配置为普通GPIO功能,
fpioa.set_function(62,FPIOA.GPIO62)
fpioa.set_function(20,FPIOA.GPIO20)
fpioa.set_function(63,FPIOA.GPIO63)
fpioa.set_function(53,FPIOA.GPIO53)
# 实例化Pin62, Pin20, Pin63为输出,分别用于控制红、绿、蓝三个LED灯
LED_R = Pin(62, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 红灯
LED_G = Pin(20, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 绿灯
LED_B = Pin(63, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 蓝灯
# 按键引脚为53,按下时为高电平,所以这里设置为下拉并设置为输入模式
button = Pin(53, Pin.IN, Pin.PULL_DOWN) # 使用下拉电阻
# 板载RGB灯是共阳结构,设置引脚为高电平时关闭灯,低电平时点亮灯
# 初始化时先关闭所有LED灯
LED_R.high() # 关闭红灯
LED_G.high() # 关闭绿灯
LED_B.high() # 关闭蓝灯
# 基础控制RGB灯亮灭试验:选择一个LED灯并让其闪烁
# 默认选择红色LED灯,后续可以通过变量改变需要控制的灯
LED = LED_R # 当前控制的LED为红色LED
while True:
if button.value() == 1:
LED.high()
else:
LED.low()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
前半部分和我们在前面学习的点亮RGB灯是一样的,就是初始化灯对应的引脚。不同的是我们这里还对按键用到的GPIO(Pin53)进行了初始化,引脚62、20和63将用于控制LED灯,而引脚53将用于读取按钮的状态,将控制LED灯的引脚设置为了输出模式,将读取按钮的GPIO设置为了输入模式。
然后把按钮配置为了下拉输入模式,代表当按钮没有被按下是,输入信号为低电平(0),按下时为高电平(1)。
由于板载的LED灯是共阳结构,这里设置引脚为高电平从而所有LED灯熄灭。
接下来就到主循环了,通过不断检查按钮对应GPIO的状态来控制LED的开关,如果按钮被按下(button.value()
为 高电平(1)),LED会被设置为高电平,即熄灭。如果按钮未被按下,则LED会被设置为低电平,即点亮。
可以看到我们这里并没有进行按键消抖处理,这里按钮的作用是直接控制LED灯的熄灭,而不是在不同状态之间切换。当我们按下按钮时,LED灯熄灭;而当我们释放按钮时,LED灯将再次点亮。在上面的程序中,我们关注的是按钮是否被按下(按下就熄灭LED灯),而不是按钮有没有改变状态。如果我们需要判断按钮的改变状态来切换LED灯状态,就必须要进行消抖处理了,详情请看下面的程序。
6.7 用按键切换RGB灯状态
流程图如下:
flowchart TD A[开始] --> B[创建 FPIOA 对象] B --> C[设置 GPIO 引脚功能] C --> D[实例化 LED 和按键引脚] D --> E[初始化 LED 状态并设置消抖时间] E --> F[进入主循环] F --> G[获取按键状态和当前时间] G --> H{按键从 0 变为 1?} H -- 是 --> I{时间间隔 > 消抖时间?} I -- 是 --> J[切换 LED 状态] J --> K{当前 LED 状态?} K -- 亮 --> L[熄灭 LED] K -- 灭 --> M[点亮 LED] L --> N[更新最后按下时间] M --> N N --> O[更新上次按键状态] O --> F H -- 否 --> P[更新上次按键状态] P --> F
# 立创·庐山派-K230-CanMV开发板资料与相关扩展板软硬件资料官网全部开源
# 开发板官网:www.lckfb.com
# 技术支持常驻论坛,任何技术问题欢迎随时交流学习
# 立创论坛:www.jlc-bbs.com/lckfb
# 关注bilibili账号:【立创开发板】,掌握我们的最新动态!
# 不靠卖板赚钱,以培养中国工程师为己任
from machine import Pin
from machine import FPIOA
import time
# 创建FPIOA对象,用于初始化引脚功能配置
fpioa = FPIOA()
# 设置引脚功能,将指定的引脚配置为普通GPIO功能,
fpioa.set_function(62,FPIOA.GPIO62)
fpioa.set_function(20,FPIOA.GPIO20)
fpioa.set_function(63,FPIOA.GPIO63)
fpioa.set_function(53,FPIOA.GPIO53)
# 实例化Pin62, Pin20, Pin63为输出,分别控制红、绿、蓝三个LED灯
LED_R = Pin(62, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 红灯
LED_G = Pin(20, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 绿灯
LED_B = Pin(63, Pin.OUT, pull=Pin.PULL_NONE, drive=7) # 蓝灯
# 按键引脚为53,按下时高电平,设置为输入模式
button = Pin(53, Pin.IN, Pin.PULL_DOWN) # 使用下拉电阻
# 初始选择控制红灯
LED = LED_R # 默认控制红灯
# 初始化时关闭所有LED灯(共阳:高电平时为灭灯)
LED_R.high()
LED_G.high()
LED_B.high()
# 消抖时间设置为20毫秒
debounce_delay = 20 # 毫秒
last_press_time = 0 # 上次按键按下的时间,单位为毫秒
# 记录LED当前状态,True表示亮,False表示灭
led_on = False
# 记录按键状态,用于检测按下和松开的状态变化
button_last_state = 0 # 上次按键状态
# 主循环
while True:
button_state = button.value() # 获取当前按键状态
current_time = time.ticks_ms() # 获取当前时间(单位:毫秒)
# 检测按键从未按下(0)到按下(1)的变化(上升沿)
if button_state == 1 and button_last_state == 0:
# 检查按键是否在消抖时间外
if current_time - last_press_time > debounce_delay:
# 切换LED的状态
if led_on:
LED.high() # 熄灭LED
else:
LED.low() # 点亮LED
led_on = not led_on # 反转LED状态
last_press_time = current_time # 更新按键按下时间
# 更新上次按键状态
button_last_state = button_state
# 简单延时,防止主循环过于频繁
time.sleep_ms(10)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
前半部分和【按键控制板载RGB灯亮灭】一样,这里不再赘述。
不同的是,在该程序中引入了按键消抖处理,以及通过按钮状态的变化来控制LED灯的亮灭切换,和前面的代码相比,不只是简单地根据按钮的按下与否来控制LED的亮灭,而是实现了按键状态的变化检测。
在这个程序中我们设置按钮的消抖时间为20毫秒,然后创建了几个变量来辅助进行状态记录,last_press_time
用来记录上次按键按下的时间,单位为毫秒;led_on
用来记录LED灯的亮灭状态;button_last_state
用来记录上次检查按钮时的按键状态。
接下来就是主循环了,首先获取当前按钮状态和时间。如果按钮的状态从未按下(0,低电平)变为按下(1,高电平),且在消抖延迟后,程序将切换LED的状态(点亮或熄灭),然后更新LED当前状态和最后按键按下的时间。
这个程序最重要的改进就是进行了按键的消抖,确保每次按钮的状态变化都有效,避免由于机械抖动造成的错误信号。
参考资料: