嵌入式学习--江协stm32day4

发布于:2025-06-09 ⋅ 阅读:(19) ⋅ 点赞:(0)

只能说拖延没有什么好结果,欠下的债总是要还的。

ADC

模拟信号转化为数字信号,例如温度传感器将外部温度的变化(模拟信号),转换为内部电压的变化(数字信号)

IN是八路输入,下方是选择输入端,ALE是锁使能,DAC是数字信号,通过与模拟信号在比较器的比较,通过SAR的调整逐步逼近,最终生成八位输出

这里推荐大家在复习的时候借助ai啊,这样比再去视频里找效率高的多

1. 输入通道与选择

  • 外部模拟输入ADCx_IN0 ~ ADCx_IN15,共 16 路外部引脚,可接传感器等模拟信号。
  • 内部模拟信号
    • 温度传感器:内置温度传感器的模拟输出(用于采集芯片温度)。
    • V_REFINT:内部参考电压(稳定的基准电压,可用于校准或辅助测量)。

2. 转换触发控制

ADC 转换可通过 软件触发 或 硬件触发 启动,硬件触发支持灵活的外部 / 定时器同步:

  • 注入组触发(JEXTTRIG)
    • 触发源由 JEXTSEL[2:0] 配置,可选 TIM1_TRGOTIM8_CH4 等定时器触发输出,或外部引脚 EXTI_15
    • 用于紧急场景(如突发信号优先采集)。
  • 规则组触发(EXTTRIG)
    • 触发源由 EXTSEL[2:0] 配置,可选 TIM1_CH1TIM2_TRGO 等定时器触发,或外部引脚 EXTI_11
    • 用于周期性采集(如定时器定时触发,实现 “定时采样”)。
  • 重映射控制(如 ADCx_ETRGINJ_REMAP):调整触发信号的引脚映射(STM32 引脚功能可重映射,适配硬件布局)。

3. 转换核心与时钟

  • 模拟至数字转换器:核心模块,将选中的模拟信号转换为 12 位数字量(STM32 标准 ADC 精度)。
  • ADCCLK:转换时钟,来自 ADC 预分频器(需配置分频比,控制转换速度,避免时钟过高导致误差)。

4. 数据存储与传输

  • 规则通道数据寄存器(16 位):存储规则通道的转换结果,支持 DMA 请求(转换完成后直接触发 DMA,将数据搬运到内存,减轻 CPU 负担)。
  • 注入通道数据寄存器(4×16 位):存储 4 路注入通道的结果,无 DMA 支持(因注入通道优先级高,数据需快速响应,直接存寄存器供 CPU 读取)。

5. 监控与中断机制

  • 模拟看门狗:监测转换结果是否在 阈值高限(12位) 和 阈值低限(12位) 之间:
    • 若超出范围,触发 AWD 标志位,结合 AWDIE(中断使能),向 NVIC 发送中断请求(用于异常监测,如电压超限报警)。
  • 转换结束中断
    • EOC(规则转换结束):规则通道转换完成标志,EOCIE 使能后触发中断。
    • JEOC(注入转换结束):注入通道转换完成标志,JEOCIE 使能后触发中断。

四种转换模式

单次转换:每次只转换序列一

非扫描模式:每次转换后停止

因为只支持12位,但用16位储存需要选择对齐模式

  1. 采样:指对模拟信号按一定时间间隔进行取值,获取模拟信号在离散时间点上的瞬时值,就像每隔固定时间给模拟信号拍张 “快照”。例如对一个随时间连续变化的电压信号,每隔 0.01 秒记录一次其电压值。
  2. 保持:将采样得到的瞬时值在一段时间内维持不变,以便后续的量化和编码处理。相当于把 “快照” 固定住,使其在后续操作中有稳定的数值。比如采样得到一个电压值后,在完成量化编码前,让这个电压值保持恒定。
  3. 量化:把采样保持后的信号幅值按一定的量化等级进行划分,将其变为离散的数字量。例如将 0 - 5V 的电压范围划分为 10 个量化等级,每个等级 0.5V,采样得到的电压值就根据所处范围对应到相应量化等级。
  4. 编码:将量化后的结果用二进制代码等特定代码形式表示出来,最终得到数字信号。比如量化后的结果是第 3 个等级,编码为二进制的 “011” 。

AD单通道

#include "stm32f10x.h"                  // Device header
void AD_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStructure.ADC_NbrOfChannel=1;
	ADC_InitStructure.ADC_ScanConvMode=DISABLE;
	ADC_Init(ADC1,&ADC_InitStructure);
	
	ADC_Cmd(ADC1,ENABLE);
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1)==SET);
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1)==SET);
	
	
}
uint16_t AD_GetValue()
{
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
	return ADC_GetConversionValue(ADC1);
	
}

AD多通道

#include "stm32f10x.h"                  // Device header
void AD_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStructure.ADC_NbrOfChannel=1;
	ADC_InitStructure.ADC_ScanConvMode=DISABLE;
	ADC_Init(ADC1,&ADC_InitStructure);
	
	ADC_Cmd(ADC1,ENABLE);
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1)==SET);
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1)==SET);
	
	
}
uint16_t AD_GetValue( uint8_t ADC_Channel)
{
	ADC_RegularChannelConfig(ADC1, ADC_Channel,1,ADC_SampleTime_55Cycles5);
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
	return ADC_GetConversionValue(ADC1);
	
}

DMA

1. DMA 控制器(DMA1、DMA2)
  • 作用:管理数据传输的 “指挥官”,内置 多个通道(如 DMA1 有通道 1/2/7,DMA2 有通道 1/2/5),每个通道可独立配置 “源地址、目标地址、传输长度、触发源” 等参数。
  • 通道分工:不同通道对应不同外设请求(如 DMA1 通道 1 可接 TIM2,通道 7 接 ADC1;DMA2 通道 5 接 USB),通过 仲裁器 决定同一 DMA 内通道的优先级。
2. 仲裁器
  • 功能:解决 “同一 DMA 内多个通道同时请求传输” 的冲突,按 “通道优先级(软件配置) + 硬件优先级(通道编号,如通道 7 比通道 1 优先级高)” 裁决,确保高优先级数据先传输。
3. AHB 从设备 & 总线矩阵
  • AHB 从设备:DMA 作为 AHB 总线的 “从设备”,可访问 SRAM、Flash 等 AHB 总线上的存储区域。
  • 总线矩阵:协调 ICode(指令总线,取 Flash 指令)、DCode(数据总线,取 Flash/SRAM 数据)、系统总线(访问外设) 的访问冲突,让 DMA、CPU 能并行工作(如 CPU 取指令时,DMA 可同时传输数据)。
4. 外设侧(APB1/APB2 总线)
  • 外设举例:ADC1/2(模拟转数字)、USART(串口)、TIM(定时器)、GPIO 等,这些外设可产生 DMA 请求信号(如 ADC 转换完成后发请求,触发数据从 ADC 寄存器→SRAM 传输)。

DMA数据转运

#include "stm32f10x.h"                  // Device header

uint16_t My_DMA_Size;
void MyDMA_Init(uint32_t AddrA,uint32_t AddrB,uint16_t Size)
{
	My_DMA_Size=Size;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr=AddrA;
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Enable;
	DMA_InitStructure.DMA_MemoryBaseAddr= AddrB;
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize=Size;
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
	DMA_InitStructure.DMA_M2M=DMA_M2M_Enable;
	DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;
	DMA_Init(DMA1_Channel1,&DMA_InitStructure);

	DMA_Cmd(DMA1_Channel1,DISABLE);
}

void MyDMA_Transfer()
{
	DMA_Cmd(DMA1_Channel1,DISABLE);
	DMA_SetCurrDataCounter(DMA1_Channel1,My_DMA_Size);
	DMA_Cmd(DMA1_Channel1,ENABLE);
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
	DMA_ClearFlag(DMA1_FLAG_TC1);
}

DMA+AD多通道

#include "stm32f10x.h"                  // Device header

uint16_t AD_Value[4];

void AD_Init()
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1,2,ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2,3,ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3,4,ADC_SampleTime_55Cycles5);

	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStructure.ADC_NbrOfChannel=4;
	ADC_InitStructure.ADC_ScanConvMode=ENABLE;
	ADC_Init(ADC1,&ADC_InitStructure);
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;
	DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryBaseAddr= (uint32_t)&AD_Value;
	DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;
	DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize=4;
	DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
	DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
	DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;
	DMA_Init(DMA1_Channel1,&DMA_InitStructure);

	DMA_Cmd(DMA1_Channel1,ENABLE);
	
	ADC_DMACmd(ADC1,ENABLE);	
	ADC_Cmd(ADC1,ENABLE);
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1)==SET);
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1)==SET);
	
	
}
void AD_GetValue( )
{
	DMA_Cmd(DMA1_Channel1,DISABLE);
	DMA_SetCurrDataCounter(DMA1_Channel1,4);
	DMA_Cmd(DMA1_Channel1,ENABLE);
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1)==RESET);
	DMA_ClearFlag(DMA1_FLAG_TC1);
	
}

只能说拖延只会让自己难受,六级和期末考试摆在那里,拖延就需要2天把剩余的学完,整天都得按在椅子上了....