基于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作为与微机通讯的串口。
串口端口 | UART0 | UART1 | UART2 |
---|---|---|---|
TXD端口线 | 1 | 10 | 17 |
RXD端口线 | 3 | 9 | 16 |
ESP32裁判系统通过CH340G将USB端口转换成标准的UART端口,与ESP32的UART1相连。
在设计中,串口UART1设置的端口设置似乎与ESP32的标准的缺省位置不同。
-
UART1端口设置:
-
RXD1
:PIN17-SD2
TXD1
:PIN18-SD3
▲ 图1.1 ESP32核心板串口端口560
2、对于ESP32主板的修改
(1)USB 串口电阻二极管
对于TXD1,RXD1上的R14(330Ω)与D2(1N5819)取消。
▲ 消除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、通过USB连入微机
将ESP32模块通过USB接入微机,在计算机“设备管理区”中出现USB-SERIAL CH340(COM44)。
▲ 图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
§03 比赛系统通讯
- 比赛系统来自于SCDET19,现在拷贝到:
>D:\\zhuoqing\\window\\cb\\SmartCar\\SCDETXX\\SCDET21
1、通信协议
上位机是通过USB转UART模块与控制模块通信。对于上位机由于是虚拟串口,所以串口的波特率,数据位数,停止位与起始位等对于通信没有影响。
(1)单片机UART协议
对于下位机,设置UART协议为:
-
UART通讯协议:
-
波特率
:115200
数据位
:8位
停止位
:1位
起始位
:1位
校验位
:无
(2)发送与接收命令帧个数
下面通信协议是站在底层模块的角度来定义发送与接收命令帧。
- 发送命令帧:
帧字节 | 字节1 | 字节2 | 字节3 | 字节4 | 字节5 | 字节6 | 字节7 |
---|---|---|---|---|---|---|---|
字节定义 | 0x55 | Cmd | byte1 | byte2 | byte3 | byte4 | Check |
-
命令字节含义:
-
0x55
:固定帧头
Cmd
:返回的工作模式,详见【1-2】
byte1,2,3,4
:长整型参数,byte1高字节,byte4低字节
check
:校验和
校验和的计算公式:
- check=(0x55+cmd+byte1+byte2+byte3+byte4)^0xff
工作模式 | 代码 | 备注 |
---|---|---|
SENDFLAG_NOCHECK | 0x80 | |
SENDFLAG_CHECK | 0x81 | 此时发送当前定时器(32bit)数值 |
SENDFLAG_LAST | 0x82 | |
SENDFLAG_STOP | 0xff | |
SENDFLAG_SNAPSHORT | 0x83 |
发送命令帧是通过函数DSSendCOmmand(mode,time)
来进行。其中
-
DSSendCommand函数参数:
-
mode
:1-byte,返回状态
time
:4-byte,时间参数
- 接收命令站:
【表1-3 接收命令数据帧】
帧字节 | 字节1 | 字节2 | 字节3 | 字节4 |
---|---|---|---|---|
字节定义 | Cmd | byte1 | byte2 | Check |
-
命令帧字节定义:
-
Cmd
:命令字节
byte1,byte2
:短整型参数,一般是时间参数time
Check
:校验和
校验和计算公式:
- check=(Cmd+byte1+byte2)^0xff
下面给出了接收命令中的命令字节定义,以及相应的返回命令帧内容。请注意,返回命令是通过DSSendCommand(mode,time)
完成,所以在表格“备注”中只给出上述函数的两个参数(mode,time)
。
接受命令 | 代码 | 功能 | 备注 |
---|---|---|---|
DSCMD_HELLO | 0x00 | 测试连通性 | 返回命令帧参数(DSRET_HELLO, 0x0) DSRET_HELLO:0x90 |
DSCMD_INIT | 0x01 | 对于模块进行初始化: (1) 清除定时器-32bit (2) 允许发送; (3) 将接收到time设置为检测3秒延迟 (4) 初始化其它参数 (5) 设置发送使能为1 | 返回命令参数(DSRET_INIT, 0x0) DSRET_INIT:0x91 |
DSCMD_STARTSEND | 0x10 | 开始发送命令: (1) 将接受到的time设置为发送延迟周期 | 返回命令参数(SENDFLAG_LAS,lastcount) |
DSCMD_STOPSEND | 0x11 | 清除发送使能状态 | 返回命令参数(SENDFLAG_CHECK, Count32) |
DSCMD_BEEP | 0x12 | 启动Beep声音 | 无返回 |
DSCMD_SENDSNAPSHORT | 0x13 | 发送Snapshot: (1)停止发送 | 返回命令参数(SENDFLAG_CHECK, Count32) |
DSCMD_TURNOFFLEIGHT | 0x14 | 关灭所有的信标灯 | 仅仅用于信标灯控制 |
DSCMD_SETCONTINUECHECK | 0x15 | 设置连续检测状态,不再有延迟时间了 | 无 |
DSCMD_SETBEACONSEEQUENCY | 0x16 | ||
DSCMD_BEACONSTART | 0x17 | 启动第一个信标 | |
DSCMD_BEACONSTOP | 0x18 | 停止信标灯 | |
DSCMD_GETBEACONSTATE | 0x19 | 获取信标灯状态 | |
DSCMD_BEACONINIT | 0x12 | 对于信标灯进行初始化 | |
错误字节 | == | 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的竞赛裁判系统功能调试-与微机通讯的主要内容,如果未能解决你的问题,请参考以下文章