简介这份课程设计文档面向电子信息工程、自动化等专业修读单片机课程的学生用于完成数字温度计课程设计及报告撰写。内容以AT89C51为主控配合DS18B20单总线温度传感器、4位一体共阴LED数码管显示、上下限温度设置与蜂鸣器红灯报警电路覆盖设计目的、设计要求、系统框图、时钟与复位电路、传感器与显示电路、报警电路及完整C源程序可直接作为课程设计模板与调试参考。资源包共1个文件为doc格式文档压缩包约1.34MB含封面、任务书栏目与正文便于按章节直接改写。已有4053人学习下载说明该方案在课程设计场景中接受度较高。读者可据此掌握一线总线测温时序、数码管动态显示与报警阈值设定等关键环节并对照源程序理解按键调节上下限、温度闪烁提示等实现细节。1. 数字温度计这门课设51单片机加DS18B20到底能做出什么答辩前一晚数码管上的温度还卡在 85℃ 上不去下不来——做基于51单片机数字温度计的课程设计几乎人人都会撞上这一幕。这套方案的内核其实很朴素一颗 51 内核单片机当主控一根 IO 口挂 DS18B20 数字温度传感器配数码管或 LCD1602 显示再加蜂鸣器做上下限报警愿意的话还能把温度从串口发到上位机画曲线。它解决的是“把温度从模拟量变成一串能直接显示、能直接判断的数字”这件事量程 -55℃ 到 125℃12 位分辨率 0.0625℃0 到 85℃ 区间误差 ±0.5℃做室温监测、水温控制、孵化箱、机柜告警都够用。适合两类人正在交课程设计的同学以及手上有块旧开发板、想回头把单总线时序补一遍的工程师。原因也简单——单总线时序、定时器扫描、串口通信这些基本功全被压在一张原理图上绕不过去也偷不了懒。2. 选型先立住51DS18B20LCD1602 这条链路为什么值得照抄动手焊板子之前先把“为什么是这套组合”讲清楚。选型糊涂后面调试就会变成玄学读数不对时你分不清是传感器坏了、时序错了还是显示译码写反了。这一章把三件事定下来——传感器怎么选、最小系统要哪些外围、显示用哪种。2.1 三种测温方案摆一起比热敏电阻、DS18B20、I2C 数字温度芯片课程设计里最常见的三种测温和方案差别不在“能不能测”而在“标定工作量”和“占用资源”。方案接口典型精度外围器件软件工作量适用场景NTC 热敏电阻 分压模拟量需 ADC 或 RC 充放电±0.5℃ 起步不标定更差分压电阻、基准非线性查表 逐点标定成本极敏感、精度要求低DS18B20单总线1 根 IO±0.5℃0~85℃一只 4.7k 上拉电阻严格时序 补码换算课设、多点测温、长线I2C 数字温度芯片SCL/SDA 两线±0.5℃~±1℃两只上拉、地址引脚标准 I2C 读写板上已有 I2C 总线51 内核单片机内部没有 ADC少数增强型号才有走 NTC 路线要么外挂 ADC 芯片要么用 RC 充放电测时间常数——后者对电源电压和电容温漂极其敏感标定表得自己做答辩时被问一句“你这个表怎么来的”就很难接。I2C 方案精度不错但要占用两根 IO还要处理总线仲裁和应答。DS18B20 只吃一根 IO精度出厂已标定代价是把复杂度从硬件挪到了时序上。提示如果题目只要求“测量并显示温度”DS18B20 是性价比最高的选择如果题目明确要求“体现模拟电路设计能力”那才考虑 NTC 加 ADC 的路线。2.2 单总线省引脚代价全在时序上单总线1-Wire只有一根数据线靠“时隙”区分 0 和 1所有通信由主机发起。理解三个基本时隙后面写驱动就不会背代码复位时隙主机拉低总线至少 480μs然后释放从机若在线会在释放后 15~60μs 内主动拉低 60~240μs这叫存在脉冲。写 1 时隙主机拉低 1~15μs 后立刻释放整个时隙不短于 60μs从机在 15~60μs 窗口内采样到高电平即为 1。写 0 时隙主机拉低 60~120μs 再释放从机采样到低电平即为 0。读时隙主机先拉低至少 1μs 再释放从机在总线上输出数据位主机必须在拉低后的 15μs 内采样晚了从机就撤了。数据按低位先出一个字节 8 个时隙。这套机制的时间容差其实很宽——复位可以 480μs 也可以 900μs写 0 可以 60μs 也可以 120μs唯独读时隙的 15μs 采样窗口卡得死。这就决定了延时函数的调法宁可整体偏快也别偏慢。2.3 最小系统接线表晶振、复位、P0 上拉一个都不能省硬件上最容易翻车的地方不是传感器是 P0 口。51 的 P0 口是开漏输出不接上拉电阻时输出高电平是浮空的接 LCD1602 数据口会表现为“屏幕亮了但全是黑块”或者“字符乱码”很多人第一反应是程序写错了其实是硬件。网络连接参数/说明晶振XTAL1、XTAL2 各接一只电容到地11.0592MHz 22pF×2串口要用就选这个频点复位RST 接 10μF 电容到 VCC10k 电阻到 GND上电复位 按键复位并联EA接 VCC使用片内程序存储器时必须拉高P0 口10k 排阻上拉到 VCC接 LCD 数据口或数码管段码时必须加DS18B20DQ 接 P3.3同时经 4.7k 上拉到 VCC上拉不能省寄生供电时更关键蜂鸣器P2.0 经 NPN 三极管驱动有源蜂鸣器IO 直接驱动电流不够按键P3.2、P3.4 接 GND内部上拉上下限调整、模式切换这里有个血泪经验DS18B20 有两种供电方式三线供电VDD 接 3.3V 或 5V和寄生供电VDD 接 GND靠 DQ 线偷电。课设建议一律用三线供电寄生供电在转换期间需要主机强上拉稍不注意就是“读出来永远是 85℃”。2.4 显示怎么选数码管动态扫描与 LCD1602 的引脚账数码管便宜、亮度高、看着有“仪表感”但动态扫描要用定时器还要消隐LCD1602 能显示字符和符号接线多 6 根控制线但刷新简单。对比项4 位共阳数码管LCD1602占用 IO段码 8 根 位选 4 根可译码到 2 根数据 8 根或 4 根 控制 3 根显示内容数字、小数点、少量符号ASCII 字符可显示“Temp:”“ALARM”软件成本定时器中断扫描 段码表 消隐初始化时序 忙标志判断常见坑重影、亮度不均、位选串扰上电初始化顺序、对比度电位器我的建议是答辩要好看用 LCD1602要体现底层功力用数码管两个都上也不亏——数码管走 P0P1LCD1602 走 P2互不冲突正好一页报告能画出两张图。3. 把温度读出来复位、写位、读位三个时隙的手写实现这一章是整篇的核心。DS18B20 的驱动不复杂但每一行都跟时序绑着写错一个延时就是“读出来全是 0xFF”。我们按“延时基准 → 复位 → 读写位 → 完整读温度”的顺序推。3.1 微秒基准怎么定11.0592MHz 与 12MHz 的延时函数差异51 的一个机器周期是 12 个时钟周期。11.0592MHz 下约 1.085μs12MHz 下正好 1μs。这个 8.5% 的差异在串口波特率上是致命的11.0592 能把 9600 的误差压到 0但在单总线时序上通常在容差内。问题在于C 语言写不出精确的微秒延时——循环体编译成几条指令、编译器优不优化都会改变实际宽度。所以正确做法不是抄一个函数而是先校准再使用#include intrins.h /* 约 n 微秒nop 数量需按实测校准 */ void delay_us(unsigned int us) { while (us--) { _nop_(); _nop_(); } } /* 校准用让 P1.0 输出方波逻辑分析仪量高电平宽度 */ void delay_calib(void) { while (1) { P1_0 0; delay_us(1000); P1_0 1; delay_us(1000); } }逻辑说明delay_us里每轮循环执行一次自减、一次比较跳转、两条空指令编译后大约 6~8 个机器周期。跑一次delay_calib用逻辑分析仪抓 P1.0如果高电平是 7000μs 而不是 1000μs说明单轮循环约 7μs把两条_nop_()删掉或改成空循环再量。参数上只有一个自由度——循环体里的空指令条数反复调到delay_us(1000)实测落在 950~1050μs 之间即可。毫秒级延时不要用delay_us叠加直接用定时器或者长循环void delay_ms(unsigned int ms) /* 11.0592MHz 下约 1ms 每单位 */ { unsigned int i, j; for (i 0; i ms; i) for (j 0; j 112; j); /* 内层系数按实测调 */ }注意delay_ms(750)会阻塞 CPU 750ms期间数码管不刷新、按键不响应。真正的工程写法是把转换启动和读数拆到两个时间点中间让主循环正常跑。3.2 复位与存在脉冲判断器件在不在的第一步复位是每次通信的起点也是排查故障的第一现场。返回值为 0 表示器件应答了返回 1 表示总线上没人——接线断了、上拉没焊、器件烧了都走这条分支。sbit DQ P3^3; /* DS18B20 数据脚 */ /* 返回 0检测到存在脉冲返回 1无器件应答 */ bit ds_reset(void) { bit presence; DQ 0; delay_us(500); /* 拉低 480~960us取下限附近即可 */ DQ 1; /* 释放总线靠上拉电阻拉高 */ delay_us(70); /* 等 15~60us 后从机拉低留余量 */ presence DQ; /* 0 表示从机应答 */ delay_us(430); /* 补足整个复位时隙给从机恢复时间 */ return presence; }逻辑说明拉低 500μs 满足“至少 480μs”释放后等 70μs 再采样正好落在存在脉冲的 60~240μs 区间内最后补 430μs保证整个时隙超过 960μs避免下一次操作踩到从机的恢复期。三个延时加起来约 1000μs是单总线里唯一“越长越安全”的地方。参数上唯一需要动的是第一个 500——如果线缆很长超过 3 米可以加到 600~700μs给分布电容留充放电时间。3.3 写字节读字节低位先出与 15 微秒采样窗口读写都建立在位操作上先封装位再拼字节。写的时候注意写 0 的拉低时间不能超过 120μs否则从机会误判为复位脉冲。void ds_write_bit(bit b) { DQ 0; if (b) { /* 写 1拉低 10us 后释放 */ delay_us(10); DQ 1; delay_us(55); /* 补足 60us 以上时隙 */ } else { /* 写 0拉低 65us 再释放 */ delay_us(65); DQ 1; delay_us(5); /* 时隙间至少 1us 恢复 */ } } bit ds_read_bit(void) { bit b; DQ 0; /* 拉低启动读时隙 */ delay_us(2); DQ 1; /* 释放从机开始输出 */ delay_us(10); /* 关键15us 内采样 */ b DQ; delay_us(50); /* 补足时隙等从机释放总线 */ return b; } void ds_write_byte(unsigned char dat) { unsigned char i; for (i 0; i 8; i) { ds_write_bit(dat 0x01); /* 低位先出 */ dat 1; } } unsigned char ds_read_byte(void) { unsigned char i, dat 0; for (i 0; i 8; i) { dat 1; if (ds_read_bit()) dat | 0x80; /* 低位先出故先右移再补高位 */ } return dat; }逻辑说明ds_read_byte里“先右移再补 0x80”这个顺序是低位先出的直接结果很多人写成先或再移读出来刚好是位反转温度会变成一个离谱的大数。ds_read_bit里的 10μs 是整段代码中最敏感的参数多 5μs 就可能读到从机已经释放后的高电平表现为“温度恒为 125℃ 或全 1”。参数上写 1 的 10μs 和写 0 的 65μs 都在容差范围内可以按实测微调读时隙的 10μs 不要动改也只能往小改。3.4 一次完整的温度读取跳过ROM、启动转换、读暂存器单器件时用“跳过 ROM”0xCC省掉 64 位地址匹配总线挂多个器件时才需要“搜索 ROM”0xF0或“匹配 ROM”0x55。完整流程是复位 → 跳过 ROM → 启动转换0x44→ 等待 → 复位 → 跳过 ROM → 读暂存器0xBE→ 连读 9 字节。/* 返回原始码0x7FFF 表示无器件应答 */ int ds_read_raw(void) { unsigned char tl, th; int raw; if (ds_reset()) return 0x7FFF; ds_write_byte(0xCC); /* 跳过 ROM */ ds_write_byte(0x44); /* 启动一次温度转换 */ if (ds_reset()) return 0x7FFF; ds_write_byte(0xCC); ds_write_byte(0xBE); /* 读暂存器 */ tl ds_read_byte(); /* 字节 0温度低 8 位 */ th ds_read_byte(); /* 字节 1温度高 8 位 */ raw ((int)th 8) | tl; return raw; }逻辑说明暂存器一共 9 字节前两字节是温度第 3、4 字节是上下限报警值第 5 字节是配置寄存器最后一个是 CRC。这里只读两字节就结束虽然从机还等着被读但每次通信前都会复位不影响下一次。参数说明上面这段在“启动转换”和“读暂存器”之间没有延时实际使用时必须在两次调用之间留够转换时间——12 位精度需要 750ms。常见做法是主循环每 1 秒调一次中间用定时器做显示扫描而不是在函数里死等。4. 显示、报警、上传把原始码变成能看懂的温度值拿到raw只是拿到了一个 16 位补码离“人能看懂的温度”还差三步换算、显示、判断。4.1 补码与 0.0625℃定点换算比浮点更省DS18B20 输出的是 12 位补码最低位权重 0.0625℃。正温度直接乘负温度要先取补。51 上跑浮点要拖进几百字节的库转换一次几毫秒能不用就不用。/* 原始码 - 单位 0.1℃ 的整数范围 -550 ~ 1250 */ int raw_to_t10(int raw) { return (int)(((long)raw * 5) / 8); /* raw * 0.0625 * 10 raw * 0.625 */ } /* 拆分显示用符号、整数部分、小数部分 */ void t10_split(int t10, char *sign, unsigned char *ip, unsigned char *fp) { unsigned int a; *sign (t10 0) ? - : ; a (t10 0) ? (unsigned int)(-t10) : (unsigned int)t10; *ip a / 10; *fp a % 10; }逻辑说明raw * 5 / 8是 0.625 的整数近似误差不超过 0.05℃比 0.0625 的原始分辨率还小一档完全够显示一位小数。用long是为了防止raw * 5在 -880 这种值上溢出——int装得下但中间结果类型写明确更安全。参数说明想要两位小数就把系数改成raw * 625 / 1000代价是显示位数变多、数码管得再加一位。课设一般一位小数足够答辩时也别自己给自己加难度。负数的处理有个坑-t10在int上是合法的但如果t10是-32768就会溢出。温度范围只有 -55℃不会碰到但写代码时心里要有这根弦。4.2 数码管动态扫描定时器里刷新才不闪动态扫描的本质是“一次只亮一位靠人眼视觉暂留合成四位”。放在主循环里扫一旦遇到 750ms 的转换延时就会集体闪烁放在定时器中断里扫主循环再忙也不影响。/* 共阳数码管段码 0~9最高位为小数点位 */ code unsigned char SEG[] {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; unsigned char disp_buf[4]; /* 待显示的 4 位段码 */ unsigned char digit 0; void timer0_isr(void) interrupt 1 { TH0 (65536 - 1000) / 256; /* 1ms 一次 */ TL0 (65536 - 1000) % 256; P1 0xFF; /* 先全灭消隐 */ P0 disp_buf[digit]; /* 送段码 */ P1 ~(1 digit); /* 位选低电平有效 */ if (digit 4) digit 0; }逻辑说明消隐必须在送段码之前否则上一位的段码会短暂停留在新选通的位上形成“重影”。1ms 刷新一位四位一轮 4ms刷新率 250Hz肉眼完全看不出闪。参数说明定时器初值按晶振算11.0592MHz 下 1ms 需要 921 个机器周期所以是65536-921上面写的 1000 只是示意实际要按晶振改。位选如果经三极管驱动极性要跟着翻。4.3 上下限报警与回差为什么阈值要留 0.5℃ 余量最朴素的写法是“超过 30℃ 就响”结果是温度在 30.0℃ 附近抖动时蜂鸣器哒哒哒响个不停。原因很简单传感器分辨率 0.0625℃噪声轻松超过这个数阈值上必然来回穿越。解决方法是加回差滞回超过上限才置位报警要跌到上限以下 0.5℃ 才解除。#define ALARM_HI 300 /* 上限 30.0℃单位 0.1℃ */ #define ALARM_LO 100 /* 下限 10.0℃单位 0.1℃ */ #define HYST 5 /* 回差 0.5℃ */ bit alarm_on 0; void alarm_check(int t10) { if (!alarm_on (t10 ALARM_HI || t10 ALARM_LO)) alarm_on 1; else if (alarm_on t10 ALARM_HI - HYST t10 ALARM_LO HYST) alarm_on 0; BEEP alarm_on ? 0 : 1; /* 低电平驱动 NPN 三极管 */ }逻辑说明alarm_on是状态变量不是即时比较结果。置位条件用“或”解除条件用“与”中间夹着 0.5℃ 的死区这样温度在阈值附近抖动时不会反复触发。参数说明HYST取 0.5℃ 对应 8 个最小刻度对抗噪声足够如果现场干扰大可以加到 1.0℃。上下限不要贴得太近低于 2℃ 的窗口在滞回逻辑下会退化成常报警。4.4 串口把温度送出去9600 波特率与帧格式课设加个串口输出报告里就能放一张“温度-时间曲线”比干巴巴的截图有说服力得多。11.0592MHz 晶振配 9600 波特率误差为 0这是选这个频点的唯一理由。void uart_init(void) { SCON 0x50; /* 方式 1允许接收 */ TMOD | 0x20; /* 定时器 1 方式 28 位自动重装 */ TH1 0xFD; /* 11.0592MHz 下 9600bps */ TL1 0xFD; TR1 1; ES 1; EA 1; } void uart_send_str(unsigned char *s) { while (*s) { SBUF *s; while (!TI); TI 0; } } /* 主循环里每秒调用一次T25.3\r\n */ void report_temperature(int t10) { char sign; unsigned char ip, fp, buf[8]; t10_split(t10, sign, ip, fp); buf[0] T; buf[1] (sign -) ? - : ; buf[2] 0 ip / 10; buf[3] 0 ip % 10; buf[4] .; buf[5] 0 fp; buf[6] \r; buf[7] \n; uart_send_bytes(buf, 8); }逻辑说明TH1 0xFD是 9600 波特率在 11.0592MHz、SMOD0 时的标准值换成 12MHz 晶振误差会到 8% 以上通信会随机丢字节——这是很多人“仿真好好的实物上位机收乱码”的根因。参数说明发送用查询方式等 TI 标志最简单但会阻塞如果主循环任务多改成中断里发。数据帧用T开头、\r\n结尾上位机串口助手按行解析最省事不需要自己写协议。5. 避坑与排查六个让课程设计卡到凌晨的现场问题下面这六条每一条都能让人从晚上八点坐到凌晨两点。按“现象 → 原因 → 解决”记遇到问题先对号入座比盲目改代码快得多。5.1 读数类的三个坑85℃、全 0、上电首读失败现象一温度恒定显示 85℃怎么加热都不变。原因85℃ 是 DS18B20 上电复位后暂存器的默认值说明主机根本没读到新数据。常见分支有三个——复位时隙没检测到存在脉冲但代码没判断、启动转换后没等够 750ms 就读、或者器件处于寄生供电但主机没有强上拉。 解决先让ds_read_raw把“无应答”明确返回出来用一个 LED 指示复位结果确认返回值不是 0x7FFF 之后再检查转换等待时间。如果是寄生供电要么改成三线要么在启动转换后把 DQ 强拉高。现象二读出来全是 0x00 或全是 0xFF。原因全 0 通常是读时隙采样太晚从机已经释放总线读到的都是低电平全 0xFF 是总线一直是高电平说明从机压根没响应或者上拉电阻没焊、DQ 接错脚。 解决用万用表量 DQ 静态电压三线供电时应接近 VCC如果一直是 0V 或浮空先查硬件。软件上把ds_read_bit里的 10μs 改小到 8μs 试一次能读出正常值就说明采样点晚了。现象三上电第一次读永远失败之后正常。原因上电瞬间电源爬升慢DS18B20 内部复位电路还没准备好第一次复位时序被吞掉。 解决在main开头加delay_ms(100)再初始化同时把第一次读取的结果丢弃从第二次开始用。5.2 时序与硬件类的两个坑长线和仿真现象四在开发板上好好的焊到自己板子上就不行或者杜邦线一长就乱码。原因单总线是准双向口加弱上拉线长超过 1 米后分布电容把上升沿拖慢读时隙采样时电平还没爬到阈值。 解决把 4.7k 上拉改成 2.2k功耗增加但在 5V 下可接受缩短走线必要时用双绞线并把地线跟 DQ 绞在一起。软件上把复位后的等待从 70μs 加到 90μs给上升沿留时间。现象五电路仿真软件里跑得完美实物就是不出数。原因仿真软件对单总线时序做了“理想化”处理延时偏差、上拉不足、电源纹波它都不管。代码在仿真里能过只说明逻辑对不说明时序对。 解决把仿真当“逻辑验证工具”不当“时序验证工具”。实物调试必须要有一台逻辑分析仪几十块钱的那种就够抓一次复位波形存在脉冲能不能看到一目了然。注意逻辑分析仪是这套课设里唯一值得买的调试工具。没有它你只能靠“改延时碰运气”那就是玄学了。5.3 显示与报警类的一个坑闪烁与误报警现象六数码管有重影或者温度一变化蜂鸣器就哒哒响。原因重影是动态扫描没消隐上一位段码残留在新位选通期间误报警是阈值没有回差0.0625℃ 的量化噪声在阈值附近来回穿越。 解决扫描中断里严格执行“先灭位选、再送段码、最后开位选”报警逻辑改成 4.3 节的滞回写法并在软件上加一层 4 点滑动平均把噪声压下去。/* 4 点滑动平均抑制 ±0.1℃ 级别的抖动 */ int smooth(int t10) { static int win[4] {0,0,0,0}; static unsigned char idx 0; win[idx] t10; idx (idx 1) 0x03; return (win[0] win[1] win[2] win[3]) / 4; }逻辑说明idx用位与代替取模省两个机器周期窗口长度取 4 是折中——太长反应慢太短压不住噪声。参数上如果被测对象是水温这种大热惯性系统窗口可以加到 8。6. 把课设做成能写进简历的作品CRC、掉电保存与报告里的三张图课程设计交完就删代码是最可惜的一件事。加三个小功能这套东西就能从“作业”变成“作品”。6.1 加一条 CRC让读数不再是黑匣子DS18B20 暂存器第 9 字节是 CRC读满 9 字节校验一次能直接把“线太长导致偶发误码”这类问题挡在数据层。/* 单总线常用 CRC-8多项式 x^8x^5x^41 */ unsigned char crc8(unsigned char *p, unsigned char n) { unsigned char i, c 0; while (n--) { c ^ *p; for (i 0; i 8; i) c (c 0x01) ? ((c 1) ^ 0x8C) : (c 1); } return c; }把读取函数改成连读 9 字节前 8 字节算 CRC 与第 9 字节比对不等就丢弃本次数据、沿用上次值。代价是 20 来行代码收益是现场偶发跳变基本消失。6.2 参数存起来上下限不该每次上电重设上下限每次上电都回到默认值答辩老师一定会问“为什么不能保存”。51 内部有 Flash可以划一段做参数区没有的话外挂一只 EEPROM 芯片也行。注意写 Flash 前要先擦除扇区且擦写次数有限别在主循环里写只在按键确认时写一次。精度配置也顺便定下来转换时间直接决定主循环节奏配置位分辨率最大转换时间适用009 位 / 0.5℃93.75ms只做告警要快0110 位 / 0.25℃187.5ms一般显示1011 位 / 0.125℃375ms需要趋势曲线1112 位 / 0.0625℃750ms课设默认也是出厂值改配置用“写暂存器”命令0x4E依次写 TH、TL、配置字节写完记得再读回来确认。6.3 报告与答辩三张图一份表文档部分别写成代码说明书的搬运。真正加分的是一张系统框图单片机、传感器、显示、报警、串口五个方块加箭头、一张主程序流程图初始化、读温、换算、显示、判断、上传闭环、一张单总线复位时序图标出 480μs、70μs、240μs 三个时间点再加一份实测数据表——用标准温度计做参照从 10℃ 到 60℃ 每隔 10℃ 记一组算出误差列。有了这份表“±0.5℃”就不是抄手册而是你量出来的。我自己带新人做这套东西最常说的一句话是先把复位波形抓出来再谈代码。当年第一次做这个课设我改了三个小时延时函数最后发现是 P0 口没接上拉电阻——从那以后我桌上一直放着一台逻辑分析仪和一张最小系统接线表先量再改比什么都快。这套方案本身不值钱值钱的是你从“能跑”走到“知道为什么能跑”的那段路。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?