生成一个点数、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;
}