土木本科生的STM32探索之旅:ADC+DMA采集光敏电阻,usart串口发送到电脑串口助手

发布时间:2026/10/24 3:48:06

土木本科生的STM32探索之旅:ADC+DMA采集光敏电阻,usart串口发送到电脑串口助手 一、项目背景与原理1.1 项目目标本项目的核心目标是用 STM32 自带的 ADC 读取光敏电阻的模拟电压值利用 DMA 实现数据的自动传输解放 CPU 资源将采集到的数据通过 USART 串口发送到电脑在串口助手上实时显示1.2 关键技术原理光敏电阻光照越强电阻值越小。通过分压电路将电阻变化转化为电压变化再由 ADC 采集电压值。ADC模数转换器将光敏电阻输出的连续模拟电压转换为单片机能处理的数字信号12 位精度数值范围 0~4095。DMA直接存储器访问让数据从 ADC 外设直接传输到内存无需 CPU 干预实现高效连续采样。USART 串口通信将采集到的数字数据通过串口发送到电脑端的串口助手进行显示。二、硬件连接我使用的是 STM32F103VET6 开发板硬件连接非常简单光敏电阻电路由于是集成在STM32F103VET6 开发板上的不用进行硬件的连接下面我就放上它的原理图。我对原理图的认识如下可能存在错误若有理解错误的地方请大家谅解电路分为两路独立的信号采集通道最终都通过排针J3连接到 STM32 的PC1和PC2引脚ADC1 输入通道。通道 12PC2光敏电阻分压采集通道。通道 11PC1可调分压采集通道。此张表格信息来自高博士ppt或哔哩哔哩网课以上图片的解释来自AI。若是大家仍然有不理解的地方可以参考以下链接的课程内容。[13-02]STM32的ADC外设详解_哔哩哔哩_bilibili串口连接STM32 的USART1_TXPA9接 USB 转 TTL 模块的RXSTM32 的USART1_RXPA10接 USB 转 TTL 模块的TX开发板和 USB 转 TTL 模块的GND共地。三、CubeMX 配置硬核操作过程3.1 基础配置新建工程ADC_DMA_USART_2选择对应的 STM32F103VET6 芯片。配置 RCC 时钟使用外部晶振将系统时钟配置为 72MHz。配置 SYS选择 Serial Wire 调试模式。3.2 ADC1配置模式选择Scan Conversion Mode 扫描模式 关闭Continuous Conversion Mode 连续转换 开启转换通道数Number Of Conversion 设置为 2通道配置Rank1ADC1_IN11 PC1 电位器Rank2ADC1_IN12 PC2 光敏电阻采样时间都设为55.5 Cycles数值更稳定这个adc1选择了11和12通道时钟会跳出来一个红色的警告我把右下角这里调整了一下红色的警告就消失了3.3 DMA 配置在ADC1设置中开启DMA请求。3.4 USART 配置打开USART1模式选择异步通信。波特率设置为115200数据位 8无校验位停止位 1。配置完成后点击菜单栏上面的小齿轮生成初始化代码。进入到main.c代码增加用户代码以及计算的公式。借助AI工具它提供了一定的代码给我们软件自己会生成一定代码会有点代码重复#include stdio.h //标准输入输出头文件支持printf、scanf #include string.h // 字符串处理头文件支持strlen、strcmp、strcpy等 ADC_HandleTypeDef hadc1; DMA_HandleTypeDef hdma_adc1; UART_HandleTypeDef huart1;代码在软件中粘贴后的情况#define ADC_DMA_BATCH_LEN 2 //ADC DMA一次搬运数据个数 uint16_t adc_dma_buffer[ADC_DMA_BATCH_LEN]; //ADC DMA接收缓冲区存放ADC采样原始值 uint8_t adc_dma_cplt_flg 0; // ADC DMA传输完成标志位0未完成1完成 #define ADC_VREF_PLUS 3300.0f //ADC参考电压 3.3V单位mV #define ADC_RESOLUTION 4095.0f //ADC分辨率 12位 最大数值 0~4095代码在软件中粘贴后的情况由于写本篇博客文章中间有断开写文章的时间不是连续不是一气呵成的。中间可能就有一点问题且代码是基于AI辅助做成的为了大家方便我这里就把main.c代码直接放在了下方。/* USER CODE BEGIN Header */ /** ****************************************************************************** * file : main.c * brief : Main program body ****************************************************************************** * attention * * Copyright (c) 2026 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. ****************************************************************************** */ /* USER CODE END Header */ #include main.h #include stdio.h #include string.h ADC_HandleTypeDef hadc1; DMA_HandleTypeDef hdma_adc1; UART_HandleTypeDef huart1; /* USER CODE BEGIN PV */ #define ADC_DMA_BATCH_LEN 2 uint16_t adc_dma_buffer[ADC_DMA_BATCH_LEN]; uint8_t adc_dma_cplt_flg 0; #define ADC_VREF_PLUS 3300.0f #define ADC_RESOLUTION 4095.0f /* USER CODE END PV */ /* USER CODE BEGIN 0 */ float ADC_Value_To_Volt(uint16_t adc_value) { return (float)adc_value * ADC_VREF_PLUS / ADC_RESOLUTION / 1000.0f; } float Volt_To_LightRes(float volt) { return (volt * 10.0f) / (3.3f - volt); } void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { if (hadc-Instance ADC1) { HAL_ADC_Stop_DMA(hadc1); adc_dma_cplt_flg 1; } } /* USER CODE END 0 */ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_ADC1_Init(void); static void MX_USART1_UART_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_DMA_Init(); MX_ADC1_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ HAL_ADC_Start_DMA(hadc1, (uint32_t *)adc_dma_buffer, ADC_DMA_BATCH_LEN); /* USER CODE END 2 */ while (1) { if (adc_dma_cplt_flg) { char buf[64]; float light_volt ADC_Value_To_Volt(adc_dma_buffer[1]); float light_res Volt_To_LightRes(light_volt); sprintf(buf, LIGHT: ADC%d | %.2fV | %.2fkΩ\r\n, adc_dma_buffer[1], light_volt, light_res); HAL_UART_Transmit(huart1, (uint8_t *)buf, strlen(buf), 100); adc_dma_buffer[0] 0; adc_dma_buffer[1] 0; HAL_ADC_Start_DMA(hadc1, (uint32_t *)adc_dma_buffer, ADC_DMA_BATCH_LEN); adc_dma_cplt_flg 0; } HAL_Delay(200); } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit {0}; RCC_OscInitStruct.OscillatorType RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL RCC_PLL_MUL9; if (HAL_RCC_OscConfig(RCC_OscInitStruct) ! HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(RCC_ClkInitStruct, FLASH_LATENCY_2) ! HAL_OK) { Error_Handler(); } PeriphClkInit.PeriphClockSelection RCC_PERIPHCLK_ADC; PeriphClkInit.AdcClockSelection RCC_ADCPCLK2_DIV6; if (HAL_RCCEx_PeriphCLKConfig(PeriphClkInit) ! HAL_OK) { Error_Handler(); } } static void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig {0}; hadc1.Instance ADC1; hadc1.Init.ScanConvMode ADC_SCAN_ENABLE; hadc1.Init.ContinuousConvMode ENABLE; hadc1.Init.DiscontinuousConvMode DISABLE; hadc1.Init.ExternalTrigConv ADC_SOFTWARE_START; hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion 2; if (HAL_ADC_Init(hadc1) ! HAL_OK) { Error_Handler(); } sConfig.Channel ADC_CHANNEL_11; sConfig.Rank ADC_REGULAR_RANK_1; sConfig.SamplingTime ADC_SAMPLETIME_55CYCLES_5; if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { Error_Handler(); } sConfig.Channel ADC_CHANNEL_12; sConfig.Rank ADC_REGULAR_RANK_2; sConfig.SamplingTime ADC_SAMPLETIME_55CYCLES_5; if (HAL_ADC_ConfigChannel(hadc1, sConfig) ! HAL_OK) { Error_Handler(); } } static void MX_USART1_UART_Init(void) { huart1.Instance USART1; huart1.Init.BaudRate 115200; huart1.Init.WordLength UART_WORDLENGTH_8B; huart1.Init.StopBits UART_STOPBITS_1; huart1.Init.Parity UART_PARITY_NONE; huart1.Init.Mode UART_MODE_TX_RX; huart1.Init.HwFlowCtl UART_HWCONTROL_NONE; huart1.Init.OverSampling UART_OVERSAMPLING_16; if (HAL_UART_Init(huart1) ! HAL_OK) { Error_Handler(); } } static void MX_DMA_Init(void) { __HAL_RCC_DMA1_CLK_ENABLE(); HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); } static void MX_GPIO_Init(void) { __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); } void Error_Handler(void) { __disable_irq(); while (1) { } } #ifdef USE_FULL_ASSERT void assert_failed(uint8_t *file, uint32_t line) { } #endif大家可以对比一下借助ai分析解析一下代码内容3.5 编译无误以后将代码烧录进单片机3.6 打开串口助手观察代码运行后的实验情况串口助手有网页版也有电脑端的大家可以自行选择。为了方便我这里就用了波特律动网页版串口助手网址如下串口设置光敏电阻无遮挡的情况LIGHT: ADC816 | 0.66V | 2.49kΩ 大致在这个范围内波动光敏电阻手指遮挡的情况LIGHT: ADC2734 | 2.20V | 20.09kΩ 大致在这个范围内波动光敏电阻特性光线越强 → 电阻越小光线越暗 → 电阻越大数据算是符合物理规律相关的操作视频请各位小伙伴关注我的哔哩哔哩视频动态实验有问题的话可以在博客的评论区或者视频的评论区留言感谢各位小伙伴的支撑大家一起共同进步不会c的小谢的个人空间-不会c的小谢个人主页-哔哩哔哩视频3.7 基于AI的实验总结
延伸阅读

更多相关文章

2026/10/24 3:48:06

2000–2024年 企业创新韧性指标EIR数据 xlsx

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/24 3:48:06

1985-2024年 各地级市污水处理厂详细指标数据 xlsx

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/24 4:33:10

MINIZIP压缩解压缩:zlib分工、静态库集成与内存流打包

简介:面向需要在C/C项目中集成ZIP压缩解压能力的开发者,这份MINIZIP工程包提供了可直接链接使用的静态库与配套头文件。MINIZIP基于ZLIB构建,接口简洁、体积轻量,适合嵌入式与资源受限环境,并支持跨平台调用和UTF-8等多…

2026/10/24 4:33:10

Vue+Python进销存系统实战:从库存管理到可视化大屏落地

干了这么多年开发,最常被小企业主问的一句话是:“能不能帮我那把Excel里的库存理清楚?”这其实不是表格美化问题,而是整个进销存流程数字化的问题。最近刚上线了一套vuepython的B/S架构进销存管理系统,项目编号是i59u2…

2026/10/24 4:33:10

水豚鼠标助手:让投影课堂鼠标变清晰电子教鞭

教室投影幕布亮起来的那一刻,满屏课件里那个又细又白的鼠标箭头总是被光线“吃掉”。学生频繁问“老师你说的是哪一行”,我不得不反复走到屏幕前用手比划,一节课下来在讲台和投影仪之间来来回回走了十几趟。后来我试着在电脑上装了水豚鼠标助…

2026/10/24 4:33:10

小熊猫C++免安装版:便携工具链配置与GDB调试实战

简介:小熊猫Dev-C免安装包是面向C/C初学者、教学者及轻量开发者的集成开发环境,基于已停止更新的Dev-C持续改进,解压后无需额外配置即可使用。7z压缩包约59.64MB,含约2000个文件,以h/hpp标准头文件、py辅助脚本、a静态…

2026/10/24 4:33:10

大疆司空平台OpenAPI无权限异常排查思路与实战

先说一个我实际见过的现象:平台侧文档看得明明白白,AppKey配了,权限也勾了,调一个普通接口却报403,群里排查半天,最后发现只是接口的权限点在测试环境和生产环境不一致。这类问题在大疆司空平台OpenAPI接入…

2026/10/24 4:28:10

ACPI驱动PCI配置空间访问调用链解析:从Handler到GetPciAddress

1. 从一条调用栈说起有段时间我在调试一个设备驱动加载失败的案例,现象很奇怪:设备在资源管理器里报“无法启动(代码 10)”,但电源和中断资源看起来都分配正常。我把调试器挂上去,在关键路径上下了断点&…

2026/10/23 22:56:35

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/24 0:02:40

MATLAB缩进快捷键与批量格式化实战指南

1. 被自动缩进折磨的那些年如果你写过MATLAB代码,大概率经历过这种场景:从某个文档、网页或者聊天记录里复制了一段代码,粘贴进编辑器之后,每一行前面都带着莫名其妙的空格,有的行首是四个空格,有的是一个T…

2026/10/24 0:02:40

用Poco实现Qt风格信号与槽的跨平台C++方案

简介:本资源是一份面向C中级开发者的技术实践工程,聚焦于在非Qt框架环境下模拟实现Qt核心通信机制——信号与槽,借助Poco网络库的事件系统完成解耦式对象通信。适用于需在跨平台C项目中引入松耦合回调机制、但受限于无法集成Qt依赖的开发场景…

2026/10/24 0:02:40

ESXi裸机虚拟化安装指南:从硬件兼容到虚拟机部署

1. 为什么还要折腾ESXi:从一台闲置机器说起手里攒了几台淘汰下来的迷你主机,配置不算差,i5加16G内存,扔了可惜,装个桌面系统又觉得浪费。这种场景下,ESXi就成了一个绕不开的选择。它是一套裸机虚拟化平台&a…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑