STM32双重ADC快速交叉模式采集一个通道数据,采用定时器触发主ADC,库函数编写
时间: 2023-06-13 09:05:41 浏览: 194
基于STM32的定时器触发ADC采集数据
3星 · 编辑精心推荐
在STM32中,双重ADC快速交叉模式可以实现高速高精度的模拟信号采集,而定时器可以提供定时触发ADC采集的功能。下面是使用STM32库函数编写的双重ADC快速交叉模式采集单通道数据的代码:
```c
#include "stm32f10x.h"
#define ADC1_DR_Address ((u32)0x4001244C) // ADC1数据寄存器地址
void ADC1_Init(void);
void ADC2_Init(void);
void TIM3_Init(void);
u16 Get_ADC_Value(void);
int main(void)
{
u16 ADC_Value;
ADC1_Init(); // 初始化ADC1
ADC2_Init(); // 初始化ADC2
TIM3_Init(); // 初始化定时器3
while(1)
{
ADC_Value = Get_ADC_Value(); // 获取ADC采集值
// 处理ADC采集数据
}
}
// 初始化ADC1
void ADC1_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // 使能ADC1时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 使能DMA1时钟
// 配置PA0为模拟输入通道
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置DMA1通道1为ADC1数据传输
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_Value;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
// 配置ADC1
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Mode = ADC_Mode_RegInjecSimult; // 双重ADC快速交叉模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 单通道采样
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次采样
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO; // 定时器3触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// 配置ADC1注入通道
ADC_InjectedSequencerLengthConfig(ADC1, 1); // 注入通道序列长度为1
ADC_InjectedChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); // 配置注入通道为PA0,采样时间为239.5个时钟周期
// 配置ADC1常规通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); // 配置常规通道为PA0,采样时间为239.5个时钟周期
// 启动DMA1通道1
DMA_Cmd(DMA1_Channel1, ENABLE);
// 启动ADC1
ADC_Cmd(ADC1, ENABLE);
// 启动ADC1注入转换
ADC_ExternalTrigInjectedConvCmd(ADC1, ENABLE);
}
// 初始化ADC2
void ADC2_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); // 使能ADC2时钟
// 配置PA0为模拟输入通道
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置ADC2
ADC_DeInit(ADC2);
ADC_InitStructure.ADC_Mode = ADC_Mode_RegInjecSimult; // 双重ADC快速交叉模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 单通道采样
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次采样
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO; // 定时器3触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC2, &ADC_InitStructure);
// 配置ADC2注入通道
ADC_InjectedSequencerLengthConfig(ADC2, 1); // 注入通道序列长度为1
ADC_InjectedChannelConfig(ADC2, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); // 配置注入通道为PA0,采样时间为239.5个时钟周期
// 配置ADC2常规通道
ADC_RegularChannelConfig(ADC2, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); // 配置常规通道为PA0,采样时间为239.5个时钟周期
// 启动ADC2
ADC_Cmd(ADC2, ENABLE);
// 启动ADC2注入转换
ADC_ExternalTrigInjectedConvCmd(ADC2, ENABLE);
}
// 初始化定时器3
void TIM3_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能定时器3时钟
// 定时器3配置
TIM_TimeBaseStructure.TIM_Period = 999; // 自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0000; // 重复计数器值
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// 定时器3触发ADC1和ADC2注入转换
TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);
ADC_ExternalTrigInjectedConvCmd(ADC1, ENABLE);
ADC_ExternalTrigInjectedConvCmd(ADC2, ENABLE);
// 启动定时器3
TIM_Cmd(TIM3, ENABLE);
}
// 获取ADC采集值
u16 Get_ADC_Value(void)
{
return ADC_Value;
}
```
以上代码中,定义了`ADC1_Init()`、`ADC2_Init()`、`TIM3_Init()`和`Get_ADC_Value()`四个函数。`ADC1_Init()`和`ADC2_Init()`分别用于初始化ADC1和ADC2,`TIM3_Init()`用于初始化定时器3,`Get_ADC_Value()`用于获取ADC采集值。
在`ADC1_Init()`和`ADC2_Init()`中,首先使能了GPIOA时钟和相应的ADC时钟和DMA时钟,然后配置了PA0为模拟输入通道,并启动了DMA1通道1。接着,配置了ADC1和ADC2为双重ADC快速交叉模式,注入和常规通道采样时间均为239.5个时钟周期,以及定时器3触发。最后,启动了ADC1和ADC2。
在`TIM3_Init()`中,首先使能了定时器3时钟,并配置了定时器3的各个参数。接着,将定时器3的更新事件作为触发源,触发了ADC1和ADC2的注入转换,并启动了定时器3。
在`Get_ADC_Value()`中,直接返回了ADC采集值。
需要注意的是,以上代码中的`ADC_Value`是全局变量,用于存储ADC采集值。在`DMA_InitStructure.DMA_MemoryBaseAddr`中的`&ADC_Value`表示将ADC采集值存储在`ADC_Value`中。
同时,以上代码中的定时器3分频系数为71,时钟频率为72MHz / 72 = 1MHz,定时器周期为1ms。如果需要采集更快速的数据,可以减小分频系数,例如设置为35,时钟频率为72MHz / 36 = 2MHz,定时器周期为0.5ms。但是需要注意的是,分频系数过小会导致定时器精度不足,需要根据实际情况进行调试。
阅读全文