在实际嵌入式开发项目中仿真是一个至关重要的环节它允许我们在硬件制造之前验证电路设计和软件逻辑从而节省成本、缩短开发周期。对于基于STM32单片机的应用如一个观光车状态监测系统使用Proteus进行仿真设计能够直观地观察传感器数据采集、处理逻辑以及人机交互界面的运行效果。本文将以STM32F103C8T6为核心控制器带你从零开始在Proteus环境中搭建一个完整的观光车状态监测系统仿真模型并完成从项目创建、电路设计、代码编写到仿真运行的全过程。本文适合已经具备C语言和单片机基础希望学习如何将STM32与Proteus结合进行系统级仿真的开发者。通过本文你将掌握在Proteus中为STM32添加外设、编写控制逻辑、处理传感器模拟信号以及驱动显示模块的完整流程。最终你将获得一个可运行的仿真项目能够监测模拟的车辆速度、温度、电池电压等状态并在LCD上实时显示。1. 理解仿真系统的核心构成与设计思路在动手搭建电路和编写代码之前我们需要明确这个“观光车状态监测系统”需要实现哪些功能以及如何在Proteus的虚拟环境中模拟这些功能。这决定了我们后续的元件选型、电路连接和软件架构。1.1 系统功能需求分析一个典型的观光车状态监测系统需要感知车辆自身的运行状态和环境参数。在仿真中我们无法接入真实的物理传感器但可以通过Proteus提供的虚拟仪器和信号源来模拟传感器信号。基于此我们规划以下核心监测功能速度监测模拟获取观光车的实时行驶速度。我们可以使用一个可调电阻电位器或数字信号源来模拟速度传感器的脉冲信号。温度监测模拟监测车内或环境温度。使用LM35或DS18B20的温度传感器模型并通过电压或数字信号来模拟温度变化。电池电压监测模拟监测观光车电池的剩余电量。使用一个直流电压源来模拟电池并通过STM32的ADC模数转换器进行采样。状态显示将监测到的数据实时显示出来。使用LCD1602或LCD12864字符液晶模块这是Proteus中常用的显示器件。报警指示当某项参数超过安全阈值时提供视觉或听觉报警。例如使用LED和蜂鸣器。1.2 Proteus仿真环境下的实现策略在真实硬件中STM32通过GPIO、ADC、定时器、UART等外设与传感器和显示器通信。在Proteus中我们需要找到对应的虚拟元件模型并理解它们与STM32模型的交互方式STM32模型Proteus内置了STM32F103C8T6的仿真模型。我们需要为其加载编译好的固件.hex文件。传感器模拟ADC输入对于速度电位器模拟、电池电压电压源我们可以将其连接到STM32的ADC输入引脚。在仿真中通过调整电位器阻值或电压源大小来模拟参数变化。数字传感器对于DS18B20单总线协议Proteus有对应的模型可以设置其温度值STM32代码需要实现单总线协议来读取。显示模块LCD1602并行接口在Proteus中仿真成熟我们需要按照其时序编写驱动代码。调试与观测Proteus的虚拟终端Virtual Terminal可以模拟串口方便我们打印调试信息。虚拟示波器和逻辑分析仪可用于观察信号波形。1.3 开发工具链准备进行STM32的Proteus仿真需要两套工具协同工作嵌入式代码开发工具用于编写、编译、调试STM32的C语言程序生成可供Proteus加载的.hex文件。常见选择有Keil MDK-ARM、STM32CubeIDE、IAR Embedded Workbench等。本文将以Keil uVision5为例。电路仿真工具即Proteus用于绘制原理图、放置仿真模型并运行仿真。建议使用Proteus 8 Professional或更高版本。2. 搭建Proteus仿真电路原理图电路原理图是仿真的基础。我们将按照功能模块在Proteus ISIS中逐步搭建整个系统。2.1 创建新工程与添加主控芯片打开Proteus ISIS新建一个工程File-New Project。设置工程名称和保存路径。在元件选择模式快捷键P打开元件库。在关键词中输入STM32F103C8从结果中选择STM32F103C8通常来自STM32F103C8T6库并放置到图纸中。2.2 添加电源、晶振与复位电路虽然Proteus仿真对最小系统要求不严格但为了模拟真实环境建议添加电源放置POWER和GROUND符号。为STM32的VDD/VDDA引脚连接POWER代表3.3VVSS/VSSA引脚连接GROUND。晶振放置CRYSTAL元件连接至STM32的OSC_IN(PA0/PA8具体看型号) 和OSC_OUT引脚并各接一个20pF左右的电容 (CAP) 到地。在STM32的仿真模型中有时可以省略外部晶振模型使用内部时钟源。复位电路放置一个BUTTON按键和一个RES电阻如10kΩ。电阻一端接VDD另一端接STM32的NRST引脚按键并联在NRST和GND之间。按下按键时将NRST拉低触发复位。2.3 添加状态监测输入模块这部分电路用于模拟传感器信号输入。速度模拟电位器放置一个POT-HG滑动变阻器。将其一端接VDD3.3V另一端接GND中间滑动端连接至STM32的一个ADC通道引脚例如PA1(ADC1_IN1)。通过滑动变阻器改变分压模拟速度传感器输出的0-3.3V电压信号。温度模拟可调电压源放置一个DC VOLTMETER直流电压表用于观测和一个可调直流电压源。在元件库中搜索BATTERY或使用DC信号源。将电压源的正极通过一个限流电阻如1kΩ连接到STM32的另一个ADC通道引脚例如PA2(ADC1_IN2)。负极接地。调整电压源值例如0-1.5V对应0-150°C来模拟温度传感器如LM3510mV/°C的输出。电池电压模拟类似温度模拟使用另一个DC信号源模拟电池电压。考虑到分压采样可以连接一个电阻分压网络后再接入STM32的ADC通道引脚例如PA3(ADC1_IN3)。2.4 添加状态输出与显示模块LCD显示模块在元件库中搜索LM016L这是LCD1602的常用模型。放置到图纸中。连接其数据线D0-D7到STM32的任意一个8位GPIO端口例如PB0-PB7。连接控制线RS(数据/命令选择)、RW(读/写选择)、E(使能信号) 到STM32的其他GPIO引脚例如PA4,PA5,PA6。连接VSS到地VDD到电源VEE对比度调节通过一个电位器连接到电源或地来调节显示对比度。报警指示模块放置一个LED发光二极管和一个BUZZER蜂鸣器。LED阳极通过一个限流电阻如220Ω连接到STM32的GPIO引脚如PC13阴极接地。代码控制该引脚输出高电平点亮LED。蜂鸣器一端连接STM32的GPIO引脚如PC14另一端接地对于有源蜂鸣器或通过一个三极管驱动对于无源蜂鸣器。在仿真中简单连接一个BUZZER模型即可。2.5 添加调试接口放置一个VIRTUAL TERMINAL虚拟终端。将其RXD引脚连接到STM32的一个USART_TX引脚如PA9(USART1_TX)TXD引脚可以悬空或连接至STM32的USART_RX。在虚拟终端的属性中设置与代码中匹配的波特率如115200、数据位、停止位等。这样可以在仿真运行时通过串口打印调试信息。完成后的原理图核心部分应类似下图文字描述[STM32F103C8T6] | |-- PA1 (ADC1_IN1) --- POT-HG (速度模拟) |-- PA2 (ADC1_IN2) --- DC Source Resistor (温度模拟) |-- PA3 (ADC1_IN3) --- DC Source Voltage Divider (电池电压模拟) | |-- PB0-PB7 (GPIO) --- LM016L D0-D7 |-- PA4 (GPIO) ------- LM016L RS |-- PA5 (GPIO) ------- LM016L RW |-- PA6 (GPIO) ------- LM016L E | |-- PC13 (GPIO) ------ LED Resistor (超速报警) |-- PC14 (GPIO) ------ BUZZER (温度报警) | |-- PA9 (USART1_TX) -- VIRTUAL TERMINAL RXD |-- GND -------------- VIRTUAL TERMINAL GND3. 使用Keil MDK开发STM32监测程序电路设计完成后我们需要编写STM32的程序实现数据采集、处理和显示。3.1 创建Keil工程与基础配置打开Keil uVision5新建一个基于STM32F103C8设备的工程。在工程中我们需要添加或编写以下关键文件main.c主程序文件。stm32f10x_it.c中断服务程序文件可选但建议保留。system_stm32f10x.c系统初始化文件。startup_stm32f10x_md.s启动文件Keil通常会自动添加。外设库文件可以使用标准外设库StdPeriph Lib或HAL库。本文示例使用标准外设库需要添加stm32f10x_adc.c,stm32f10x_gpio.c,stm32f10x_rcc.c,stm32f10x_usart.c,stm32f10x_tim.c如果用到定时器等。lcd1602.c/lcd1602.h自定义的LCD1602驱动文件。配置工程选项Options for TargetTarget标签页确认晶振频率Xtal (MHz)设置为8.0如果使用外部8MHz晶振或根据仿真模型调整。Output标签页勾选Create HEX File这是生成Proteus可加载文件的关键。C/C标签页在Define框中添加USE_STDPERIPH_DRIVER。在Include Paths中添加标准外设库的头文件路径。3.2 编写外设驱动与核心逻辑以下是关键代码模块的编写要点和示例片段。1. LCD1602驱动实现 (lcd1602.c/h)这是一个基础且必须的模块需要严格按照LCD1602的时序编写。// lcd1602.h #ifndef __LCD1602_H #define __LCD1602_H #include stm32f10x.h #define LCD_RS_PIN GPIO_Pin_4 #define LCD_RS_PORT GPIOA #define LCD_RW_PIN GPIO_Pin_5 #define LCD_RW_PORT GPIOA #define LCD_E_PIN GPIO_Pin_6 #define LCD_E_PORT GPIOA #define LCD_DATA_PORT GPIOB // 使用PB0-PB7作为数据口 void LCD_Init(void); void LCD_WriteCmd(uint8_t cmd); void LCD_WriteData(uint8_t dat); void LCD_SetCursor(uint8_t row, uint8_t col); void LCD_ShowString(uint8_t row, uint8_t col, char *str); void LCD_ShowNum(uint8_t row, uint8_t col, uint32_t num, uint8_t len); #endif// lcd1602.c 中的初始化与写命令函数示例 void LCD_Init(void) { // 初始化GPIO时钟和引脚模式推挽输出... // 延时等待LCD上电稳定... LCD_WriteCmd(0x38); // 8位数据接口2行显示5x8点阵 LCD_WriteCmd(0x0C); // 显示开光标关闪烁关 LCD_WriteCmd(0x06); // 读写后地址指针自动加1 LCD_WriteCmd(0x01); // 清屏 DelayMs(5); } void LCD_WriteCmd(uint8_t cmd) { LCD_RS_PORT-BRR LCD_RS_PIN; // RS0写命令 LCD_RW_PORT-BRR LCD_RW_PIN; // RW0写操作 LCD_DATA_PORT-ODR (LCD_DATA_PORT-ODR 0xFF00) | cmd; // 输出命令 LCD_E_PORT-BSRR LCD_E_PIN; // E1 DelayUs(10); LCD_E_PORT-BRR LCD_E_PIN; // E0 DelayUs(100); }2. ADC多通道采集需要初始化ADC并循环采集我们连接的三个通道速度、温度、电压。// adc.c void ADC1_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); // 配置PA1, PA2, PA3为模拟输入 GPIO_InitStructure.GPIO_Pin GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AIN; GPIO_Init(GPIOA, GPIO_InitStructure); ADC_DeInit(ADC1); ADC_InitStructure.ADC_Mode ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode DISABLE; // 单通道非扫描 ADC_InitStructure.ADC_ContinuousConvMode DISABLE; // 单次转换 ADC_InitStructure.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel 1; ADC_Init(ADC1, ADC_InitStructure); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); } uint16_t ADC_GetValue(uint8_t ch) { ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5); ADC_SoftwareStartConvCmd(ADC1, ENABLE); while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); return ADC_GetConversionValue(ADC1); }3. 主程序逻辑 (main.c)主程序负责协调所有模块实现数据采集、计算、显示和报警判断的循环。#include stm32f10x.h #include lcd1602.h #include adc.h #include stdio.h #include usart.h // 串口初始化与发送函数 // 全局变量存储处理后的数据 float g_speed_kph 0.0; float g_temperature_c 0.0; float g_battery_voltage 0.0; // 报警阈值 #define SPEED_ALARM_THRESHOLD 30.0 // 公里/小时 #define TEMP_ALARM_THRESHOLD 80.0 // 摄氏度 #define VOLTAGE_ALARM_THRESHOLD_LOW 10.0 // 伏特 void System_Init(void) { // 初始化系统时钟、延时函数等 RCC_Configuration(); NVIC_Configuration(); SysTick_Init(); USART1_Init(115200); // 初始化串口用于调试 LCD_Init(); ADC1_Init(); // 初始化报警LED和蜂鸣器的GPIO为输出模式... } void Data_Acquisition_Process(void) { uint16_t adc_val; // 1. 采集速度通道 (PA1, ADC1 Channel1) adc_val ADC_GetValue(ADC_Channel_1); // 假设电位器电压0-3.3V对应速度0-100 km/h g_speed_kph (adc_val / 4095.0) * 3.3 * (100.0 / 3.3); // 简化计算 // 2. 采集温度通道 (PA2, ADC1 Channel2) adc_val ADC_GetValue(ADC_Channel_2); // 假设模拟LM3510mV/°C运放增益为1则电压(V) 温度(°C) * 0.01 g_temperature_c (adc_val / 4095.0) * 3.3 / 0.01; // 3. 采集电池电压通道 (PA3, ADC1 Channel3) adc_val ADC_GetValue(ADC_Channel_3); // 假设分压比为1/3则实际电压 ADC电压 * 3 g_battery_voltage (adc_val / 4095.0) * 3.3 * 3.0; } void Display_Update(void) { char buf[17]; // LCD1602每行16字符 结束符 // 第一行显示速度 sprintf(buf, Speed:%5.1f km/h, g_speed_kph); LCD_ShowString(0, 0, buf); // 第二行显示温度和电压 sprintf(buf, T:%3.0fC V:%4.1fV, g_temperature_c, g_battery_voltage); LCD_ShowString(1, 0, buf); } void Alarm_Check(void) { // 检查速度报警 if(g_speed_kph SPEED_ALARM_THRESHOLD) { GPIO_SetBits(GPIOC, GPIO_Pin_13); // 点亮LED } else { GPIO_ResetBits(GPIOC, GPIO_Pin_13); // 熄灭LED } // 检查温度报警 if(g_temperature_c TEMP_ALARM_THRESHOLD) { GPIO_SetBits(GPIOC, GPIO_Pin_14); // 触发蜂鸣器 } else { GPIO_ResetBits(GPIOC, GPIO_Pin_14); // 关闭蜂鸣器 } // 电池低压报警可以增加其他指示如LCD闪烁或另一个LED } int main(void) { System_Init(); LCD_ShowString(0, 0, TourCar Monitor); LCD_ShowString(1, 0, Initializing...); DelayMs(1000); LCD_Clear(); while(1) { Data_Acquisition_Process(); Display_Update(); Alarm_Check(); // 通过串口发送数据到Proteus虚拟终端用于调试 printf(S:%.1f T:%.1f V:%.1f\r\n, g_speed_kph, g_temperature_c, g_battery_voltage); DelayMs(500); // 每500ms更新一次 } }3.3 编译与生成HEX文件在Keil中完成代码编写后点击Rebuild(F7) 编译整个工程。确保编译0 Error(s), 0 Warning(s)。编译成功后在工程输出目录默认为Objects文件夹下会生成.hex文件例如project.hex。记下这个文件的路径。4. 联合仿真与功能验证这是将硬件设计与软件逻辑结合的关键一步。4.1 在Proteus中加载程序回到Proteus原理图界面。双击原理图中的STM32芯片打开其属性编辑对话框。在Program File一栏点击右侧的文件夹图标浏览并选择Keil生成的.hex文件。在Clock Frequency一栏输入与代码中系统时钟一致的频率例如8MHz如果使用内部HSI或72MHz如果使用PLL将外部8MHz晶振倍频。此处的频率必须与代码中SystemInit()函数配置的主频一致否则定时、串口波特率等都会出错。点击OK保存。4.2 运行仿真并观察结果点击Proteus ISIS界面左下角的Play(运行) 按钮启动仿真。观察LCD1602显示屏。应该能看到初始信息然后显示实时更新的速度、温度和电压值。打开虚拟终端窗口如果之前放置了。应该能看到串口打印的调试信息。交互测试测试速度变化用鼠标点击并拖动原理图中的电位器滑块改变其阻值。观察LCD上速度值的变化以及当速度超过30km/h时报警LED是否点亮。测试温度变化双击模拟温度信号的直流电压源修改其电压值例如从0.5V调到1.0V模拟温度从50°C升到100°C。观察LCD温度显示变化以及当温度超过80°C时蜂鸣器是否响起Proteus中蜂鸣器模型会显示一个声波符号并可能发出系统提示音。测试电压变化类似地调整模拟电池电压的电源值观察显示变化。4.3 使用虚拟仪器进行深度观测Proteus提供了强大的虚拟仪器可以帮助我们分析信号。示波器可以连接到STM32的任意GPIO或ADC输入引脚观察PWM波形、通信时序或模拟信号。逻辑分析仪非常适合分析LCD1602的RS,RW,E和数据线的时序验证驱动代码是否正确。电压表/电流表可以测量电路中任意点的电压电流。例如将示波器的A通道连接到STM32的ADC输入引脚如PA1然后调整电位器可以在示波器上看到输入电压的模拟变化。5. 仿真调试与常见问题排查在Proteus中仿真STM32问题通常出现在软硬件配置不匹配或时序错误上。5.1 常见问题现象与解决方案问题现象可能原因检查与解决步骤仿真无法启动或STM32模型显示红色1. 未加载HEX文件或路径错误。2. HEX文件损坏或编译选项错误。3. 时钟频率设置错误。1. 双击STM32确认Program File路径正确指向有效的.hex文件。2. 回到Keil确认编译无误并重新生成HEX。检查Options for Target-Output中已勾选Create HEX File。3. 确认Proteus中STM32的Clock Frequency与代码中系统主频一致。LCD1602无显示或显示乱码1. 接线错误RS, RW, E, 数据线。2. 初始化序列或时序不正确。3. 对比度引脚VEE电压不合适。4. 代码中端口操作错误。1. 对照原理图检查LCD引脚与STM32 GPIO的连接是否正确。2. 使用逻辑分析仪抓取LCD控制线时序与LCD1602数据手册对比。确保E使能脉冲宽度、数据建立/保持时间满足要求微秒级。3. 调整连接在VEE引脚上的电位器改变对比度。4. 检查lcd1602.c中的引脚定义和底层GPIO_Write函数是否正确。ADC采样值不变化或始终为01. ADC通道配置错误。2. GPIO未配置为模拟输入模式。3. 模拟信号源未正确连接或未启用。4. ADC采样周期太短。1. 检查ADC_RegularChannelConfig函数中的通道号是否与原理图连接一致。2. 确认ADC对应引脚的GPIO初始化模式为GPIO_Mode_AIN。3. 在Proteus中双击信号源如DC电压源确认其值非零且已启用。检查连线是否连通。4. 尝试增加ADC_SampleTime如ADC_SampleTime_239Cycles5。虚拟终端无输出或乱码1. 串口引脚连接错误TX接RX。2. 波特率、数据位、停止位不匹配。3. 代码中串口未初始化或初始化参数错误。1. 确认STM32的USART_TX引脚连接到了虚拟终端的RXD引脚。2. 双击虚拟终端检查波特率设置如115200是否与代码中USART_Init函数配置一致。3. 检查代码中是否使能了USART和对应GPIO的时钟并正确配置了引脚复用功能。报警功能LED/蜂鸣器不动作1. 报警阈值设置不合理。2. GPIO输出驱动能力或模式错误。3. 外设LED/蜂鸣器电路连接错误。1. 通过虚拟终端打印出采集到的数据确认其是否超过阈值。2. 检查报警相关GPIO的初始化是否为推挽输出模式GPIO_Mode_Out_PP。3. 在Proteus中可以用电压探针测量报警GPIO引脚的电平看代码是否成功控制其高低变化。5.2 调试技巧使用Proteus与Keil的联合调试可选对于复杂问题可以尝试使用Proteus的远程调试功能与Keil进行联调。在Proteus中菜单Debug-Use Remote Debug Monitor。在Keil中需要配置调试器为Proteus VSM Simulator。这通常需要安装一个名为VDM(Virtual Debug Manager) 的插件并配置TCP/IP连接至Proteus。配置成功后可以在Keil中设置断点、单步执行、查看变量和寄存器同时观察Proteus中电路的反应。注意联合调试配置相对复杂且对版本兼容性要求高。对于本项目级别的仿真通过虚拟终端打印日志和虚拟仪器观测信号通常足以定位大部分问题。6. 项目优化与扩展方向完成基础仿真后可以从以下几个方面深化和扩展这个项目使其更贴近实际工程。6.1 软件层面的优化使用DMA进行ADC采集当前代码在主循环中轮询ADC效率低且可能影响显示刷新。可以配置ADC的连续扫描模式并启用DMA让ADC在后台自动循环采集多个通道采集完成后通过DMA中断通知主程序主程序直接读取处理好的数据。加入滤波算法ADC采样值可能存在抖动。可以在软件中对连续几次的采样值进行平均滤波或中值滤波使显示更稳定。状态机与模块化将数据采集、显示更新、报警判断、通信等任务模块化并使用状态机或实时操作系统如FreeRTOS的思想来管理提高代码的可维护性和可扩展性。参数标定与校准在Data_Acquisition_Process函数中我们使用了简单的线性公式将ADC值转换为物理量。实际项目中需要标定。可以设计一个校准模式通过按键输入已知物理量自动计算并存储转换系数到STM32的Flash中。6.2 硬件仿真层面的扩展增加更多传感器在Proteus中尝试添加更多传感器模型如超声波测距模块SRF04、红外避障传感器、陀螺仪/加速度计通过I2C/SPI接口模型模拟。加入无线通信添加一个虚拟的蓝牙HC-05模型或Wi-Fi模块模拟将监测数据发送到上位机或手机APP。设计上位机界面使用Proteus的COMPIM元件与电脑的实际串口连接然后使用Pythonpyserial、C#或LabVIEW等工具编写一个简单的上位机程序接收并图形化显示车辆状态数据。模拟车辆控制增加电机驱动电路如L298N模型和直流电机模型通过STM32的PWM控制电机转速实现一个简单的速度闭环控制仿真。6.3 从仿真到实物的注意事项仿真成功是迈向实物制作的重要一步但两者仍有差异电源与去耦实物中必须在STM32的每个电源引脚附近放置去耦电容通常为100nF和10uF仿真中可以省略但实物必须加上。驱动能力仿真中LED直接接GPIO可能工作实物中必须串联限流电阻220Ω-1kΩ。驱动蜂鸣器或电机通常需要三极管或MOS管。晶振与负载电容仿真对时钟要求宽松实物中外部晶振的负载电容通常两个20pF必须根据晶振参数精确选择。下载与调试接口仿真直接加载HEX文件实物需要通过ST-LINK、J-Link或串口进行程序下载和调试。需要在原理图中预留SWD(SWCLK, SWDIO) 或JTAG接口。PCB布局布线仿真不涉及PCB但实物制作时模拟信号如ADC输入走线要远离数字信号和电源线以减少干扰。通过这个完整的Proteus仿真项目你不仅掌握了STM32F103C8T6的基础外设编程更重要的是理解了如何在一个虚拟的、可控的环境中构建和验证一个嵌入式系统。这种“先仿真后实物”的开发流程能极大提高复杂嵌入式项目的开发效率和成功率。接下来你可以尝试将本项目的核心代码移植到真实的STM32开发板上并对照排查清单逐一解决从仿真到实物可能遇到的新问题。