STM32F103ZET6利用定时器控制ADC采样并用DMA存储,然后用FFT算法计算低频周期性变化直流信号的频率和幅值,使用HAL库
时间: 2024-05-14 17:14:49 浏览: 97
实现。
以下是实现步骤:
1. 定义ADC采样通道和DMA缓存区。
```
#define ADC_CHANNEL ADC_CHANNEL_0
#define ADC_BUFFER_SIZE 256
uint16_t ADC_Buffer[ADC_BUFFER_SIZE];
```
2. 配置ADC和DMA,使其能够进行采样和存储。
```
ADC_HandleTypeDef hadc;
DMA_HandleTypeDef hdma_adc;
void MX_ADC_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.ScanConvMode = DISABLE;
hadc.Init.ContinuousConvMode = ENABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_13CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
{
Error_Handler();
}
}
void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
/* DMA1_Channel1 init */
hdma_adc.Instance = DMA1_Channel1;
hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc.Init.Mode = DMA_CIRCULAR;
hdma_adc.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&hdma_adc) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(&hadc, DMA_Handle, hdma_adc);
}
```
3. 配置定时器,使其能够触发ADC采样。
```
TIM_HandleTypeDef htim;
void MX_TIM_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim.Instance = TIM2;
htim.Init.Prescaler = 72-1; // 1 MHz
htim.Init.CounterMode = TIM_COUNTERMODE_UP;
htim.Init.Period = 100-1; // 10 kHz
htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_Base_Init(&htim) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
```
4. 在定时器中断中开启ADC采样和DMA传输,并在DMA传输完成中断中进行FFT计算。
```
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2) {
HAL_ADC_Start_DMA(&hadc, (uint32_t*)ADC_Buffer, ADC_BUFFER_SIZE);
}
}
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)
{
if (hdma->Instance == DMA1_Channel1) {
if (hdma->State == HAL_DMA_STATE_READY) {
arm_cfft_radix4_instance_f32 S;
uint32_t ifftFlag = 0;
uint32_t doBitReverse = 1;
float32_t maxValue;
arm_rfft_fast_f32(&S, (float32_t*)ADC_Buffer, (float32_t*)ADC_Buffer, ifftFlag);
arm_cmplx_mag_f32((float32_t*)ADC_Buffer, (float32_t*)ADC_Buffer, ADC_BUFFER_SIZE/2);
arm_max_f32((float32_t*)ADC_Buffer, ADC_BUFFER_SIZE/2, &maxValue, NULL);
arm_scale_f32((float32_t*)ADC_Buffer, 1.0f/maxValue, (float32_t*)ADC_Buffer, ADC_BUFFER_SIZE/2);
}
}
}
```
5. 在主函数中初始化ADC、DMA和定时器,并启动定时器。
```
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC_Init();
MX_DMA_Init();
MX_TIM_Init();
HAL_TIM_Base_Start_IT(&htim);
while (1)
{
}
}
```
通过以上步骤,我们可以实现定时器控制ADC采样并用DMA存储,然后用FFT算法计算低频周期性变化直流信号的频率和幅值的功能。
阅读全文