基于纳芯微评估板NSSinePad-NS800RT5039的WS2812B灯板控制
该项目使用了纳芯微评估板NSSinePad-NS800RT5039和STCC4传感器,实现了控制WS2812B灯板的设计,它的主要功能为:通过SPI输出时序数据,控制42*5颗灯珠的WS2812B灯板,并能够呈现不同的炫彩效果。。
标签
SPI
WS2812B
纳芯微
WeDesign活动
HonestQiao
更新2025-12-04
19

一、项目概述

本项目基于纳芯微NS800RT5039评估板,成功实现了WS2812B LED灯板的SPI驱动控制,并完成了基础外设功能验证。项目不仅完成了基础任务要求的UART输出和ePWM波形生成,还自主扩展了WS2812B LED控制功能,成功驱动了42列×5行共210颗LED的灯板,实现了多种动态光效。本项目为大规模LED灯墙控制提供了重要的技术验证和实践经验。


二、硬件系统设计

2.1 硬件选型与配置

组件

型号/规格

关键参数

备注

主控芯片

NS800RT5039

Cortex-M0@64MHz, 128KB Flash, 32KB RAM

评估板自带

评估板

NSSinePad-NS800RT5039

提供完整外设接口

官方SDK

LED灯板

WS2812B RGB LED

42列×5行=210颗,24位色深

单线串行控制

调试工具

带屏十二指神探


ADALM2000(M2K)

8通道逻辑分析仪


掌上电子实验室

用于PWM数据分析


用于WS2812B数据分析

电源模块

PD口袋电源

5V/3A输出,支持PPS

独立供电

2.2 硬件连接架构

                       供电系统
↗ ↖
5V/3A GND
↓ ↓
WS2812B灯板 ← SPI数据 → NS800RT5039评估板
(VCC+GND) (SPI1-SIMO) (UART+ePWM输出)
↓ ↓
串口调试 逻辑分析仪

2.3 电源设计考虑

我使用的灯板,是低功耗的,使用5V供电,最高亮度全白色的时候,单颗灯珠的电流为14毫安,210颗LED最大电流为:

Imax=210×14mA=2.9A


实际使用中应采用以下策略:

  1. 外接5V/3A独立电源,避免开发板电源过载
  2. 软件层面限制最大亮度(通常使用50%亮度)
  3. 实际工作电流控制在1.5A以内,确保系统稳定


三、软件架构设计

3.1 整体架构

应用层 (main.c)
├── 演示调度器
├── 动画效果库
└── 用户交互

驱动层 (ws2812b.c/h)
├── 硬件抽象层 (SPI初始化)
├── 数据缓冲区管理
├── 坐标映射系统
└── 时序生成引擎

硬件层 (NS800RT5039 SDK)
├── SPI控制器
├── DMA引擎
├── 定时器系统
└── GPIO管理


3.2 核心问题解决:

问题现象:

初期测试中发现,设置42列LED时仅能点亮21列,硬件仅响应一半数据量。


问题分析:

经深入调试发现,NS800RT5xxx系列芯片的SPI控制器在特定配置下存在硬件特性:实际传输的数据量会减半。

但是,深层的具体原因还没有完全找到,日后再分析。


解决方案探索:

先后尝试了多种方法:

  1. 调整SPI数据宽度:8位→16位→32位(无效)
  2. 修改发送策略:分批发送、DMA传输(无效)
  3. 检查GPIO配置:更换引脚、检查复用功能(无效)
  4. 分析时序波形:使用逻辑分析仪确认SPI输出(数据确实减半)


最终解决方案:数据翻倍补偿

在软件层面实现透明的数据补偿机制:

// ws2812b.h
#define WS2812B_PHYSICAL_COLUMNS (42U) // 用户可见的物理列数
#define WS2812B_PHYSICAL_ROWS (5U) // 用户可见的物理行数
#define WS2812B_COLUMNS (WS2812B_PHYSICAL_COLUMNS * 2) // 内部缓冲列数
#define WS2812B_ROWS (WS2812B_PHYSICAL_ROWS) // 内部缓冲行数

问题解决后,两块或者更多灯板级联,都能够完全正常的控制显示。


工作原理示意图

用户操作:设置第N列颜色

驱动层:同时写入内部缓冲区第2N列和第2N+1

SPI发送:420LED数据(84列×5行)

硬件处理:数据量自动减半

实际输出:210LED数据(42列×5行)✓


3.3 WS2812B时序实现

时序计算

WS2812B采用单线协议,传输的数据,有严格的时序要求:


WS2812B协议要求:

  • 0码:T0H ≈ 0.4μs, T0L ≈ 0.85μs
  • 1码:T1H ≈ 0.8μs, T1L ≈ 0.45μs
  • 复位:低电平 > 50μs

通常选用SPI频率:6.4MHz
SPI周期:TSPI=16.4MHz156nsTSPI=6.4MHz1156ns


编码方案:

  • WS2812B "0" → SPI: 1000 (0x8)
    • 高电平:1×156ns = 156ns
    • 低电平:3×156ns = 468ns
    • 接近原始要求(400ns/850ns)
  • WS2812B "1" → SPI: 1110 (0xE)
    • 高电平:3×156ns = 468ns
    • 低电平:1×156ns = 156ns
    • 接近原始要求(800ns/450ns)


性能分析

每颗LED数据传输时间:

TLED=24×4SPI/×156ns=14.976μsTLED=24×4SPI/×156ns=14.976μs


210颗LED总传输时间:

Ttotal=210×14.976μs+50μs(复位)3.195msTtotal=210×14.976μs+50μs(复位)3.195ms


理论最大刷新率:

Fmax=13.195ms313HzFmax=3.195ms1313Hz


实际测试刷新率约300Hz,完全满足流畅动画要求。


四、功能实现详情

4.1 基础任务完成情况

任务1:UART串口输出

基于SDK示例examples/device_support/ns800rt5xxx/examples/uart/uart_ex1_send_receive_pollin修改,成功输出指定字符串:

printf("Hello, NOVOSENSE Wedesign project.\r\n");

实际串口输出:



任务2:ePWM互补波形输出

给予SDK示例examples/device_support/ns800rt5xxx/examples/epwm/epwm_ex11_configure_signal配置ePWM模块生成2MHz、50%占空比互补波形:

// 关键配置参数
EPWM_SignalParams pwmSignal = {
.frequency = 2000000, // 2MHz
.dutyCycle = 0.5, // 50%占空比
.phase = 0.5, // 相位50%
.complementary = true, // 互补输出
// ... 其他配置
};

通过代码中的配置,可以得知对应的ePWM的输出引脚:

然后,从原理图上,可以查到,GPIO0、GPIO1在J11上引出:

具体位于开发板如下位置:GPIO0->I2C1-SDA、GPIO1->I2C1-SCL


将GPIO0、GPIO1连接到带屏十二指神探(已刷逻辑分析仪固件):

打开PulseView,找到对应的逻辑分析仪设备:

编译下载运行后,就能收到输出的PWM信号了:

放大,然后使用标尺测量,可以看到具体的频率:

经检验,符合任务要求。


五、LED驱动API设计与实现详解

5.1 整体架构设计

本项目的LED驱动系统采用分层架构设计,从上到下分为应用层、API层、驱动层和硬件抽象层,实现了高内聚、低耦合的设计目标:

应用层 (Application)
├── 动画效果库
├── 用户交互逻辑
└── 系统调度器

API (WS2812B API)
├── 颜色管理函数
├── 坐标映射系统
├── 区域控制接口
└── 动画辅助工具

驱动层 (Driver Layer)
├── 数据编码器
├── 缓冲区管理器
├── SPI时序控制器
└── 错误处理机制

硬件抽象层 (HAL)
├── SPI硬件配置
├── GPIO引脚管理
└── 时钟系统配置


5.2 数据结构设计

颜色结构体设计

typedef struct {
uint8_t r; /*!< Red component (0-255) */
uint8_t g; /*!< Green component (0-255) */
uint8_t b; /*!< Blue component (0-255) */
} WS2812B_Color;

关键特性

  1. 内存对齐:3字节紧凑存储,减少内存占用
  2. 平台无关:使用标准uint8_t类型,保证跨平台兼容性
  3. 直接映射:结构与WS2812B芯片的24位数据格式完全对应


缓冲区设计

// 颜色缓冲区:存储每个LED的RGB值
WS2812B_Color g_ws2812b_pixels[WS2812B_LED_COUNT];

// SPI数据缓冲区:存储编码后的传输数据
uint8_t g_ws2812b_spi_buffer[WS2812B_BUFFER_SIZE + WS2812B_RESET_BYTES];


数据翻倍补偿机制

// ws2812b.h
#define WS2812B_PHYSICAL_COLUMNS (42U) // 用户可见的物理列数
#define WS2812B_PHYSICAL_ROWS (5U) // 用户可见的物理行数
#define WS2812B_COLUMNS (WS2812B_PHYSICAL_COLUMNS * 2) // 内部缓冲列数
#define WS2812B_ROWS (WS2812B_PHYSICAL_ROWS) // 内部缓冲行数
#define WS2812B_LED_COUNT (WS2812B_COLUMNS * WS2812B_ROWS) // 内部LED计数


5.3 API函数详细设计

5.3.1 初始化与基础控制

WS2812B_Init()函数

void WS2812B_Init(void)
{
/* Clear pixel buffer */
memset(g_ws2812b_pixels, 0, sizeof(g_ws2812b_pixels));
/* Clear SPI buffer */
memset(g_ws2812b_spi_buffer, 0, sizeof(g_ws2812b_spi_buffer));
/* Initialize SPI */
WS2812B_SPI_Init();
}

设计要点

  • 双缓冲区清零,确保系统启动状态确定
  • 模块化初始化,便于扩展其他外设
  • 错误安全:先准备缓冲区再初始化硬件


WS2812B_Update()函数

void WS2812B_Update(void)
{
uint32_t totalBytes = WS2812B_BUFFER_SIZE + WS2812B_RESET_BYTES;
uint32_t i;
uint32_t data32;

/* 1. 颜色数据编码 */
WS2812B_PrepareBuffer();

/* 2. SPI数据传输 */
for (i = 0; i < totalBytes; i += 4)
{
/* FIFO状态检查 */
while (SPI_getTxFifoEmptyUnitStatus(WS2812B_SPI) == 0UL);

/* 32位数据组装(大端序) */
data32 = ((uint32_t)g_ws2812b_spi_buffer[i] << 24) |
((uint32_t)g_ws2812b_spi_buffer[i + 1] << 16) |
((uint32_t)g_ws2812b_spi_buffer[i + 2] << 8) |
(uint32_t)g_ws2812b_spi_buffer[i + 3];

/* 非阻塞发送 */
SPI_writeDataNonBlocking(WS2812B_SPI, data32);
}

/* 3. 传输完成等待 */
while (SPI_isBusy(WS2812B_SPI));
}

设计要点

  • 三阶段处理:编码→传输→同步
  • 32位优化:利用NS800RT5xxx的32位SPI接口提高效率
  • 非阻塞发送:提高CPU利用率
  • 传输完整性:确保所有数据发送完成


5.3.2 像素级控制API

WS2812B_SetPixel()函数

void WS2812B_SetPixel(uint16_t index, WS2812B_Color color)
{
if (index < WS2812B_LED_COUNT)
{
g_ws2812b_pixels[index] = color;
}
}

WS2812B_SetPixelXY()函数

void WS2812B_SetPixelXY(uint8_t col, uint8_t row, WS2812B_Color color)
{
if (col < WS2812B_PHYSICAL_COLUMNS && row < WS2812B_ROWS)
{
/* 物理坐标到内部坐标的双重映射 */
uint16_t index1 = (col * 2) * WS2812B_ROWS + row;
uint16_t index2 = (col * 2 + 1) * WS2812B_ROWS + row;
g_ws2812b_pixels[index1] = color;
g_ws2812b_pixels[index2] = color;
}
}

设计要点

  • 透明补偿:用户使用物理坐标(0-41),内部自动映射到(0-83, 1-84)
  • 边界检查:防止数组越界
  • 双重写入:解决SPI硬件数据减半问题


坐标映射原理

物理坐标系 (用户视角)      内部坐标系 (驱动视角)
0列,第0行 → 第0列第0+1列第0
0列,第1行 → 第0列第1+1列第1
...
41列,第4行 → 第82列第4+83列第4


5.3.3 区域控制API

WS2812B_SetColumn()函数

void WS2812B_SetColumn(uint8_t col, WS2812B_Color color)
{
if (col < WS2812B_PHYSICAL_COLUMNS)
{
/* 同时设置两个内部列 */
uint16_t startIndex1 = (col * 2) * WS2812B_ROWS;
uint16_t startIndex2 = (col * 2 + 1) * WS2812B_ROWS;
for (uint8_t row = 0; row < WS2812B_ROWS; row++)
{
g_ws2812b_pixels[startIndex1 + row] = color;
g_ws2812b_pixels[startIndex2 + row] = color;
}
}
}

优化策略

  • 循环展开:小循环(5次)无需展开优化
  • 局部变量:使用局部变量减少计算
  • 提前退出:边界检查失败立即返回


WS2812B_SetRow()函数

void WS2812B_SetRow(uint8_t row, WS2812B_Color color)
{
if (row < WS2812B_ROWS)
{
/* 遍历所有内部列 */
for (uint8_t col = 0; col < WS2812B_COLUMNS; col++)
{
uint16_t index = col * WS2812B_ROWS + row;
g_ws2812b_pixels[index] = color;
}
}
}

设计特点

  • 行操作不涉及坐标映射,直接遍历所有内部列
  • 保持API一致性,所有函数都有边界检查


5.3.4 颜色管理API

WS2812B_RGB()函数

WS2812B_Color WS2812B_RGB(uint8_t r, uint8_t g, uint8_t b)
{
WS2812B_Color color;
color.r = r;
color.g = g;
color.b = b;
return color;
}


WS2812B_HSV()函数

WS2812B_Color WS2812B_HSV(uint16_t h, uint8_t s, uint8_t v)
{
/* HSV到RGB的快速转换算法 */
if (s == 0) return WS2812B_RGB(v, v, v);

h = h % 360;
uint8_t region = h / 60;
uint8_t remainder = (h - (region * 60)) * 255 / 60;

uint8_t p = (v * (255 - s)) >> 8;
uint8_t q = (v * (255 - ((s * remainder) >> 8))) >> 8;
uint8_t t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;

switch (region) {
case 0: return WS2812B_RGB(v, t, p);
case 1: return WS2812B_RGB(q, v, p);
case 2: return WS2812B_RGB(p, v, t);
case 3: return WS2812B_RGB(p, q, v);
case 4: return WS2812B_RGB(t, p, v);
default: return WS2812B_RGB(v, p, q);
}
}

算法优势

  • 整数运算:避免浮点运算,提高性能
  • 快速转换:使用移位代替除法
  • 色域完整:支持完整的HSV色彩空间


WS2812B_Wheel()函数

WS2812B_Color WS2812B_Wheel(uint8_t position)
{
WS2812B_Color color;

if (position < 85) {
color.r = position * 3;
color.g = 255 - position * 3;
color.b = 0;
} else if (position < 170) {
position -= 85;
color.r = 255 - position * 3;
color.g = 0;
color.b = position * 3;
} else {
position -= 170;
color.r = 0;
color.g = position * 3;
color.b = 255 - position * 3;
}

return color;
}


WS2812B_ScaleBrightness()函数

WS2812B_Color WS2812B_ScaleBrightness(WS2812B_Color color, uint8_t brightness)
{
WS2812B_Color result;
result.r = (color.r * brightness) >> 8; // 快速除法:/256
result.g = (color.g * brightness) >> 8;
result.b = (color.b * brightness) >> 8;
return result;
}

性能优化

  • 移位运算:用>>8代替/256,提高速度
  • 饱和处理:乘法结果可能超过255,但移位后自动截断
  • 内存局部性:局部变量result优化寄存器使用


5.3.5 预定义颜色常量

#define WS2812B_COLOR_RED       ((WS2812B_Color){255, 0, 0})
#define WS2812B_COLOR_GREEN ((WS2812B_Color){0, 255, 0})
#define WS2812B_COLOR_BLUE ((WS2812B_Color){0, 0, 255})
#define WS2812B_COLOR_WHITE ((WS2812B_Color){255, 255, 255})
#define WS2812B_COLOR_BLACK ((WS2812B_Color){0, 0, 0})
#define WS2812B_COLOR_YELLOW ((WS2812B_Color){255, 255, 0})
#define WS2812B_COLOR_CYAN ((WS2812B_Color){0, 255, 255})
#define WS2812B_COLOR_MAGENTA ((WS2812B_Color){255, 0, 255})
#define WS2812B_COLOR_ORANGE ((WS2812B_Color){255, 128, 0})
#define WS2812B_COLOR_PURPLE ((WS2812B_Color){128, 0, 255})

设计考虑

  • 编译时常量:使用宏定义,零运行时开销
  • 类型安全:明确的WS2812B_Color类型
  • 易用性:直观的颜色名称


5.4 数据编码与SPI时序

5.4.1 编码算法

核心编码函数

static void WS2812B_EncodeByte(uint8_t byte, uint8_t *output)
{
/* 每个输入位扩展为4个SPI输出位 */
output[0] = ((byte & 0x80) ? (WS2812B_SPI_BIT_1 << 4) : (WS2812B_SPI_BIT_0 << 4)) |
((byte & 0x40) ? WS2812B_SPI_BIT_1 : WS2812B_SPI_BIT_0);
output[1] = ((byte & 0x20) ? (WS2812B_SPI_BIT_1 << 4) : (WS2812B_SPI_BIT_0 << 4)) |
((byte & 0x10) ? WS2812B_SPI_BIT_1 : WS2812B_SPI_BIT_0);
output[2] = ((byte & 0x08) ? (WS2812B_SPI_BIT_1 << 4) : (WS2812B_SPI_BIT_0 << 4)) |
((byte & 0x04) ? WS2812B_SPI_BIT_1 : WS2812B_SPI_BIT_0);
output[3] = ((byte & 0x02) ? (WS2812B_SPI_BIT_1 << 4) : (WS2812B_SPI_BIT_0 << 4)) |
((byte & 0x01) ? WS2812B_SPI_BIT_1 : WS2812B_SPI_BIT_0);
}

编码逻辑

输入字节:   b7 b6 b5 b4 b3 b2 b1 b0
输出字节0: [b7编码高4] [b6编码低4]
输出字节1: [b5编码高4] [b4编码低4]
输出字节2: [b3编码高4] [b2编码低4]
输出字节3: [b1编码高4] [b0编码低4]

编码映射表

WS2812B "0"SPI 位模式: 1 0 0 0 (0x8)
WS2812B "1"SPI 位模式: 1 1 1 0 (0xE)


5.4.2 时序参数计算

理论计算

SPI时钟频率: 6.4MHz
SPI位周期: 1/6.4MHz ≈ 156ns

WS2812B "0"码要求:
高电平: 0.4μs (400ns)400/1562.56
低电平: 0.85μs (850ns)850/1565.45
实际编码:1+3= 1:3比例

WS2812B "1"码要求:
高电平: 0.8μs (800ns)800/1565.13
低电平: 0.45μs (450ns)450/1562.88
实际编码:3+1= 3:1比例

实际验证

  • 使用逻辑分析仪测量实际波形
  • 验证时序符合WS2812B规格
  • 调整SPI频率微调时序


5.5 性能优化策略

5.5.1 内存优化

双缓冲策略

颜色缓冲区 (420LED) → 编码转换 → SPI缓冲区 (2580字节)

优化效果

  • 零动态分配:全部静态数组,无堆碎片
  • 连续内存:数组连续存储,缓存友好
  • 大小固定:编译时确定,无运行时开销


5.5.2 计算优化

查表法替代实时计算

// 可选的查表优化(当前使用计算)
static const uint8_t ws2812b_encoding_table[2][4] = {
{0x8, 0x8, 0x8, 0x8}, // WS2812B "0"
{0xE, 0xE, 0xE, 0xE} // WS2812B "1"
};


循环展开优化

// 手动展开循环(当前代码已优化)
for (i = 0; i < count; i++) {
// 处理4位一组
}


5.5.3 通信优化

SPI传输优化

  1. 32位传输:利用硬件特性,每次发送4字节
  2. FIFO缓冲:减少CPU等待时间
  3. DMA预备:预留DMA接口,支持未来扩展


5.4 API使用示例

5.4.1 基础使用

// 初始化
WS2812B_Init();

// 设置单个LED
WS2812B_SetPixelXY(0, 0, WS2812B_COLOR_RED);

// 设置整列
WS2812B_SetColumn(10, WS2812B_COLOR_GREEN);

// 更新显示
WS2812B_Update();

5.5.2 高级效果

// 创建渐变色
WS2812B_Color gradient = WS2812B_HSV(hue, 255, 255);
gradient = WS2812B_ScaleBrightness(gradient, brightness);

// 动画循环
for (int i = 0; i < WS2812B_PHYSICAL_COLUMNS; i++) {
WS2812B_SetColumn(i, WS2812B_Wheel(i * 6));
}
WS2812B_Update();

5.6 实际效果展示

最终,具体的呈现效果如下:


六、调试与验证

6.1 调试工具与方法

  1. 逻辑分析仪:验证SPI时序和PWM波形
  2. 串口调试:输出系统状态和调试信息
  3. 分段测试:逐步验证各功能模块
  4. 边界测试:测试极限条件下的稳定性

6.2 关键测试结果

SPI时序验证

使用逻辑分析仪捕获SPI输出,确认:

  • SPI频率稳定在6.4MHz
  • 编码正确:0x8对应WS2812B"0",0xE对应"1"
  • 复位时间>50μs,符合要求

WS2812B信号分析,使用了ADALM2000(M2K),能够获得更好的分析结果。

放大后,能够看到具体的数据解析:

image.png

截取10个时钟周期的信号:

从上图可以看到,输出的CLK,为6.47MHz。因为WS2812B对信号的时序有一定的容错能力,所以这个时钟频率,是可以满足要求的。


数据补偿验证

通过以下测试确认解决方案有效:

  1. 设置第0列红色 → 第0列正确显示红色
  2. 设置第41列蓝色 → 第41列正确显示蓝色
  3. 全屏白色测试 → 210颗LED全部点亮
  4. 快速颜色切换测试 → 无残影、无错位


6.3 稳定性测试

  • 连续运行测试:2小时不间断运行,无异常
  • 温度测试:芯片温度稳定在45°C以下
  • 电压波动测试:5.01V-5.9V范围内工作正常


七、创新点与技术特色

7.1 硬件特性自适应方案

针对NS800RT5xxx SPI硬件特性,使用SPI来驱动WS2812B灯板。

该方案具有以下优点:

  • 透明性:用户API保持原有设计
  • 通用性:适用于任何需要驱动WS2812B的场景
  • 高效性:额外开销极小,仅增加少量内存

7.2 高性能动画引擎

  1. HSV色彩支持:提供更直观的颜色控制
  2. 非阻塞更新:动画渲染与SPI传输分离
  3. 可扩展架构:轻松添加新动画效果

7.3 完整的开发工具链

  • 基于Keil MDK的完整工程
  • 详细的API文档
  • 多种演示示例
  • 配置参数灵活可调


八、项目总结与展望

8.1 项目成果

  1. 基础任务完成:UART、ePWM功能验证通过
  2. 扩展任务实现:成功驱动210颗WS2812B LED
  3. 完整开发资源:提供可直接使用的代码和文档

8.2 技术收获

  1. 深入理解硬件特性:掌握了NS800RT5xxx SPI控制器的工作机制
  2. 实际问题解决能力:从问题定位到方案设计的完整过程
  3. 系统集成经验:硬件、驱动、应用层的协同设计
  4. 性能优化技巧:时序优化、内存管理、实时性保障


九、心得体会

通过本次WeDesign7项目,我深刻体会到:

  1. 硬件理解的重要性:嵌入式开发不仅要懂软件,更要深入理解硬件特性
  2. 问题解决的方法论:从现象观察、原因分析到方案验证的系统性方法
  3. 创新思维的价值:在约束条件下创造性地解决问题
  4. 工程实践的严谨性:每个细节都可能影响系统稳定性

纳芯微NS800RT5xxx系列芯片展现出了优秀的性能和可靠性,其完善的SDK和文档体系大大降低了开发难度。

本次活动不仅提供了实践平台,更促进了技术交流和创新思考。


附件下载
spi_ws2812b_test.zip
团队介绍
一个狂热的开源爱好者和传播者,同时也是一名极客爱好者,长期关注嵌入式发展和少儿创客教育,既擅长互联网系统架构设计与研发,又拥有丰富的嵌入式研发经验。为人精力充沛,古道热肠,圈内人称乔大妈、乔帮主。
团队成员
HonestQiao
HonestQiao
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号