stm32自用函数、代码参考


生成一个点数、vpp、频率、采样率可控的正弦波数组

/**
 * @brief       生成正弦波数组
 * @param       output: 输出数组指针,存储生成的正弦波数据
 * @param       length: 数组长度,生成的数据点数
 * @param       frequency: 正弦波频率 (Hz)
 * @param       sampling_rate: 采样频率 (Hz)
 * @param       vpp: 峰峰值电压,实际幅值为vpp/2
 * @retval      无
 */
void generate_sine_wave(float32_t *output, uint16_t length, float32_t frequency, float32_t sampling_rate, float32_t vpp)
{
    float32_t omega = 2.0f * PI * frequency / sampling_rate;

    for(uint16_t i = 0; i < length; i++)
    {
        output[i] = 0.5*vpp * arm_sin_f32(omega * i);
    }
}

简单的中值滤波,可以使测量值更为稳定

float32_t Avg = 0;
float32_t Mid_BUFF[1000]; // 中值滤波器缓冲区
float32_t Mid_Result[1000]; // 排序后结果
arm_sort_instance_f32 S; // 排序实例------arm dsp

// 具体程序中调用
arm_sort_init_f32(&S, ARM_SORT_QUICK,ARM_SORT_ASCENDING);    // 初始化排序实---升序排列
arm_sort_f32(&S, Mid_BUFF, Mid_Result, Mid_CNT);//排序
for (int i = 30; i < 70; i++)       //  中值滤波
{
    Avg += Mid_Result[i];
}
Avg /= 40;                    // 求平均值

某次实际应用,取了2次平均,但是感觉意义没有特别大


// ADC中断回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(hadc);
    HAL_ADC_Stop_DMA(&hadc1);  // 关闭 ADC_1 DMA采样
    HAL_TIM_Base_Stop(&htim3);  // 失能定时器3
// ----------------------------------------------------------------------------------数据处理开始----------------------------------------------------------------------------------//
    for(int i=0;i<FFT_LENGTH;i++)
    {
        //adcBuff_1_f[i] =0.001f *adcBuff_1[i] - 8.0212f;

        adcBuff_1_f[i] = 1.0f* adcBuff_1[i];
        Mid_BUFF[i]= adcBuff_1_f[i];  // 将采集到的数据存入中值滤波器缓冲区
        //printf("%f\n",adcBuff_1_f[i]);
    }


//    for(int i=0;i<FFT_LENGTH;i++)  // 取一半长度的有用信息打印
//    {
//        input_data = adcBuff_1_f[i];
//
//
//        filtered_output += input_data;  // 累加输入数据
//        // 使用滤波后的数据
//        //printf("原始数据: %f, 滤波后: %f\n", input_data, filtered_output);
//
//        //printf("%f\n",input_data);  // 打印原始数据
//
//    }
//    filtered_output /= FFT_LENGTH;  // 计算平均值作为滤波后的输出
    arm_sort_init_f32(&S, ARM_SORT_QUICK,ARM_SORT_ASCENDING);    // 初始化排序实---升序排列
    arm_sort_f32(&S, Mid_BUFF, Mid_Result,FFT_LENGTH );//排序
    for (int i = 100; i < 900; i++)       //  中值滤波
    {
        Avg += Mid_Result[i];
    }
    Avg /= 800;
    //Avg = (Avg - 33202.5)/4900.0f;
    if(CNT == 100)
    {
        Avg_2 /= 100;
       Avg_2 = 0.8252f * Avg_2 - 6858.7f;
        printf("%f\n", Avg_2);
        Avg_2 = 0.0f;
        CNT = 0;
    }
    else
    {
        Avg_2 += Avg;
        CNT++;
    }
//    Avg = 0.8251f * Avg - 6857.7f;
//    printf("%f\n", Avg);
    Avg = 0.0f;
    //---------------------------------------------------------------------  数据处理完成后,再开始启动下一次同步采样-------------------------------------------------------------------//
    HAL_ADC_Start_DMA(&hadc1,(uint32_t *)adcBuff_1,FFT_LENGTH);  // enable ADC_1 DMA采样
    HAL_TIM_Base_Start(&htim3);  // 重新使能定时器3
}

ad9959驱动

1.配置引脚

 

2.代码

 所有数据修改之后,只用IO_Update一次,否则可能会引入问题

  /* USER CODE BEGIN 2 */

    AD9959_Init();    //ad9959初始化 别忘了
    ad9959(CH0, 15000000, 1023, 0); //设置通道0的频率为10MHz,幅度为最大值1023,相位为0度
    ad9959(CH1, 15000000, 1023, 90); //设置通道0的频率为10MHz,幅度为最大值1023,相位为90度
    // 更新数据到 DDS 模块
    IO_Update();
  /* USER CODE END 2 */

void ad9959(uint8_t Channel, uint32_t Freq, uint16_t Ampli,  uint16_t Phase)
{
    // 设置通道 CH0 的输出频率
    AD9959_Set_Fre(CH0, Freq);
    // 设置通道 CH0 的输出幅度为最大值(1023)   1023对应500mVpp(实测并不一定, 有偏差)
    AD9959_Set_Amp(CH0, Ampli);
    // 设置通道 CH0 的输出相位为 0 度
    AD9959_Set_Phase(CH0, Phase);

}

//----------扫频函数-------------------
void freq_sweep(uint8_t Channel,uint32_t freq_start, uint32_t freq_end, uint32_t step, uint16_t Ampli, uint16_t Phase)
{
    // 设置起始频率
    uint32_t freq = freq_start;
    // 循环遍历频率范围
    while (freq <= freq_end)
    {
        // 设置频率、幅度和相位
        ad9959(Channel, freq, Ampli, Phase);
        // 延时 100ms
        HAL_Delay(100);
        // 步进增加频率
        freq += step;
    }

 ADS131驱动

1.H7要通过杜邦线输出一个16Mhz的时钟

2.配置外部中断,连接到131板子rdry,每次采集完成,rdry就会拉高一次,H7接收该信号产生中断,停止中断,出局处理,再重新开启中断。

3. 使用参考

初始化

  /* USER CODE BEGIN 2 */
    RetargetInit(&huart1);  // Initialize retarget for printf
    ADS131A04_Init();    // Initialize ADS131A04
    ADS_Set_n(FFT_LENGTH);  // Set number of samples to 1024
    ADS_Set_CH_Enable(0b1111); // Enable all channels
    ADS_Start();
    HAL_TIM_Base_Start(&htim2);
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4);
    HAL_Delay(10);

  /* USER CODE END 2 */

具体


// 我个人的修改,更符合使用的直觉,采集完需要的点数之后,关闭中断,处理数据,之后再重新开启中断继续采集
void ADS_finish(ADS_obj ads)    //各通道采集完需要的点数之后缓存的结构体作为输入
{
    float32_t adc_data[FFT_LENGTH];     // 用于FFT计算的输入数据
    HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);      // 一次采集完成后,关闭中断
//----------------------------------------------数据处理部分---------------------------------------------------------------------//


              for(int i = 0;i<1024 ; i++)
          {
              //ADS_C1[i]= buf4[i]* 2.0f / 16777216.0 * 2.5;
//              ADS_C1[i] = buf4[i] * 1.0f;
                //printf("%ld\n",ads.ads_buff_ch4[i]);
                adc_data[i] = (ads.ads_buff_ch4[i] * 1.0f )/ 999936.0f - 0.00806f; // 将采集的原始数据转换为浮点数
                //printf("%lf\n",adc_data[i]);
          }

    FFT_Cal(adc_data,fft_inputbuf , fft_outputbuf ,FFT_LENGTH);
    fft_outputbuf[0] = 10;
    for(int i = 0;i<1024 ; i++)
    {
        printf("%lf\n",fft_outputbuf[i]); // 打印FFT计算结果
    }

//----------------------------------------------数据处理完成-----------------------------------------------------------------------//
    HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);    // 重新开启中断

}

计算vpp、max、min


void vpp_calc(float32_t adc_data[], uint16_t DATA_LENGTH , float32_t* max, float32_t* min, float32_t* vpp)
{
    *max = adc_data[0];
    *min = adc_data[0];

    for(int i = 1; i < DATA_LENGTH; i++)
    {
        if(adc_data[i] > *max)
        {
            *max = adc_data[i];
        }
        if(adc_data[i] < *min)
        {
            *min = adc_data[i];
        }
    }

    *vpp = *max - *min;
}

 寻找最大值下标

/*
*********************************************************************************************************
*	函 数 名:Max_Float_WithinRange
*	功能说明:寻找数组里最大值的下标,以0开始,对于数组下标而言需要加一
*	形    参:
	参数一:Data            输入数组
	参数二:Left            寻找起点
    参数三:Right           寻找终点
*	返 回 值:最大值的数组下标
*********************************************************************************************************
*/
uint16_t Max_Float_WithinRange(float32_t Data[], uint16_t Left, uint16_t Right)
{
    uint16_t i, MaxIndex;
    MaxIndex = Left;
    for (i = Left; i <= Right; ++i)
    {
        if (Data[MaxIndex] < Data[i])
        {
            MaxIndex = i;
        }
    }
    return MaxIndex;
}

 相位计算函数

//相位计算函数
    float Phase_atan(float32_t *inputSignal, uint32_t index) {
        if (inputSignal[2 * index + 1] >= 0 && inputSignal[2 * index] >= 0)
            return 0 + atan(inputSignal[2 * index + 1] / inputSignal[2 * index]) / PI * 180;
        else if (inputSignal[2 * index + 1] >= 0 && inputSignal[2 * index] <= 0)
            return 180 + atan(inputSignal[2 * index + 1] / inputSignal[2 * index]) / PI * 180;
        else if (inputSignal[2 * index + 1] <= 0 && inputSignal[2 * index] <= 0)
            return 180 + atan(inputSignal[2 * index + 1] / inputSignal[2 * index]) / PI * 180;
        else if (inputSignal[2 * index + 1] <= 0 && inputSignal[2 * index] >= 0)
            return 360 + atan(inputSignal[2 * index + 1] / inputSignal[2 * index]) / PI * 180;
    }

ap_fft

uint16_t  adcBuff_1[FFT_LENGTH * 2];   // ADC 采集数据
uint16_t  adcBuff_2[FFT_LENGTH * 2];   // ADC 采集数据
float adcBuff_1_f[FFT_LENGTH * 2-1] = {0};   // ADC 数据转化校验
float adcBuff_2_f[FFT_LENGTH * 2-1] = {0};   // ADC 数据转化校验
//float32_t adcBuff_1_f_WIN[FFT_LENGTH * 2 ];  // ADC_1加窗后的数据
//float32_t adcBuff_2_f_WIN[FFT_LENGTH * 2  ];  // ADC_2加窗后的数据

float fft_inputbuf_1[FFT_LENGTH * 2];
float fft_outputbuf_1[FFT_LENGTH];
float fft_inputbuf_2[FFT_LENGTH * 2];
float fft_outputbuf_2[FFT_LENGTH];

float32_t  hanning_win[FFT_LENGTH];  // 汉宁窗函�???????????
float32_t hanning_win_norm[FFT_LENGTH];  // 汉宁窗函数归�???????????化结�???????????

float HanNing[FFT_LENGTH] = {0};
float fft_conv[FFT_LENGTH * 2 - 1] = {0};
uint32_t wave[FFT_LENGTH * 2-1] = {0};  // 用于存储FFT计算的信�??????????

float32_t Phase;
 uint8_t over_flag=0;                                            //采集完成标志  


/* USER CODE BEGIN 2 */
    RetargetInit(&huart1);  // Initialize retarget for printf

    // ADC校准
    HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET_LINEARITY, ADC_SINGLE_ENDED);
    HAL_ADCEx_Calibration_Start(&hadc2, ADC_CALIB_OFFSET_LINEARITY, ADC_SINGLE_ENDED);

    //arm_cfft_radix4_init_f32(&scfft,FFT_LENGTH,0,1);//初始化scfft结构�??????,设定FFT参数

    hanning_window(HanNing);
    convolve(HanNing, fft_conv);
    normalize(fft_conv, FFT_LENGTH * 2 - 1);  // 归一化卷积结�???????????

    HAL_TIM_Base_Start(&htim6);        // 使能定时�???????????3
    HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t *) wave, 2 * FFT_LENGTH - 1);

  /* USER CODE END 2 */
/* USER CODE BEGIN 4 */

    void hanning_window(float *w) {
        uint16_t n;
        for (n = 0; n < FFT_LENGTH; n++) {
            w[n] = 0.5 * (1 - cos(2 * PI * n / FFT_LENGTH));
        }
    }
    void convolve(float *w, float *y) {
        int n, m;
        for (n = 0; n < 2 * FFT_LENGTH - 1; n++) {
            y[n] = 0;
            for (m = 0; m < FFT_LENGTH; m++) {
                if (n - m >= 0 && n - m < FFT_LENGTH) {
                    y[n] += w[m] * w[n - m];
                }
            }
        }
    }
// 计算序列的和
    float sum(float *x, int n) {
        int i;
        float s = 0;
        for (i = 0; i < n; i++) {
            s += x[i];
        }
        return s;
    }
// 归一化序�???????????
    void normalize(float *x, int n) {
        float s = sum(x, n);
        int i;
        for (i = 0; i < n; i++) {
            x[i] /= s;
        }
    }
//相位计算函数
    float Phase_atan(float32_t *inputSignal, uint32_t index) {
        if (inputSignal[2 * index + 1] >= 0 && inputSignal[2 * index] >= 0)
            return 0 + atan(inputSignal[2 * index + 1] / inputSignal[2 * index]) / PI * 180;
        else if (inputSignal[2 * index + 1] >= 0 && inputSignal[2 * index] <= 0)
            return 180 + atan(inputSignal[2 * index + 1] / inputSignal[2 * index]) / PI * 180;
        else if (inputSignal[2 * index + 1] <= 0 && inputSignal[2 * index] <= 0)
            return 180 + atan(inputSignal[2 * index + 1] / inputSignal[2 * index]) / PI * 180;
        else if (inputSignal[2 * index + 1] <= 0 && inputSignal[2 * index] >= 0)
            return 360 + atan(inputSignal[2 * index + 1] / inputSignal[2 * index]) / PI * 180;
    }
//   全相位傅里叶变换
    float32_t AP_FFT(float32_t wave_1[], float32_t wave_2[], uint16_t Length) {
        float32_t fft_inputbuf_1[Length * 2];
        float32_t fft_inputbuf_2[Length * 2];
        float32_t fft_outputbuf_1[Length];
        float32_t fft_outputbuf_2[Length];
        float32_t Phase_1;
        float32_t Phase_2;
        float32_t Phase;
        float32_t Fmax_1;
        float32_t Fmax_2;
        arm_cfft_radix4_instance_f32 scfft;
        uint32_t Amax_pos_1;
        uint32_t Amax_pos_2;
    //arm_cfft_radix4_init_f32(&scfft,Length,0,1);//初始化scfft结构�?,设定FFT参数
//     for (int i = 0; i < 2*Length-1; i++)
//    {
//        wave_2[i]=((single[i] >> 16)/65535.0f*2-1.00f)*3.57f-0.139f;
//        wave_1[i]=((single[i] & 0xffff)/65535.0f*2-1.00f)*3.57f-0.139f;
//    }
//    Printf(wave_1,Length);

        for (int i = 0; i < 2 * Length - 1; i++) {
            wave_1[i] = wave_1[i] * fft_conv[i];    //加窗
            wave_2[i] = wave_2[i] * fft_conv[i];    //加窗
        }
//   Printf(fft_conv,Length*2-1);
        for (int i = 0; i < Length - 1; i++) {
            wave_1[i] = wave_1[i] + wave_1[Length + i];
            wave_2[i] = wave_2[i] + wave_2[Length + i];
        }
//    Printf(wave_1,Length);
        for (int i = 0; i < Length; i++) {
            fft_inputbuf_1[i * 2] = wave_1[i];
            fft_inputbuf_1[i * 2 + 1] = 0;
            fft_inputbuf_2[i * 2] = wave_2[i];
            fft_inputbuf_2[i * 2 + 1] = 0;
        }
//    arm_cfft_radix4_f32(&scfft,fft_inputbuf_1);
//    arm_cfft_radix4_f32(&scfft,fft_inputbuf_2);
        arm_cfft_f32(&arm_cfft_sR_f32_len512, fft_inputbuf_1, 0, 1);
        arm_cfft_f32(&arm_cfft_sR_f32_len512, fft_inputbuf_2, 0, 1);

        arm_cmplx_mag_f32(fft_inputbuf_1, fft_outputbuf_1, Length);
        arm_cmplx_mag_f32(fft_inputbuf_2, fft_outputbuf_2, Length);
        // 去除直流
        fft_outputbuf_1[0] = 0;
        fft_outputbuf_2[0] = 0;

        for (int h = 0; h < Length; h++) {
            fft_outputbuf_1[h] /= Length / 2;
            fft_outputbuf_2[h] /= Length / 2;
        }
//    Printf(fft_outputbuf_1,Length);
        arm_max_f32(fft_outputbuf_1, Length / 2, &Fmax_1, &Amax_pos_1);     //使用Length会让频率点在后半部分,导致频率计算错误,导致ARR->0
        arm_max_f32(fft_outputbuf_2, Length / 2, &Fmax_2, &Amax_pos_2);     //使用Length会让频率点在后半部分,导致频率计算错误,导致ARR->0
        Phase_1 = Phase_atan(fft_inputbuf_1, Amax_pos_1);
        //Phase_1-=0.04f;                     //根据实际情况补偿,非必要不加
        Phase_2 = Phase_atan(fft_inputbuf_2, Amax_pos_2);
        Phase = Phase_1 - Phase_2;

        if (Phase > 180) Phase = -360 + Phase;
        else if (Phase < -180) Phase = 360 + Phase;
        return Phase;  // 返回相位�???????????
        //printf("Phase1=%f Phase_2=%f Phase=%f\r\n",Phase_1,Phase_2,Phase);
    }


// ADC中断回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(hadc);
    HAL_TIM_Base_Stop(&htim6);
// ----------------------------------------------------------------------------------数据处理�??????�??????----------------------------------------------------------------------------------//
    for (int i = 0; i < 2 * FFT_LENGTH - 1; i++) {
//            adcBuff_2_f[i] = ((wave[i] >> 16) / 65535.0f * 2 - 1.00f) * 3.57f - 0.139f;
//            adcBuff_1_f[i] = ((wave[i] & 0xffff) / 65535.0f * 2 - 1.00f) * 3.57f - 0.139f;
        adcBuff_2_f[i] =  (1.0f * (wave[i] >> 16) - 23091) /2430 - 4.3f; // ;
        adcBuff_1_f[i] = ( ( (1.01f *( wave[i] & 0xffff )- 23522 ))/2423 -4.35f) ;//
//        adcBuff_2_f[i]=(  ((float)(wave[i]>>16 & 0x0000FFFF) / 65535.0f * 3.3f - 1.65f -0.0395f) *2.14592274678f  );//校赛
//        adcBuff_1_f[i]=(  ((float)(wave[i] & 0x0000FFFF) / 65535.0f * 3.3f - 1.65f -0.0300f) *2.155172413793f);
    }
//    for (int i = 0; i <  FFT_LENGTH ; i++) {
//        printf("%f\n", adcBuff_1_f[i]);
//    }
    Phase = AP_FFT(adcBuff_1_f, adcBuff_2_f, FFT_LENGTH);
        printf("%f\n", Phase);

    //---------------------------------------------------------------------  数据处理完成后,再开始启动下�??????次同步采�??????-------------------------------------------------------------------//
    HAL_TIM_Base_Start(&htim6);  // 重新使能定时�?6
    HAL_ADCEx_MultiModeStart_DMA(&hadc1, (uint32_t *) wave, 2 * FFT_LENGTH - 1);
}

简单的adc dma采集

  /* USER CODE BEGIN 2 */
    RetargetInit(&huart1);  // Initialize retarget for printf
    hanning(WIN_Data_f,FFT_LENGTH);  // 汉宁窗函数
    // ADC校准
    HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET_LINEARITY, ADC_DIFFERENTIAL_ENDED);
    HAL_ADC_Start_DMA(&hadc1,(uint32_t *)adcBuff,FFT_LENGTH);  // 开启ADC  DMA采样
    HAL_TIM_Base_Start(&htim3); 		// 使能定时器3,定时器3用于触发ADC采样

  /* USER CODE END 2 */

adc中断回调函数中做数据处理 


void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
    HAL_TIM_Base_Stop(&htim3);
//-----------------------------------------------------数据处理----------------------------------------------------------//
    for(int i=0;i<FFT_LENGTH;i++)
    {
        adcBuff_f[i] = (adcBuff[i] -7083)/1209.5f - 1.0f;
    }
    //Normalizd_Win_Fun(WIN_Data_f, WIN_Data_f_Norm,FFT_LENGTH);  // 归一化窗函数
    Add_Win_Fun(adcBuff_f, adcBuff_f_WIN, WIN_Data_f, FFT_LENGTH);  // 加窗函数

    FFT_Cal(adcBuff_f_WIN , fft_inputbuf, fft_outputbuf,FFT_LENGTH);
    fft_outputbuf[0] = 0;  // 将直流分量置为0
    max_index = Max_Float_WithinRange(fft_outputbuf, 0, FFT_LENGTH/2);
    second_index =  Max_Float_WithinRange(fft_outputbuf, max_index + 20, FFT_LENGTH/2);
    //
    for(int i=0;i<FFT_LENGTH/2;i++)  // 取一半长度的有用信息打印
    {
        printf("%f\n",fft_outputbuf[i]);
    }
    vpp_calc(adcBuff_f, FFT_LENGTH, &max, &min, &vpp);  // 计算Vpp
//    for(int i=0;i<FFT_LENGTH;i++)
//    {
//        printf("%f\n",adcBuff_f[i]);
//    }

//        printf("%d\n",max_index);


//    freq = (float)max_index * 1000000.0f / FFT_LENGTH;  // 计算频率
//    printf("%f\n",freq);
//printf("%d\n",second_index);
//printf("%f\n",vpp);

//------------------------------------------------------数据处理结束-----------------------------------------------------//
    HAL_ADC_Start_DMA(&hadc1,(uint32_t *)adcBuff,FFT_LENGTH);  // 开启ADC DMA采样
    HAL_TIM_Base_Start(&htim3); 		// 使能定时器3,定时器3用于触发ADC采样

}

DAC出波

COMP比较器

此处是一个示例,RC充电时间计数,到达比较阈值结束计时,所以在比较器中断中停止计数器,将计数值拿来用

 

    HAL_DAC_SetValue(&hdac1,DAC_CHANNEL_2,DAC_ALIGN_12B_R,DAC2_Value);
    HAL_DAC_Start(&hdac1,DAC_CHANNEL_2);
    __HAL_TIM_CLEAR_FLAG(&htim2,TIM_IT_UPDATE);
    __HAL_COMP_CLEAR_C1IFLAG();
    HAL_COMP_Start(&hcomp1);    // 启动比较器
    __HAL_TIM_SET_COUNTER(&htim2,0);

// 比较器中断回调函数
void HAL_COMP_TriggerCallback(COMP_HandleTypeDef *hcomp){
    TIM2_cnt=__HAL_TIM_GET_COUNTER(&htim2);
    T=TIM2_cnt/200.f;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值