STM32之ADC详解

一、ADC概述       

        ADC(模拟量转数字量转换器),在 STM32 开发中,利用 ADC 端口的电压数据,转换为对应的具体数字量数据内容。可通过 ADC 方式获取常用数据内容有:

  • 光敏电阻、电池电量、油箱油量

        ADC 转换的数据,可用于执行器控制行为,如低电量警告、油箱油量不足警告(即【阈值警告】 【阈值处理】 ,通过设置阈值,数据达到或超出时触发相应警示或控制逻辑 ) 。

二、ADC 工作原理

1.ADC 的主要特征

2. ADC 内部架构框图

一、整体架构与核心组件

  1. 模拟输入部分
    • 外部输入通道ADCx_IN0 ~ ADCx_IN15 是 16 组外部模拟信号输入引脚,可连接光敏电阻、电压传感器等外设,采集外部模拟电压。
    • 内部传感器:集成温度传感器(需结合 V_REFINT 参考电压工作 ),用于检测芯片内部温度,方便实现温度补偿、过热保护等功能。
    • 模拟多路开关:最多支持 16 通道规则通道、4 通道注入通道切换,按需选通一路模拟信号送入转换器,实现多通道分时复用。
  2. 转换核心
    • 模拟至数字转换器:采用逐次逼近法,以 ADCCLK(来自 ADC 预分频器,需配置分频保证时钟稳定 )为基准时钟,将模拟电压与内部基准电压比较,逐位确定数字量,完成 0~3.3VVref+ = 3.3VVref- = 0V 时 )模拟信号到 12 位数字量(范围 0000 0000 0000 ~ 1111 1111 1111 )的转换。
    • 参考电压V_REF+V_REF- 是 ADC 转换基准,决定量程。3.3V 输入时,电压分辨率为 3.3V/4096 ≈ 0.0008V,即 1 个数字量对应约 0.8mV 电压变化。

二、通道与转换模式

  1. 规则通道
    • 通道特点:最多 16 通道,用于常规、连续的多通道采样,像循环采集电池电压、多路传感器数据。
    • 触发控制:通过 EXTSEL[2:0] 选择定时器触发源(如 TIM1_CH1TIM2_CH2 等 ),实现定时采样;也可由外部中断触发,灵活适配不同场景需求。
    • 数据存储:转换结果存入 规则通道数据寄存器(16 位),支持 DMA 请求,转换完成后直接通过 DMA 传输数据到内存,减轻 CPU 负担。
  2. 注入通道
    • 通道特点:最多 4 通道,优先级高于规则通道,用于紧急、需快速响应的采样(如安全阈值监测 )。
    • 触发控制:由 JEXTSEL[2:0] 选定时器触发源(如 TIM1_TRGOTIM4_CH3 等 ),或 JEXTRIG 控制位手动触发。
    • 数据存储:结果存入 注入通道数据寄存器(4×16 位),可独立处理,快速响应特殊需求。

三、中断与阈值监测(模拟看门狗)

  1. 中断机制
    • 转换结束中断:规则通道(EOC)、注入通道(JEOC)转换完成时,置标志位并可使能中断,触发 ADC中断 到 NVIC,通知 CPU 读取数据,实现实时处理。
    • 阈值中断:模拟看门狗比较转换结果与 阈值高限(12 位)阈值低限(12 位),超出范围置 AWD 标志位,使能中断(AWDIE)后触发中断,用于电压超限报警(如电池过压 / 欠压、传感器异常 )。
  2. 模拟看门狗:实时监控 ADC 转换结果,一旦超出设定阈值,立即触发中断或标志位,快速响应异常,保障系统安全。

四、工作流程总结

  1. 信号输入:外部 / 内部模拟信号经 ADCx_IN 或内部传感器进入,模拟多路开关选通通道。
  2. 触发转换:规则 / 注入通道通过定时器、外部中断等触发,启动 模拟至数字转换器 工作。
  3. 数据转换:逐次逼近法转换模拟电压为 12 位数字量,存入对应数据寄存器。
  4. 结果处理:可触发中断通知 CPU 读取,或通过 DMA 传输数据;模拟看门狗实时监测,超限触发报警,实现从模拟信号采集到数字信号处理、异常响应的完整流程,支撑 STM32 对模拟量的精准采集与智能控制 。

五、举例讲解

一、场景与需求

  • 常规任务:每隔 100ms 采集 3 路信号
    • 电池电压(ADC1_IN0,规则通道)
    • 车外温度(ADC1_IN1,规则通道,接温度传感器)
    • 光照强度(ADC1_IN2,规则通道,接光敏电阻)
  • 紧急任务:实时监测电池电压,一旦超出 2.8V~3.6V 范围,立即触发报警
    • 复用电池电压信号到 ADC1_IN8(注入通道,优先级更高)

二、工作流程拆解(多转换触发逻辑)

1. 硬件连接与通道准备
  • 外部信号接入
    • 电池电压、温度传感器、光敏电阻的模拟信号,分别接到 ADC1_IN0/IN1/IN2(规则通道);
    • 电池电压同时接到 ADC1_IN8(注入通道,用于紧急阈值监测)。
  • 多路开关配置
    • 规则通道:使能 IN0/IN1/IN2,共 3 路,用于循环采样;
    • 注入通道:使能 IN8,共 1 路,用于紧急监测。
2. 触发转换的两种方式

(1) 规则通道触发(常规采集)

 
  • 触发源:定时器触发(如 TIM3_TRGO,配置为 100ms 触发一次)。
  • 流程
    ① 定时器每 100ms 产生一个触发信号 → 触发规则通道转换;
    ② 模拟多路开关按顺序选通 IN0IN1IN2
    ③ ADC 依次对 3 路信号进行转换(逐次逼近法),结果存入规则数据寄存器
 

(2) 注入通道触发(紧急监测)

 
  • 触发源:软件触发 + 模拟看门狗(双重保障)。
  • 流程
    ① 初始触发:系统启动时,手动触发一次注入通道转换(读取初始电池电压);
    ② 持续监测:ADC 转换后,模拟看门狗自动比较结果与阈值(2.8V~3.6V):
    • 若在范围内:不触发中断,等待下一次规则通道触发时,顺带重新触发注入转换(或定时触发);
    • 若超出范围:立即置 AWD 标志位 → 触发注入中断 → CPU 跳转到中断函数处理(如点亮故障灯、记录日志)。
3. 数据处理与响应
  • 规则通道数据
    转换完成后,通过 DMA 自动将 3 路结果搬运到内存数组 → 程序读取数组,计算电池电量、温度值、光照强度,更新仪表盘显示。

  • 注入通道数据
    若触发中断(电压超限):
    ① 中断函数中读取注入数据寄存器 → 获取实时电池电压;
    ② 执行紧急逻辑(如:点亮红色故障灯、发送 CAN 报警帧、限制非关键用电设备)。

4. 多转换并行的关键逻辑
  • 优先级:注入通道优先级 > 规则通道。若规则通道转换中触发注入中断,ADC 会暂停规则转换,优先处理注入通道,保障紧急任务响应。
  • 资源复用:同一模拟信号(如电池电压)可接入多个通道(规则 + 注入),实现 “常规轮询 + 紧急监测” 的差异化需求。

3. ADC 数据转换规则

ADC 转换核心信息:

  • 转换方法:ADC 转换器采用逐次逼近法进行数据转换
  • 采样精度:12 位,数值范围 0000 0000 0000 ~ 1111 1111 1111(对应十进制 0 ~ 4095 )
  • 参考电压Vref+ = 3.3VVref- = 0V
  • 电压分辨率3.3V / 4096 ≈ 0.0008V(即 1 个 ADC 数值对应约 0.8mV 电压 )
  • 示例场景:假设 ADC 读取到电压为 1.83V ,可基于上述参数换算数字量

三、ADC 编程实现和相关寄存器

1.  ADC 时钟问题

  • 分析依据:根据原理图进行分析
  • 引脚与通道对应:当前引脚为 PF8 引脚,其对应的 ADC 通道是 ADC3_IN6
  • 时钟归属:ADC3 所在的时钟为 APB2 总线时钟,即 ADC3 的时钟由 APB2 总线提供 ,在 STM32 中,不同的外设会挂载在不同的总线(如 APB1、APB2 等 )上,其时钟由对应总线时钟源分频等配置后提供,这里明确了 ADC3 依赖 APB2 总线时钟来进行工作时序的驱动 。

2. ADC_CR1 寄存器

3. ADC_CR2 寄存器

        当前寄存器主要控制,ADC 采用数据通道,通信触发规则,数据对齐方式,校验和 ADC开启。

ADC_CR2寄存器的配置内容:

  • SWSTART(位 22):置 1,用于开始规则通道的转换
  • EXTTRIG(位 20):置 1,使能规则通道的外部触发转换模式
  • EXTSEL(位 19 - 17):设为 111,选择启动规则通道组转换的外部事件
  • ALIGN(位 11):置 0,配置数据右对齐
  • RSTCAL(位 3):置 1,执行复位校准操作
  • CAL(位 2):置 1,进行 A/D 校准
  • CONT(位 1):置 1,使能连续转换模式
  • ADON(位 0):置 1,开启 A/D 转换器 ,各配置项共同定义了 ADC 的转换启动、触发、校准、数据对齐及运行模式等关键参数 。

总结理解:

        当 EXTRIG 位置为 0 的时候,转换完全是由软件也就是手动触发,每次将 SWSTART 置为 1 的时候触发一次转换,转换的配置按照预设的通道序列(ADC_SQRx)、采样时间(ADC_SMPRx)、分辨率(ADC_CR1.RES)等位配置执行,硬件会在启动转换的同时自动清除 SWSTART 位。

 

        而当 SWSTART 置 1、EXTRIG 也为 1,且 EXTSEL 为 111 时,转换的触发源仍为软件写 SWSTART=1,但触发信号需先进入外部触发选择系统,再由该系统转发给 ADC 以触发转换;转换配置同样遵循预设的通道、采样时间等位配置,硬件也会在启动转换时自动清除 SWSTART 位,核心是通过 “外部触发框架” 实现软件触发,可复用外部触发的联动功能。

两种软件触发场景的关键差异对比表

维度EXTRIG=0 + 写 SWSTART(纯软件触发)EXTRIG=1 + EXTSEL=111 + 写 SWSTART(软件模拟外部触发)
触发路径软件 → 直接发送触发信号给 ADC,无中间环节软件 → 写 SWSTART 生成信号 → 外部触发选择系统(EXTSEL 控制)→ 转发信号给 ADC
硬件联动能力仅执行基础转换,结果需软件手动读取(或单独配置中断)可复用外部触发的配套功能,如转换后自动启动 DMA 传输、触发特定中断等
触发延迟低(信号直达 ADC,无额外逻辑开销)略高(多一层外部触发系统的信号转发,存在微小延迟)
核心适用场景简单手动触发需求,如初始化检测、按键触发单次采集,无需额外硬件联动需软件触发 + 外部触发配套功能的场景,如软件手动触发后希望 DMA 自动搬运数据,或统一触发逻辑框架
SWSTART 清除时机硬件启动转换的同时自动清 0硬件启动转换的同时自动清 0(与纯软件触发一致)
外部事件干扰无(外部触发系统已关闭,定时器、GPIO 等无法触发)无(EXTSEL=111 仅响应软件 SWSTART 信号,其他外部事件不干扰)

4. ADC_SMPR 寄存器

5. ADC_SQR 寄存器

在 ADC 规则通道配置中,需两个寄存器配合实现:

  • ADC_SQR1:用于配置规则通道开启的数量(即决定要转换的规则通道总数 )。
  • ADC_SQR3:用于配置 SQ1(规则通道序列中的第 1 个转换通道 )寄存器位对应的具体通道,此处为 ADC3_IN6(指定第 1 个转换的规则通道是 ADC3 的 IN6 通道 ) 。

总结理解:

        当配置了多个规则序列(如 SQ1 = 通道 A、SQ2 = 通道 B)并开启连续转换(CONT=1)时,扫描模式(SCAN)的状态决定了 ADC 的采集行为:开启扫描模式(SCAN=1)时,ADC 会按 SQ1→SQ2 的顺序循环采集所有配置通道,转换结果交替存入 ADC_DR(前序数据会被覆盖);关闭扫描模式(SCAN=0)时,ADC 仅重复采集 SQ1 通道,完全忽略其他序列配置,ADC_DR 中始终存储 SQ1 通道的最新数据。简言之,SCAN 位是多通道序列执行的总开关,控制 ADC 是否按完整序列顺序采集,还是仅固定采集第一个通道。

四、示例代码:

adc.c:

#include "adc.h"void LSEN_Init(void)
{// 1. RCC 时钟使能,需要提供 GPIOF 和 ADC3 RCC->APB2ENR |= (0x01 << 7) | (0x01 << 15);// 2. GPIOF --> PF8 模拟输入模式 ==> 0000GPIOF->CRH &= ~(0x0F);/*3. ADC 配置*//*3.1 ADC 预分配倍数配置因为当前 STM32F103ZET6 对应 72 MHz,ADCCLK 不得大于 14 MHz,预分频倍数最小可以选择 6*/RCC->CFGR &= ~(0x03 << 14);RCC->CFGR |= (0x02 << 14);/*3.2 配置 ADC 的工作通道选择工作通道为 ADC3_IN6,规则通道打开一个,配置 SQ1*/ADC3->SQR1 &= ~(0x0F << 20);ADC3->SQR3 &= ~(0x1F);ADC3->SQR3 |= 0x06;/*3.3 ADC 采用周期采样周期选择 239.5 + 12.5 最大 ADC 采样周期,可以获取到更大的数据精度。*/ADC3->SMPR2 |= (0x07 << 18);/*3.4. 配置 ADC CR 寄存器相关内容CR1- DUALMOD位 [19:16] : ADC 独立模式 ==> 0000- SCAN [位8] :  扫描模式关闭 ==> 0CR2- SWSTART [位22] : 开始转换规则通道 ==> 1- EXTTRIG [位20]:规则通道的外部触发转换模式 ==> 1- EXTSEL [位19:17]: 选择启动规则通道组转换的外部事件 ==> 111- ALIGN [位11]::数据对齐(Data alignment)  ==> 0 右对齐- CONT [位1]::连续转换(Continuous conversion) ==> 1*/ADC3->CR1 &= ~(0x0F << 16);ADC3->CR1 &= ~(0x01 << 8);ADC3->CR2 &= ~(0xFFFFFFFF);ADC3->CR2 |= (0x01 << 22);  // SWSTART [位22] : 开始转换规则通道 ==> 1ADC3->CR2 |= (0x01 << 20);  // EXTTRIG [位20]:规则通道的外部触发转换模式 ==> 1ADC3->CR2 |= (0x07 << 17);  // EXTSEL [位19:17]: 选择启动规则通道组转换的外部事件 ==> 111ADC3->CR2 &= ~(0x01 << 11); // ALIGN [位11]::数据对齐(Data alignment)  ==> 0 右对齐ADC3->CR2 |= (0x01 << 1);/*3.5 ADC 复位 + 校准ADC 自校准 + 重启过程- RSTCAL [位3]::复位校准(Reset calibration) ==> 1	- CAL [位2]::A/D校准(A/D Calibration) ==> 1- ADON [位0]::开/关A/D转换器(A/D converter ON/ OFF) ==> 1*/ADC3->CR2 &= ~(0x01); // 关闭 ADCDelay_ms(10);         // 延时 10 msADC3->CR2 |= 0x01;    // 打开 ADC/*开始复位校准,给予对应寄存器标志位 1,如果 ADC 复位校准结束对应寄存器位置硬件清除为 0*/ADC3->CR2 |= (0x01 << 3); // while 循环是等待当前复位校准结束 while ((ADC3->CR2 & (0x01 << 3)));Delay_ms(10); /*开始 A/D 校准,给予对应寄存器标志位 1,ADC A/D 校准之后对应寄存器位置硬件清除为 0*/ADC3->CR2 |= (0x01 << 2);// while 循环是等待当前 A/D 校准结束 while ((ADC3->CR2 & (0x01 << 2)));ADC3->CR2 |= 0x01;    // 打开 ADC
}u16 LSEN_GetValue(void)
{/*ADC->SR 状态寄存器 EOC [位1] 位置,如果数据未转换完成EOC 为 0 ,转换完成 EOC 为 1*/while (!(ADC3->SR & (0x01 << 1)));return ADC3->DR;}

adc.h:

#ifndef _ADC_H
#define _ADC_H#include "stm32f10x.h"#include "delay.h"/*** @brief 光敏电阻初始化函数*/
void LSEN_Init(void);u16 LSEN_GetValue(void);#endif

delay.c:

#include "delay.h"void Delay_us(u32 us)
{while (us--) {// 利用 __NOP() 操作占用 MCU 一次执行周期特征,调用 72 个 __NOP// 不建议使用 for 循环或者 while 循环,循环判断都需要占用一个 MCU 执行周期__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();}
}void Delay_ms(u32 ms)
{Delay_us(ms * 1000);
}

delay.h:

#ifndef _DELAY_H
#define _DELAY_H#include "stm32f10x.h"/*** @brief 延时微秒控制函数,延时单位是 us** @param us 延时微秒时间*/
void Delay_us(u32 us);/*** @brief 延时毫秒控制函数,延时单位是 ms** @param ms 延时毫秒时间*/
void Delay_ms(u32 ms);#endif

usart.c:

#include "usart1.h"USART1_Data usart1_val = {0};void USART1_Init(u32 brr)
{/*1. 时钟使能 GPIOA 和 USART1,两者都在 APB2 时钟控制USART1 对应位 14,GPIOA 对应位2*/RCC->APB2ENR |= (0x01 << 2) | (0x01 << 14);/*2. PA9 和 PA10 GPIO 配置PA9 是 MCU 的 TX 数据发送端,GPIO 工作模式选择【复用推挽输出模式】PA10 是 MCU 的 RX 数据发送端,GPIO 工作模式选择【浮空输入模式】*/GPIOA->CRH &= ~(0x00FF << 4);GPIOA->CRH |= 0x0B << 4;  // PA9 -->  TX【复用推挽输出模式】GPIOA->CRH |= 0x04 << 8;  // PA10 --> RX【浮空输入模式】/*3. USART1 串口配置3.1 8n1 配置,NRZ 数据格式配置,8个数据位,0 个校验位,1 个停止位3.2 USART1 对应 TE 和 RE 开启,打开 USART1 的发送数据和读取数据能力3.3 USART1 BRR 波特率配置*/// 3.1 8n1 配置,如果仅使用寄存器方式配置当前代码,可以省略一下过程// 当前代码是为了后续的 【标准库】和【Hal库】,也是代码逻辑的一部分USART1->CR1 &= ~(0x01 << 12); // 【8】USART1->CR1 控制寄存器对应 M (位12) 明确当前数据字长为 8 数据位USART1->CR1 &= ~(0x01 << 10); // 【n】USART1->CR1 控制寄存器对应 PCE (位10), 明确当前不使用校验位USART1->CR2 &= ~(0x03 << 12); // 【1】USART1->CR2 控制寄存器对应 STOP (位13,12), 限制当前数据停止位为 1// 3.2 USART1 对应 TE 和 RE 开启USART1->CR1 |= (0x03 << 2); // TE(位3) RE(位2) 进行赋值 1 开始操作// 3.3 USART1 BRR 波特率配置// 假设波特率是 115200 ==> USARTDIV 数据float usart_div = 72 * 1000 * 1000 / (16 * brr);// usart_div == 39.0625/*将 usart_div 进行拆解,分别对应整数部分和小数部分内容,提供给当前 USART1 中用于计算波特率对应寄存器位。*/int usart_div_Mantissa = (u32)usart_div;int usart_div_fraction = (u32)((usart_div - usart_div_Mantissa) * 16);// 两个数据进行组合 提供给 USART1 波特率寄存器的数据为 USART1->BRR |= (usart_div_Mantissa << 4) | usart_div_fraction;// 4. 启动 USART1 USART1->CR1 |= (0x01 << 13);
}void USART1_SendByte(u8 byte)
{/*利用 USART1_SR 寄存器,判断之前的数据内容是否发送完成,如果没有发送完成,本次发送操作进入【阻塞状态】如果 USART1_SR TC ==> 0 表示之前的数据发送未完成如果 USART1_SR TC ==> 1 表示之前的数据发送完毕TC Transmission Complete*/while (0 == (USART1->SR & (0x01 << 6)));/*将需要发送的数据存储到 USART1->DR 数据寄存器中,DR 会将数据直接提供给 TDR 寄存器,TDR 寄存器会将数据提供给移位寄存器,SR 寄存器 TC TC 寄存器位置 0发送完毕会将 SR 寄存器的中,TC 寄存器位置修改为 1*/USART1->DR = byte;
}void USART1_SendBuffer(u8 *buffer, u16 count) 
{while (count--){USART1_SendByte(*buffer);buffer++;}
}void USART1_SendString(const char * str) 
{while (*str){USART1_SendByte(*str);str++;}
}u8 USART1_ReceiveByte(void)
{u8 data = 0;/*判断在 USART1->SR 寄存器中,对应的 RXNE (Read data register not empty) 标志位如果没有数据可以收到,RXNE 为 0如果有数据可以读取,RXNE 为 1while 进行 RXNE 标志位判断,如果没有数据当前循环【阻塞后续代码】*/while (0 == (USART1->SR & (0x01 << 5)));data = (u8)USART1->DR; return data;
}/*
非重要知识点,仅实现 printf 函数功能重定向,可以实现
printf 打印操作数据 USART1 发送到 PC
*/
int fputc(int c, FILE *stream)
{USART1_SendByte(c);return c;
}void USART1_Interrupt_Enable(void)
{/*当前 USART1 的控制寄存器中,打开 IDLEIE 数据总线空闲中断使能打开 RXNEIE 数据总线空闲中断使能*/USART1->CR1 |= (0x01 << 4) | (0x01 << 5);/*设置当前 USART1 对应的中断优先级为 0001 在全局优先级设置为 2 的情况下  占先 0 次级 1*/NVIC_SetPriority(USART1_IRQn, 1); // 0001 占先 0 次级 1/*告知当前 MCU 使能对应的 USART1_IRQn 中断*/NVIC_EnableIRQ(USART1_IRQn);
}/*
完成 USART1 对应的 USART1_IRQn 对应的中断处理函数
当前中断处理函数是用于接收的数据内容进行处置操作,将接收的数据
存储到 USART1_Data 结构体中,对应的 u8 data[DATA_SIZE] 数组
*/
void USART1_IRQHandler(void)
{u32 val = 0;/*usart1_val.flag ==> 1 表示当前数据接收完毕,同时已经回显到PC 端 USART 工具*/if (usart1_val.flag){// 对当前数据空间进行擦除,memset(&usart1_val, 0, sizeof(USART1_Data));}/*如果当前触发的中断为 【RXNE 中断】,表示数据在通过串口传递到 MCU 中*/if (USART1->SR & (0x01 << 5)){usart1_val.data[usart1_val.count++] = USART1->DR;/*当前接收到的有效字节个数 == DATA_SIZE,当前数据缓冲区数组已满*/if (DATA_SIZE == usart1_val.count){USART1_SendBuffer(usart1_val.data, usart1_val.count);usart1_val.flag = 1;}}/*如果当前数据总线空闲 【IDLE 中断】,表示数据传递完毕*/if (USART1->SR & (0x01 << 4)){/*表示当前数据接收已完成*/usart1_val.flag = 1;/*需要完成对于当前 USART1->SR IDLE 数据总线空闲中断标志位进行清除操作。【官方要求】1. 读取 USART1->SR 寄存器2. 读取 USART1->DR 寄存器*/val = USART1->SR;val = USART1->DR;// 将数据回显到 PC 端 USART 调试工具USART1_SendBuffer(usart1_val.data, usart1_val.count);}
}

usart.h:

#ifndef _USART1_H
#define _USART1_H#include "stm32f10x.h"#include "stdio.h"
#include "stdlib.h"
#include "string.h"#define DATA_SIZE (256)typedef struct usart1_data
{u8 data[DATA_SIZE]; // 接受数据缓冲区u8 flag;            // 数据处理标志位u16 count;           // 读取到的有效字节个数
} USART1_Data;extern USART1_Data usart1_val;/*** @brief USART1 初始化函数,需要完成*     1. PA9 和 PA10 GPIO 配置*     2. USART1 配置** @param brr 用户提供的对应当前 USART1 的波特率*/
void USART1_Init(u32 brr);/*** @brief USART1 发送一个字节数据到其他设备** @param byte 发送的字节数据。*/
void USART1_SendByte(u8 byte);void USART1_SendBuffer(u8 *buffer, u16 count);void USART1_SendString(const char * str);/*** @brief USART1 接受外部输入的数据内容,当前函数是接收一个字节数据** @return 返回值是接收到的数据内容*/
u8 USART1_ReceiveByte(void);/*
后续代码中需要利用【中断】对代码内容进行优化1. 接收数据终止条件2. 提供外部可以持续使用数据内容3. 数据发送中断判断
*//*** @brief USART1 串口中断使能函数*/
void USART1_Interrupt_Enable(void);#endif

main.c:

#include "stm32f10x.h"//#include "led.h"
//#include "key.h"
#include "delay.h"
//#include "beep.h"
#include "usart1.h"
#include "adc.h"int main(void)
{//Led_Init();LSEN_Init();USART1_Init(115200);USART1_Interrupt_Enable();//Led1_Ctrl(1);while (1){u16 adc_data = LSEN_GetValue();printf("adc_data : %d\r\n", adc_data);printf("U_LSEN : %f\r\n", 3.3 / 4096 * adc_data);Delay_ms(500);}
}

https://github.com/0voice

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94454.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94454.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入理解计算机网络:从基础到应用的全面解析

标题&#xff1a;深入理解计算机网络&#xff1a;从基础到应用的全面解析 引言 计算机网络已经渗透到我们生活的方方面面。从家庭Wi-Fi到全球互联网&#xff0c;我们每天都在通过各种设备进行数据交换。本文将带领你走进计算机网络的世界&#xff0c;深入探讨网络的基础知识、常…

以结构/序列/功能之间的关系重新定义蛋白质语言模型的分类:李明辰博士详解蛋白质语言模型

上海交通大学第三届「AI for Bioengineering 暑期学校」于 2025 年 8 月 8—10 日正式开启。本次暑期学校汇聚了自全球 70 余所高校、 10 余所科研机构及 10 余家行业领军企业的 200 余位青年才俊、科研学者和产业代表&#xff0c;共同聚焦于人工智能&#xff08;AI&#xff09…

【大语言模型 15】因果掩码与注意力掩码实现:深度学习中的信息流控制艺术

【大语言模型 15】因果掩码与注意力掩码实现&#xff1a;深度学习中的信息流控制艺术 关键词&#xff1a;因果掩码、注意力掩码、下三角掩码、Padding掩码、序列建模、GPT解码器、BERT编码器、批量处理优化、自回归语言模型、信息流控制 摘要&#xff1a;在Transformer架构中&a…

大型电动化工程机械设备智能施工试验场的网络设计方案

随着工程机械设备逐步迈向智能化、电动化和无人化&#xff0c;传统施工试验场已经难以满足现代化施工设备的研发、测试和验证需求。为了适应这一趋势&#xff0c;建设一个基于高性能网络架构的大型智能施工试验场成为关键。本文将从网络架构、设备选型和功能实现等方面&#xf…

SPMI总线协议(一)

1、简单说明 系统电源管理接口( System Power Management Interface简称SPMI)是一种双线串行接口,用于连接片上系统(SoC)处理器系统的集成电源控制器(PC)与一个或多个电源管理集成电路(PMIC)电压调节系统。SPMI 使系统能够使用单个 SPMI 总线动态调整 SoC 内部电压域的…

数据存储的思考——从RocketMQ和Mysql的架构入手

数据存储是后台服务系统永远绕不开的知识 笔者希望能够从宏观的角度出发&#xff0c;思考数据存储系统的共性和设计方案&#xff0c;尝试从Mysql和RocketMQ的角度去思考谈谈系统存储架构的设计哲学 前置的知识 什么是RocketMQ、什么是Mysql&#xff0c;他们对于后端系统的主用…

MySQL 面试题系列(二)

目录1: SQL 中常见的 JOIN 类型有哪些&#xff1f;请分别说明其连接逻辑和适用场景。2: UNION 和 UNION ALL 有什么区别&#xff1f;它们各自的适用场景是什么&#xff1f;3: 什么是视图 (View)&#xff1f;它的作用和优缺点是什么&#xff1f;4: 什么是索引 (Index)&#xff1…

PostgreSQL诊断系列(2/6):锁问题排查全攻略——揪出“阻塞元凶”

&#x1f517; 接上一篇《PostgreSQL全方位体检指南》&#xff0c;今天我们深入数据库的“神经系统”——锁机制&#xff0c;解决最令人头疼的“卡顿”问题。 你是否经历过&#xff1a; 某个SQL执行着就不动了&#xff1f;应用界面卡在“加载中”&#xff1f;UPDATE 语句迟迟不…

crc16是什么算法

核心概念​CRC16​ 是一种循环冗余校验算法&#xff0c;属于哈希函数的一种。它的核心目的是检测数据的错误&#xff0c;通常用于数字网络和存储设备中&#xff0c;来验证数据在传输或存储后是否依然完整、无误。你可以把它想象成一个数据的“指纹”或“摘要”。发送方计算出一…

Day8--HOT100--160. 相交链表,206. 反转链表,234. 回文链表,876. 链表的中间结点

Day8–HOT100–160. 相交链表&#xff0c;206. 反转链表&#xff0c;234. 回文链表&#xff0c;876. 链表的中间结点 每日刷题系列。今天的题目是力扣HOT100题单。 链表题目。 160. 相交链表 思路【我】&#xff1a; 1&#xff0c;计算链表长度 2&#xff0c;令A为较短链&am…

Rust面试题及详细答案120道(58-65)-- 集合类型

《前后端面试题》专栏集合了前后端各个知识模块的面试题&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

Horse3D游戏引擎研发笔记(八):在QtOpenGL环境下,按需加载彩虹四边形的顶点属性 (Unity、Unreal Engine、Three.js与Godot)

在上一篇博客中&#xff0c;我们探讨了如何在QtOpenGL环境下使用改进的Uniform变量管理方式绘制多彩四边形。本文将延续这一主题&#xff0c;深入探讨如何在QtOpenGL环境下按需加载彩虹四边形的顶点属性。这一功能是Horse3D引擎渲染系统的重要组成部分&#xff0c;旨在实现灵活…

模块化设计+微米级精度,GelSight Modulus 触觉型3D轮廓仪深入检测“盲区”

当航空航天工程师在精密舱体中搜寻微米级缺陷&#xff0c;汽车检查员在车间复杂结构里排查隐患&#xff0c;能源领域创新者尝试突破检测边界时&#xff0c;深耕视触觉 3D 显微技术的企业——GelSight&#xff0c;正以全新研发的GelSight Modulus触觉型3D轮廓仪&#xff08;简称…

Pytorch安装详细步骤

第一步&#xff1a;检查显卡支持的的CUDA版本 1.打开NVIDIA控制面板 首先鼠标右击桌面-显示更多选项-NVIDIA控制面板-点击弹出界面右上角的(系统信息)-点击弹出界面的(组件) 2.查看驱动版本 打开系统信息 点击组件,查看 以观测到红色方框内的信息可以看到(NVIDIA CUDA 13.0.…

2025职场进阶:低门槛技能实用手册

每到年初&#xff0c;都会有人问&#xff1a;如果只能投入有限的时间与预算&#xff0c;先考哪一两本证书更划算&#xff1f;本文把近两年的岗位需求、学习可获得性与花费周期做了综合权衡&#xff0c;给出一个以“先提升通用能力&#xff0c;再叠加行业资质”为主线的组合方案…

SDC命令详解:使用set_timing_derate命令进行约束

相关阅读 SDC命令详解https://blog.csdn.net/weixin_45791458/category_12931432.html?spm1001.2014.3001.5482 目录 指定降额比例 指定降额对象列表/集合 指定沿 指定最大、最小条件 指定早、晚条件 指定路径的类型 指定降额类型 指定约束 指定增量 写在最后 由于制造…

C++语言程序设计——03 进制ASCII码

目录一、进制表示与转换&#xff08;一&#xff09;不同进制表示&#xff08;二&#xff09;进制转换方法二、ASCII 码&#xff08;一&#xff09;ASCII 码表&#xff08;二&#xff09;ASCII 码转换&#xff08;三&#xff09;大小写英文字母转换【总结&#xff1a;如何记忆AS…

AtCoder Beginner Contest 420-Toggle Maze

题目描述 有一个 H行 W 列的网格。用 (i,j) 表示位于第 i 行&#xff08;从上往下数&#xff09;第 j 列&#xff08;从左往右数&#xff09;的格子。每个格子的状态用字符 Ai,j表示&#xff0c;含义如下&#xff1a; . &#xff1a;空格子。 #’ &#xff1a;障碍格子。 S &am…

20、DMA----释放CPU压力,加快传输

1、DMA介绍DMA&#xff0c;全称为&#xff1a;Direct Memory Access&#xff0c;即直接存储器访问。DMA传输方式无需CPU直接控制传输&#xff0c;也没有中断处理方式那样保留现场和恢复现场的过程&#xff0c;通过硬件为RAM与I/O设备开辟一条直接传送数据的通路&#xff0c;能使…

深入OpenHarmony OTA硬核升级

技术背景 OpenHarmony OTA(Over-The-Air)升级子系统为设备提供了远程升级能力,通过统一的升级接口屏蔽底层芯片差异,支持轻量系统、小型系统和标准系统的全量升级、差分升级和变分区升级。 核心特性 跨系统支持:覆盖轻量系统(Hi3861)、小型系统(Hi3516DV300)、标准系…