基于ESP32的竞赛裁判系统功能调试-与微机通讯

Posted 卓晴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于ESP32的竞赛裁判系统功能调试-与微机通讯相关的知识,希望对你有一定的参考价值。

简 介: 通过调试测试了基于ESP32设计的智能车竞赛的比赛系统方案与比赛软件联系的功能。

关键词 智能车竞赛比赛系统ESP32

 

§01 赛系统与微机通讯


基于ESP32智能车竞赛比赛系统硬件初步调试-5-6 基础上,调试智能车竞赛 基于ESP32裁判系统 与微机通讯功能。通讯功能主要包括两大类:

  • 通过USB(Type-C USB接口)与微机相连;
  • 通过WiFi与微机相连;

在调试完成之后,通过与比赛系统原有的通讯功能相连,完成比赛系统整体的功能调用。

1、USB连接接口

在ESP32模块上存在三个UART端口。其中UART0被用于REPL接口。在ESP32裁判系统设计中,使用了UART1作为与微机通讯的串口。

【表1-1 ESP32三个UART端口引线缺省端口】

串口端口UART0UART1UART2
TXD端口线11017
RXD端口线3916

ESP32裁判系统通过CH340G将USB端口转换成标准的UART端口,与ESP32的UART1相连。

在设计中,串口UART1设置的端口设置似乎与ESP32的标准的缺省位置不同。

UART1端口设置:
RXD1:PIN17-SD2
TXD1:PIN18-SD3

▲ 图1.1 ESP32核心板串口端口560

▲ 图1.1 ESP32核心板串口端口560

2、对于ESP32主板的修改

(1)USB 串口电阻二极管

对于TXD1,RXD1上的R14(330Ω)与D2(1N5819)取消。

▲ 消除RXD1,TXD1上的电阻和二极管

▲ 消除RXD1,TXD1上的电阻和二极管

(2)使用UART2

根据后面测试,使用UART1出现错误。修改使用UART2。

3、裁判系统通信协议

参见后面的【3】部分的内容。

 

§02 试USB端口


1、测试ESP32UART

(1)测试程序

import time
from machine                import UART,Pin
led = Pin(5, Pin.OUT)
uart1 = UART(1, baudrate=115200, rx=9, tx=10)
print("Test UART1...")
count = 0
while True:
    count += 1
    if count & 1:
        led.on()
    else: led.off()
    uart1.write(b'U')
    time.sleep_ms(10)

(2)测量输出波形

通过测量TXD1上的波形,确认TXD1输出的信息。

▲ 图2.1 TXD1上的波形

▲ 图2.1 TXD1上的波形

2、通过USB连入微机

将ESP32模块通过USB接入微机,在计算机“设备管理区”中出现USB-SERIAL CH340(COM44)。

▲ 图2.2 USB对应的微机的端口

▲ 图2.2 USB对应的微机的端口

(1)测试发送与接收

【Ⅰ.ESP32程序】
#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# TESTUART1.PY                 -- by Dr. ZhuoQing 2021-06-12
#
# Note:
#============================================================

import time
from machine                import UART,Pin

led = Pin(5, Pin.OUT)

uart1 = UART(1, baudrate=115200, rx=9, tx=10)

print("Test UART1...")
count = 0
#------------------------------------------------------------
a  = 85
b = a.to_bytes(1, 'little')
print(b)

#------------------------------------------------------------
while True:
    count += 1
    if count & 0x10:
        led.on()
    else: led.off()
    #--------------------------------------------------------

    #--------------------------------------------------------
#    uart1.write(b'U')

    if uart1.any() > 0:
        str = uart1.read()
        print(type(str))
        print(str)

        bb = str[0]+1

        uart1.write(bb.to_bytes(1, 'little'))

    time.sleep_ms(10)

#------------------------------------------------------------
#        END OF FILE : testuart1.PY
#============================================================
【Ⅱ.测试程序】

★ 注意:下面的程序使用UART1出现错误。

#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# TESTUART1PC.PY               -- by Dr. ZhuoQing 2021-06-12
#
# Note:
#============================================================

from head import *
import serial
from _ast import Or
from serial.serialutil import SerialException

#------------------------------------------------------------
testcmd = serial.Serial()
testcmd.baudrate = 115200
testcmd.timeout = 0.05
try:
    testcmd.port = 'COM44'
except:
    printf('Set testcmd port COM44 error. ')

try:
    testcmd.open()
except serial.serialutil.SerialException:
    printf('Open testcmd port COM44 error.')
else:
    printf('Open testcmd port COM44 Ok.')
#------------------------------------------------------------

while True:
    testcmd.write(b'U')
    byte = testcmd.read(1)
    printf(byte)

    time.sleep(.1)

#------------------------------------------------------------
#        END OF FILE : TESTUART1PC.PY
#============================================================
【Ⅲ.测试结果】

发送‘U’,接收到’V’。

3、出现问题

(1)错误现象

不知道为什么?进行初始化之后,出现了错误:

Guru Meditation Error: Core  0 panic'ed (IllegalInstruction). Exception was unhandled.
Memory dump at 0x40105a60: ffbf0000 ffffffff ffffffff
Core 0 register dump:
PC      : 0x40105a67  PS      : 0x00060e30  A0      : 0x8010ebec  A1      : 0x3ffce950  
A2      : 0x00000009  A3      : 0x00000000  A4      : 0x0ffd114c  A5      : 0x00000000  
A6      : 0x00000001  A7      : 0x00000000  A8      : 0x3ff440a4  A9      : 0x00000004  
A10     : 0x00000000  A11     : 0x3ff49054  A12     : 0x00060e20  A13     : 0x00000001  
A14     : 0x0000cdcd  A15     : 0x00000029  SAR     : 0x00000017  EXCCAUSE: 0x00000000  
EXCVADDR: 0x00000000  LBEG    : 0x4000c46c  LEND    : 0x4000c477  LCOUNT  : 0xffffffff  

ELF file SHA256: 0000000000000000

Backtrace: 0x40105a64:0x3ffce950 0x4010ebe9:0x3ffce980 0x400f7422:0x3ffce9b0 0x400f76bd:0x3ffcea20 0x400e8f4d:0x3ffcea70 0x400df7ed:0x3ffcea90 0x400ed0b9:0x3ffceab0 0x400e3944:0x3ffceb50 0x400df7ed:0x3ffcebd0 0x400df816:0x3ffcebf0 0x40104c52:0x3ffcec10 0x40104ded:0x3ffceca0 0x400f60a1:0x3ffcecf0 0x4009b831:0x3ffced20

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:5148
load:0x40078000,len:12880
load:0x40080400,len:3484
entry 0x40080630
MicroPython v1.14 on 2021-02-02; ESP32 module with ESP32
Type "help()" for more information.

为什么会出现这个问题,现在还不得而知。

(2)修改方法

使用UART2 替代UART1。

uart1 = UART(2, baudrate=115200, rx=16, tx=17, timeout=10)
#uart1 = UART(1, baudrate=115200, rx=9, tx=10, timeout=10)

修改之后问题解决了

▲ 图2.3  使用短路线将原来的UART1修改成UART2560

▲ 图2.3 使用短路线将原来的UART1修改成UART2560

 

§03 赛系统通讯


  • 比赛系统来自于SCDET19,现在拷贝到:
    >D:\\zhuoqing\\window\\cb\\SmartCar\\SCDETXX\\SCDET21

1、通信协议

上位机是通过USB转UART模块与控制模块通信。对于上位机由于是虚拟串口,所以串口的波特率,数据位数,停止位与起始位等对于通信没有影响。

(1)单片机UART协议

对于下位机,设置UART协议为:

UART通讯协议:
波特率:115200
数据位:8位
停止位:1位
起始位:1位
校验位:无

(2)发送与接收命令帧个数

下面通信协议是站在底层模块的角度来定义发送与接收命令帧。

  • 发送命令帧:

【表1-1 发送命令数据帧】

帧字节字节1字节2字节3字节4字节5字节6字节7
字节定义0x55Cmdbyte1byte2byte3byte4Check
命令字节含义:
0x55:固定帧头
Cmd:返回的工作模式,详见【1-2】
byte1,2,3,4:长整型参数,byte1高字节,byte4低字节
check:校验和
校验和的计算公式:
check=(0x55+cmd+byte1+byte2+byte3+byte4)^0xff

【表1-2 工作模式字节】

工作模式代码备注
SENDFLAG_NOCHECK0x80
SENDFLAG_CHECK0x81此时发送当前定时器(32bit)数值
SENDFLAG_LAST0x82
SENDFLAG_STOP0xff
SENDFLAG_SNAPSHORT0x83

发送命令帧是通过函数DSSendCOmmand(mode,time)来进行。其中

DSSendCommand函数参数:
mode:1-byte,返回状态
time:4-byte,时间参数
  • 接收命令站:
    【表1-3 接收命令数据帧】
帧字节字节1字节2字节3字节4
字节定义Cmdbyte1byte2Check
命令帧字节定义:
Cmd:命令字节
byte1,byte2:短整型参数,一般是时间参数time
Check:校验和
校验和计算公式:
check=(Cmd+byte1+byte2)^0xff

下面给出了接收命令中的命令字节定义,以及相应的返回命令帧内容。请注意,返回命令是通过DSSendCommand(mode,time)完成,所以在表格“备注”中只给出上述函数的两个参数(mode,time)

【表1-4 接收命令字节定义】

接受命令代码功能备注
DSCMD_HELLO0x00测试连通性返回命令帧参数(DSRET_HELLO, 0x0)
DSRET_HELLO:0x90
DSCMD_INIT0x01对于模块进行初始化:
(1) 清除定时器-32bit
(2) 允许发送;
(3) 将接收到time设置为检测3秒延迟
(4) 初始化其它参数
(5) 设置发送使能为1
返回命令参数(DSRET_INIT, 0x0)
DSRET_INIT:0x91
DSCMD_STARTSEND0x10开始发送命令:
(1) 将接受到的time设置为发送延迟周期
返回命令参数(SENDFLAG_LAS,lastcount)
DSCMD_STOPSEND0x11清除发送使能状态返回命令参数(SENDFLAG_CHECK, Count32)
DSCMD_BEEP0x12启动Beep声音无返回
DSCMD_SENDSNAPSHORT0x13发送Snapshot:
(1)停止发送
返回命令参数(SENDFLAG_CHECK, Count32)
DSCMD_TURNOFFLEIGHT0x14关灭所有的信标灯仅仅用于信标灯控制
DSCMD_SETCONTINUECHECK0x15设置连续检测状态,不再有延迟时间了
DSCMD_SETBEACONSEEQUENCY0x16
DSCMD_BEACONSTART0x17启动第一个信标
DSCMD_BEACONSTOP0x18停止信标灯
DSCMD_GETBEACONSTATE0x19获取信标灯状态
DSCMD_BEACONINIT0x12对于信标灯进行初始化
错误字节==BEEP-OFF

 

§04 试程序


1、ESP32代码

#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# TESTALL.PY                  -- by Dr. ZhuoQing 2021-06-13
#
# Note:
#============================================================

from machine                import UART,Pin,Timer,ADC
import time
import machine

#------------------------------------------------------------
machine.freq(240000000)

led = Pin(5, Pin.OUT)
speaker = Pin(21, Pin.OUT)
speaker.off()

#------------------------------------------------------------

adc1 = ADC(Pin(36))
adc2 = ADC(Pin(39))
adc3 = ADC(Pin(34))
adc4 = ADC(Pin(35))

adc1.atten(ADC.ATTN_6DB)
adc2.atten(ADC.ATTN_6DB)
adc3.atten(ADC.ATTN_6DB)
adc4.atten(ADC.ATTN_6DB)

SAMPLE_NUM = const(500)

ad1dim = [0] * SAMPLE_NUM
ad2dim = [0] * SAMPLE_NUM

SAMPLE_AVERAGE_LENGTH   = 40
ad3average = [0] * SAMPLE_AVERAGE_LENGTH
ad4average = [0] * SAMPLE_AVERAGE_LENGTH
ad34point = 0
ad3sigma = 0
ad4sigma = 0

#------------------------------------------------------------
AD34_BASE_ALPHA         = 0.0005
ad3baseline = 0
ad4baseline = 0

AD34_CHECK_THRESHOLD    = 250
ad3checktime = 0
ad4checktime = 0

#------------------------------------------------------------
sample_point = 0
stop_flag = 0

sample_mode = 0                     # 0 : sample adc3, adc4
                                    # 1 : sample adc1, adc2

total_count = 0

#------------------------------------------------------------
uart1 = UART(2, baudrate=115200, rx=16, tx=17, timeout=10)

#------------------------------------------------------------
DSCMD_NONE          = 0xff
DSCMD_HELLO         = 0x00
DSCMD_INIT          = 0x01
DSCMD_STARTSEND     = 0x10
DSCMD_STOPSEND      = 0x11
DSCMD_BEEP          = 0x12
DSCMD_SENDSNAPSHOT  = 0x13
DSCMD_TURNOFFLIGHT  = 0x14
DSCMD_SETCONTINUECHECK = 0x15
DSCMD_SETBEACONSEQUENCY = 0x16
DSCMD_BEACONSTART   = 0x17
DSCMD_BEACONSTOP    = 0x18
DSCMD_GETBEACONSTATE = 0x19
DSCMD_BEACONINIT    = 0x1a

DSRET_NCHECK        = 0x80
DSRET_CHECK         = 0x81
DSRET_LAST          = 0x82
DSRET_HELLO         = 0x90
DSRET_INIT          = 0x91

SENDFLAG_LAST       = 0x82
SENDFLAG_CHECK      = 0x81
SENDFLAG_NOCHECK    = 0x80
SENDFLAG_STOP       = 0xff
SENDFLAG_SNAPSHOT   = 0x83

#------------------------------------------------------------
def receCmd():
    if uart1.any() == 0: return DSCMD_NONE,0

    framebyte = uart1.read(4)
    if len(framebyte) != 4: return DSCMD_NONE, 0

    framelist = list(framebyte)
    time = int.from_bytes(framebyte[1:3], 'big')
    sumnum = sum(framelist[0:3]) & 0xff ^ 0xff

    if sumnum != framelist[3]: return DSCMD_NONE, 0
    return framelist[0], time

#------------------------------------------------------------
def sendCmd(cmd, time):
    senddim = [0x55,cmd]
    senddim.extend(list(time.to_bytes(4, 'big')))
    sumnum = sum(senddim)&0xff^0xff
    senddim.extend([sumnum])

    sendbytes = bytes(senddim)
    uart1.write(sendbytes)

#------------------------------------------------------------
def procCmd(cmd, time):
    global count32,sendflag,delay3s,count32,sendenableflag
    global initflag,lastcount32,snapshot32,speakercount,senddelay,sendcount

    if cmd == DSCMD_NONE: return

    if cmd == DSCMD_HELLO:
        sendCmd(DSRET_HELLO, 0x0)
        return

    if cmd == DSCMD_INIT:
        sendCmd(DSRET_INIT, 0x0)
        count32 = 0x0
        delay3s = time
        count3s = time

        initflag = 1
        lastcount32 = 0
        snapshot32 = 0

        sendcount = 0
        sendenableflag = 1
        sendflag = SENDFLAG_STOP

        return

    if cmd == DSCMD_STARTSEND:
        sendCmd(SENDFLAG_LAST, lastcount32)
        count3s = delay3s
        sendflag = 0x0
        sendenableflag = 0x1
        senddelay = time
        sendcount = 0

        return

    if cmd == DSCMD_STOPSEND:
        sendCmd(SENDFLAG_CHECK, count32)
        sendenableflag = 0
        sendflag = 0
        sendcount = 0
        return

    if cmd == DSCMD_BEEP:
        speakercount = 500
        return

    if cmd in (DSCMD_SETBEACONSEQUENCY,
               DSCMD_BEACONSTART,
               DSCMD_BEACONSTOP,
               DSCMD_GETBEACONSTATE,
               DSCMD_TURNOFFLIGHT,
               DSCMD_BEACONINIT):
        return

    print(cmd, time)

#------------------------------------------------------------
speakercount = 500

def speaker1ms():
    global speakercount

    if speakercount > 0:
        speakercount -= 1
        speaker.on()
    else:
        speaker.off()

#------------------------------------------------------------
def sendTime():
    global count32,snapshot32,lastcount32,sendflag

    if sendflag == SENDFLAG_STOP:   return
    if initflag == 0:               return

    timesend = count32
    if sendflag == SENDFLAG_LAST:
        timesend = lastcount32
    elif sendflag == SENDFLAG_CHECK or sendflag == SENDFLAG_NOCHECK:
        timesend = count32
    elif sendflag == SENDFLAG_SNAPSHOT:
        timesend = snapshot32
        sendCmd(SENDFLAG_SNAPSHOT, snapshot32)
        sendflag = SENDFLAG_NOCHECK

    sendCmd(sendflag, timesend)
    sendflag = SENDFLAG_STOP

#------------------------------------------------------------
count32 = 0                         # Global 1ms counter
sendflag = SENDFLAG_STOP            # send flag
sendenableflag = 0                  # Enable send
senddelay = 100                     # Everay send period
sendcount = 0                       # count for send delay
delay3s = 3000                      # No check delay
count3s = 3000                      # count for no check delay
initflag = 0                        #
lastcount32 = 0                     #
snapshot32 = 0                      #

#------------------------------------------------------------

#------------------------------------------------------------
def ADC4Sample(_):
    global count32,sendenableflag,sendflag,senddelay,sendcount
    global delay3s,count3s,initflag,lastcount32,snapshot32
    global speakercount

    #--------------------------------------------------------

    count32 += 1
    speaker1ms()

    #--------------------------------------------------------
    if count32 & 0x100:
        led.on()
    else: led.off()

    #--------------------------------------------------------
    if sendenableflag != 0:
        sendcount += 1
        if sendcount >= senddelay:
            sendcount = 0
            if sendflag == SENDFLAG_STOP:
                if count32 < delay3s:
           

以上是关于基于ESP32的竞赛裁判系统功能调试-与微机通讯的主要内容,如果未能解决你的问题,请参考以下文章

基于ESP32的智能车竞赛新版裁判系统的软件功能要求与实现

基于ESP32的竞赛裁判系统功能调试-光电条检测板

基于ESP32的竞赛裁判系统功能调试-硬件修改建议

基于ESP32的竞赛裁判系统功能调试-计时线圈功能

基于ESP32智能车竞赛裁判系统第二版硬件调试-6-26

第十七届智能车竞赛比赛系统软件修改-多车组时间延迟