针对您在STM32F103C8T6上使用ADC时程序无法正常运行的问题,结合startup警告和串口输出异常,以下是系统的解决方案:
核心问题分析
- 启动文件警告:STM32F103C8T6属于中等容量(Medium Density)设备,若使用HD(High Density)或CL(Connectivity Line)启动文件会导致硬件不匹配。
- ADC配置问题:时钟分频、采样时间、校准流程错误会导致ADC无法工作。
- 串口无输出:系统崩溃或阻塞导致串口无法输出调试信息。
解决方案
1. 修复启动文件(关键步骤)
- 正确启动文件:使用
startup_stm32f10x_md.s(MD = Medium Density)
- 操作步骤:
- 移除现有启动文件(如
startup_stm32f10x_hd.s)
- 添加MD启动文件路径:
STM32F10x_StdPeriph_Lib_V3.5.0LibrariesCMSISCM3DeviceSupportSTSTM32F10xstartuparm
- KEIL工程配置:
- 启用
STM32F10X_MD 宏定义(Options for Target → C/C++ → Preprocessor Symbols)

2. ADC关键配置修复
// ADC初始化修正代码
void ADC1_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
// 1. 时钟配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 72MHz/6=12MHz (<14MHz上限)
// 2. GPIO配置(PA1为ADC输入)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入模式
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3. ADC参数配置
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 单通道禁用扫描
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;// 连续转换
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// 4. 通道采样时间配置(关键!)
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
// 5. 校准流程(必须执行)
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
// 6. 启动转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
3. 串口调试修复
// 确保串口初始化正确(USART1示例)
void USART1_Init(uint32_t baudrate) {
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// TX (PA9)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// RX (PA10)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStruct);
USART_InitStruct.USART_BaudRate = baudrate;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1, &USART_InitStruct);
USART_Cmd(USART1, ENABLE);
}
// 重定向printf
int fputc(int ch, FILE *f) {
USART_SendData(USART1, (uint8_t)ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return ch;
}
4. 主函数逻辑优化
int main(void) {
uint16_t adc_value;
// 初始化顺序很重要!
SystemInit(); // 系统时钟初始化(默认72MHz)
USART1_Init(115200);
ADC1_Init();
printf("System Startedrn"); // 测试串口
while(1) {
if(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)) {
adc_value = ADC_GetConversionValue(ADC1);
printf("ADC: %drn", adc_value); // 打印采样值
ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
}
Delay_ms(100); // 简单延时
}
}
调试技巧
最小系统测试:
- 暂时注释ADC代码,只保留串口输出"Hello World",验证基础系统
- 用万用表测量PA1引脚电压(0~3.3V)
常见错误排查表: |
现象 |
可能原因 |
解决措施 |
|---|
程序完全不运行 |
启动文件错误 |
替换为MD启动文件 |
ADC返回值始终为0 |
GPIO未配置为模拟模式 |
检查GPIO_Mode_AIN |
ADC值固定为4095 |
输入电压超过3.3V |
检查传感器供电 |
采样值跳动剧烈 |
未执行校准 |
添加ADC校准流程 |
串口输出乱码 |
波特率不匹配 |
核对终端和代码波特率设置 |
硬件检查:
- 确保BOOT0引脚接地(正常启动模式)
- 检查NRST复位电路(10K电阻+104电容)
- ADC输入电压范围:0~3.3V(严禁超过)
经过上述修正后,90%以上的ADC异常问题可解决。如果仍有问题,建议使用ST-Link单步调试,观察ADC寄存器状态(特别是ADC_CR2和ADC_SR寄存器)。