尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

STC89C52单片机驱动DS18B20温度传感器:单总线通信协议详解与实战

STC89C52单片机驱动DS18B20温度传感器:单总线通信协议详解与实战
📅 发布时间:2026/7/31 6:42:56

1. 项目概述:从“点灯”到“测温”的进阶

玩过51单片机的朋友,大多都是从点亮一个LED灯开始的。当流水灯、数码管、按键这些基础外设都玩转之后,下一个让你既兴奋又有点头疼的挑战,往往就是与各种传感器打交道。而DS18B20这款数字温度传感器,绝对是这个阶段绕不开的“经典科目”。它以其独特的“单线通信”协议,成为了无数单片机初学者从“控制”走向“感知”世界的第一道坎。今天,我们就来彻底拆解这个项目:如何用经典的STC89C52单片机,通过一根线,稳定、准确地读取DS18B20的温度数据。

这个项目的核心价值在于,它不仅仅是一个温度读取功能。它是一次对单片机底层时序操作的深度训练,是对“单总线”这种特殊通信协议的完整实践。理解了它,你就能触类旁通,为后续学习更复杂的I2C、SPI等通信协议打下坚实的基础。无论是想做一个简单的室内温度计,还是为更复杂的智能家居、环境监控系统做技术储备,这个项目都是绝佳的练手素材。接下来,我将以一个过来人的身份,带你从原理到代码,从接线到调试,完整走一遍这个流程,并分享那些在官方数据手册里不会写的“踩坑”经验。

2. 核心器件与通信协议深度解析

2.1 主角登场:STC89C52与DS18B20

首先,我们得认识一下两位“主角”。

STC89C52,可以说是国内单片机教育的“国民芯片”。它是8051内核的增强型,拥有8K字节的Flash程序存储器,512字节的RAM,以及32个通用I/O口。对于本项目而言,它的优势在于资源完全够用,开发环境(如Keil)成熟,资料极其丰富。我们只需要其中一个普通的I/O口(例如P3.7)就能完成与DS18B20的通信。

DS18B20,则是Dallas(现Maxim Integrated)公司出品的单总线数字温度传感器。它的“神奇”之处在于:

  • 单线接口:仅需一根数据线(DQ)即可实现单片机与传感器之间的双向通信,同时这根线还能通过“寄生电源”方式为传感器供电,真正做到最少连线。
  • 数字输出:直接将温度值转换为9~12位的数字量,通过单总线串行传送,抗干扰能力强,无需额外的A/D转换器。
  • 精度可选:测温范围-55°C到+125°C,在-10°C到+85°C范围内精度为±0.5°C。用户可编程设定9~12位的分辨率,分辨率越高,温度转换所需时间越长。
  • 唯一64位光刻ROM序列号:每个DS18B20有唯一的ID,这使得一根总线上可以挂载多个传感器,通过寻址来区分。

2.2 单总线协议:一根线上的“精密舞蹈”

单总线协议是DS18B20工作的核心,它规定了严格的时序。你可以把它想象成两个人用一盏灯在黑暗里发莫尔斯电码,必须严格遵守“亮多久代表开始,灭多久代表等待,闪烁一下代表‘0’,闪烁长一下代表‘1’”的规则。任何一方节奏错了,通信就会失败。

协议流程主要分为几个阶段:初始化(复位脉冲+存在脉冲)、ROM命令、功能命令、数据读写。其中,最基础、最关键的是复位脉冲、存在脉冲以及读写时序。

初始化过程(复位与检测):

  1. 主机拉低总线:单片机将DQ线拉低至少480µs,这个“长低电平”就是一个复位脉冲,相当于对所有挂在总线上的DS18B20喊:“注意!我要开始通信了!”
  2. 主机释放总线:单片机将DQ引脚设置为高电平(或输入模式,靠上拉电阻拉高),等待15-60µs。
  3. 从机回应:DS18B20检测到复位脉冲结束(上升沿)后,会等待约15-60µs,然后主动将总线拉低60-240µs,发出一个“存在脉冲”,意思是:“我在呢,准备好了!”
  4. 主机检测:单片机在这段时间内检测DQ线,如果检测到一个低电平脉冲,说明总线上有DS18B20设备,初始化成功。

注意:这个等待和检测的时机非常关键。如果主机释放总线后等待时间太短就去检测,可能抓不到从机的回应;如果等待时间太长,从机的回应脉冲已经结束,也会检测失败。通常采用延时60µs后检测的方式比较稳妥。

写时序(主机发送‘0’或‘1’):

  • 写‘0’时序:主机拉低总线,并持续保持低电平至少60µs(一般保持到整个写时隙结束,约60-120µs),然后在两个写时隙之间至少提供1µs的恢复时间。
  • 写‘1’时序:主机拉低总线,但必须在15µs内释放总线(拉高),然后依靠上拉电阻将总线保持在高电平,直到写时隙结束。

读时序(主机读取数据):

  1. 主机拉低总线至少1µs,然后释放。
  2. 主机释放后,必须尽快(在15µs内)读取总线电平。因为DS18B20会在主机发起读时隙后,在15µs内将有效数据送到总线上。
  3. 读取的电平如果为低,代表数据‘0’;为高,代表数据‘1’。
  4. 整个读时隙从开始到结束,应持续至少60µs,之后需要至少1µs的恢复时间才能进行下一次操作。

实操心得:很多初学者代码调不通,90%的问题出在时序上。STC89C52在12MHz晶振下,一个_nop_()空操作指令的延时大约是1µs。但编译器优化、函数调用开销都会影响延时精度。最可靠的方法是使用示波器或逻辑分析仪抓取DQ线上的波形,与数据手册的时序图逐个对比。这是排查单总线问题最直接有效的手段。

3. 硬件电路设计与关键细节

一个稳定可靠的硬件电路是软件正确运行的前提。DS18B20的接线有标准电源模式和寄生电源模式两种,我强烈建议初学者使用标准电源模式。

3.1 推荐电路:标准电源模式

VCC (5V) | | +++ | | 4.7KΩ 上拉电阻 (R1) | | +++ | +-------------------> 到单片机I/O口 (如 P3.7) | === GND | DS18B20 +-----+ | VDD|----> 接 VCC (5V) | DQ |----> 接上拉电阻节点 | GND |----> 接 GND +-----+

为什么推荐标准电源模式?在寄生电源模式下,DS18B20在执行温度转换或拷贝数据到EEPROM等大电流操作时,会通过DQ线“偷电”。这要求总线在特定时刻必须提供足够的强上拉(例如用MOS管将总线直接拉到VCC),否则可能导致电源电压不足,芯片工作异常甚至复位,导致读取失败或一直返回85°C(上电默认值)。标准电源模式单独供电,彻底避免了电源问题,让调试集中在通信时序上,大大降低了入门难度。

关键元件选择:

  • 上拉电阻R1:典型值为4.7KΩ,范围在2KΩ~5.1KΩ之间。它的作用是在主机释放总线(设置为高电平或输入)时,将总线电平稳定地拉到高电平,为数据传输提供确定的电平状态。阻值太小会增大功耗,阻值太大会导致上升沿过慢,在长导线时可能影响通信。

3.2 布线注意事项

  1. 电源去耦:在DS18B20的VCC和GND引脚之间,尽量靠近芯片放置一个0.1µF的瓷片电容,用于滤除电源噪声。
  2. 总线长度:单总线对分布电容敏感。如果通信线超过1米,或者环境干扰较大,可以考虑降低上拉电阻阻值(如2.2KΩ),或者使用屏蔽线。
  3. 多点挂载:如果总线上有多个DS18B20,每个传感器的VDD和GND都必须连接好。总线(DQ)是并联的。此时,搜索ROM、匹配ROM等命令就变得至关重要。

4. 软件驱动编写与代码逐行解析

理解了协议和硬件,我们就可以动手写代码了。下面我将用一个经过实际项目验证的驱动代码为例,逐函数解析其实现要点。

4.1 基础宏定义与延时函数

#include <REG52.H> #include <INTRINS.H> // 用于_nop_()函数 // 定义DS18B20数据线连接的单片机引脚 sbit DQ = P3^7; // 根据你的实际接线修改 // 微秒级延时函数(基于12MHz晶振粗略调整) void Delay_us(unsigned int t) { while(t--); }

注意:Delay_us是一个非常不精确的延时函数,它受编译器优化等级影响很大。这里仅用于示意。在实际项目中,为了获得更精确的时序,通常会使用定时器中断来产生基准延时,或者针对特定编译器(如Keil)和优化等级,通过实验(结合示波器)校准出一个相对准确的延时函数。例如,对于STC89C52@12MHz,一个while(i--);循环,i与微秒的对应关系需要实测。

4.2 核心时序函数实现

4.2.1 初始化函数(复位与检测)

bit DS18B20_Init(void) { bit ack = 0; DQ = 1; // 先拉高 Delay_us(8); DQ = 0; // 主机拉低,发起复位脉冲 Delay_us(480); // 保持低电平480us以上(推荐480-960us) DQ = 1; // 主机释放总线 Delay_us(60); // 等待15-60us后检测 ack = DQ; // 读取存在脉冲,低电平有效 Delay_us(420); // 等待存在脉冲结束(总共延时约480us) return ~ack; // 如果ack为0(检测到低电平),则返回1(初始化成功) }

解析:这个函数严格遵循了初始化时序。Delay_us(60)后检测,正好落在DS18B20拉低总线(存在脉冲)的时间窗口内。最后Delay_us(420)是为了补足从开始拉低到结束的总时间,确保时序完整。返回值用~ack,这样当检测到存在脉冲(ack=0)时,函数返回1(真),更符合逻辑习惯。

4.2.2 写一个字节函数

void DS18B20_WriteByte(unsigned char dat) { unsigned char i; for(i=0; i<8; i++) { DQ = 0; // 拉低开始写时隙 _nop_(); _nop_(); // 极短延时,约2us,保证拉低被识别 DQ = dat & 0x01; // 送出数据位的最低位 Delay_us(60); // 保持60-120us DQ = 1; // 释放总线 dat >>= 1; // 准备下一个数据位 // 这里可以加一个很短的延时(如几微秒)作为恢复时间 } }

解析:写‘0’和写‘1’的差异在于,主机拉低后,是持续拉低(写0)还是很快释放(写1)。这里采用了一种简化的写法:无论写0写1,都拉低总线并保持60us,区别在于拉低后立即将总线电平设置为要写的值。对于写‘1’,DQ = dat & 0x01这一句在拉低后很快(几个指令周期内)又将总线置高,模拟了“快速释放”的效果。这种方法代码简洁,在12MHz下通常能工作。

4.2.3 读一个字节函数

unsigned char DS18B20_ReadByte(void) { unsigned char i, dat = 0; for(i=0; i<8; i++) { dat >>= 1; // 先右移,低位在先 DQ = 0; // 主机拉低,启动读时隙 _nop_(); _nop_(); // 短暂保持,大于1us即可 DQ = 1; // 主机释放总线 _nop_(); _nop_(); // 等待约5-10us,让DS18B20输出稳定 if(DQ) { // 在15us内读取总线电平 dat |= 0x80; // 如果为高,则该位为1 } Delay_us(50); // 等待读时隙结束(总时长约60us) } return dat; }

解析:读时序的关键在于“主机拉低后迅速释放并立即采样”。_nop_(); _nop_();用于产生一个极短的延时,确保拉低动作被识别,然后立即释放。释放后再等待几个_nop_(),这是为了避开总线从低到高的上升沿,并留出时间让DS18B20驱动总线电平稳定。随后读取DQ的值。dat的组装采用“先右移后或”的方式,因为数据是从低位开始传送的。

4.3 温度读取流程函数

有了底层的读写函数,我们就可以按照DS18B20的命令序列来读取温度了。

float DS18B20_ReadTemp(void) { unsigned char LSB, MSB; int temp_raw; float temperature; if(!DS18B20_Init()) // 1. 初始化 return 999.9; // 初始化失败,返回一个错误值(如999.9) DS18B20_WriteByte(0xCC); // 2. 跳过ROM命令(总线上只有一个传感器时) DS18B20_WriteByte(0x44); // 3. 启动温度转换命令 // 等待转换完成。对于12位分辨率,最大转换时间为750ms。 // 这里可以用查询DS18B20忙状态的方式,更高效。简单起见,我们延时等待。 Delay_us(100000); // 延时约100ms,假设分辨率不是最高,实际项目需根据分辨率调整或查询 if(!DS18B20_Init()) // 4. 再次初始化,准备读数据 return 999.9; DS18B20_WriteByte(0xCC); // 5. 跳过ROM命令 DS18B20_WriteByte(0xBE); // 6. 读暂存器命令 // 7. 读取温度数据(前两个字节) LSB = DS18B20_ReadByte(); MSB = DS18B20_ReadByte(); // 8. 数据转换 temp_raw = (MSB << 8) | LSB; // 合成16位有符号整数 // 判断正负温度 if(temp_raw & 0x8000) { // 温度为负 temp_raw = ~temp_raw + 1; // 取反加1,得到原码的绝对值(补码转原码) temperature = - (temp_raw * 0.0625); // 12位分辨率时,LSB为0.0625°C } else { // 温度为正 temperature = temp_raw * 0.0625; } return temperature; }

解析:

  1. 跳过ROM (0xCC):当总线上只有一个DS18B20时,可以用此命令跳过地址匹配,直接操作设备,简化流程。
  2. 启动转换 (0x44):发送此命令后,DS18B20开始进行温度A/D转换。这里是一个常见的坑点:转换需要时间(分辨率越高,时间越长,12位时最长750ms)。代码中用了简单的延时,在实际产品中,这会阻塞CPU。更好的做法是:启动转换后,单片机可以去执行其他任务,然后通过定时器或者查询DQ线(发送“读电源模式”命令后读位)的方式来判断转换是否完成。
  3. 读暂存器 (0xBE):此命令用于读取DS18B20内部暂存器的内容,共9个字节。我们只关心前两个字节(温度值)。
  4. 数据解析:读到的16位数据中,高5位(bit15-bit11)是符号位。如果温度是负值,这5位全为1。数据以补码形式存放。计算时,先将其视为16位有符号整数,然后乘以分辨率(默认12位时为0.0625)即可得到实际温度值。上面的代码展示了补码转原码再计算的过程。更简洁的方法是:temperature = (float)((short)temp_raw) * 0.0625;利用C语言的有符号短整型转换直接得到带符号的十进制值。

5. 系统集成与主程序框架

将驱动函数集成到一个完整的系统中,例如一个每2秒刷新一次温度的简易温度计。

#include <REG52.H> #include <stdio.h> // 用于sprintf // 假设数码管显示函数已存在 extern void DisplayString(char *str); void main() { float temp; char disp_buf[10]; while(1) { temp = DS18B20_ReadTemp(); if(temp > 150.0) { // 简单的错误判断,999.9是错误值 sprintf(disp_buf, "Err"); } else { sprintf(disp_buf, "%4.1fC", temp); // 格式化为"XX.XC" } DisplayString(disp_buf); // 在数码管或LCD上显示 Delay_ms(2000); // 延时2秒再读 } }

6. 调试技巧与常见问题排查实录

即使代码看起来正确,第一次成功读取温度也常常需要一番周折。下面是我总结的“踩坑”记录和排查指南。

6.1 问题一:永远返回85.0°C或0.0°C

这是最常见的问题。

  • 返回85.0°C:这是DS18B20的上电默认温度值。出现此问题,几乎可以断定单片机根本没有成功启动DS18B20进行温度转换,或者读取的是默认值。请按以下步骤检查:

    1. 检查初始化(复位/存在脉冲):用示波器看DQ线。主机拉低480us后释放,是否能看到一个60-240us的低电平脉冲(存在脉冲)?如果没有,说明硬件连接或电源有问题,DS18B20没有响应。重点检查VCC和GND是否接反、虚焊,上拉电阻是否接好,电源电压是否足够(4.5V-5.5V)。
    2. 检查启动转换命令:确认0x44命令是否成功发送。发送完这个命令后,必须等待足够长的转换时间。如果你延时太短(比如只延时了1ms),然后立刻去读,读到的就是未完成转换的旧数据(很可能是85)。尝试将等待转换的延时增加到800ms以上。
    3. 寄生电源模式问题:如果你使用的是寄生电源模式,在温度转换期间,电流需求增大,如果总线无法提供足够电流,芯片可能复位。强烈建议切换到标准电源模式调试。
  • 返回0.0°C:可能的原因有:

    1. 读到的数据全为0:检查读时序,特别是采样点是否在DS18B20驱动有效的时间内(主机拉低释放后的15us内)。采样过早或过晚都可能读到总线空闲状态(高电平,被上拉电阻拉高)或不确定状态。
    2. 数据拼接错误:确认读取的两个字节LSB和MSB的顺序是否正确。DS18B20是低位先送。LSB = ReadByte(); MSB = ReadByte();这个顺序是对的。
    3. 计算错误:检查温度计算公式。temp_raw是16位有符号数,直接乘以0.0625。可以用一个已知值测试,比如读取到的十六进制是0x0191(十进制401),那么温度就是401*0.0625=25.0625°C。

6.2 问题二:温度值跳动大,不稳定

  • 电源噪声:确保电源稳定,在DS18B20的VCC和GND引脚就近并联一个0.1µF的瓷片电容。
  • 总线干扰:通信线过长或靠近干扰源。尽量缩短连线,使用双绞线或屏蔽线。可以适当减小上拉电阻(如从4.7KΩ改为2.2KΩ),增强驱动能力。
  • 软件滤波:这是最常用的方法。连续读取N次(如10次),然后排序,去掉最大最小值,再取平均。或者采用一阶滞后滤波(本次温度 = 上次温度 * 0.9 + 本次读数 * 0.1)。
    #define FILTER_NUM 10 float TempFilter(void) { float temp_arr[FILTER_NUM], sum=0, temp; int i,j; float min, max; // 采集 for(i=0; i<FILTER_NUM; i++) { temp_arr[i] = DS18B20_ReadTemp(); Delay_ms(10); } // 冒泡排序找最大最小(简单示例) // ... 排序代码 ... // 去掉头尾各一个,求平均 for(i=1; i<FILTER_NUM-1; i++) { sum += temp_arr[i]; } return sum/(FILTER_NUM-2); }

6.3 问题三:通信时好时坏,偶尔失败

  • 时序临界:你的延时函数可能处于临界状态。稍微的环境变化(温度、电压)或编译器优化等级改变,就可能导致时序不满足。务必用示波器校准关键延时,特别是初始化等待时间和读/写时隙的保持时间。确保所有时间参数都在数据手册规定的最小值和最大值之间,并留有一定余量。
  • 中断干扰:如果单片机在操作单总线期间被高优先级中断打断,可能导致时序拉长,通信失败。在DS18B20_Init、DS18B20_WriteByte、DS18B20_ReadByte等关键函数中,可以临时关闭全局中断,操作完成后再打开。
    void DS18B20_WriteByte(unsigned char dat) { EA = 0; // 关闭总中断 // ... 原有的写字节代码 ... EA = 1; // 打开总中断 }

6.4 高级调试工具:逻辑分析仪

如果你有逻辑分析仪(即使是几十元的简易款),调试单总线协议会变得无比轻松。将探头连接到DQ线,设置合适的采样率(如4MHz),触发条件设为下降沿。然后运行你的程序,你就能清晰地看到:

  • 复位脉冲的宽度是否够480us。
  • 是否存在一个明显的存在脉冲低电平。
  • 每一个读/写时隙的波形是否符合规范:写1是否快速释放?读采样点是否在正确位置? 通过对比抓取的波形和数据手册的时序图,可以精准定位是哪个环节的时序出现了偏差。

7. 项目优化与扩展思路

当基础功能稳定后,可以考虑以下优化和扩展,这会让你的项目更接近实际产品。

7.1 优化一:非阻塞式温度读取

如前所述,等待温度转换的几百毫秒是巨大的CPU资源浪费。我们可以实现一个状态机来管理温度读取流程。

enum TempState {TEMP_IDLE, TEMP_START_CONV, TEMP_WAITING, TEMP_READ_DATA}; enum TempState temp_state = TEMP_IDLE; unsigned long conv_start_time; float current_temp; void TempTask(void) { switch(temp_state) { case TEMP_IDLE: if(DS18B20_Init()) { DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0x44); // 启动转换 conv_start_time = GetSystemTick(); // 获取当前系统滴答计数 temp_state = TEMP_WAITING; } break; case TEMP_WAITING: // 假设12位分辨率,需要750ms if(GetSystemTick() - conv_start_time > 750) { temp_state = TEMP_READ_DATA; } break; case TEMP_READ_DATA: if(DS18B20_Init()) { DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0xBE); // ... 读取并计算温度,存入current_temp ... temp_state = TEMP_IDLE; // 可以设置一个标志,通知主程序温度已更新 temp_updated = 1; } else { // 初始化失败,可能重试或回到IDLE temp_state = TEMP_IDLE; } break; } } // 在主循环中,定期调用TempTask,而不需要阻塞延时 void main() { while(1) { TempTask(); // 这里可以处理显示、按键等其他任务 if(temp_updated) { DisplayTemp(current_temp); temp_updated = 0; } // ... 其他代码 ... } }

7.2 扩展一:连接多个DS18B20

单总线的优势在于可以挂载多个设备。每个DS18B20有唯一的64位ROM ID。流程变为:

  1. 搜索ROM:使用“搜索ROM”算法(一种二叉树搜索),列出总线上所有设备的ROM ID。
  2. 匹配ROM:发送“匹配ROM”命令(0x55),后跟指定的64位ROM ID,之后的操作就只针对这个设备。
  3. 轮流读取:依次匹配每个传感器,启动转换、读取温度。注意,温度转换命令可以同时发给所有设备(使用“跳过ROM”命令),然后等待足够时间后,再轮流匹配并读取每个传感器的结果,这样效率最高。

7.3 扩展二:设置报警阈值与分辨率

DS18B20的暂存器中有高温(TH)和低温(TL)报警阈值寄存器,以及配置寄存器(用于设置分辨率)。你可以通过写暂存器命令(0x4E)来配置它们。例如,设置12位分辨率:向配置寄存器写入0x7F(二进制01111111,高5位保留,低2位为11代表12位分辨率)。这些配置掉电后丢失,如果想保存,需要执行“拷贝暂存器到EEPROM”命令(0x48)。

通过这个完整的项目实践,你收获的不仅仅是一个温度读数。你深入理解了严格的硬件时序在嵌入式通信中的重要性,掌握了用软件模拟复杂协议的方法,积累了宝贵的调试和排查硬件问题的经验。这些能力,在你未来面对SPI Flash、OLED屏幕、无线模块等更复杂的器件时,都将成为你快速上手的底气。

相关新闻

  • STM32H747上CNN模型部署实战:从LeNet-5到实时图像识别
  • Unity集成DeepSeek API:Newtonsoft.Json配置避坑指南
  • Lightning转USB-A/C转换器核心原理与实现方案深度解析

最新新闻

  • C#与.NET框架核心架构解析:从CLR到现代语言特性
  • Mermaid Live Editor终极指南:5分钟学会免费在线图表编辑神器!
  • ncRNA酵母双杂交技术:优化RNA-蛋白质互作检测方案
  • 终极Windows和Office激活指南:3分钟告别烦人的激活弹窗
  • 打破行业供需壁垒!深圳全咨数字科技,赋能工程咨询行业数字化升级
  • α-β-γ滤波器:从原理到实践,理解卡尔曼滤波的直观内核

日新闻

  • 7步掌握KMS智能激活工具:Windows和Office永久激活完整方案
  • 如何在Windows上运行iOS应用:ipasim跨平台模拟器终极指南
  • 2026年重庆工伤赔偿律师口碑推荐:洪家木律师用专业赢得信赖 - 本地品牌推荐

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号