裸机 寄存器 AVR-GCC 学习之 DS18B20 温度传感器单总线协议、复位时序、CRC 校验系列第十五篇承接第十四坑光敏/热敏分压 ADC 采集对比 NTC 热敏电阻DS18B20 单总线数字测温无需分压电路、精度更高基于 ATmega16A 纯寄存器实现完整单总线时序、ROM 指令、功能指令、CRC8 校验用于小车驱动板/电机实时温度监测过热保护硬件兼容 HL2 PB 口 DS1302 复用引脚全程无库函数。记录时间2026 年 7 月 27 日编译环境AVR-GCC 12芯片 ATmega16A-PU主频 12.000MHz第十五篇文章不足之处麻烦留言指正谢谢。0. 本文核心速查索引你想实现的功能跳转章节DS18B20 怎么接线PB7 与 DS1302 冲突怎么处理第二章复位脉冲、写位、读位的标准时序是什么第三章完整可运行的 DS18B20 驱动代码含 CRC 校验第六章温度怎么换算成摄氏度正负温度怎么处理第六章 6.8 节怎么编译烧录Makefile 怎么配第七章烧录后 LCD 上应该看到什么现象第八章读数错误、无应答、负温度异常怎么解决第九章一、前言DS18B20 优势与实操问题1. 模块优势NTC 热敏依靠 ADC 分压易受电源、走线干扰精度差DS18B20 单总线数字输出9~12 位可编程分辨率-55~125℃宽量程单根 IO 挂载多片传感器自带 CRC 校验保证数据可靠适合电机长期温度监测。2. 实操问题复位脉冲、存在脉冲时序时长不达标传感器无响应写 0/写 1、读位时序混淆读写数据全乱码PB7 同时复用 DS1302 RST 和数码管段选单总线电平被外设覆盖通讯失败4.7K 上拉电阻缺失总线浮空通讯完全无应答未做 CRC 校验干扰下读取错误温度数值误触发过热保护忽略温度高低字节符号位负温度换算逻辑出错匹配 ROM/跳过 ROM 指令使用场景混淆多传感器组网读取错乱IO 未配置开漏输出总线电平拉不动通讯无应答。二、硬件接线与端口冲突说明2.1 HL2 开发板 DS18B20 硬件引脚硬件文档固定分配DS1302/DS18B20 共用 PB7引脚功能说明PB7DS18B20 DQ / DS1302 RST两者短接不能同时操作VCC5V模块供电GNDGND公共地上拉电阻检查成功率 50%→100% 的关键模块版带小 PCB 的 DS18B20 模块通常已板载 4.7K 上拉电阻可直接使用裸头版只有三根线的 DS18B20 传感器必须外接 4.7KΩ 电阻将 VCC 和 DQ 之间焊接一个 4.7K 电阻如果总线无上拉DQ 释放后浮空所有通讯都会失败。这是最容易被忽略的问题2.2 DS1302 硬件冲突详细说明引脚DS1302 功能DS18B20 功能冲突PB7RST片选/复位DQ单总线数据 直接短接PB5SCLK—不影响PB6DATA—不影响关键结论DS1302 的 RST 和 DS18B20 的 DQ 共用 PB7 引脚两者不能同时工作——读写 DS18B20 前必须确保 DS1302 处于非通讯状态RST0即 PB7 为低电平建议在 DS18B20 操作期间暂停 DS1302 的所有通讯操作完成后恢复。2.3 PB 端口资源冲突PB5/PB6/PB7 为 DS1302 专用三线同时作为数码管段选、ISP 下载 SPI 总线。冲突处理铁律DS18B20 读写全程需要独占 PB7操作前关闭数码管位选PORTB ~DIG_ALL_CS而非PORTB0xFF确保 DS1302 RST0PB7 为低电平DS1302 非通讯状态读写完成后恢复数码管动态扫描。2.4 单总线电气规则单总线为开漏通讯IO 输出低电平拉总线释放 IO 后依靠4.7K 上拉电阻恢复高电平不能强行输出高电平驱动总线——必须将 IO 设为输入高阻态靠上拉拉高。三、DS18B20 单总线底层标准时序系统晶振 12MHz软件延时精准匹配时序要求。3.1 复位时序最关键text主机拉低 DQ ≥ 480us → 释放 DQ 等待 15~60us → 读取存在脉冲 ↓ 传感器拉低总线 60~240us存在脉冲主机操作拉低总线 ≥ 480μs强制复位释放总线设为输入等待 60μs读取总线电平低电平 传感器存在高电平 无传感器继续等待剩余恢复时间总复位周期 ≥ 960μs。3.2 写位时序操作时序要求写 0拉低 DQ ≥ 60μs释放总线间隔 ≥ 1μs写 1拉低 DQ 1~15μs 立刻释放依靠上拉恢复高电平间隔 ≥ 1μs关键点写 1 时拉低时间必须 15μs否则传感器会误判为写 0。3.3 读位时序text主机拉低 DQ ≤ 1μs → 释放 DQ → 15μs 内读取总线电平 → 完整周期 ≥ 60μs关键点必须在拉低后15μs 内完成采样否则读到的是无效电平。四、DS18B20 标准指令集4.1 ROM 指令多片组网指令功能使用场景0xCC跳过 ROM单传感器专用本小车使用0x33读 ROM读取 64 位 ROM ID0x55匹配 ROM多传感器组网时指定某一片0xF0搜索 ROM枚举总线上所有传感器4.2 功能指令指令功能说明0x44启动温度转换耗时 750ms12 位分辨率0xBE读取暂存器9 字节前 2 字节温度第 9 字节 CRC0x4E写暂存器设置 TH/TL/分辨率五、CRC8 校验原理多项式X⁸ X⁵ X⁴ 1对应十六进制 0x31左移一位为 0x8C作用输入 8 位数据流逐字节运算最终校验值与传感器返回第 9 字节对比相等代表数据无干扰避免电机大电流干扰读取错误温度。CRC 计算步骤初始化crc 0对每个字节crc ^ byte对每个 bit如果crc 0x01则crc (crc 1) ^ 0x8C否则crc 1最终 CRC 值用于比对。六、纯寄存器底层完整代码含整数运算 端口保护6.1 头文件与宏定义c#define F_CPU 12000000UL #include avr/io.h #include avr/interrupt.h #include util/delay.h #include stdint.h typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef int16_t s16; // DS18B20 单总线引脚 PB7 #define DQ (1 PB7) // 数码管位选引脚与系列前文一致使用 PD/PC 口 // 注意为避免与 PB7 冲突数码管位选改用 PD/PC 口 #define DIG_CS1 (1 PD5) #define DIG_CS2 (1 PD4) #define DIG_CS3 (1 PC7) #define DIG_CS4 (1 PC6) #define DIG_ALL_CS (DIG_CS1 | DIG_CS2 | DIG_CS3 | DIG_CS4) // 温度阈值45℃ × 10 450 #define TEMP_ALARM 4506.2 IO 底层操作封装c// 总线底层操作开漏模式 // 拉低总线输出低电平 static inline void DQ_OutLow(void) { DDRB | DQ; PORTB ~DQ; } // 释放总线设为输入高阻态靠上拉拉高 static inline void DQ_Release(void) { DDRB ~DQ; } // 读取总线电平 static inline u8 DQ_Read(void) { return (PINB DQ) ? 1 : 0; }6.3 复位时序c// 复位总线 // 返回: 1检测到传感器存在脉冲0无设备 u8 DS18B20_Reset(void) { u8 ack; // ★ 阶段1主机拉低总线 ≥ 480μs DQ_OutLow(); _delay_us(500); // 500μs 480μs 最小要求 // ★ 阶段2释放总线等待传感器应答 DQ_Release(); _delay_us(60); // 等待 15~60μs 后读取存在脉冲 // ★ 阶段3读取存在脉冲传感器拉低 60~240μs ack DQ_Read(); // ★ 阶段4等待剩余恢复时间总复位周期 ≥ 960μs _delay_us(400); // 存在脉冲为低电平ACK0代表传感器存在 return (ack 0) ? 1 : 0; }6.4 写位时序c// 写1位 void DS18B20_WriteBit(u8 bit) { if (bit) { // ★ 写1拉低 1~15μs 后释放传感器在 15~60μs 采样 DQ_OutLow(); _delay_us(5); // 5μs在允许范围内 DQ_Release(); _delay_us(60); // 补足整个写周期 ≥60μs } else { // ★ 写0拉低 ≥60μs DQ_OutLow(); _delay_us(60); DQ_Release(); _delay_us(5); // 恢复时间 } }6.5 读位时序c// 读1位 u8 DS18B20_ReadBit(void) { u8 bit; // ★ 阶段1主机拉低总线 ≤1μs DQ_OutLow(); _delay_us(1); // ★ 阶段2释放总线等待传感器输出数据 DQ_Release(); _delay_us(14); // 在 15μs 前采样 // ★ 阶段3读取总线电平 bit DQ_Read(); // ★ 阶段4等待读位周期结束≥60μs _delay_us(45); return bit; }6.6 字节读写c// 写1字节 void DS18B20_WriteByte(u8 dat) { for (u8 i 0; i 8; i) { DS18B20_WriteBit(dat 0x01); dat 1; } } // 读1字节 u8 DS18B20_ReadByte(void) { u8 dat 0; for (u8 i 0; i 8; i) { dat 1; if (DS18B20_ReadBit()) { dat | 0x80; } } return dat; }6.7 CRC8 校验多项式 0x31c// CRC8 校验 // 多项式: X^8 X^5 X^4 1 (0x31) // 简化计算用 0x8C (0x31 左移一位) u8 DS18B20_CRC(u8 *buf, u8 len) { u8 crc 0; for (u8 i 0; i len; i) { crc ^ buf[i]; for (u8 j 0; j 8; j) { if (crc 0x01) { crc (crc 1) ^ 0x8C; } else { crc 1; } } } return crc; }6.8 温度读取函数核心c// 读取温度 // 返回: 温度值 × 10整数例如 25.3℃ → 253 // 9999 读取失败 / 校验错误 s16 DS18B20_ReadTemp(void) { u8 buf[9]; s16 temp_x10; u8 portb_backup; // ★ 保存 PORTB 状态关闭数码管位选 portb_backup PORTB; PORTD ~(DIG_CS1 | DIG_CS2); PORTC ~(DIG_CS3 | DIG_CS4); _delay_us(10); // 1. 复位 跳过 ROM 启动转换 if (!DS18B20_Reset()) { PORTD | (portb_backup (DIG_CS1 | DIG_CS2)); PORTC | (portb_backup (DIG_CS3 | DIG_CS4)); return 9999; } DS18B20_WriteByte(0xCC); // 跳过 ROM单传感器 DS18B20_WriteByte(0x44); // 启动温度转换 _delay_ms(750); // 12位分辨率最大转换时间 // 2. 复位 跳过 ROM 读暂存器 if (!DS18B20_Reset()) { PORTD | (portb_backup (DIG_CS1 | DIG_CS2)); PORTC | (portb_backup (DIG_CS3 | DIG_CS4)); return 9999; } DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0xBE); // 读暂存器 for (u8 i 0; i 9; i) { buf[i] DS18B20_ReadByte(); } // 3. CRC 校验 if (DS18B20_CRC(buf, 8) ! buf[8]) { PORTD | (portb_backup (DIG_CS1 | DIG_CS2)); PORTC | (portb_backup (DIG_CS3 | DIG_CS4)); return 9999; // CRC 错误数据不可信 } // 4. ★ 温度换算整数运算无浮点 // buf[0] 温度低字节buf[1] 温度高字节 u16 temp_raw (buf[1] 8) | buf[0]; // ★ 判断符号位 bit11 if ((temp_raw 0x0800) 0) { // ★ 正温度bit110 // 放大10倍temp_raw × 0.0625 × 10 temp_raw × 0.625 // 整数运算×625 / 1000 temp_x10 (s16)(((s32)temp_raw * 625) / 1000); } else { // ★ 负温度bit111取补码 temp_raw (~temp_raw) 1; temp_x10 -(s16)(((s32)temp_raw * 625) / 1000); } // 5. 释放总线恢复 PORTB DQ_Release(); _delay_us(10); PORTD | (portb_backup (DIG_CS1 | DIG_CS2)); PORTC | (portb_backup (DIG_CS3 | DIG_CS4)); return temp_x10; }6.9 进阶读取 64 位 ROM ID多传感器组网用c// 读取 64 位 ROM ID8字节 // 用于多传感器组网前枚举设备 void DS18B20_ReadROM(u8 *rom_id) { u8 portd_backup PORTD; u8 portc_backup PORTC; PORTD ~(DIG_CS1 | DIG_CS2); PORTC ~(DIG_CS3 | DIG_CS4); _delay_us(10); DS18B20_Reset(); DS18B20_WriteByte(0x33); // 读 ROM 指令 for (u8 i 0; i 8; i) { rom_id[i] DS18B20_ReadByte(); } DQ_Release(); _delay_us(10); PORTD portd_backup; PORTC portc_backup; }6.10 进阶设置分辨率c// 设置 DS18B20 分辨率 // res: 0x1F9位(93.75ms), 0x3F10位(187.5ms) // 0x5F11位(375ms), 0x7F12位(750ms,默认) void DS18B20_SetResolution(u8 res) { u8 portd_backup PORTD; u8 portc_backup PORTC; PORTD ~(DIG_CS1 | DIG_CS2); PORTC ~(DIG_CS3 | DIG_CS4); _delay_us(10); DS18B20_Reset(); DS18B20_WriteByte(0xCC); // 跳过 ROM DS18B20_WriteByte(0x4E); // 写暂存器 DS18B20_WriteByte(0x00); // TH不用 DS18B20_WriteByte(0x00); // TL不用 DS18B20_WriteByte(res); // 配置寄存器 DQ_Release(); _delay_us(10); PORTD portd_backup; PORTC portc_backup; }七、配套 Makefile 工程构建7.1 完整 Makefilemakefile#---------------------------------------------------------------------------- # 慧净电子 HL-1/HL-2 小车系列通用 Makefile # 适用于 ATmega16A-PU 12MHzAVR-GCC avrdude 环境 #---------------------------------------------------------------------------- # 1. 项目与硬件配置 # 注意芯片型号为 atmega16标准写法 MCU atmega16 F_CPU 12000000UL TARGET main SRC main.c # 2. 编译工具链 CC avr-gcc OBJCOPY avr-objcopy SIZE avr-size # 编译选项 CFLAGS -mmcu$(MCU) -Os -Wall -DF_CPU$(F_CPU) OBJ $(SRC:.c.o) # 3. 烧录工具配置 # 【!!! 请根据实际编程器修改 !!!】 AVRDUDE avrdude PROGRAMMER -c usbasp # PROGRAMMER -c stk500v2 -P COM3 AVRDUDE_FLAGS $(PROGRAMMER) -p $(MCU) # 4. 编译与烧录目标 all: $(TARGET).hex $(TARGET).elf size %.o: %.c $(CC) -c $(CFLAGS) -o $ $ $(TARGET).elf: $(OBJ) $(CC) $(CFLAGS) -o $ $^ %.hex: %.elf $(OBJCOPY) -O ihex -R .eeprom $ $ size: $(TARGET).elf $(SIZE) -C --mcu$(MCU) $ flash: all $(AVRDUDE) $(AVRDUDE_FLAGS) -U flash:w:$(TARGET).hex:i clean: rm -f $(OBJ) $(TARGET).elf $(TARGET).hex help: echo make all 编译项目 echo make flash 编译并烧录 echo make clean 清理临时文件 echo make size 查看代码大小 .PHONY: all flash clean size help7.2 编译烧录命令bashmake clean # 清理之前的编译产物 make # 编译项目或 make all make flash # 烧录到芯片八、小车温度监测主逻辑过热停机保护8.1 主函数c// 外部外设函数声明 extern void Timer1_PWM_Init(void); extern void Motor_DIR_Init(void); extern void Set_Motor_Speed(u8 l, u8 r); extern void Car_Stop(void); extern void Digit_Dynamic_Refresh(void); extern void Lcd8_Init(void); extern void Lcd_Show_Str_P(u8 line, u8 pos, const char *str); extern void Lcd_Write_Data(u8 dat); extern void Beep_On(void); extern void Beep_Off(void); // 主函数 int main(void) { // 外设初始化 Timer1_PWM_Init(); Motor_DIR_Init(); Digit_Init(); Lcd8_Init(); // LCD 初始显示 Lcd_Show_Str_P(1, 0, PSTR(DS18B20 INIT )); Lcd_Show_Str_P(2, 0, PSTR(TEMP: . C)); s16 last_temp 0; while (1) { // 读取温度 s16 temp_data DS18B20_ReadTemp(); if (temp_data 9999) { // 传感器错误 Lcd_Show_Str_P(1, 0, PSTR(DS18B20 ERR )); Lcd_Show_Str_P(2, 0, PSTR(CHECK WIRING )); Beep_On(); Car_Stop(); } else { // 正常显示 Beep_Off(); // 第一行温度值 Lcd_Show_Str_P(1, 0, PSTR(TEMP:)); u8 integer_part temp_data / 10; u8 decimal_part temp_data % 10; Lcd_Write_Data(0 (integer_part / 10)); Lcd_Write_Data(0 (integer_part % 10)); Lcd_Write_Data(.); Lcd_Write_Data(0 decimal_part); Lcd_Show_Str_P(1, 10, PSTR(C)); // ★ 过热保护 if (temp_data TEMP_ALARM) { Car_Stop(); Lcd_Show_Str_P(2, 0, PSTR(OVER HEAT! )); Beep_On(); } else { Set_Motor_Speed(140, 140); Lcd_Show_Str_P(2, 0, PSTR(NORMAL TEMP )); } } // ★ 每秒测温一次DS18B20 转换需要时间 _delay_ms(1000); } }8.2 非阻塞测温引导进阶性能优化上述代码中_delay_ms(750)会阻塞主循环。若需在测温期间继续执行电机控制、数码管刷新等任务建议改用状态机实现非阻塞测温。核心思路触发转换后记录时间戳不等待主循环中检查是否已过 750ms时间到后读取温度数据。九、实验现象与验证烧录完成后按以下步骤操作验证程序。9.1 上电初始状态场景LCD 显示电机/蜂鸣器传感器正常TEMP: 25.5 C NORMAL TEMP电机运转蜂鸣器静音传感器未接/损坏DS18B20 ERR CHECK WIRING电机停转蜂鸣器长鸣9.2 升温实验操作预期现象手指捏住 DS18B20 传感器温度数值缓慢上升如 25.5℃ → 33.0℃约 1~2 秒更新一次持续加热至超过 45℃电机立即停转蜂鸣器持续报警LCD 显示OVER HEAT!移走热源温度降至 45℃ 以下电机恢复运转蜂鸣器停止LCD 显示NORMAL TEMP9.3 错误注入实验操作预期现象拔掉 DS18B20 传感器LCD 显示DS18B20 ERR电机停转蜂鸣器报警重新插上传感器自动恢复显示当前温度9.4 CRC 校验验证操作预期现象注释掉 CRC 校验代码电机运行时温度可能随机跳变如 25℃ → 120℃恢复 CRC 校验代码温度读数稳定错误数据被过滤十、实操总结问题 1复位/读写时序延时错误传感器无应答现象DS18B20_Reset()固定返回 0完全读不出温度。根源复位拉低不足 480μs、读位延时超过 15μs 采样失效。解决严格按照标准时序配置 12MHz 延时数值禁止随意删减_delay_us()。问题 2未释放 IO 强行输出高电平总线通讯卡死现象偶尔读出乱码多次读取直接无应答。根源单总线开漏结构不能 DDRB 输出高电平驱动总线必须置为输入靠上拉拉高。解决总线高电平统一使用DQ_Release()切换输入模式。问题 34.7K 上拉电阻缺失总线浮空无通讯现象复位始终返回 0但传感器供电正常。根源裸头版 DS18B20 无板载上拉电阻DQ 释放后浮空。解决在 VCC 和 DQ 之间焊接 4.7KΩ 电阻。这是硬件问题软件无法解决。问题 4数码管未关闭直接读写 PB7电平冲突通讯失败现象数码管刷新期间测温报错关闭数码管读取正常。根源动态数码持续改写 PORTB拉低/拉高 DQ 引脚破坏单总线时序。解决每次测温开头关闭数码管位选PORTD ~DIG_CS和PORTC ~DIG_CS而非PORTB0xFF那是点亮段码。同时确保 DS1302 的 RST0。问题 5无 CRC 校验电机干扰下读取虚假温度现象电机启动瞬间温度跳变至 120℃误触发过热停机。根源大电流电磁干扰单总线字节接收出错。解决读取 9 字节后校验 CRC校验不通过丢弃本次数据返回错误码9999。问题 6负温度未做补码转换低温读数溢出超大正数现象环境 0℃以下温度数值显示上千度保护逻辑误触发。根源忽略 12 位温度寄存器符号位bit11未做取反1 补码换算。解决判断 bit11 符号位负数执行补码转换后再计算摄氏度代码 6.8 节已实现。问题 7误用匹配 ROM 0x55 指令单传感器读取失效现象复位后发送 0x55 直接无应答。根源单片 DS18B20 必须使用跳过 ROM 指令 0xCC匹配 ROM 用于多片组网。解决小车单传感器固定使用 0xCC 跳过 ROM 指令。十一、进阶拓展功能优化方向实现思路收益分辨率配置写配置寄存器设置 9/10/11/12 位9 位时转换仅需 93.75ms多传感器组网读 ROM ID0x33 匹配 ROM0x55底盘/驱动板双路测温非阻塞测温状态机管理转换过程不阻塞主循环不影响电机/PWM 实时控制DS1302 分时复用操作 DS18B20 时确保 DS1302 RST0两外设共存AT24C02 存储阈值保存过热阈值掉电不丢失用户自定义保护温度蓝牙实时上传温度数据通过 PD0/PD1 发送上位机远程监控分辨率配置示例c// 设置为 9 位分辨率转换时间 93.75ms DS18B20_SetResolution(0x1F);十二、实操验证调试步骤硬件检查确认 4.7K 上拉电阻已连接裸头版DS18B20 的 VCC/GND/DQ 接线正确。烧录程序执行make flash烧录。上电自检LCD 显示当前室温如TEMP: 25.5 C电机运转。升温测试手指捏住传感器温度缓慢上升。过热保护加热至超过 45℃电机停转、蜂鸣器报警。CRC 验证屏蔽 CRC 校验代码电机运行时观察温度是否跳变恢复后数据稳定。错误恢复拔掉传感器LCD 显示DS18B20 ERR重新插上自动恢复。多外设并行同时运行电机 PWM、LCD、动态数码、DS18B20 测温互不干扰。十三、常见问题 FAQ问题答案DS18B20_Reset()始终返回 0检查 4.7K 上拉电阻是否焊接检查 DQ 是否接 PB7检查传感器 VCC/GND 是否接反温度读出来固定为 0℃检查_delay_ms(750)是否存在检查 DS18B20 供电是否稳定温度跳变很大±10℃检查 CRC 校验是否开启检查数码管是否关闭PORTD ~DIG_CS负数温度显示为超大正数检查符号位判断逻辑temp_raw 0x0800参考 6.8 节代码电机一转温度就跳变检查 CRC 校验是否开启检查电机电源和传感器电源是否共地检查传感器排线是否靠近电机线编译报错 undefined reference to ...检查 Makefile 中 SRC 是否包含所有 .c 文件DS1302 和 DS18B20 一起用就失败两者共用 PB7不能同时操作。测温时确保 DS1302 RST0PB7 低电平十四、全文实操总结硬件铁律DS18B20 单总线 DQ 引脚 PB7开漏通讯依靠 4.7K 上拉电阻裸头版必须外接。PB7 同时为 DS1302 的 RST 引脚两者不能同时操作测温前确保 DS1302 RST0。时序铁律复位拉低 ≥480μs写 0 拉低 ≥60μs写 1 拉低 1~15μs 后释放读位在拉低 1μs 释放后 15μs 内采样。12MHz 系统延时不可随意修改。指令铁律单片传感器固定使用 0xCC 跳过 ROM0x44 启动转换需等待 750ms12 位分辨率。9 字节暂存器第 9 位为 CRC 校验码校验通过才采信数据。温度换算温度寄存器为 12 位补码格式bit11 为符号位。正温度temp_raw × 0.625负温度取补码后-temp_raw × 0.625。使用整数运算×625/1000避免软件浮点库。抗干扰铁律测温前关闭数码管位选PORTD ~DIG_CS和PORTC ~DIG_CS而非PORTB0xFFCRC 校验过滤电磁干扰操作前保存/恢复 PORTD/PORTC 状态。性能优化750ms 阻塞延时可通过状态机改造为非阻塞模式不影响电机/PWM 实时控制。9 位分辨率可将转换时间缩短至 93.75ms。到此我的第十五篇文章就此完成感谢你的阅读不足之处麻烦留言指正谢谢。