【K210】K210学习笔记四——定时器的使用

这篇具有很好参考价值的文章主要介绍了【K210】K210学习笔记四——定时器的使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

本人大四学生,电赛生涯已经走到尽头,一路上踩过不少坑,但运气也不错拿了两年省一,思来想去,决定开始写博客,将电赛经验分享一二,能力有限,高手轻喷。
往期的博客讲述了 K210 的感光元件模块 sensor 的配置,机器视觉模块 image 中部分函数的使用(目前是用 find_blobs 函数实现一些寻找不同颜色的目标点,寻找不同颜色的线,后面会更新更多 image 模块中的函数使用方法),以及按键、LCD、LED的使用。

sensor 的学习笔记传送门
【K210】K210学习笔记一——sensor
image 的学习笔记传送门
【K210】K210学习笔记二——image
按键、LCD、LED的使用 的学习笔记传送门
【K210】K210学习笔记三——按键、LCD、LED的使用

本文着重于 K210 的定时器配置及使用方法,结合往期代码,做一个简单的巡线小车。无需将目标信息传输到STM32,仅用K210上的定时器输出PWM即可完成。主要讲一下是怎么样使用定时器的,另外跟随目标的逻辑是怎么样的。若要将识别信息传输至STM32,可看本人往期博客,了解串口发送与接收,传送门如下。

串口通信 传送门
【串口通信】K210与STM32串口通信、K210与OpenMV串口通信

定时器

定时器配置

配置定时器需要导入一些模块,这里连同PWM的模块也一起导入,后面的配置就不需要导入了。

from machine import Timer, PWM                              # 从 machine 模块中导入 定时器模块 Timer 脉宽调制模块 PWM

与往期一样的,定义一个类来保存定时器的一些属性,我个人喜欢定义类来保存,因为这样可以提高效率,提高代码可读性,变量名称看起来不会很怪,可以一下子知道这个变量是什么。

#__________________________________________________________________
# 定时器的使用
# 定义定时器属性类
class timer_property():
    cnt     = 0                                             # 定时器计数值
    cnt_max = 0                                             # 定时器计数值上限
    period  = 0                                             # 定时器周期
    freq    = 0                                             # 定时器频率
    

然后就是实例化类,我是打算将定时器0配置为一个计数器,每次触发定时器中断,这个计数器的值加1,加到上限值,就将计数器的值置0,这样我们就可以在 while 循环中,判断这个计数器的值是否等于0,从而控制一些不需要高频率执行的函数的执行周期(比如各种打印信息) ,这种方法会比之前博文中使用的计数器自增控制周期的方法 更准确。但会存在一定的误差的,这是因为是在 while 循环中做的判断,while 循环的周期是不一定的(周期就是fps 比如fps等于20 则代表一秒会有20个循环),如果图像识别的速度很慢(数据量大),那么 while 循环的周期就很长,可能一秒就只有几次。

# 定时器0 配置_______________________________________________________
# 定时器0 实例化类
timer0 = timer_property()                                   # 实例化定时器属性类 timer_property() 为 timer0
timer0.cnt_max = 9                                          # 设定 定时器0 的计数值上限为 9
timer0.period = 100                                         # 设定 定时器0 的周期为 100

我在回调函数中只是做一个计数器值自增的操作,你也可以将需要间隔一定时间做的函数放到回调函数中,但需要注意的是,这个函数千万不能占用太长的时间,否则得不偿失。这也就是为什么我只在回调函数中做一个简单的计数器值自增,将实际要控制执行周期的函数放到 while 循环中的原因。

# 定时器0 定义回调函数
def timer0_back(tim0):
    if timer0.cnt < timer0.cnt_max:                         # 若 定时器0 的计数值小于 定时器0 的计数值上限
        timer0.cnt = timer0.cnt + 1                         # 计数值自增
    else:
        timer0.cnt = 0                                      # 超出计数值上限 则计数值重置为0
        

然后就是定时器的初始化,这里配置的是定时器0,通道0,模式为周期性(模式有一次性、周期性、PWM,一般都是周期性或PWM,一次性使用的很少),周期的单位为ms,周期为设定值 timer0.period这个变量在之前被设置为100,也就是说,定时器0的周期是100ms。

# 定时器0 初始化
tim0 = Timer(Timer.TIMER0,                                  # 定时器编号 定时器0
            Timer.CHANNEL0,                                 # 定时器通道 通道0
            mode = Timer.MODE_PERIODIC,                     # 定时器模式 周期性
            unit = Timer.UNIT_MS,                           # 定时器周期单位 ms
            period = timer0.period,                         # 定时器周期 timer0.period 若 unit 为 Timer.UNIT_MS 则周期为 timer0.period ms
            callback = timer0_back)                         # 定时器触发中断后执行的回调函数 timer0_back
            

定时器使用方法

使用方法就很简单了,在 while 循环中,做一个判断,当定时器0的计数器值被重置为0的时候,执行函数即可。我这里控制的是打印各参数信息的函数,因为我不需要这些参数发送的太快,发送太快我也看不清。你可以用它来控制你想控制的其他函数,比如可以用来控制串口发送,如果这里加一句串口发送函数的话,那么这个串口发送函数就是1秒发送一次。

    if timer0.cnt == 0:                                     # 如果 timer0.cnt 等于 0 此步骤的目的是控制打印周期 不要打印的太快
        print_sensor()                                      # 打印sensor参数
        print_blobs_property(black,"Black-")                # 打印黑色色块参数
        print_blobs_property(red,  "Red-  ")                # 打印红色色块参数
        

测试

将K210连接到MaixPy IDE,然后运行即可,在串行终端可以看到这些参数差不多间隔1s就会被打印一次。
【K210】K210学习笔记四——定时器的使用

小车简单巡线

PWM配置

首先还是定义一个电机类,来保存电机的信息,推荐大家养成这个习惯,对大家有好处。

# 定时器1 配置_______________________________________________________
# 电机类定义
class motor_property():
    motor1      = 0                                         # 电机1 占空比
    motor2      = 0                                         # 电机2 占空比
    motor3      = 0                                         # 电机3 占空比
    motor4      = 0                                         # 电机4 占空比

    motor1_pin  = 0                                         # 电机1 引脚
    motor2_pin  = 0                                         # 电机2 引脚
    motor3_pin  = 0                                         # 电机3 引脚
    motor4_pin  = 0                                         # 电机4 引脚

    control_x   = 0                                         # 被控坐标 x
    control_y   = 0                                         # 被控坐标 y
    

然后是实例化电机类,这里我只写了电机1和电机2,如果你要做四驱小车,可以再写电机3和电机4。 然后PWM输出引脚(也就是电机所接的引脚)我是设置电机1的引脚为14,电机2的引脚为13。这个是K210开发板上红灯和绿灯的引脚,主要是当前放暑假在家,手头上没有小车,所以这里先用LED来观察一下效果,看看逻辑是否正确,回校后我会在小车上进行测试,并更新此博文

# 实例化电机类
motor = motor_property()                                    # 实例化电机类 motor_property() 为 motor
motor.motor1 = 50                                           # 电机1的占空比 初始设置为 50%
motor.motor2 = 50                                           # 电机2的占空比 初始设置为 50%
motor.motor1_pin  = 14                                      # 电机1的引脚 14为红灯引脚 这里先用灯的亮灭观察效果
motor.motor2_pin  = 13                                      # 电机2的引脚 13为绿灯引脚 这里先用灯的亮灭观察效果

然后实例化一个定时器属性类,保存一下PWM占空比的频率信息。这里设置是1K,如果你需要改成其他数值也可以,比如10K。

# 定时器1 实例化类
timer1 = timer_property()                                   # 实例化定时器属性类 timer_property() 为 timer1
timer1.freq = 1000                                          # 设定 定时器1 的频率为 1000

然后就是PWM定时器的设置,这里我用的是定时器1,我这里只设置了两个通道,如果你要做四驱车,就复制一下这个代码,改个名字即可

# 定时器1 通道0 初始化
tim1_ch0 = Timer(Timer.TIMER1,                              # 定时器编号 定时器1
                 Timer.CHANNEL0,                            # 定时器通道 通道0
                 mode = Timer.MODE_PWM)                     # 定时器模式 PWM

# 定时器1 通道1 初始化
tim1_ch1 = Timer(Timer.TIMER1,                              # 定时器编号 定时器1
                 Timer.CHANNEL1,                            # 定时器通道 通道1
                 mode = Timer.MODE_PWM)                     # 定时器模式 PWM
                 

然后是创建电机对象,需要注意的就是这里要跟上面的那些参数名字对应的上。

# 创建对象 电机1 通道为 定时器1的通道0 频率为 定时器1的频率 占空比为 电机1的占空比 引脚为 电机1的引脚
motor1 = PWM(tim1_ch0, freq = timer1.freq, duty = motor.motor1, pin = motor.motor1_pin)

# 创建对象 电机2 通道为 定时器1的通道1 频率为 定时器1的频率 占空比为 电机2的占空比 引脚为 电机2的引脚
motor2 = PWM(tim1_ch1, freq = timer1.freq, duty = motor.motor2, pin = motor.motor2_pin)

控制小车巡线的方法

控制小车巡线就太简单了,将摄像头识别到的坐标,和要被控制到的坐标值传入即可,转换成0到50之间的值,然后控制电机转速即可。这不单单是巡线可以这样做,你也可以控制小车跟随其他目标,比如你可以拿一个红色的纸,放到摄像头的左边,小车就会往左边开。

# 定义电机占空比控制函数
def motor_control(motor, x):
    val = 0
    if x < motor.control_x:                                 # 若 当前坐标 小于 被控坐标x 即当前状态小车在目标的 左边
        val = (motor.control_x - x) * 0.3125                # 获取坐标差值 并转换为 0~50 之间的值
        motor.motor1 = 50 - val                             # 减小 电机1 占空比 电机1为左电机 使小车右转
        motor.motor2 = 50 + val                             # 增大 电机2 占空比 电机2为右电机 使小车右转

    elif x > motor.control_x:                               # 若 当前坐标 大于 被控坐标x 即当前状态小车在目标的 右边
        val = (x - motor.control_x) * 0.3125                # 获取坐标差值 并转换为 0~50 之间的值
        motor.motor1 = 50 + val                             # 增大 电机1 占空比 电机1为左电机 使小车左转
        motor.motor2 = 50 - val                             # 减小 电机2 占空比 电机2为右电机 使小车左转

    motor.motor1 = int(motor.motor1)                        # 将 电机1占空比 转换为 整数
    motor.motor2 = int(motor.motor2)                        # 将 电机1占空比 转换为 整数
    

具体实现是这样实现的,首先会拍摄一张图片,然后在这张图片中找红色色块,获取红色色块的坐标值,然后设定将该坐标值控制到160。通过电机占空比控制函数获取占空比,将占空比重新装载即可,逻辑就是。
比如我识别到红色色块的坐标为20,而我要控制它走到160的位置,20说明小车当前在该红色目标的右边,那么我就要控制它左转,同样的,如果识别到的坐标是300,那就说明小车在目标左边,右转即可,如此一来便可完成巡线或者是目标跟踪。

#__________________________________________________________________
# 主函数
while(True):

    clock.tick()                                            # 跟踪运行时间

    img = sensor.snapshot()                                 # 拍摄一张照片

    #opv_find_blobs(black,1)                                # 找黑色色块 led标志为1 表示黑色
    opv_find_blobs(red,2)                                   # 找红色色块 led标志为2 表示红色

    point_control(key)                                      # 按键控制下的目标点获取函数

    lcd.display(img)                                        # LCD 显示图像
    lcd_key()                                               # LCD 显示按键信息及目标点信息

    #led_control(red.led_flag)                              # LED 标记色块识别情况

    motor.control_x = 160                                   # 控制目标处于 x轴中心点 160
    motor_control(motor,red.cx)                             # 电机占空比控制函数获取电机控制占空比

    motor1.duty(motor.motor1)                               # 将获取到的电机1占空比 装载
    motor2.duty(motor.motor2)                               # 将获取到的电机2占空比 装载

    if timer0.cnt == 0:                                     # 如果 timer0.cnt 等于 0 此步骤的目的是控制打印周期 不要打印的太快
        print_sensor()                                      # 打印sensor参数
        print_blobs_property(black,"Black-")                # 打印黑色色块参数
        print_blobs_property(red,  "Red-  ")                # 打印红色色块参数

#__________________________________________________________________

测试

这部分先用LED灯的情况来模拟,后面会装到小车上进行测试,后续会更新此博文。
可以看到位置差不多在160附近的时候,motor1和motor2的占空比为50左右,表示直走。
【K210】K210学习笔记四——定时器的使用
此时两个灯亮的程度基本相当,呈现黄色,说明逻辑正确。
【K210】K210学习笔记四——定时器的使用

可以看到位置差不多在280附近的时候,motor1的占空比为87,motor2的占空比为12,表示右转。
【K210】K210学习笔记四——定时器的使用
此时绿灯较亮,绿灯是13号引脚,被电机2占空比控制,因为灯是低电平点亮,因此电机2占空比为12,绿灯较亮,说明逻辑正确。
【K210】K210学习笔记四——定时器的使用

可以看到位置差不多在47附近的时候,motor1的占空比为14,motor2的占空比为85,表示左转。
【K210】K210学习笔记四——定时器的使用
此时红灯较亮,红灯是14号引脚,被电机1占空比控制,因为灯是低电平点亮,因此电机1占空比为14,红灯较亮,说明逻辑正确。
【K210】K210学习笔记四——定时器的使用
小车的测试等待我回学校后更新!

完整源码

完整源码如下所示,大家可以复制该源码,进行测试,下一次学习笔记将会记录K210串口的配置,虽然往期教程已经做过了,但下期我将会重制一下,争取让代码更加好用,我们下期再见~!
等下一期做完串口,K210这一系列可能不会日更,后期我会着手于写K210跑训练模型,以及怎么训练模型的教程,难度比现在来得大,因此更新的速度会放缓
但我一定会保持质量,做到句句有注释,句句有原因,思路清晰, 喜欢我的教程的,希望能换到你们的一个关注。文章来源地址https://www.toymoban.com/news/detail-434889.html

# Timer_V1.0 - By: FITQY - 周二 8 月 23 日 2022
#__________________________________________________________________
# 导入模块
import sensor, time, image                                  # 导入感光元件模块 sensor 跟踪运行时间模块 time 机器视觉模块 image
import utime                                                # 导入延时模块 utime
from fpioa_manager import fm                                # 从 GPIO 模块中导入 引脚注册模块 fm
from Maix import GPIO                                       # 从 Maix 模块中导入 模块 GPIO
import lcd                                                  # 导入 LCD 模块
from machine import Timer, PWM                              # 从 machine 模块中导入 定时器模块 Timer 脉宽调制模块 PWM

#__________________________________________________________________
# 感光元件设置
sensor.reset()                                              # 重置并初始化感光元件 默认设置为 摄像头频率 24M 不开启双缓冲模式
#sensor.reset(freq=24000000, dual_buff=True)                # 设置摄像头频率 24M 开启双缓冲模式 会提高帧率 但内存占用增加

sensor.set_pixformat(sensor.RGB565)                         # 设置图像格式为 RGB565 (彩色) 除此之外 还可设置格式为 GRAYSCALE 或者 YUV422
sensor.set_framesize(sensor.QVGA)                           # 设置图像大小为 QVGA (320 x 240) 像素个数 76800 K210最大支持格式为 VGA

sensor.set_auto_exposure(1)                                 # 设置自动曝光
#sensor.set_auto_exposure(0, exposure=120000)               # 设置手动曝光 曝光时间 120000 us

sensor.set_auto_gain(0, gain_db = 12)                       # 设置画面增益 17 dB 影响实时画面亮度
sensor.set_auto_whitebal(0, rgb_gain_db = (0,0,0))          # 设置RGB增益 0 0 0 dB 影响画面色彩呈现效果 在 K210 上无法调节增益 初步判定是感光元件 ov2640 无法支持

#sensor.set_contrast(0)                                     # 设置对比度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释
#sensor.set_brightness(0)                                   # 设置亮度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释
#sensor.set_saturation(0)                                   # 设置饱和度 0 这个参数无法读取 且调这个参数对画面似乎不会产生影响 暂时注释

sensor.set_vflip(1)                                         # 打开垂直翻转 如果是 01Studio 的 K210 不开启会导致画面方向与运动方向相反
sensor.set_hmirror(1)                                       # 打开水平镜像 如果是 01Studio 的 K210 不开启会导致画面方向与运动方向相反

sensor.skip_frames(time = 2000)                             # 延时跳过2s 等待感光元件稳定

#__________________________________________________________________
# 创建时钟对象
clock = time.clock()                                        # 创建时钟对象 clock

#__________________________________________________________________
# 打印sensor参数
def print_sensor():
    print("Exposure: "+str(sensor.get_exposure_us()))       # 打印 曝光时间
    print("Gain: "+str(sensor.get_gain_db()))               # 打印 画面增益
    print("RGB: "+str(sensor.get_rgb_gain_db()))            # 打印 RGB 增益

#__________________________________________________________________
# 目标点输入类 举例 对标 2022 年 TI 杯送货无人机 中的目标点输入部分
class point_input():
    point1  = 0                                             # 目标点 1
    point2  = 0                                             # 目标点 2
    cross   = 0                                             # 穿圈模式标志位
    send    = 0                                             # 目标点发送标志位

point = point_input()                                       # 实例化目标点输入类 point_input() 为 point

# 按键控制下的目标点获取函数
def point_control(ckey):
    if ckey.control == 1:                                   # 按键确认及发送控制标志位为1 即 按键3 按下
        ckey.control = 0                                    # 重置标志位
        if ckey.cs == 0:                                    # 如果当前为模式 0
            point.send = 1                                  # 目标点发送标志置为 1 串口开始发送

        elif ckey.cs == 1:                                  # 如果当前为模式 1
            point.point1 = ckey.cinput                      # 将按键输入值赋值给目标点 1

        elif ckey.cs == 2:                                  # 如果当前为模式 2
            point.point2 = ckey.cinput                      # 将按键输入值赋值给目标点 2

        elif ckey.cs == 3:                                  # 如果当前为模式 3
            point.cross = ckey.cinput                       # 将按键输入值赋值给 穿圈模式标志位

    if ckey.csflag == 1:                                    # 如果检测到按键模式切换
        ckey.csflag = 0                                     # 重置按键模式切换标志位
        ckey.cinput = 0                                     # 重置按键输入值

#__________________________________________________________________
# 按键的使用
# 定义按键控制类
class key_control():                                        # 定义按键控制类
    cnt     = 0                                             # 按键计数值
    cs      = 0                                             # 按键模式选择标志位
    csmax   = 0                                             # 按键模式上限
    csflag  = 0                                             # 按键模式切换标志位
    cinput  = 0                                             # 按键输入值保存位
    control = 0                                             # 按键确认及发送控制标志位

# 实例化按键类
key = key_control()                                         # 实例化按键控制类 key_control() 为 key
key.csmax = 4                                               # 按键模式上限为 4 即最多有 4 个模式

# 注册按键引脚
fm.register(16, fm.fpioa.GPIOHS0, force = True)             # 配置 16 脚为 KEY0 使用高速 GPIO 口 强制注册
fm.register(18, fm.fpioa.GPIOHS1, force = True)             # 配置 18 脚为 KEY1 使用高速 GPIO 口 强制注册
fm.register(19, fm.fpioa.GPIOHS2, force = True)             # 配置 19 脚为 KEY2 使用高速 GPIO 口 强制注册
fm.register(20, fm.fpioa.GPIOHS3, force = True)             # 配置 20 脚为 KEY3 使用高速 GPIO 口 强制注册

# 创建按键对象
KEY0 = GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY0
KEY1 = GPIO(GPIO.GPIOHS1, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY1
KEY2 = GPIO(GPIO.GPIOHS2, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY2
KEY3 = GPIO(GPIO.GPIOHS3, GPIO.IN, GPIO.PULL_UP)            # 创建按键对象 KEY3

# 中断回调函数 KEY0 控制按键模式选择
def key0_switch(KEY0):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY0.value() == 0:                                   # 确认 按键0 按下
        key.csflag = 1                                      # 标记按键模式切换
        if key.cs < key.csmax:                              # 控制按键模式选择 自增
            key.cs = key.cs + 1
        else:                                               # 若达到上限 则重新从 0 开始
            key.cs = 0

# 中断回调函数 KEY1 按键输入值自增
def key1_switch(KEY1):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY1.value() == 0:                                   # 确认 按键1 按下
        key.cinput = key.cinput + 1                         # 按键输入值自增

# 中断回调函数 KEY2 按键输入值自减
def key2_switch(KEY2):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY2.value() == 0:                                   # 确认 按键2 按下
        key.cinput = key.cinput - 1                         # 按键输入值自减

# 中断回调函数 KEY3 按键确认及发送控制标志位
def key3_switch(KEY3):
    utime.sleep_ms(10)                                      # 延时 10ms 消除按键抖动
    if KEY3.value() == 0:                                   # 确认按键按下
        key.control = 1                                     # 按键确认及发送控制标志位

# 开启中断 下降沿触发
KEY0.irq(key0_switch, GPIO.IRQ_FALLING)                     # 开启 按键0 外部中断 下降沿触发
KEY1.irq(key1_switch, GPIO.IRQ_FALLING)                     # 开启 按键1 外部中断 下降沿触发
KEY2.irq(key2_switch, GPIO.IRQ_FALLING)                     # 开启 按键2 外部中断 下降沿触发
KEY3.irq(key3_switch, GPIO.IRQ_FALLING)                     # 开启 按键3 外部中断 下降沿触发

#__________________________________________________________________
# LCD 的使用
# LCD 初始化
lcd.init()                                                  # lcd初始化

# LCD 按键信息及目标点信息显示函数
def lcd_key():
    lcd.draw_string(0, 0,  "key_cs: "+str(key.cs), lcd.BLUE, lcd.WHITE)
    lcd.draw_string(0, 15, "cinput: "+str(key.cinput), lcd.BLUE, lcd.WHITE)
    lcd.draw_string(0, 30, "point1: "+str(point.point1), lcd.BLUE, lcd.WHITE)
    lcd.draw_string(0, 45, "point2: "+str(point.point2), lcd.BLUE, lcd.WHITE)
    lcd.draw_string(0, 60, "cross : "+str(point.cross), lcd.BLUE, lcd.WHITE)
    lcd.draw_string(0, 75, "red_cx: "+str(red.cx), lcd.BLUE, lcd.WHITE)
    lcd.draw_string(0, 90, "motor1: "+str(motor.motor1), lcd.BLUE, lcd.WHITE)
    lcd.draw_string(0, 105,"motor2: "+str(motor.motor2), lcd.BLUE, lcd.WHITE)
    lcd.draw_string(0, 120,"FPS   : "+str(clock.fps()), lcd.BLUE, lcd.WHITE)

#__________________________________________________________________
# LED 的使用
# 注册LED引脚
fm.register(14, fm.fpioa.GPIO2, force = True)               # 配置 14 脚为 LED_R 强制注册
fm.register(13, fm.fpioa.GPIO1, force = True)               # 配置 13 脚为 LED_G 强制注册
fm.register(12, fm.fpioa.GPIO0, force = True)               # 配置 12 脚为 LED_B 强制注册

# 创建LED对象
LED_R = GPIO(GPIO.GPIO2, GPIO.OUT)                          # 创建 LED_R 对象
LED_G = GPIO(GPIO.GPIO1, GPIO.OUT)                          # 创建 LED_G 对象
LED_B = GPIO(GPIO.GPIO0, GPIO.OUT)                          # 创建 LED_B 对象

# LED控制函数
def led_control(led_flag):                                  # LED控制函数 根据传入 led_flag 点亮对应的灯
    if led_flag == 0:                                       # 传入参数为 0 所有灯打开
        LED_R.value(0)
        LED_G.value(0)
        LED_B.value(0)

    elif led_flag == 1:                                     # 传入参数为 1 所有灯关闭
        LED_R.value(1)
        LED_G.value(1)
        LED_B.value(1)

    elif led_flag == 2:                                     # 传入参数为 2 红灯常亮
        LED_R.value(0)
        LED_G.value(1)
        LED_B.value(1)

    elif led_flag == 3:                                     # 传入参数为 3 绿灯常亮
        LED_R.value(1)
        LED_G.value(0)
        LED_B.value(1)

    elif led_flag == 4:                                     # 传入参数为 4 蓝灯常亮
        LED_R.value(1)
        LED_G.value(1)
        LED_B.value(0)

    else:                                                   # 其他情况 紫灯
        LED_R.value(0)
        LED_G.value(1)
        LED_B.value(0)

#__________________________________________________________________
# 定时器的使用
# 定义定时器属性类
class timer_property():
    cnt     = 0                                             # 定时器计数值
    cnt_max = 0                                             # 定时器计数值上限
    period  = 0                                             # 定时器周期
    freq    = 0                                             # 定时器频率

# 定时器0 配置_______________________________________________________
# 定时器0 实例化类
timer0 = timer_property()                                   # 实例化定时器属性类 timer_property() 为 timer0
timer0.cnt_max = 9                                          # 设定 定时器0 的计数值上限为 9
timer0.period = 100                                         # 设定 定时器0 的周期为 100

# 定时器0 定义回调函数
def timer0_back(tim0):
    if timer0.cnt < timer0.cnt_max:                         # 若 定时器0 的计数值小于 定时器0 的计数值上限
        timer0.cnt = timer0.cnt + 1                         # 计数值自增
    else:
        timer0.cnt = 0                                      # 超出计数值上限 则计数值重置为0

# 定时器0 初始化
tim0 = Timer(Timer.TIMER0,                                  # 定时器编号 定时器0
            Timer.CHANNEL0,                                 # 定时器通道 通道0
            mode = Timer.MODE_PERIODIC,                     # 定时器模式 周期性
            unit = Timer.UNIT_MS,                           # 定时器周期单位 ms
            period = timer0.period,                         # 定时器周期 timer0.period 若 unit 为 Timer.UNIT_MS 则周期为 timer0.period ms
            callback = timer0_back)                         # 定时器触发中断后执行的回调函数 timer0_back

# 定时器1 配置_______________________________________________________
# 电机类定义
class motor_property():
    motor1      = 0                                         # 电机1 占空比
    motor2      = 0                                         # 电机2 占空比
    motor3      = 0                                         # 电机3 占空比
    motor4      = 0                                         # 电机4 占空比

    motor1_pin  = 0                                         # 电机1 引脚
    motor2_pin  = 0                                         # 电机2 引脚
    motor3_pin  = 0                                         # 电机3 引脚
    motor4_pin  = 0                                         # 电机4 引脚

    control_x   = 0                                         # 被控坐标 x
    control_y   = 0                                         # 被控坐标 y

# 实例化电机类
motor = motor_property()                                    # 实例化电机类 motor_property() 为 motor
motor.motor1 = 50                                           # 电机1的占空比 初始设置为 50%
motor.motor2 = 50                                           # 电机2的占空比 初始设置为 50%
motor.motor1_pin  = 14                                      # 电机1的引脚 14为红灯引脚 这里先用灯的亮灭观察效果
motor.motor2_pin  = 13                                      # 电机2的引脚 13为绿灯引脚 这里先用灯的亮灭观察效果

# 定时器1 实例化类
timer1 = timer_property()                                   # 实例化定时器属性类 timer_property() 为 timer1
timer1.freq = 1000                                          # 设定 定时器1 的频率为 1000

# 定时器1 通道0 初始化
tim1_ch0 = Timer(Timer.TIMER1,                              # 定时器编号 定时器1
                 Timer.CHANNEL0,                            # 定时器通道 通道0
                 mode = Timer.MODE_PWM)                     # 定时器模式 PWM

# 定时器1 通道1 初始化
tim1_ch1 = Timer(Timer.TIMER1,                              # 定时器编号 定时器1
                 Timer.CHANNEL1,                            # 定时器通道 通道1
                 mode = Timer.MODE_PWM)                     # 定时器模式 PWM

# 创建对象 电机1 通道为 定时器1的通道0 频率为 定时器1的频率 占空比为 电机1的占空比 引脚为 电机1的引脚
motor1 = PWM(tim1_ch0, freq = timer1.freq, duty = motor.motor1, pin = motor.motor1_pin)

# 创建对象 电机2 通道为 定时器1的通道1 频率为 定时器1的频率 占空比为 电机2的占空比 引脚为 电机2的引脚
motor2 = PWM(tim1_ch1, freq = timer1.freq, duty = motor.motor2, pin = motor.motor2_pin)

# 定义电机占空比控制函数
def motor_control(motor, x):
    val = 0
    if x < motor.control_x:                                 # 若 当前坐标 小于 被控坐标x 即当前状态小车在目标的 左边
        val = (motor.control_x - x) * 0.3125                # 获取坐标差值 并转换为 0~50 之间的值
        motor.motor1 = 50 - val                             # 减小 电机1 占空比 电机1为左电机 使小车右转
        motor.motor2 = 50 + val                             # 增大 电机2 占空比 电机2为右电机 使小车右转

    elif x > motor.control_x:                               # 若 当前坐标 大于 被控坐标x 即当前状态小车在目标的 右边
        val = (x - motor.control_x) * 0.3125                # 获取坐标差值 并转换为 0~50 之间的值
        motor.motor1 = 50 + val                             # 增大 电机1 占空比 电机1为左电机 使小车左转
        motor.motor2 = 50 - val                             # 减小 电机2 占空比 电机2为右电机 使小车左转

    motor.motor1 = int(motor.motor1)                        # 将 电机1占空比 转换为 整数
    motor.motor2 = int(motor.motor2)                        # 将 电机1占空比 转换为 整数

#__________________________________________________________________
# 寻找色块
# 定义类
class color_property():
    cx                      =  0                            # 色块 x轴 中心坐标
    cy                      =  0                            # 色块 y轴 中心坐标
    flag                    =  0                            # 色块标志位 1 找到 0 未找到
    color                   =  0                            # 色块颜色标志位 例如 你可以用 1 来表示 黑色
    density                 =  0                            # 色块密度比 反映色块锁定程度 值越大 锁定程度越好
    pixels_max              =  0                            # 色块像素最大值
    led_flag                =  0                            # LED标志位 方便调试用

    color_threshold         = (0, 0, 0, 0, 0, 0)            # 色块颜色阈值
    color_roi               = (0,0,320,240)                 # 色块寻找区域(感兴趣区域)
    color_x_stride          =  1                            # 色块 x轴 像素最小宽度 色块如果比较大可以调大此参数 提高寻找速度
    color_y_stride          =  1                            # 色块 y轴 像素最小宽度 色块如果比较大可以调大此参数 提高寻找速度
    color_pixels_threshold  =  100                          # 色块 像素个数阈值 例如调节此参数为100 则可以滤除色块像素小于100的色块
    color_area_threshold    =  100                          # 色块 被框面积阈值 例如调节此参数为100 则可以滤除色块被框面积小于100的色块
    color_merge             =  True                         # 是否合并寻找到的色块 True 则合并 False 则不合并
    color_margin            =  1                            # 色块合并间距 例如调节此参数为1 若上面选择True合并色块 且被找到的色块有多个 相距1像素 则会将这些色块合并

# 实例化类
# 黑色
black = color_property()
black.color_threshold         = (0, 50, -10, 10, -10, 10)
black.color_roi               = (0,0,320,240)
black.color_x_stride          =  1
black.color_y_stride          =  1
black.color_pixels_threshold  =  100
black.color_area_threshold    =  100
black.color_merge             =  True
black.color_margin            =  1

# 红色
red   = color_property()
red.color_threshold           = (0, 100, 20, 127, -10, 127)

#red.color_roi                = (0,0,320,240)
red.color_roi                 = (0,110,320,20)

red.color_x_stride            =  1
red.color_y_stride            =  1

#red.color_pixels_threshold   =  100
#red.color_area_threshold     =  100
red.color_pixels_threshold    =  10
red.color_area_threshold      =  10

red.color_merge               =  True
red.color_margin              =  1

# 绿色 预留
green = color_property()

# 蓝色 预留
blue  = color_property()

# 定义寻找色块函数
def opv_find_blobs(color,led_flag):
    color.pixels_max = 0                                    # 重置 色块 最大像素数量
    color.flag       = 0                                    # 重置 色块 标志位
    color.led_flag   = 0                                    # 重置 led 标志位

    for blobs in img.find_blobs([color.color_threshold],    # 色块颜色阈值
    roi = color.color_roi,                                  # 色块寻找区域(感兴趣区域)
    x_stride = color.color_x_stride,                        # 色块 x轴 像素最小宽度 色块如果比较大可以调大此参数 提高寻找速度
    y_stride = color.color_y_stride,                        # 色块 y轴 像素最小宽度 色块如果比较大可以调大此参数 提高寻找速度
    pixels_threshold = color.color_pixels_threshold,        # 色块 像素个数阈值 例如调节此参数为100 则可以滤除色块像素小于100的色块
    area_threshold = color.color_area_threshold,            # 色块 被框面积阈值 例如调节此参数为100 则可以滤除色块被框面积小于100的色块
    merge = color.color_merge,                              # 是否合并寻找到的色块 True 则合并 False 则不合并
    margin = color.color_margin):                           # 色块合并间距 例如调节此参数为1 若上面选择True合并色块 且被找到的色块有多个 相距1像素 则会将这些色块合并
        img.draw_rectangle(blobs[0:4])                      # 圈出找到的色块
        if color.pixels_max < blobs.pixels():               # 找到面积最大的色块
            color.pixels_max = blobs.pixels()
            color.cx = blobs.cx()                           # 将面积最大的色块的 x轴 中心坐标值 赋值给 color
            color.cy = blobs.cy()                           # 将面积最大的色块的 y轴 中心坐标值 赋值给 color
            color.flag = 1                                  # 标志画面中有找到色块
            color.density = blobs.density()                 # 将面积最大的色块的 色块密度比 赋值给 color
            color.led_flag = led_flag                       # 将控制led颜色的标志位的值 赋值给 color

    if color.flag == 1:                                     # 标记画面中被找到的最大色块的中心坐标
        img.draw_cross(color.cx,color.cy, color=127, size = 15)
        img.draw_circle(color.cx,color.cy, 15, color = 127)

# 定义打印色块参数函数
def print_blobs_property(color,name):
    print(name,"cx:",color.cx,"cy:",color.cy,"flag:",color.flag,"color:",color.color,"density:",color.density,"led_flag:",color.led_flag)

#__________________________________________________________________
# 调试区
led_control(1)                                              # 关闭一下所有灯 再进入 while 循环 使显示结果正确

#__________________________________________________________________
# 主函数
while(True):

    clock.tick()                                            # 跟踪运行时间

    img = sensor.snapshot()                                 # 拍摄一张照片

    #opv_find_blobs(black,1)                                # 找黑色色块 led标志为1 表示黑色
    opv_find_blobs(red,2)                                   # 找红色色块 led标志为2 表示红色

    point_control(key)                                      # 按键控制下的目标点获取函数

    lcd.display(img)                                        # LCD 显示图像
    lcd_key()                                               # LCD 显示按键信息及目标点信息

    #led_control(red.led_flag)                              # LED 标记色块识别情况

    motor.control_x = 160                                   # 控制目标处于 x轴中心点 160
    motor_control(motor,red.cx)                             # 电机占空比控制函数获取电机控制占空比

    motor1.duty(motor.motor1)                               # 将获取到的电机1占空比 装载
    motor2.duty(motor.motor2)                               # 将获取到的电机2占空比 装载

    if timer0.cnt == 0:                                     # 如果 timer0.cnt 等于 0 此步骤的目的是控制打印周期 不要打印的太快
        print_sensor()                                      # 打印sensor参数
        print_blobs_property(black,"Black-")                # 打印黑色色块参数
        print_blobs_property(red,  "Red-  ")                # 打印红色色块参数

#__________________________________________________________________

到了这里,关于【K210】K210学习笔记四——定时器的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【K210】K210学习笔记三——按键、LCD、LED的使用

    本人大四学生,电赛生涯已经走到尽头,一路上踩过不少坑,但运气也不错拿了两年省一,思来想去,决定开始写博客,将电赛经验分享一二,能力有限,高手轻喷。 往期的博客讲述了 K210 的感光元件模块 sensor 的配置,机器视觉模块 image 中部分函数的使用(目前是用 find

    2024年02月11日
    浏览(49)
  • stm32——hal库学习笔记(定时器)

    使用纯软件(CPU死等)的方式实现定时(延时)功能 使用精准的时基,通过硬件的方式,实现定时功能 递增计数模式实例说明 中心对齐模式实例说明 TIM6 和TIM7 控制寄存器 1(TIMx_CR1) TIM6 和TIM7 DMA/中断使能寄存器(TIMx_DIER) TIM6 和TIM7 状态寄存器(TIMx_SR) TIM6 和TIM7 计数器(TIMx_CNT)

    2024年02月21日
    浏览(56)
  • stm32学习笔记-6TIM定时器

    注:笔记主要参考B站 江科大自化协 教学视频“STM32入门教程-2023持续更新中”。 注:工程及代码文件放在了本人的Github仓库。 定时器是STM32中功能最强大、结构最复杂的一个外设。定时器将包括四部分8小节: 第一部分主要讲定时器基本定时的功能,也就是指定一个时间,让

    2024年02月15日
    浏览(57)
  • 江科大stm32视频学习笔记——TIM定时中断&定时器外部时钟

    目录 一、TIM(Timer)定时器简介  1.1 定时器类型 摘要 1.1.1 基本定时器 1.1.2 通用定时器 1.1.3 高级定时器  1.2 定时中断基本结构 1.2.1 结构框图 1.2.2 时序图 二、定时器定时中断定时器外部时钟 2.1 内部时钟闹钟代码 2.1.1 Timer.c 2.1.2 Buzzer.c加入间隔发声函数 2.1.3 main.c 2.1.4 实验视频

    2024年01月23日
    浏览(64)
  • 学习笔记|定时器|STC中断|定时器时间计算|STC32G单片机视频开发教程(冲哥)|第十一集:定时器的作用和意义

    什么是定时器:定时器-与非网 上节课的一段代码: TimeCount++然后一个延时1毫秒,每运行1ms,变量就会加一。 系统已经运行了多少个毫秒。 实际使用时的代码如下, 判断按键有沿有按下的时候,我们等待按键松开,还有一个while循环。 如果没有松开,会一直死在这一行。所以,

    2024年02月09日
    浏览(65)
  • MSP432学习笔记14:定时器A的学习整理

    本文整理学习一下定时器A的相关基础知识,本文比较偏向理解与理论性, 主要是深入在官方手册层面进行对定时器A的深入研究,定时器 A的相关实践基本上在之前的文章中都有提及: 1.定时器A定时中断: MSP432学习笔记7:定时器A_定时中断_msp432时钟_NULL指向我的博客-CSDN博客

    2024年02月16日
    浏览(53)
  • 正点原子--STM32基本定时器学习笔记(1)

    目录 1. 定时器概述 1.1 软件定时原理 1.2 定时器定时原理 1.3 定时器分类 1.4 定时器特性表 1.5 基本、通用、高级定时器的功能整体区别 2. 基本定时器简介 3. 基本定时器框图 时钟树分析 这部分是笔者对基本定时器的理论知识进行学习与总结!主要记录学习过程中遇到的重难点

    2024年02月19日
    浏览(58)
  • 【STM32】学习笔记(TIM定时器)-江科大

    定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断 16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时 不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发

    2024年02月10日
    浏览(53)
  • MSP432学习笔记9:定时器A-----捕获

    今日得以继续我的MSP432电赛速通之旅~~~ 目录 基础知识: 相关库函数: 一般配置步骤: 首先定义一个初始化函数:

    2024年02月07日
    浏览(55)
  • MSP432学习笔记7:定时器A中断

    型号:MSP432P401r 今日得以继续我的MSP432电赛速通学习之路...... 今日学习的是定时器A中断! 目录 基础工程在此下载: 更改后的实验演示工程在此下载: 定时器A基础介绍:

    2024年02月09日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包