基于ESP32和XIAO系列开发板的多功能扩展板设计
一、项目概述
本项目针对ESP32和XIAO系列开发板,设计了一款多功能扩展板,型号命名为EXEB-F3,即ESP32 and XIAO Expansion Board for FastBond3。
EXEB-F3实物图
本人设计EXEB-F3的初衷,是因为以往在参加硬禾学堂举办的活动中,经常会用到各种开发板和模块,也多次用到面包板。但是面包板很容易出现接线错误、接触不良等现象,影响学习效率。因此,借此次FastBond3的机会,本人决心做一款开发板扩展板。
EXEB-F3扩展板上插入开发板、传感器等模块后,可产生多种应用效果。
EXEB-F3应用1-颜色识别
EXEB-F3应用2-电机驱动
EXEB-F3扩展板具有以下特点:
兼容多种板卡。本人手里的板卡很多,最常用的还是ESP32系列开发板和Seeed科技的XIAO系列开发板。EXEB-F3扩展板设计了大小两处开发板插槽,大卡槽可以兼容乐鑫科技的ESP32-S3-DevKitC-1、ESP32-S2-DevKitC-1等开发板。小卡槽支持Seeed科技的SeeedXIAO系列,如Seeed Studio XIAO SAMD21、Seeed Studio XIAO ESP32S3等开发板,也支持其它品牌与上述板卡引脚兼容的开发板。
适配多种模块。扩展板引出了丰富的接口,可快速连接各种模块。如I2C接口的OLED单色屏、SPI接口的彩色屏、UART接口的MP3模块、PWM接口的电机驱动模块、GPIO接口的颜色传感器模块、I2C接口的手势传感器模块等都能够即插即用。
支持多种工业通讯。扩展板上设计了RS232、RS485、CAN总线等电路,便于测试各种工业通讯,可连接PLC、触摸屏等。
具有多种组合功能。扩展板上设计了组合针脚,通过短接帽可进行资源分配与组合。比如CAN总线电路、MP3模块、OLED屏等可以通过短接帽选择给ESP32开发板还是XIAO开发板使用。ESP32开发板的UART1端口,可以选择连接MP3模块或RS232电路。这样就出现了多种组合形式,功能更加丰富和灵活。
二、硬件设计
2.1系统框图
EXEB-F3硬件系统框图如下图所示
系统包括电源电路、XIAO开发板插槽、ESP32开发板插槽、CAN电路、RS485电路、RS232电路、电机驱动模块、颜色传感器模块、MP3模块等外围模块插槽。
2.2主要模块及元件明细表
序号 | 型号 | 名称 | 生产单位 | 备注 |
1 | L7805 | 电源芯片 | ST | 5V |
2 | LM317T | 电源芯片 | ST |
|
3 | MAX3232ESE
| RS232芯片 | MAXIM公司(ADI公司) |
|
4 | SP3485
| RS485芯片 | UMW(友台半导体) |
|
5 | TJA1051T-3
| CAN收发器 | NXP |
|
6.1 | Seeed Studio XIAO SAMD21 | XIAO开发板 (SAMD21芯片) | Seeed |
|
6.2 | Seeed Studio XIAO ESP32S3 | XIAO开发板(ESP32-S3芯片) | Seeed |
|
7.1 | YD-ESP32-23 | ESP32-S3兼容板 |
|
|
7.2 | ESP32-S2-DevKitC-1 | ESP32-S2开发板 | 乐鑫 |
|
8.1 | DRI0044 | 微型双路直流电机驱动模块 | DFRobot | 芯片TB6612FNG |
8.2 | 电机驱动模块 | 双路电机驱动模块 | 国产 | 芯片TB6612FNG |
9 | SEN0101 | 颜色传感器模块 | DFRobot | 芯片TCS3200 |
10 | SEN0315 | 手势传感器模块 | DFRobot | 芯片PAJ7620U2 |
11 | JQ8900-16P | MP3模块 | 国产 |
|
12 | 0.96寸单色屏 128*64 | OLED单色屏 (I2C接口) | 国产 | 驱动芯片SSD1306 |
13 | 0.96 80*160(RGB)IPS | 彩色屏 (SPI接口) | 国产 | 驱动芯片ST7735 |
2.3电路原理
电源电路
EXEB-F3的供电电压为DC12V,通过L7805产生两路5V电源。双路电源设计是为了防止电机或音频功放工作时对其它芯片电源产生影响。
另外,使用LM317T将12V转3.3V。
因本人大学期间购买的L7805和LM317芯片,已积灰15年以上,这次是去库存使用。电路设计使用时还是建议选用贴片元件,如12转5V可以选用LM317G, 5V转3.3V可以选用AMS1117-3V3等芯片。
CAN电路
CAN电路的CAN收发器芯片使用TJA1051T-3,下图是典型电路。
增加了ESD2CAN24T2Q芯片,完成静电保护功能。
RS485电路
485电路使用的SP3485也是一款常用芯片。
自动收发电路相比较普通的485电路,区别在于多一个三极管控制485的使能引脚,实现了485的自动收发切换,不需要单片机连接芯片的发送或接收使能端。
RS232电路
RS232电路主芯片使用MAX3232,下面是典型应用电路。
ESP32开发板(简称“大板”)插槽
大板插槽引出了ESP32开发板的各种引脚,可插入ESP32-S2或S3系列开发板。如SPI引脚连接TFT彩色屏,UART2端口接485电路,UART1端口连接232电路,GPIO11和12作为CAN控制器与CAN收发器连接。I2C引脚接OLED单色屏。
部分GPIO接口引出,连接电机驱动模块或接颜色传感器。
XIAO开发板(简称“小板”)插槽
小板插槽,专门为“XIAO”系列开发板设计,引出了CAN总线连接接口(D0、D1)、I2C接口和UART口,可根据需要连接外设。
组合引脚
组合引脚是为了便于资源分配使用,通过短接帽切换引脚连接,实现多种组合,更加方便和灵活。
J7和J8是CAN总线电路切换,可选择给小开发板或大开发板使用。
J9和J10是I2C接口单色屏电路切换,可选择给小开发板或大开发板使用。
J11和J12为大开发板的GPIO15和16口的功能切换,可以配置成UART口连接485电路,也可以配成I2C口连接手势传感器。
J13和J14为大开发的UART口功能切换,可以选择连接232电路,也可连接MP3的串口。此外,J13和J14也可以将MP3分配给小开发板使用。
三、应用场景
EXEB-F3扩展板支持的开发板和模块较多,通过组合方式,可以实现多种应用。
比如,使用ESP32-S3兼容板,结合板载的CAN电路、RS485电路、RS232电路,可以实现一个工业用协议转换器。
也可以将板载工业总线电路和MP3语音模块等组合,实现一个语音报警器。
还可以使用ESP32和电机驱动模块,做智能蓝牙小车,本人在电子森林也发布过类似项目。
本人此次设计EXEB-F3扩展板,主要目的还是搭建一个多功能的开发平台,通过组合方式使用多样的接口,开发丰富的功能,在娱乐中达到学习的目的。
四、调试工具制作
《PCAN-Like CAN总线报文监测工具设计》
4.1 项目来源
本人在工作中,经常会用到CAN总线,许多PLC、显示屏、传感器等都采用CAN总线通讯方式。在CAN总线通讯网络中,经常会使用电脑检测CAN总线上的报文。常用的开发工具是PCAN,如下图所示
PCAN报文监控工具
进口的PCAN价格昂贵,因此衍生出很多类似PCAN的监测工具。本人参考网上的candleLight模块的原理,修改了电源等芯片,使用kicad重新绘制了电路,制作完成了这款CAN总线报文监测工具,命名为“PCAN-Like”。下面是PCAN-Like的实物图。
PCAN-Like报文监控工具
4.2 硬件设计
PCAN-Like的原理图,如下图:
PCAN-Like模块对外有CAN口和USB口,CAN口接入CAN总线网络,USB口连接电脑。通过上位机软件监测总线报文。
PCAN-Like模块使用USB供电,电源芯片采用AMS1117-3.3,处理器以STM32F072C8T6单片机为核心,内部集成CAN控制器接口,外部与TJA1051T-3 CAN收发器连接。单片机外部使用2个LED指示灯,显示CAN总线收发状态。
PCAN-Like更新程序,可采用SWD或USB方式,使用USB更新时,需要将BOOT0接3V3.
本人推荐使用SWD下载。
下图为PCAN-Like的PCB效果图。
PCAN-Like报文监控工具PCB效果图
4.3软件及工具
candleLight提供了固件,用户可自行烧录candleLight_fw.bin文件。该固件同时适用于STM32F072C8T6和STM32F042C6T6等处理器。
更新固件后,上位机使用cangaroo软件监控报文。
五、综合应用实例
《基于ESP32-S3和EXEB-F3扩展板的颜色识别、播报与通讯系统》
本项目使用两块EXEB-F3扩展板,分别搭载ESP32-S3兼容板和Seeed Studio XIAO ESP32S3开发板,两块扩展板通过CAN总线通讯,构成颜色识别、播报与通讯系统。
系统包括ESP32-S3开发板(简称开发板)、EXEB-F3扩展板、颜色传感器、MP3语音模块、显示屏、RS485电路等部分。
颜色传感器模块采集颜色信息,发送到扩展板1,开发板根据传感器数值,通过程序判断颜色,并显示到SPI彩色屏上,并通过UART口连接的MP3模块进行语音播报。
同时,颜色信息经过扩展板1的RS485电路,以Modbus协议的形式将颜色信息发送到工控触摸屏上,实现通讯功能。
此外,扩展板1的CAN口,通过CAN总线,将颜色信息发送到扩展板2,扩展板2的单色屏对颜色信息进行显示。
调试过程中,为了便于监测CAN总线报文,使用到了上一章的PCAN-Like模块。
下面是系统框图
代码讲解
扩展板1(ESP32-S3)代码
#include <Arduino.h>
#include <U8g2lib.h>
#include <TFT_eSPI.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
#include <HardwareSerial.h>
#include <ModbusRtu.h>
#define TXEN 4 //寄存器类型4
HardwareSerial SerialPort(2); // 使用 UART2连接485芯片
//modbus发送的数组
uint16_t ModbusSlaveSendData[16] = {
1, 2, 3, 4, 5, 6, 7, 8,9,10,11,12,13,14,15,16};
Modbus slave(1,Serial2,TXEN); //做modbus slave,地址1;使用串口2发送;
#include "driver/twai.h"
#define RX_PIN 11 //CAN控制器引脚
#define TX_PIN 12
#define TRANSMIT_RATE_MS 300
#define POLLING_RATE_MS 300
static bool driver_installed = false;
unsigned long previousMillis = 0;
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /* clock=*/13, /* data=*/14); // 单色I2C屏引脚定义
TFT_eSPI tft = TFT_eSPI();
//语音模块控制指令
unsigned char hexdata_on[4]={0xaa,0x02,0x00,0xac};//播放
unsigned char hexdata_pause[4]={0xaa,0x03,0x00,0xad};//暂停
unsigned char hexdata_off[4]={0xaa,0x04,0x00,0xae};//停止
unsigned char hexdata_sound1[5]={0xaa,0x13,0x01,0x01,0xBF};//设置音量1级
unsigned char hexdata_sound3[5]={0xaa,0x13,0x01,0x03,0xc1};//设置音量3级
unsigned char hexdata_sound5[5]={0xaa,0x13,0x01,0x05,0xc3};//设置音量5级
unsigned char hexdata_sound8[5]={0xaa,0x13,0x01,0x08,0xc6};//设置音量8级
unsigned char hexdata_sound10[5]={0xaa,0x13,0x01,0x0a,0xc8};//设置音量10级
unsigned char hexdata_sound20[5]={0xaa,0x13,0x01,0x14,0xd2};//设置音量20级
unsigned char hexdata_next[4]={0xaa,0x06,0x00,0xb0};//下一首
unsigned char hexdata_previous[4]={0xaa,0x05,0x00,0xaf};//上一首
unsigned char hexdata_music1[6]={0xaa,0x07,0x02,0x00,0x01,0xb4};//指定第1首 最后一个数是“和校验”,前面数据求和
unsigned char hexdata_music2[6]={0xaa,0x07,0x02,0x00,0x02,0xb5};//指定第2首 最后一个数是“和校验”,前面数据求和
unsigned char hexdata_music3[6]={0xaa,0x07,0x02,0x00,0x03,0xb6};//指定第3首 最后一个数是“和校验”,前面数据求和
unsigned char hexdata_music7[6]={0xaa,0x07,0x02,0x00,0x07,0xba};//指定第7首
unsigned char hexdata_music8[6]={0xaa,0x07,0x02,0x00,0x08,0xbb};//指定第8首
#define S0_PIN 1 //颜色传感器与开发板连接引脚定义
#define S1_PIN 2
#define S2_PIN 42
#define S3_PIN 41
#define OUT_PIN 40 //传感器的输出脚
int iColorCode;//颜色代码,0-未知,1-红色,2-绿色,3-蓝色
int r_RGB, g_RGB, b_RGB;
bool bPlayRed=true; //增加放音标志,确保只播放一次
bool bPlayGreen=true;
bool bPlayBlue=true;
void setup() {
u8g2.begin();
u8g2.enableUTF8Print();
u8g2.setFont(u8g2_font_wqy16_t_gb2312);
tft.init();
tft.setRotation(3); //设置屏幕方向
tft.fillScreen(TFT_WHITE);
Serial.begin(9600); //启动uart0
Serial1.begin(9600, SERIAL_8N1, 18, 17);//UART1连接语音模块
Serial2.begin(9600, SERIAL_8N1, 15, 16);//9600,数据位8,停止位1,无校验。GPIO15为RX,GPIO16为TX
slave.start();
while (!Serial1);
delay(3000);
Serial1.write(hexdata_sound10,5);//设置音量,10级,等级越大,音量越大
pinMode(S0_PIN,OUTPUT); //设定引脚输入输出模式
pinMode(S1_PIN,OUTPUT);
pinMode(S2_PIN,OUTPUT);
pinMode(S3_PIN,OUTPUT);
pinMode(OUT_PIN,INPUT);//控制器采集传感器信号
digitalWrite(S0_PIN,HIGH); //频率缩放20% S0-HIGH,S1-LOW
digitalWrite(S1_PIN,LOW);
//CAN总线初始化
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)TX_PIN, (gpio_num_t)RX_PIN, TWAI_MODE_NORMAL);
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS(); //Look in the api-reference for other speed sets.波特率设置
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
// Install TWAI driver
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
Serial.println("Driver installed");
} else {
Serial.println("Failed to install driver");
return;
}
// Start TWAI driver
if (twai_start() == ESP_OK) {
Serial.println("Driver started");
} else {
Serial.println("Failed to start driver");
return;
}
// Reconfigure alerts to detect TX alerts and Bus-Off errors
uint32_t alerts_to_enable = TWAI_ALERT_TX_IDLE | TWAI_ALERT_TX_SUCCESS | TWAI_ALERT_TX_FAILED | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR;
if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) {
Serial.println("CAN Alerts reconfigured");
} else {
Serial.println("Failed to reconfigure alerts");
return;
}
// TWAI driver is now successfully installed and started
driver_installed = true;
}
void loop()
{
float k_R=6.0, k_G=6.8, k_B=6.9;
int r_H, g_H, b_H;
int r_L, g_L, b_L;
int data_RGB_TFT16;
digitalWrite(S2_PIN, LOW);//只采集红光
digitalWrite(S3_PIN, LOW);
r_L = pulseIn(OUT_PIN, LOW);
r_H = pulseIn(OUT_PIN, HIGH);
r_RGB=calcRGB(r_L,r_H,k_R);
Serial.print("r_RGB = ");
Serial.print(r_RGB);
Serial.print(" ");
delay(100);
digitalWrite(S2_PIN, HIGH);//只采集绿光
digitalWrite(S3_PIN, HIGH);
g_L = pulseIn(OUT_PIN, LOW);
g_H = pulseIn(OUT_PIN, HIGH);
g_RGB=calcRGB(g_L,g_H,k_G);
Serial.print("g_RGB = ");
Serial.print(g_RGB);
Serial.print(" ");
delay(100);
digitalWrite(S2_PIN, LOW);//只采集蓝光
digitalWrite(S3_PIN, HIGH);
b_L = pulseIn(OUT_PIN, LOW);
b_H = pulseIn(OUT_PIN, HIGH);
b_RGB=calcRGB(b_L,b_H,k_B);
Serial.print("b_RGB = ");
Serial.print(b_RGB);
Serial.print(" ");
Serial.println();
delay(100);
//判断颜色
if ((r_RGB > g_RGB) && (r_RGB > b_RGB) && (r_RGB>200))
{
iColorCode=1;
Serial.println("Colour Red");
tft.fillScreen(TFT_RED);
}
else if ((g_RGB > r_RGB) && (g_RGB > b_RGB)&& (g_RGB>100))
{
iColorCode=2;
Serial.println("Colour Green");
tft.fillScreen(TFT_GREEN);
}
else if ((b_RGB > r_RGB) && ( b_RGB > g_RGB) && (b_RGB>100))
{
iColorCode=3;
Serial.println("Colour Blue");
tft.fillScreen(TFT_BLUE);
}
else
{
iColorCode=0;
Serial.println("READY");
tft.fillScreen(TFT_WHITE);
}
ModbusSlaveSendData[0]=r_RGB; //将颜色信息写入modbus寄存器中
ModbusSlaveSendData[1]=g_RGB;
ModbusSlaveSendData[2]=b_RGB;
ModbusSlaveSendData[3]=iColorCode;
slave.poll(ModbusSlaveSendData, 16 ); //将modbus Slave数据发送到modbus poll
can_send_message();//将颜色信息写入CAN报文并发送
u8g2Display();//OLED显示子程序
MP3Control();//放音控制
}
//计算RGB值
int calcRGB(int time_L,int time_H,float k)
{
int data1;
byte data_Output;
time_L = pulseIn(OUT_PIN, LOW); //检测低电平的时间长度 ms
time_H = pulseIn(OUT_PIN, HIGH);//检测高电平的时间长度 ms
data1=int(1000.0/(time_L+time_H)*k);
if (data1<=255)
{data_Output=data1;
}
else
{data_Output=255;
}
return data_Output;
}
void u8g2Display()
{
u8g2.enableUTF8Print(); //中文字体需要有此行,否则只能显示字母
u8g2.setFont(u8g2_font_wqy16_t_gb2312);//设置中文字体16
u8g2.setFontDirection(0);
u8g2.firstPage();
do {
if (iColorCode==1)
{
u8g2.drawUTF8(50,40,"红");
u8g2.drawStr(45,60,"RED");
}
else if(iColorCode==2)
{
u8g2.drawUTF8(50,40,"绿");
u8g2.drawStr(35,60,"GREEN");
}
else if(iColorCode==3)
{
u8g2.drawUTF8(50,40,"蓝");
u8g2.drawStr(40,60,"BLUE");
}
else
{
u8g2.drawUTF8(50,40,"就绪");
u8g2.drawStr(40,60,"READY");
}
u8g2.setFont(u8g2_font_wqy12_t_gb2312);//设置中文字体12
u8g2.drawUTF8(10,10,"R=");
u8g2.setCursor(25, 10);//设置X,Y起始坐标
u8g2.print(r_RGB);
u8g2.drawUTF8(50,10,"G=");
u8g2.setCursor(65, 10);//设置X,Y起始坐标
u8g2.print(g_RGB);
u8g2.drawUTF8(90,10,"B=");
u8g2.setCursor(105, 10);//设置X,Y起始坐标
u8g2.print(b_RGB);
} while ( u8g2.nextPage() );
}
void MP3Control()
{
if (iColorCode==1)
{ if(bPlayRed)
{Serial1.write(hexdata_music1,6); //播放 红色
// delay(500);
bPlayRed=false;
bPlayGreen=true;
bPlayBlue=true;
}
}
else if (iColorCode==2)
{ if(bPlayGreen)
{Serial1.write(hexdata_music2,6);//播放 绿色
// delay(500);
bPlayRed=true;
bPlayGreen=false;
bPlayBlue=true;
}
}
else if (iColorCode==3)
{ if(bPlayBlue)
{Serial1.write(hexdata_music3,6);//播放 蓝色
// delay(500);
bPlayRed=true;
bPlayGreen=true;
bPlayBlue=false;
}
}
else
{
bPlayRed=true;
bPlayGreen=true;
bPlayBlue=true;
}
Serial.print("bPlayRed = ");
Serial.print(bPlayRed);
Serial.print(" ");
Serial.println();
Serial.print("bPlayGreen = ");
Serial.print(bPlayGreen);
Serial.print(" ");
Serial.println();
Serial.print("bPlayBlue = ");
Serial.print(bPlayBlue);
Serial.print(" ");
Serial.println();
}
void can_send_message()
{
if (!driver_installed) {
// Driver not installed
delay(1000);
return;
}
// Check if alert happened
uint32_t alerts_triggered;
twai_read_alerts(&alerts_triggered, pdMS_TO_TICKS(POLLING_RATE_MS));
twai_status_info_t twaistatus;
twai_get_status_info(&twaistatus);
// Handle alerts
if (alerts_triggered & TWAI_ALERT_ERR_PASS) {
Serial.println("Alert: TWAI controller has become error passive.");
}
if (alerts_triggered & TWAI_ALERT_BUS_ERROR) {
Serial.println("Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus.");
Serial.printf("Bus error count: %d\n", twaistatus.bus_error_count);
}
if (alerts_triggered & TWAI_ALERT_TX_FAILED) {
Serial.println("Alert: The Transmission failed.");
Serial.printf("TX buffered: %d\t", twaistatus.msgs_to_tx);
Serial.printf("TX error: %d\t", twaistatus.tx_error_counter);
Serial.printf("TX failed: %d\n", twaistatus.tx_failed_count);
}
if (alerts_triggered & TWAI_ALERT_TX_SUCCESS) {
Serial.println("Alert: The Transmission was successful.");
Serial.printf("TX buffered: %d\t", twaistatus.msgs_to_tx);
}
// Send message
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= TRANSMIT_RATE_MS) {
previousMillis = currentMillis;
twai_message_t message;
message.extd=0;
message.rtr=0;
message.identifier = 0x181;
message.data_length_code = 8;
message.data[0]=r_RGB; //将颜色信息写入CAN寄存器中
message.data[1]=g_RGB;
message.data[2]=b_RGB;
message.data[3]=iColorCode;
// Queue message for transmission
if (twai_transmit(&message, pdMS_TO_TICKS(1000)) == ESP_OK) {
printf("Message queued for transmission\n");
} else {
printf("Failed to queue message for transmission\n");
}
}
}
扩展板2(Seeed XIAO -ESP32S3)代码
#include <Arduino.h>
#include <U8g2lib.h>
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE); //硬件I2C,无需指定I2C引脚
#include "driver/twai.h"
#define RX_PIN D0
#define TX_PIN D1
// Intervall:
#define POLLING_RATE_MS 300
static bool driver_installed = false;
int iColorCode;//颜色代码,0-未知,1-红色,2-绿色,3-蓝色
int r_RGB, g_RGB, b_RGB;
void setup() {
u8g2.begin();
u8g2.enableUTF8Print();
u8g2.setFont(u8g2_font_wqy16_t_gb2312);
// Start Serial:
Serial.begin(9600);
// Initialize configuration structures using macro initializers
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t)TX_PIN, (gpio_num_t)RX_PIN, TWAI_MODE_NO_ACK);
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS(); //Look in the api-reference for other speed sets.
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
// Install TWAI driver
if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
Serial.println("Driver installed");
} else {
Serial.println("Failed to install driver");
return;
}
// Start TWAI driver
if (twai_start() == ESP_OK) {
Serial.println("Driver started");
} else {
Serial.println("Failed to start driver");
return;
}
// Reconfigure alerts to detect frame receive, Bus-Off error and RX queue full states
uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR | TWAI_ALERT_RX_QUEUE_FULL;
if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) {
Serial.println("CAN Alerts reconfigured");
} else {
Serial.println("Failed to reconfigure alerts");
return;
}
// TWAI driver is now successfully installed and started
driver_installed = true;
}
static void handle_rx_message(twai_message_t& message) {
// Process received message
if (message.extd) {
Serial.println("Message is in Extended Format");
} else {
Serial.println("Message is in Standard Format");
}
Serial.printf("ID: %x\nByte:", message.identifier);
if (!(message.rtr)) {
for (int i = 0; i < message.data_length_code; i++) {
Serial.printf(" %d = %02x,", i, message.data[i]);
}
Serial.println("");
}
}
void loop() {
if (!driver_installed) {
// Driver not installed
delay(1000);
return;
}
// Check if alert happened
uint32_t alerts_triggered;
twai_read_alerts(&alerts_triggered, pdMS_TO_TICKS(POLLING_RATE_MS));
twai_status_info_t twaistatus;
twai_get_status_info(&twaistatus);
// Handle alerts
if (alerts_triggered & TWAI_ALERT_ERR_PASS) {
Serial.println("Alert: TWAI controller has become error passive.");
}
if (alerts_triggered & TWAI_ALERT_BUS_ERROR) {
Serial.println("Alert: A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus.");
Serial.printf("Bus error count: %d\n", twaistatus.bus_error_count);
}
if (alerts_triggered & TWAI_ALERT_RX_QUEUE_FULL) {
Serial.println("Alert: The RX queue is full causing a received frame to be lost.");
Serial.printf("RX buffered: %d\t", twaistatus.msgs_to_rx);
Serial.printf("RX missed: %d\t", twaistatus.rx_missed_count);
Serial.printf("RX overrun %d\n", twaistatus.rx_overrun_count);
}
// Check if message is received
if (alerts_triggered & TWAI_ALERT_RX_DATA) {
// One or more messages received. Handle all.
twai_message_t message;
while (twai_receive(&message, 0) == ESP_OK) {
handle_rx_message(message);
if (message.identifier==0x181)
{
r_RGB=message.data[0];
g_RGB=message.data[1];
b_RGB=message.data[2];
iColorCode=message.data[3];
}
u8g2Display();
}
}
}
void u8g2Display()
{
u8g2.enableUTF8Print(); //中文字体需要有此行,否则只能显示字母
u8g2.setFont(u8g2_font_wqy16_t_gb2312);//设置中文字体16
u8g2.setFontDirection(0);
u8g2.firstPage();
do {
if (iColorCode==1)
{
u8g2.drawUTF8(50,40,"红");
u8g2.drawStr(45,60,"RED");
}
else if(iColorCode==2)
{
u8g2.drawUTF8(50,40,"绿");
u8g2.drawStr(35,60,"GREEN");
}
else if(iColorCode==3)
{
u8g2.drawUTF8(50,40,"蓝");
u8g2.drawStr(40,60,"BLUE");
}
else
{
u8g2.drawUTF8(50,40,"就绪");
u8g2.drawStr(40,60,"READY");
}
u8g2.setFont(u8g2_font_wqy12_t_gb2312);//设置中文字体12
u8g2.drawUTF8(10,10,"R=");
u8g2.setCursor(25, 10);//设置X,Y起始坐标
u8g2.print(r_RGB);
u8g2.drawUTF8(50,10,"G=");
u8g2.setCursor(65, 10);//设置X,Y起始坐标
u8g2.print(g_RGB);
u8g2.drawUTF8(90,10,"B=");
u8g2.setCursor(105, 10);//设置X,Y起始坐标
u8g2.print(b_RGB);
} while ( u8g2.nextPage() );
}
运行效果
通过放置不同色块,SPI彩色屏、工业触摸屏都能显示颜色信息,颜色信息通过CAN总线发送到另一块扩展板并在I2C单色屏显示,PCAN-Like也能监测报文并显示在电脑上,各个端口通讯正常。
六、总结
在FastBond3活动中,本人主要完成了以下工作:
1.设计制作了EXEB-F3扩展板,搭配开发板、显示屏、传感器等模块,使用Arduino编程,调试了扩展板的CAN、485、I2C、SPI、UART等主要接口,实现了两款开发板之间CAN总线通讯,完成了《基于ESP32-S3和EXEB-F3扩展板的颜色识别、播报与通讯系统》项目。
2.设计制作了PCAN-Like报文监测工具,完成了固件更新及功能验证。
本人通过FastBond3活动,加深了对工业总线电路设计的理解,提高了电路设计和焊接水平,对Kicad软件的使用也更加熟练。经过此次活动,本人对此前的项目进行了梳理,为后续的项目开发积累了宝贵经验。
未来计划把每个模块的测试程序整理后,以专题的形式开源。