331|0

67

帖子

0

TA的资源

一粒金砂(高级)

楼主
 

[嘉楠 CanMV K230]测评 ⑤多线程 [复制链接]

 

        在实际开发过程中,只靠一个while1是不够用的,需要有多线程。python中是带有多线程功能的(我平时FreeRTOS用的比较多,叫任务/task已经习惯了,后续可能顺手就打成任务/task,请见谅)

        可惜K230上不支持threading,只能支持_thread

        在python官方文档关于_thread的内容如下:https://docs.python.org/3.5/library/_thread.html#module-thread

 

一.创建线程并启动

        接下来我们就来写一个demo,运行后创建2个task,第一个task为闪灯task,第二个为串口task。这两个task中执行的内容就是之前我们写过的

import _thread
import time
from machine import Pin
from machine import UART
from machine import FPIOA

fpioa = FPIOA()

#闪灯task
def task_blink():
    #初始化52号引脚为输出模式,不拉高,驱动能力为默认的7
    LED = Pin(52, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
    
    while True:
        #开灯
        LED.value(1)
        time.sleep(1)
        #关灯
        LED.value(0)
        time.sleep(1)
        
#串口task
def task_uart():
    #初始化串口2
    fpioa.set_function(11,FPIOA.UART2_TXD)
    fpioa.set_function(12,FPIOA.UART2_RXD)
    my_uart = UART(UART.UART2, baudrate=115200, bits=UART.EIGHTBITS, parity=UART.PARITY_NONE, stop=UART.STOPBITS_ONE)
    
    #发送数据测试
    my_uart.write('UART2 send test\r\n')
    
    #一直接收数据
    while True:
        #读取一行,并以一个换行符结束。
        recv_data = my_uart.readline()
        #如果有读到数据
        if recv_data != b'':
            #把收到数据通过日志串口打印出来
            print(recv_data)
            #把收到的数据原样从串口2发出去
            my_uart.write(recv_data)
        time.sleep(0.1)
    

#创建闪灯task和串口task
_thread.start_new_thread(task_blink, ())
_thread.start_new_thread(task_uart, ())


while True:
    time.sleep(0.01) #防止CPU满跑

IMG_6612

 

二.线程停止

2.1 由别的task摧毁某个task

        在python的介绍中,_thread并没有制定摧毁某个task的接口,只有在task调用的函数退出运行,也就是要退出task中的while1

        所以,我们可以使用一个flag,来决定while1是否可以运行,我这边偷懒,直接用一个全局变量,当然在多线程的环境下,各个task之间通讯用全局变量不合适,用队列比较好,不过我这边的使用场景比较简单,也不存在竞争,可以偷懒用一下

        我们来改造一下刚才的代码,当串口收到“STOP”后,把闪灯的task摧毁。收到“START”后,开始闪灯TASK

import _thread
import time
from machine import Pin
from machine import UART
from machine import FPIOA

fpioa = FPIOA()

# 全局变量作为标志位
task_blink_run_flag = False

#闪灯task
def task_blink():
    global task_blink_run_flag
    #初始化52号引脚为输出模式,不拉高,驱动能力为默认的7
    LED = Pin(52, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
    
    while task_blink_run_flag:
        #开灯
        LED.value(1)
        time.sleep(1)
        #关灯
        LED.value(0)
        time.sleep(1)
        
#串口task
def task_uart():
    global task_blink_run_flag
    #初始化串口2
    fpioa.set_function(11,FPIOA.UART2_TXD)
    fpioa.set_function(12,FPIOA.UART2_RXD)
    my_uart = UART(UART.UART2, baudrate=115200, bits=UART.EIGHTBITS, parity=UART.PARITY_NONE, stop=UART.STOPBITS_ONE)
    
    #发送数据测试
    my_uart.write('UART2 send test\r\n')
    
    #一直接收数据
    while True:
        #读取一行,并以一个换行符结束。
        recv_data = my_uart.readline()
        #如果有读到数据
        if recv_data != b'':
            #把收到数据通过日志串口打印出来
            print(recv_data)
        
        if recv_data == b'STOP\r\n':
            print('recv stop')
            # 避免task_blink被多次stop
            if task_blink_run_flag == True:
                task_blink_run_flag = False
            else:
                print('stop task_blink fail')
        elif recv_data == b'START\r\n':
            print('recv START')
            # 避免task_blink被多次start
            if task_blink_run_flag == False:
                task_blink_run_flag = True
                _thread.start_new_thread(task_blink, ())
            else:
                print('start task_blink fail')
        time.sleep(0.1)
    

#创建闪灯task和串口task
task_blink_run_flag = True
_thread.start_new_thread(task_blink, ())
_thread.start_new_thread(task_uart, ())


while True:
    time.sleep(0.01) #防止CPU满跑

IMG_6619

 

2.2 TASK自己摧毁自己

        按照上述的思路,我们可以在task内部加一个变量,用于控制task中的while1,改造代码如下(为了看得清楚,其他部分我没动,新增了一个task)

import _thread
import time
from machine import Pin
from machine import UART
from machine import FPIOA

fpioa = FPIOA()

# 全局变量作为标志位
task_blink_run_flag = False

#闪灯task
def task_blink():
    global task_blink_run_flag
    #初始化52号引脚为输出模式,不拉高,驱动能力为默认的7
    LED = Pin(52, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
    
    while task_blink_run_flag:
        #开灯
        LED.value(1)
        time.sleep(1)
        #关灯
        LED.value(0)
        time.sleep(1)
        
#串口task
def task_uart():
    global task_blink_run_flag
    #初始化串口2
    fpioa.set_function(11,FPIOA.UART2_TXD)
    fpioa.set_function(12,FPIOA.UART2_RXD)
    my_uart = UART(UART.UART2, baudrate=115200, bits=UART.EIGHTBITS, parity=UART.PARITY_NONE, stop=UART.STOPBITS_ONE)
    
    #发送数据测试
    my_uart.write('UART2 send test\r\n')
    
    #一直接收数据
    while True:
        #读取一行,并以一个换行符结束。
        recv_data = my_uart.readline()
        #如果有读到数据
        if recv_data != b'':
            #把收到数据通过日志串口打印出来
            print(recv_data)
        
        if recv_data == b'STOP\r\n':
            print('recv stop')
            # 避免task_blink被多次stop
            if task_blink_run_flag == True:
                task_blink_run_flag = False
            else:
                print('stop task_blink fail')
        elif recv_data == b'START\r\n':
            print('recv START')
            # 避免task_blink被多次start
            if task_blink_run_flag == False:
                task_blink_run_flag = True
                _thread.start_new_thread(task_blink, ())
            else:
                print('start task_blink fail')
        time.sleep(0.1)
    

def task_destory_by_self():
    flag = True
    cnt = 0
    while flag:
        print('task_destory_by_self running')
        cnt += 1
        time.sleep(1)
        if cnt >= 5:
            flag = False  
    print('task_destory_by_self QUIT')

#创建闪灯task和串口task
task_blink_run_flag = True
_thread.start_new_thread(task_blink, ())
_thread.start_new_thread(task_uart, ())
_thread.start_new_thread(task_destory_by_self, ())


while True:
    time.sleep(0.01) #防止CPU满跑

可以看到,task_destory_by_self running打印 5次后,打印了task_destory_by_self QUIT,说明task是已经被摧毁了

IMG_6622

 

        在python的文档中,还有一种方法,就是调用_thread.exit()函数,可以在task中直接退出,当执行这个函数后,TASK立刻被摧毁,这个函数后面的代码都不会被执行。代码如下

import _thread
import time
from machine import Pin
from machine import UART
from machine import FPIOA

fpioa = FPIOA()

# 全局变量作为标志位
task_blink_run_flag = False

#闪灯task
def task_blink():
    global task_blink_run_flag
    #初始化52号引脚为输出模式,不拉高,驱动能力为默认的7
    LED = Pin(52, Pin.OUT, pull=Pin.PULL_NONE, drive=7)
    
    while task_blink_run_flag:
        #开灯
        LED.value(1)
        time.sleep(1)
        #关灯
        LED.value(0)
        time.sleep(1)
        
#串口task
def task_uart():
    global task_blink_run_flag
    #初始化串口2
    fpioa.set_function(11,FPIOA.UART2_TXD)
    fpioa.set_function(12,FPIOA.UART2_RXD)
    my_uart = UART(UART.UART2, baudrate=115200, bits=UART.EIGHTBITS, parity=UART.PARITY_NONE, stop=UART.STOPBITS_ONE)
    
    #发送数据测试
    my_uart.write('UART2 send test\r\n')
    
    #一直接收数据
    while True:
        #读取一行,并以一个换行符结束。
        recv_data = my_uart.readline()
        #如果有读到数据
        if recv_data != b'':
            #把收到数据通过日志串口打印出来
            print(recv_data)
        
        if recv_data == b'STOP\r\n':
            print('recv stop')
            # 避免task_blink被多次stop
            if task_blink_run_flag == True:
                task_blink_run_flag = False
            else:
                print('stop task_blink fail')
        elif recv_data == b'START\r\n':
            print('recv START')
            # 避免task_blink被多次start
            if task_blink_run_flag == False:
                task_blink_run_flag = True
                _thread.start_new_thread(task_blink, ())
            else:
                print('start task_blink fail')
        time.sleep(0.1)
    

def task_destory_by_self():
    cnt = 0
    while True:
        print('task_destory_by_self running')
        cnt += 1
        time.sleep(1)
        if cnt >= 5:
            print('task_destory_by_self exit')
            _thread.exit()
    print('task_destory_by_self QUIT')

#创建闪灯task和串口task
task_blink_run_flag = True
_thread.start_new_thread(task_blink, ())
_thread.start_new_thread(task_uart, ())
_thread.start_new_thread(task_destory_by_self, ())


while True:
    time.sleep(0.01) #防止CPU满跑

IMG_6623

 

 

 

点赞 关注
 
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表