对于k230,想实现按键中断,我们有两种方法:定时器检测和多线程检测:
定时器:定时器就相当于单片机内有一个闹钟,每到点就会去提醒CPU执行一个任务(函数)
目前k230有六个硬件定时器,但目前只能使用软件定时器,具体请查看api: 2.11 Timer 模块API手册 — K230 CanMV (canaan-creative.com),
使用方法:
1.初始化定时器:
from machine import Timer
tim = Timer(-1)#0-5六个硬件定时器,-1为软件定时器
软件定时器是使用软件实现,可能没有硬件定时器精确
2.开启定时器:
Timer.init(mode=Timer.PERIODIC, freq=-1, period=-1, callback=None, arg=None)
其中,我们只需要关心mode,period,callback三个参数:
mode: 运行模式,单次或周期
period: Timer运行周期,单位ms
callback: 超时回调函数
其余参数可以不用理会,接下来只需要把官方的按键翻转LED的代码copy过来即可:
'''
实验名称:定时器检测按键按下
版本:v1.0
作者:Tao
实验平台:01Studio CanMV K230
说明:通过定时器检测按键改变LED的亮灭状态
'''
from machine import Pin
from machine import FPIOA
import time
from machine import Timer
#将GPIO52、GPIO21配置为普通GPIO模式
fpioa = FPIOA()
fpioa.set_function(52,FPIOA.GPIO52)
fpioa.set_function(21,FPIOA.GPIO21)
LED=Pin(52,Pin.OUT) #构建LED对象,开始熄灭
KEY=Pin(21,Pin.IN,Pin.PULL_UP) #构建KEY对象
LED.value(0)
# 实例化一个软定时器
tim = Timer(-1)
state=0 #LED引脚状态
def keyfilp():
global state
if KEY.value()==0: #按键被按下
time.sleep_ms(10) #消除抖动
if KEY.value()==0: #确认按键被按下
state=not state #使用not语句而非~语句
LED.value(state) #LED状态翻转
print('KEY')
while not KEY.value(): #检测按键是否松开
pass
tim.init(period=100, mode=Timer.PERIODIC,callback=lambda t:keyfilp())
while 1:
pass
其中,callback的参数中lambda t:是固定内容,主函数中设置while 1是为了让主函数一直运行,因为如果主函数运行结束,那么定时器也会随之结束
多线程:多线程顾名思义就是同时执行多个函数,用法和定时器类似,但是更加简单,只需要启动线程即可:
import _thread
_thread.start_new_thread(keyfilp,())
#开启线程,第一个参数为回调函数,不需要加括号,第二个参数必须是元组,元组包含线程函数的参数,即使没有参数输入也要填入空元组
使用这个代码后,线程函数就会开始运行,同样的,当主线程执行完毕线程也会停止,接下来是完整代码:
'''
实验名称:多线程检测按键按下
版本:v1.0
作者:Tao
实验平台:01Studio CanMV K230
说明:通过多线程检测按键改变LED的亮灭状态
'''
import _thread
from machine import Pin
from machine import FPIOA
import time
from machine import Timer
#将GPIO52、GPIO21配置为普通GPIO模式
fpioa = FPIOA()
fpioa.set_function(52,FPIOA.GPIO52)
fpioa.set_function(21,FPIOA.GPIO21)
LED=Pin(52,Pin.OUT) #构建LED对象,开始熄灭
KEY=Pin(21,Pin.IN,Pin.PULL_UP) #构建KEY对象
LED.value(0)
state=0 #LED引脚状态
def keyfilp():
global state
while 1:
if KEY.value()==0: #按键被按下
time.sleep_ms(10) #消除抖动
if KEY.value()==0: #确认按键被按下
state=not state #使用not语句而非~语句
LED.value(state) #LED状态翻转
print('KEY')
while not KEY.value(): #检测按键是否松开
pass
_thread.start_new_thread(keyfilp,()) #开启线程,参数必须是元组
while 1:
pass
当然,多线程还有许多高级玩法:
1.结束当前线程:
_thread.exit()
2.互斥锁:
在多线程中,一个变量可以同时被多个线程读取,但不能被多个线程修改,这时候我们就需要使用互斥锁,当前线程获取了互斥锁后,当前线程访问(修改)的变量,其他线程就不可以再修改,直到释放为止
#创建互斥锁
Lock = _thread.allocate_lock()
#获得互斥锁
Lock.acquire()
#释放互斥锁
Lock.release()
完整API:
1、_thread.get_ident()
返回值:获取当前线程号
2、_thread.start_new_thread(function, args[, kwargs])
开启一个新线程并返回其标识。线程使用参数列表 args(必须是元组)执行函数函数。可选的 kwargs 参数指定关键字参数的字典。当函数返回时,线程将以静默方式退出。当函数因未处理的异常而终止时,将打印堆栈跟踪,然后线程退出(但其他线程继续运行)。
3、_thread.stop_thread(thread_id)
根据线程 id 对线程进行删除
4、_thread.stack_size(size)
设置创建新线程时所使用的栈大小
5、_thread.allocate_lock()
创建一个互斥锁对象
返回值:返回互斥锁对象
6、lock.acquire()
获取锁
返回值:成功返回 True ,失败返回 False 。
7、lock.release()
释放锁
8、lock.delete_locked()
删除锁
9、_thread.locked()
返回值:返回锁的状态,True 表示备某个线程占用,False 则表示没有备占用
注意:为什么要使用线程锁,这是由于在程序中,当主线程一旦运行结束,那抹就会关闭其余线程。这将会导致主线程或早或晚地结束进程,这是线程锁就会起到作用,主线程可在其余子线程结束后立即退出线程。