KE0175 Keyes STEM 电子积木编程教育开发板#

资料下载#
1. 简介#
KE0175 Keyes STEM 电子积木编程教育开发板是一款基于 ATmega328P 的单片机开发板,完全兼容 Arduino IDE 开发环境。该开发板集成了一块 1.8 寸 TFT 屏和 SD 卡模块,便于显示实验内容和储存数据。可搭配丰富的 XH2.5 接口扩展使用,外围传感器即插即用,开发板上有四个螺丝定位孔,可搭配电子积木,完成简单的造型和创意性的实验。
2. 特点#
兼容性强:完全兼容 Arduino IDE 开发环境,易于上手。
集成显示:内置 1.8 寸 TFT 屏,方便实时显示数据和信息。
扩展性好:支持 XH2.5 接口,外围传感器即插即用。
环保设计:采用环保材料,安全可靠。
多功能:适合教育、DIY 项目和创意实验。
3. 规格参数#
USB 输入电压:DC 3.3V - 5V
VIN 输入电压:DC 7~12V
IO 输出电流:80mA
VCC 输出最大电流:3A
最大功率:15W
工作温度范围:-10~50℃
微控制器:ATmega328P-AU
USB 转串口芯片:CP2102
数字 I/O 引脚:8 (D0-D7)
PWM 通道:3 (D3、D5、D6)
模拟输入通道(ADC):8 (A0-A7)
Flash Memory:32 KB(其中引导程序使用 0.5 KB)
SRAM:2 KB (ATmega328P-AU)
EEPROM:1 KB (ATmega328P-AU)
时钟速度:16MHz
4. 接口#
USB 接口:用于供电和编程。
VIN 接口:外部电源输入。
数字 I/O 引脚:用于连接传感器和执行器。
PWM 接口:用于脉宽调制输出。
模拟输入引脚:用于读取模拟信号。
SD 卡模块:用于存储数据和文件。

5. 连接图#

引脚定义
VCC:连接到 Arduino 的 5V 引脚。
GND:连接到 Arduino 的 GND 引脚。
DATA:连接到 Arduino 的数字引脚(如 D2)。
6. 示例代码#
以下是一个简单的示例代码,用于读取 SD 卡中的 BMP 图片并在 TFT 屏上显示,同时进行电压测试和流水灯测试:
注意:
1、请先将开头下载的资料里面的图片复制到SD卡根目录,并且SD卡需要使用FAT32格式;
2、上传代码时请使用开头下载的资料里面的代码,里面包含了库文件,直接复制下面代码没有库文件会报错。
#include "Adafruit_GFX.h"
#include "Adafruit_ST7735.h"
#include <SD.h>
#include <SPI.h>
#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif
// TFT 显示屏和 SD 卡将共享硬件 SPI 接口。
// 硬件 SPI 引脚特定于 Arduino 开发板类型,
// 并且不能重新映射到备用引脚。对于 Arduino Uno、
// Duemilanove 等,引脚 11 = MOSI,引脚 12 = MISO,引脚 13 = SCK。
#define SD_CS 7 // SD 卡的片选线
#define TFT_CS 8 // TFT 显示屏的片选线
#define TFT_DC 10 // TFT 的数据/命令线
#define TFT_RST 9 // TFT 的复位线(或连接到 +5V)
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
int Delay_Timer = 300;
void setup(void) {
Serial.begin(9600);
Pin_Set();
// 初始化 1.8" TFT
//tft.initR(INITR_BLACKTAB); // 初始化 ST7735S 芯片,黑片 (black tab)
tft.initR();
Serial.println("OK!");
tft.fillScreen(ST7735_BLACK);
tft.setRotation(0);
tft.setTextSize(2);
Serial.print("Initializing SD card...");
if (!SD.begin(SD_CS))
{
Serial.println("failed!");
tft.setTextColor(ST7735_RED);
tft.setCursor(30, 40);
tft.print("SD Error");
return;
}
else
{
Serial.println("SD OK");
tft.setTextColor(ST7735_RED);
tft.setCursor(30, 40);
tft.print("SD OK");
}
delay(500);
}
void loop()
{
Bmp(); //SD卡读取图片测试
//while (1);
}
void Bmp()
{
bmpDraw("car.bmp", 0, 0);
delay(Delay_Timer);
bmpDraw("avatar.bmp", 0, 0);
delay(Delay_Timer);
// bmpDraw("DEMA.bmp", 0, 0);
// delay(Delay_Timer);
// bmpDraw("DLAM.bmp", 0, 0);
// delay(Delay_Timer);
// bmpDraw("mangseng.bmp", 0, 0);
// delay(Delay_Timer);
// bmpDraw("TLP.bmp", 0, 0);
// delay(Delay_Timer);
// bmpDraw("girl.bmp", 0, 0);
// delay(Delay_Timer);
}
void Pin_Set()
{
for(int i = 0; i < 7; i++)
{
pinMode(i,OUTPUT);
}
for(int i = 14; i < 20; i++)
{
pinMode(i,OUTPUT);
}
for(int i = 0; i < 7; i++)
{
digitalWrite(i,HIGH);
}
for(int i = 14; i < 20; i++)
{
digitalWrite(i,HIGH);
}
}
// 该函数打开一个 Windows 位图 (BMP) 文件,
// 并将其显示在给定的坐标处。它通过一次读取
// 多个像素的数据(而不是逐个像素读取)来提高速度。
// 增加缓冲区大小会占用更多 Arduino 宝贵的 RAM,
// 但会使加载速度稍微快一点。20 个像素似乎是
// 一个很好的平衡点。
#define BUFFPIXEL 20
void bmpDraw(char *filename, uint8_t x, uint8_t y) {
File bmpFile;
int bmpWidth, bmpHeight; // 像素的宽+高
uint8_t bmpDepth; // 位深度(目前必须为 24)
uint32_t bmpImageoffset; // 文件中图像数据的起始位置
uint32_t rowSize; // 不一定等于 bmpWidth;可能有填充字节
uint8_t sdbuffer[3*BUFFPIXEL]; // 像素缓冲区(每个像素 R+G+B)
uint8_t buffidx = sizeof(sdbuffer); // sdbuffer 中的当前位置
boolean goodBmp = false; // 在成功解析有效的头部时设置为 true
boolean flip = true; // BMP 存储方式为自下而上
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
if((x >= tft.width()) || (y >= tft.height())) return;
Serial.println();
Serial.print("Loading image '");
Serial.print(filename);
Serial.println('\'');
// 在 SD 卡上打开请求的文件
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.print("File not found");
return;
}
// 解析 BMP 头部
if(read16(bmpFile) == 0x4D42) { // BMP 签名 (0x4D42 是 'BM')
Serial.print("File size: "); Serial.println(read32(bmpFile));
(void)read32(bmpFile); // 读取并忽略创建者字节
bmpImageoffset = read32(bmpFile); // 图像数据的起始位置
Serial.print("Image Offset: "); Serial.println(bmpImageoffset, DEC);
// 读取 DIB 头部
Serial.print("Header size: "); Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // 颜色平面数 -- 必须为 '1'
bmpDepth = read16(bmpFile); // 每像素位数 (bits per pixel)
Serial.print("Bit Depth: "); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = 未压缩
goodBmp = true; // 支持的 BMP 格式 -- 继续!
Serial.print("Image size: ");
Serial.print(bmpWidth);
Serial.print('x');
Serial.println(bmpHeight);
// BMP 的行需要填充到 4 字节的边界(如果需要)
rowSize = (bmpWidth * 3 + 3) & ~3;
// 如果 bmpHeight 是负数,则图像是自上而下顺序的。
// 这不是标准规范,但在实际应用中观察到过这种情况。
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
// 裁剪需要加载的区域
w = bmpWidth;
h = bmpHeight;
if((x+w-1) >= tft.width()) w = tft.width() - x;
if((y+h-1) >= tft.height()) h = tft.height() - y;
// 将 TFT 的地址窗口设置为裁剪后的图像边界
tft.startWrite();
tft.setAddrWindow(x, y, w, h);
for (row=0; row<h; row++) { // 对于每条扫描线...
// 定位到扫描线的起始位置。在每一行都执行此操作
// 似乎很费劲,但这种方法涵盖了裁剪和扫描线填充等
// 许多繁琐的细节。此外,只有在文件位置实际需要
// 更改时才会执行定位(避免了 SD 库中大量的簇计算)。
if(flip) // 位图以自下而上的顺序存储(正常 BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else // 位图以自上而下的顺序存储
pos = bmpImageoffset + row * rowSize;
if(bmpFile.position() != pos) { // 需要定位吗?
tft.endWrite();
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // 强制重新加载缓冲区
}
for (col=0; col<w; col++) { // 对于每个像素...
// 需要读取更多像素数据了吗?
if (buffidx >= sizeof(sdbuffer)) { // 确实需要
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // 将索引设置回开头
tft.startWrite();
}
// 将像素从 BMP 格式转换为 TFT 格式,并推送到显示屏
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
tft.pushColor(tft.color565(r,g,b));
} // 结束 pixel 循环
} // 结束 scanline 循环
tft.endWrite();
Serial.print("Loaded in ");
Serial.print(millis() - startTime);
Serial.println(" ms");
} // 结束 goodBmp 判断
}
}
bmpFile.close();
if(!goodBmp) Serial.println("BMP format not recognized.");
}
// 这些函数从 SD 卡文件中读取 16 位和 32 位类型的数据。
// BMP 数据以小端模式存储,Arduino 也是小端模式。
// 如果移植到其他平台,可能需要反转下标顺序。
uint16_t read16(File f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // 最低有效字节 (LSB)
((uint8_t *)&result)[1] = f.read(); // 最高有效字节 (MSB)
return result;
}
uint32_t read32(File f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // 最低有效字节 (LSB)
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // 最高有效字节 (MSB)
return result;
}
7. 实验现象#
上传程序后,开发板将读取 SD 卡中的图片并在 TFT 屏上显示内容。如果 SD 卡插入正确且文件存在,屏幕将显示文件内容;如果出现错误,屏幕将显示相应的错误信息。同时,电压测试结果将显示在屏幕上,流水灯测试将依次点亮数字引脚。

8. 注意事项#
确保 SD 卡中存在指定的 BMP 文件(如
car.bmp和avatar.bmp)。确保供电电压在 7-12V 范围内,避免损坏开发板。
在上传代码之前,确保选择正确的板和 COM 口。
使用合适的库文件以确保程序正常运行。
SD卡必须使用FAT32的格式。
如有更多疑问,请联系 Keyes 官方客服或加入相关创客社区交流。祝使用愉快!