关于2022年TI省赛--F题信号调制度测量装置

赛题分析

在这里插入图片描述
该装置测量并显示信号源输出的被测信号调制度等参数,识别并显示被测信号的调制方式,并且输出解调信号。该装置能实现频率为10MHz到30MHz正弦波为载波的普通单音调幅波、调频波以及载波的识别,测量对应的调幅度以及调频度输出无明显失真的解调信号。
我们采用抽样峰值检测的方法实现AM波的包络还原再重现对应的解调信号,采用带通抽样定律实现FM波的带宽计算调频度,给示波器显示输出部分采用AD9910DDS直接输出。
第三点有些难度,但不至于做不了,不过限于FM解调模块问题,不能实现全带宽的解调(因为需要有电位器微调,而在复测过程中是不允许的,这点也是坑,尽管我们小组已经使用了两块解调模块进行微调:一块店铺购买,一块自制,还是做不全)

理论分析

AM信号处理方案

方案一:

制作峰值采样电路
优点:即使载波的频率在大范围变化改电路采到的峰值任然为包络线,基本不受载波影响adc采集方便控制简单实现方便。
缺点:需要使用模拟开关以及二极管实现峰值采样,需要控制两个模拟开关交替开启,若同时打开电流较大,稍有不慎会烧毁芯片。

方案二:

使用包络检波电路
优点:电路实现简单,元器件少。
缺点:采样时容易受载波频率的影响,在载波增加时幅值会产生较大的衰减。

FM信号处理方案

方案一:

使用NE564模块,将FM波经过放大之后直接使用锁相环解调
优点: 模块适用带宽范围较大,解调后输出波形平滑不失真。
缺点: 若外部输入信号峰峰值太小会导致NE564模块的解调失败或严重自激。

方案二:

采用FPGA数字解调
优点:处理数据能力快,精度高,能够直接获取信号所有信息,对输入信号的峰峰值要求不高。
缺点:解调算法操作难度大,与外部通信实现度差。

FFT快速傅里叶变换与逆变换算法

为了较快检测到输入波形的谐波分量和失真度,本设计采用了FFT快速傅里叶变换算法。
将输入信号分解为泰勒展开式,对信号的奇偶性成两半:
在这里插入图片描述
再令:
(2.2)
在这里插入图片描述
式(2.4)只有一个常数项不同,相比普通傅里叶算法,整个计算量缩小了一半。
在实现FFT时,对于输入频率的分辨率可以表示为采样频率与采样点数之比,如式(2.5)。
(2.5)

由式(2.5)可知,输入信号基波频率不是分辨率的整数倍,某一频率的能量将会扩散到相邻频率点上,现频谱泄露的问题,既无法检测到基波频率,也无法准确测到幅值。在测量时要先对原信号频率进行测量,然后选择合适的采样频率和采样点进行计算,以此解决频谱泄露的问题。
在FFT结束并相乘后,得到多项式的点值表示,将点表示转化为系数表示,即可完成离散傅里叶逆变换。该过程可以封装表达为式(2.6)。
(2.6)
其中A意义为多项式的系数表示法;B意义为多项式的点值表示法。
在显示单周期波形时,利用快速傅里叶逆变换,用频率信息还原信号,可以突破对ADC采样点与电压值一一对应的依赖,拟合出多点曲线,使显示波形更加平滑。

带通抽样定律采样算法

根据奈奎斯特采样定理,为了能够完整地重建波形,采样至少应为最高频率的2倍。对于信号频率非常高的情况下,一般ADC达不到如此高的速度,所以带通采样能够节省采样频率,频谱将以采样频率为周期向左右两侧进行周期性延拓。
在这里插入图片描述
在这里插入图片描述
为了使带通采样的信号不发生混叠,因此平移的时候不能原信号发生混叠:
在这里插入图片描述
通过确定采样频率经过FFT计算,将带宽求出,利用带宽与调频度和最后频偏的关系式计算出来。

电路设计

在这里插入图片描述

程序设计

本题由于要用到大量的数字信号处理以及FFT计算,因此先引入DSP库准没错
在这里插入图片描述
注意:不要忘记在Cube界面中Software Packs中将DSP库勾选上,另外要在生成代码界面中勾选导入所有的 .c/ .h文件,以免DSP库导入不全。
其他的Cube配置没什么好说的,开启ADC+TIM+DMA,做到采样率能精准把控,使能DAC(DAC根据方案才使能,由于电路需求一个偏置电压),使能两串口,一个用于调试,一个用于与串口屏通信,另外需要把串口中断开启。

AD9910

/*******************************************************************************
 * @file     ad9910.h
 * @brief    ad9910驱动程序
 * @version  V2.0
 * @date     2022-7-23
 *
 * @note
 *
 ******************************************************************************/
#ifndef __AD9910_H__
#define __AD9910_H__

#include "main.h"
#include "usart.h"
#include "ad9910_RegMap.h"

#define ulong unsigned long int

extern uint8_t cfr2[4]; //cfr2控制字
extern uint8_t cfr1[4]; //cfr1控制字

#define REEST(x) 						x?HAL_GPIO_WritePin(RST_GPIO_Port,RST_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(RST_GPIO_Port,RST_Pin,GPIO_PIN_RESET)				//RST
#define AD9910_PWR(x) 			x?HAL_GPIO_WritePin(PWR_GPIO_Port,PWR_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(PWR_GPIO_Port,PWR_Pin,GPIO_PIN_RESET)				//PWR

#define PROFILE2(x) 				x?HAL_GPIO_WritePin(PF2_GPIO_Port,PF2_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(PF2_GPIO_Port,PF2_Pin,GPIO_PIN_RESET)				//PF2
#define PROFILE1(x) 				x?HAL_GPIO_WritePin(PF1_GPIO_Port,PF1_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(PF1_GPIO_Port,PF1_Pin,GPIO_PIN_RESET)				//PF1
#define PROFILE0(x) 				x?HAL_GPIO_WritePin(PF0_GPIO_Port,PF0_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(PF0_GPIO_Port,PF0_Pin,GPIO_PIN_RESET)				//PF0
#define IOUP(x) 						x?HAL_GPIO_WritePin(IOUP_GPIO_Port,IOUP_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(IOUP_GPIO_Port,IOUP_Pin,GPIO_PIN_RESET)				//IOUP
#define OSK(x) 							x?HAL_GPIO_WritePin(OSK_GPIO_Port,OSK_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(OSK_GPIO_Port,OSK_Pin,GPIO_PIN_RESET)				//OSK

#define DROVER(x) 					x?HAL_GPIO_WritePin(DRO_GPIO_Port,DRO_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(DRO_GPIO_Port,DRO_Pin,GPIO_PIN_RESET)				//DRO
#define DRCTL(x) 						x?HAL_GPIO_WritePin(DRC_GPIO_Port,DRC_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(DRC_GPIO_Port,DRC_Pin,GPIO_PIN_RESET)				//DRC
#define DRHOLD(x) 					x?HAL_GPIO_WritePin(DRH_GPIO_Port,DRH_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(DRH_GPIO_Port,DRH_Pin,GPIO_PIN_RESET)				//DPH
#define AD9910_SDIO(x) 			x?HAL_GPIO_WritePin(SDIO_GPIO_Port,SDIO_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(SDIO_GPIO_Port,SDIO_Pin,GPIO_PIN_RESET)				//SDIO

#define SCLK(x) 						x?HAL_GPIO_WritePin(SCK_GPIO_Port,SCK_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(SCK_GPIO_Port,SCK_Pin,GPIO_PIN_RESET)	     	//SCK
#define CSB(x) 							x?HAL_GPIO_WritePin(CSB_GPIO_Port,CSB_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(CSB_GPIO_Port,CSB_Pin,GPIO_PIN_RESET)				//CSB

void Init_AD9910(void);

void Freq_convert(ulong Freq);            //写频率
void Amp_convert(uint32_t Amplitude); 		//写幅度
void Set_cfr(void);
void Set_RAMprofile(void);
void Set_RAMdata(uint8_t wave_num);

void SweepFre(ulong Fre_L, ulong Fre_H, ulong StepFre, ulong SweepTime); //扫频
void Square_wave(uint32_t Sample_interval);		//方波;
void Sawtooth_wave(uint32_t Sample_interval);	//三角波

void AD9910_Init(void);

void Txd_8bit(uint8_t txData);				//ad9910写入的8位数据
void Txd_16bit(uint16_t txData);			//ad9910写入的16位数据
void Txd_32bit(uint32_t txData);			//ad9910写入的32位数据
void Txd_64bit(uint64_t txData);			//ad9910写入的64位数据

void TxCfr(void);											//ad9910发送频率值程序
void TxDRG(void);											//ad9910发送DRG参数程序
void Freq_convert_firm(uint64_t Freq);			//ad9910计算频偏字、频率字和发送程序
void write_Amplitude(uint32_t Amp);		//ad9910计算幅度字和发送程序
void SweepFre_firm(uint64_t SweepMinFre, uint64_t SweepMaxFre, uint64_t SweepStepFre, uint64_t SweepTime);		//ad9910设置扫频信号

#endif
/*******************************************************************************
 * @file     ad9910.h
 * @brief    ad9910驱动程序
 * @version  V2.0
 * @date     2022-7-23
 *
 * @note
 *
 ******************************************************************************/
 
#include "ad9910.h"

uint8_t cfr1[] = {0x00, 0x40, 0x00, 0x00};						  //cfr1控制字
uint8_t cfr2[] = {0x01, 0x00, 0x00, 0x00};						  //cfr2控制字
uint8_t cfr3[] = {0x05, 0x0F, 0x41, 0x32};						  //cfr3控制字  40M输入  25倍频  VC0=101   ICP=001;
uint8_t profile11[] = {0x3f, 0xff, 0x00, 0x00, 0x25, 0x09, 0x7b, 0x42}; //profile1控制字 0x25,0x09,0x7b,0x42
																	  //01振幅控制 23相位控制 4567频率调谐字

uint8_t ramprofile0[8] = {0x00};    //ramprofile0控制字
uint8_t drgparameter[20]={0x00};

//高14位幅度控制
const uint8_t ramdata_Square[4096] = 
{	
//方波
	0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 
	0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 
	0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 
	0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 
	0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 
	0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 
	0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 
	0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00, 0xff,0xfc,0x00,0x00,

	0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 
	0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 
	0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 
	0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 
	0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 
	0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 
	0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 
	0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
};

//高14位幅度控制
const uint8_t ramdata_Sawtooth[4096] = 
{
//锯齿波
	0x00,0x00,0x00,0x00, 0x03,0xfc,0x00,0x00, 0x07,0xf8,0x00,0x00, 0x0b,0xf4,0x00,0x00, 
	0x0f,0xf0,0x00,0x00, 0x13,0xec,0x00,0x00, 0x17,0xe8,0x00,0x00, 0x1b,0xe4,0x00,0x00, 
	0x1f,0xe0,0x00,0x00, 0x23,0xdc,0x00,0x00, 0x27,0xd8,0x00,0x00, 0x2b,0xd4,0x00,0x00, 
	0x2f,0xd0,0x00,0x00, 0x33,0xcc,0x00,0x00, 0x37,0xc8,0x00,0x00, 0x3b,0xc4,0x00,0x00, 
	0x3f,0xc0,0x00,0x00, 0x43,0xbc,0x00,0x00, 0x47,0xb8,0x00,0x00, 0x4b,0xb4,0x00,0x00, 
	0x4f,0xb0,0x00,0x00, 0x53,0xac,0x00,0x00, 0x57,0xa8,0x00,0x00, 0x5b,0xa4,0x00,0x00, 
	0x5f,0xa0,0x00,0x00, 0x63,0x9c,0x00,0x00, 0x67,0x98,0x00,0x00, 0x6b,0x94,0x00,0x00, 
	0x6f,0x90,0x00,0x00, 0x73,0x8c,0x00,0x00, 0x77,0x88,0x00,0x00, 0x7b,0x84,0x00,0x00, 	

	0x7f,0x80,0x00,0x00, 0x83,0x7c,0x00,0x00, 0x87,0x78,0x00,0x00, 0x8b,0x74,0x00,0x00, 
	0x8f,0x70,0x00,0x00, 0x93,0x6c,0x00,0x00, 0x97,0x68,0x00,0x00, 0x9b,0x64,0x00,0x00, 
	0x9f,0x60,0x00,0x00, 0xa3,0x5c,0x00,0x00, 0xa7,0x58,0x00,0x00, 0xab,0x54,0x00,0x00, 
	0xaf,0x50,0x00,0x00, 0xb3,0x4c,0x00,0x00, 0xb7,0x48,0x00,0x00, 0xbb,0x44,0x00,0x00, 
	0xbf,0x40,0x00,0x00, 0xc3,0x3c,0x00,0x00, 0xc7,0x38,0x00,0x00, 0xcb,0x34,0x00,0x00, 
	0xcf,0x30,0x00,0x00, 0xd3,0x2c,0x00,0x00, 0xd7,0x28,0x00,0x00, 0xdb,0x24,0x00,0x00, 
	0xdf,0x20,0x00,0x00, 0xe3,0x1c,0x00,0x00, 0xe7,0x18,0x00,0x00, 0xeb,0x14,0x00,0x00, 
	0xef,0x10,0x00,0x00, 0xf3,0x0c,0x00,0x00, 0xf7,0x08,0x00,0x00, 0xfb,0x04,0x00,0x00,
};

/********************************************************************
* 函数: Set_bit(uint8_t dat)
* 参数: dat: 要发送的数据
* 说明: 发送数据到AD9910
********************************************************************/
static void Set_bit(uint8_t dat)
{
	uint8_t i, sbt;
	
	sbt = 0x80;
	SCLK(0);
	for (i = 0; i < 8; i++)
	{
		if((dat & sbt) == 0)
			AD9910_SDIO(0);
		else
			AD9910_SDIO(1);
		SCLK(1);
		sbt = sbt >> 1;
		SCLK(0);
	}
}

/********************************************************************
* 函数: Set_Control_word(uint16_t Addr, uint8_t *Str)
* 参数: Addr: CFRx控制地址
				 *Str: CFRx控制字
				 num:	要发送的控制字数量,即数组长度
* 说明: 写控制字到AD9910寄存器
********************************************************************/
static void Set_Control_word(uint16_t Addr, uint8_t *Str, uint16_t num)
{
	uint8_t i = 0;
	
	CSB(0);
	Set_bit(Addr);
	
	for(i=0; i<num; i++)
		Set_bit( *(Str + i) );

	CSB(1);
	HAL_Delay_us(10);
}

/********************************************************************
* 函数: Set_cfr(void)
* 参数: 无
* 说明: 发送CFRx控制字
********************************************************************/
void Set_cfr(void)
{
	Set_Control_word(0x00, cfr1, 4);//写CFR
	Set_Control_word(0x01, cfr2, 4);
	Set_Control_word(0x02, cfr3, 4);
	IOUP(1);
	HAL_Delay_us(10);
	IOUP(0);
	HAL_Delay(1);
}

/********************************************************************
* 函数: Init_AD9910(void)
* 参数: 无
* 说明: AD9910 初始化
********************************************************************/
void Init_AD9910(void)
{
	AD9910_PWR(0);  		 //软件拉低

	PROFILE0(0);
	PROFILE1(0);
	PROFILE2(0);
	
	DRCTL(0);
	DRHOLD(0);
	REEST(1);
	HAL_Delay(5);
	REEST(0);
	
}

/********************************************************************
* 函数: Set_prodile0(void)
* 参数: 无
* 说明: AD9910 发送profile0控制字
********************************************************************/
static void Set_prodile0(void)
{
	Set_Control_word(0x0e, profile11, 8);//写profile0控制字
	IOUP(1);
	IOUP(0);
}

/********************************************************************
* 函数: Freq_convert(ulong Freq)
* 参数: Freq: 频率
* 说明: 计算频偏字、频率字
********************************************************************/
void Freq_convert(ulong Freq)
{
	ulong Temp;
	
	Temp = (ulong)Freq * 4.294967296 * 1.4285714286; //将输入频率因子分为四个字节  4.294967296=(2^32)/1000000000
	profile11[7] = (uint8_t)Temp;
	profile11[6] = (uint8_t)(Temp >> 8);
	profile11[5] = (uint8_t)(Temp >> 16);
	profile11[4] = (uint8_t)(Temp >> 24);
	Set_prodile0();
}

/********************************************************************
* 函数: Amp_convert(uint32_t Amp)
* 参数: Amp: 幅值
* 说明: 计算幅值
********************************************************************/
void Amp_convert(uint32_t Amp)
{
	ulong Temp;
	
	Temp = (ulong)(Amp * 21.84533); //将输入幅度因子分为两个字节  21.84533=(2^14)/750
	if (Temp > 0x3fff)
		Temp = 0x3fff;
	Temp &= 0x3fff;
	profile11[1] = (uint8_t)Temp;
	profile11[0] = (uint8_t)(Temp >> 8);
	Set_prodile0();
}

/********************************************************************
* 函数: Set_DRG(void)
* 参数: 无
* 说明: 发送DRG参数
********************************************************************/
static void Set_DRG(void)
{
	Set_Control_word(0x0b, drgparameter,8);
	Set_Control_word(0x0c, drgparameter+8,8);
	Set_Control_word(0x0c, drgparameter+16,4);
	
	IOUP(1);
	HAL_Delay_us(10);
	IOUP(0);
	HAL_Delay(1);
}

/********************************************************************
* 函数: SweepFre(ulong Fre_L, ulong Fre_H, ulong StepFre, ulong SweepTime)
* 参数: Fre_L: 		扫频最低频率 		 Hz
				 Fre_H: 		设置扫频上限频率 Hz
				 StepFre: 	设置步进频率 		 Hz
				 SweepTime:	设置步进时间间隔 us
* 说明: 扫频参数设置
********************************************************************/
void SweepFre(ulong Fre_L, ulong Fre_H, ulong StepFre, ulong SweepTime)
{
	ulong Temp1, Temp2, ITemp3, DTemp3, ITemp4, DTemp4;
	
	Temp1 = (ulong)Fre_L*4.294967296;
	if(Fre_H > 400000000)
		Fre_H = 400000000;
	
	Temp2 = (ulong)Fre_H*4.294967296;
	if(StepFre > 400000000)
		StepFre = 400000000;
	
	ITemp3 = (ulong)StepFre*4.294967296;
	DTemp3 = ITemp3;
	ITemp4 = (ulong)SweepTime/4;             //1GHz/4, 单位:ns
	if(ITemp4 > 0xffff)
		ITemp4 = 0xffff;
	DTemp4 = ITemp4;
	
	//扫频上下限
	drgparameter[7]=(uint8_t)Temp1;
	drgparameter[6]=(uint8_t)(Temp1>>8);
	drgparameter[5]=(uint8_t)(Temp1>>16);
	drgparameter[4]=(uint8_t)(Temp1>>24);
	drgparameter[3]=(uint8_t)Temp2;
	drgparameter[2]=(uint8_t)(Temp2>>8);
	drgparameter[1]=(uint8_t)(Temp2>>16);
	drgparameter[0]=(uint8_t)(Temp2>>24);
	
	//频率步进(单位:Hz)
	drgparameter[15]=(uint8_t)ITemp3;
	drgparameter[14]=(uint8_t)(ITemp3>>8);
	drgparameter[13]=(uint8_t)(ITemp3>>16);
	drgparameter[12]=(uint8_t)(ITemp3>>24);
	drgparameter[11]=(uint8_t)DTemp3;
	drgparameter[10]=(uint8_t)(DTemp3>>8);
	drgparameter[9]=(uint8_t)(DTemp3>>16);
	drgparameter[8]=(uint8_t)(DTemp3>>24);
	
	//步进时间间隔(单位:us)
	drgparameter[19]=(uint8_t)ITemp4;
	drgparameter[18]=(uint8_t)(ITemp4>>8);
	drgparameter[17]=(uint8_t)DTemp4;
	drgparameter[16]=(uint8_t)(DTemp4>>8);
	
	//发送DRG参数
	Set_DRG();
	cfr1[0] = 0x00; //RAM 失能
	cfr2[1] = 0x0e; //DRG 使能
	Set_cfr(); 			//发送cfrx控制字
}

/********************************************************************
* 函数: Set_RAMprofile(void)
* 参数: 无
* 说明: 发送RAM profile0控制字
********************************************************************/
void Set_RAMprofile(void)
{
		Set_Control_word(0x0e, ramprofile0, 8);//发送RAM profile0控制字

		IOUP(1);
		HAL_Delay_us(10);
		IOUP(0);
		HAL_Delay(1);
}

/********************************************************************
* 函数: Set_RAMdata(int wave_num)
* 参数: wave_num: 输出选择,1方波,0锯齿波
* 说明: 发送RAM控制字
********************************************************************/
void Set_RAMdata(uint8_t wave_num)
{        
	if(wave_num==1)
	{		
			uint16_t m = 0;
		
			CSB(0);
			Set_bit(0x16);                      //发送ram控制字地址
			for (m=0; m<4096; m++)
				Set_bit(ramdata_Square[m]); 
				CSB(1);
		
			HAL_Delay_us(10);
			IOUP(1);
			HAL_Delay_us(10);
			IOUP(0);
			HAL_Delay(1);
	}
	else
	{
			uint16_t m = 0;
		
			CSB(0);
			Set_bit(0x16);                      //发送ram控制字地址
			for (m=0; m<4096; m++)
				Set_bit(ramdata_Sawtooth[m]); 
				CSB(1);
		
			HAL_Delay_us(10);
			IOUP(1);
			HAL_Delay_us(10);
			IOUP(0);
			HAL_Delay(1);
	}	
}

/********************************************************************
* 函数: Square_wave(uint32_t Sample_interval)
* 参数: Sample_interval:  采样频率
* 说明: 产生方波
********************************************************************/
void Square_wave(uint32_t Sample_interval)
{
		ulong Temp;

		//1GHz/4, 采样间隔范围:4*(1~65536)ns
		Temp = ((1000000000/(unsigned long int)(Sample_interval)/64/4)); 
		if(Temp > 0xffff)
						Temp = 0xffff;
		ramprofile0[7] = 0x24;
		ramprofile0[6] = 0x00;
		ramprofile0[5] = 0x00;
		ramprofile0[4] = 0xc0;
		ramprofile0[3] = 0x0f;
		ramprofile0[2] = (uint8_t)Temp;
		ramprofile0[1] = (uint8_t)(Temp>>8);
		ramprofile0[0] = 0x00;
		Set_RAMprofile();
		Set_RAMdata(1); 
		cfr1[0] = 0xc0;        //RAM 使能,幅度控制
		cfr2[1] = 0x00;        //DRG 失能
		Set_cfr();             //发送cfrx控制字				
}

/********************************************************************
* 函数: Sawtooth_wave(uint32_t Sample_interval)
* 参数: Sample_interval:  采样频率
* 说明: 产生锯齿波
********************************************************************/
void Sawtooth_wave(uint32_t Sample_interval)
{
		ulong Temp;

		//1GHz/4, 采样间隔范围:4*(1~65536)ns
		Temp = ((1000000000/(unsigned long int)(Sample_interval)/64/4));
		if(Temp > 0xffff)
						Temp = 0xffff;
		ramprofile0[7] = 0x24;
		ramprofile0[6] = 0x00;
		ramprofile0[5] = 0x00;
		ramprofile0[4] = 0xc0;
		ramprofile0[3] = 0x0f;
		ramprofile0[2] = (uint8_t)Temp;
		ramprofile0[1] = (uint8_t)(Temp>>8);
		ramprofile0[0] = 0x00;
		Set_RAMprofile();
		Set_RAMdata(0); 
		cfr1[0] = 0xc0;                          //RAM 使能,幅度控制
		cfr2[1] = 0x00;                          //DRG 失能
		Set_cfr();                               //发送cfrx控制字				
}

/* ======================================================================================================================================= */

 /**
  * @brief  ad9910写入的8位数据(地址)
  * @param  txData	写入的8位数据(地址)
  * @return none
	* @note		寄存器地址,单个字节操作
  */
void Txd_8bit(uint8_t txData)
{
	uint8_t i,dat;
	dat=0x80;
	SCLK(0);
	for(i=0;i<8;i++)
	{
		if((txData&dat)==0)
			AD9910_SDIO(0);
		else
			AD9910_SDIO(1);
		SCLK(1);
		dat>>=1;
		SCLK(0);
	}
}

/**
  * @brief  ad9910发送频率值程序
  * @param  none
  * @return none
	* @note		
  */
void TxCfr(void)
{
	uint8_t i;
	CSB(0);
	Txd_8bit(regControlSFMProfile0);
	for(i=0;i<8;i++)
		Txd_8bit(profile11[i]);
	CSB(1);
	
	IOUP(1);
	HAL_Delay(1);
	IOUP(0);
}

/**
  * @brief  ad9910计算频偏字、频率字和发送程序
  * @param  Freq	填入的频率值
  * @return none
	* @note		
  */
void Freq_convert_firm(uint64_t Freq)
{
	uint64_t Temp;
	Temp=(uint64_t)Freq*4.294967296;	   //将输入频率因子分为四个字节  4.294967296=(2^32)/1000000000
	Temp=Temp*1.44;
	profile11[7]=(uint8_t)Temp;
	profile11[6]=(uint8_t)(Temp>>8);
	profile11[5]=(uint8_t)(Temp>>16);
	profile11[4]=(uint8_t)(Temp>>24);
	TxCfr();
}

/**
  * @brief  ad9910计算幅度字和发送程序
  * @param  Amp	幅度字
  * @return none
	* @note		
  */
void write_Amplitude(uint32_t Amp)
{
	uint64_t temp;
	temp = (uint64_t)Amp * 25.20615385;//将输入幅度因子分为两个字节,25.20615385 = 2^14/650;
	if(temp > 0x3fff)
		temp = 0x3fff;
	temp &= 0x3fff;
	profile11[1] = (uint8_t)temp;
	profile11[0] = (uint8_t)(temp >> 8);
	TxCfr();
}

/**
  * @brief  ad9910设置扫频信号
  * @param  Amp	幅度字
  * @return none
	* @note		
  */
void SweepFre_firm(uint64_t SweepMinFre, uint64_t SweepMaxFre, uint64_t SweepStepFre, uint64_t SweepTime)
{
	uint64_t Temp1, Temp2, ITemp3, DTemp3, ITemp4, DTemp4;
	Temp1 = (uint64_t)SweepMinFre*4.294967296;
	if(SweepMaxFre > 400000000)
		SweepMaxFre = 400000000;
	Temp2 = (uint64_t)SweepMaxFre*4.294967296;
	if(SweepStepFre > 400000000)
		SweepStepFre = 400000000;
	ITemp3 = (uint64_t)SweepStepFre*4.294967296;
	DTemp3 = ITemp3;
	ITemp4 = (uint64_t)SweepTime/4; //1GHz/4, 单位:ns
	if(ITemp4 > 0xffff)
		ITemp4 = 0xffff;
	DTemp4 = ITemp4;
	
	//扫频上下限
	drgparameter[7]=(uint8_t)Temp1;
	drgparameter[6]=(uint8_t)(Temp1>>8);
	drgparameter[5]=(uint8_t)(Temp1>>16);
	drgparameter[4]=(uint8_t)(Temp1>>24);
	drgparameter[3]=(uint8_t)Temp2;
	drgparameter[2]=(uint8_t)(Temp2>>8);
	drgparameter[1]=(uint8_t)(Temp2>>16);
	drgparameter[0]=(uint8_t)(Temp2>>24);
	//频率步进(单位:Hz)
	drgparameter[15]=(uint8_t)ITemp3;
	drgparameter[14]=(uint8_t)(ITemp3>>8);
	drgparameter[13]=(uint8_t)(ITemp3>>16);
	drgparameter[12]=(uint8_t)(ITemp3>>24);
	drgparameter[11]=(uint8_t)DTemp3;
	drgparameter[10]=(uint8_t)(DTemp3>>8);
	drgparameter[9]=(uint8_t)(DTemp3>>16);
	drgparameter[8]=(uint8_t)(DTemp3>>24);
	//步进时间间隔(单位:us)
	drgparameter[19]=(uint8_t)ITemp4;
	drgparameter[18]=(uint8_t)(ITemp4>>8);
	drgparameter[17]=(uint8_t)DTemp4;
	drgparameter[16]=(uint8_t)(DTemp4>>8);
	//发送DRG参数
	TxDRG();
}

/**
  * @brief  ad9910发送DRG参数程序
  * @param  none
  * @return none
	* @note		
  */
void TxDRG(void)
{
	uint8_t m,k;

	CSB(0);
	Txd_8bit(0x0b);    //发送数字斜坡限制地址0x0b
	for (m=0;m<8;m++)
		Txd_8bit(drgparameter[m]); 
	CSB(1);
	for(k=0;k<10;k++);
	
	CSB(0);
	Txd_8bit(0x0c);    //发送数字斜坡步长地址0x0c
	for (m=8;m<16;m++)
		Txd_8bit(drgparameter[m]); 
	CSB(1);
	for(k=0;k<10;k++);
	
	CSB(0);
	Txd_8bit(0x0d);    //发送数字斜坡速率地址0x0d
	for (m=16;m<20;m++)
		Txd_8bit(drgparameter[m]); 
	CSB(1);
	for(k=0;k<10;k++);
	
	IOUP(1);
	for(k=0;k<10;k++);
	IOUP(0);
	HAL_Delay(1);
}

static void AD9910_GPIO_Config(void)
{
	REEST(0);
}

static void AD9910_CFR_Config(void)
{
	uint8_t k,m;
	AD9910_GPIO_Config();			//IO口初始化
	AD9910_PWR(0);
	PROFILE0(0);	PROFILE1(0);	PROFILE2(0);
	DRHOLD(0);	DRCTL(0);
	REEST(1);	HAL_Delay(5);	REEST(0);
	
	CSB(0);
	Txd_8bit(regControlCFR1);
	for(m=0;m<4;m++)
		Txd_8bit(cfr1[m]);
	CSB(1);
	for (k=0;k<10;k++);
	
	CSB(0);
	Txd_8bit(regControlCFR2);
	for(m=0;m<4;m++)
		Txd_8bit(cfr2[m]);
	CSB(1);
	for (k=0;k<10;k++);
	
	CSB(0);
	Txd_8bit(regControlCFR3);
	for(m=0;m<4;m++)
		Txd_8bit(cfr3[m]);
	CSB(1);
	for (k=0;k<10;k++);
	
	IOUP(1);
	for(k=0;k<10;k++);
	IOUP(0);
	HAL_Delay(1);
}

void AD9910_Init(void)
{
	AD9910_CFR_Config();
}

/**
  * @brief  ad9910写入的16位数据
  * @param  txData	写入的16位数据
  * @return none
	* @note		POW寄存器操作,双位字节操作
  */
void Txd_16bit(uint16_t txData)
{
	uint8_t i;
	uint16_t dat;
	dat=0x8000;
	SCLK(0);
	for(i=0;i<16;i++)
	{
		if((txData&dat)==0)
			AD9910_SDIO(0);
		else
			AD9910_SDIO(1);
		SCLK(1);
		dat>>=1;
		SCLK(0);
	}
}

/**
  * @brief  ad9910写入的32位数据
  * @param  txData	写入的32位数据
  * @return none
	* @note		对CFR1~3、DAC、IO更新速率、FTW、ASF、多芯片同步、斜坡速率、RAM操作
  */
void Txd_32bit(uint32_t txData)
{
	uint8_t i;
	uint32_t dat;
	dat=0x80000000;
	SCLK(0);
	for(i=0;i<32;i++)
	{
		if((txData&dat)==0)
			AD9910_SDIO(0);
		else
			AD9910_SDIO(1);
		SCLK(1);
		dat>>=1;
		SCLK(0);
	}
}

/**
  * @brief  ad9910写入的64位数据
  * @param  txData	写入的64位数据
  * @return none
	* @note		对斜坡限值、斜坡步长、Profile0~7(单频调制、RAM)操作
  */
void Txd_64bit(uint64_t txData)
{
	uint8_t i;
	uint64_t dat;
	dat=0x8000000000000000;
	SCLK(0);
	for(i=0;i<64;i++)
	{
		if((txData&dat)==0)
			AD9910_SDIO(0);
		else
			AD9910_SDIO(1);
		SCLK(1);
		dat>>=1;
		SCLK(0);
	}
}

ADS8885

/*******************************************************************************
 * @file     ads8885.h
 * @brief    ads8885驱动头文件
 * @version  V1.0
 * @date     2021-10-27
 *
 * @note
 *
 ******************************************************************************/
#ifndef __ADS_8885_H
#define __ADS_8885_H

#include "main.h"
//#include "spi.h"
#include "soft_spi.h"
#include "gpio.h"
#include "usart.h"

extern enum {	Wire3Soft_1=0,
							Wire3Soft_2,
							Wire4Soft_1,
							Wire4Soft_2} mode;

#define CTL_H  			HAL_GPIO_WritePin(CTL_GPIO_Port, CTL_Pin, GPIO_PIN_SET)
#define CTL_L  			HAL_GPIO_WritePin(CTL_GPIO_Port, CTL_Pin, GPIO_PIN_RESET)
//#define DIN_H   		HAL_GPIO_WritePin(DIN_GPIO_Port, DIN_Pin, GPIO_PIN_SET)
//#define DIN_L   		HAL_GPIO_WritePin(DIN_GPIO_Port, DIN_Pin, GPIO_PIN_RESET)
#define CONVST_H    HAL_GPIO_WritePin(CONVST_GPIO_Port, CONVST_Pin, GPIO_PIN_SET)
#define CONVST_L    HAL_GPIO_WritePin(CONVST_GPIO_Port, CONVST_Pin, GPIO_PIN_RESET)

//uint32_t getData_3Wire(void);
uint32_t getData_3WireSoft(void);
uint32_t getData_4WireSoft(void);

double TansformData(uint8_t mode);
							
void getRData(float *data, int Avg);
		
/*                           第二块ADS8885                          */
#define CTL2_H  			HAL_GPIO_WritePin(CTL2_GPIO_Port, CTL2_Pin, GPIO_PIN_SET)
#define CTL2_L  			HAL_GPIO_WritePin(CTL2_GPIO_Port, CTL2_Pin, GPIO_PIN_RESET)
#define CVST2_H    		HAL_GPIO_WritePin(CVST2_GPIO_Port, CVST2_Pin, GPIO_PIN_SET)
#define CVST2_L    		HAL_GPIO_WritePin(CVST2_GPIO_Port, CVST2_Pin, GPIO_PIN_RESET)			

uint32_t getData2_3WireSoft(void);
double TansformData_2ADS(uint8_t mode);
void getRData_2ADS(float *data, int Avg);

#endif
#ifndef __SOFT_SPI_H
#define __SOFT_SPI_H

#include "main.h"
#include "gpio.h"
#include "usart.h"

#define MOSI_H  HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_SET)
#define MOSI_L  HAL_GPIO_WritePin(MOSI_GPIO_Port, MOSI_Pin, GPIO_PIN_RESET)
#define SCLK_H   HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_SET)
#define SCLK_L   HAL_GPIO_WritePin(SCLK_GPIO_Port, SCLK_Pin, GPIO_PIN_RESET)
#define MISO    HAL_GPIO_ReadPin(MISO_GPIO_Port, MISO_Pin)

/* CPOL = 0, CPHA = 0, MSB first MODE0*/
uint8_t SOFT_SPI_RW_MODE0( uint8_t write_dat );
uint8_t SPI_Receiver_MODE0(void);
/* CPOL=0,CPHA=1, MSB first MODE1*/
uint8_t SOFT_SPI_RW_MODE1(uint8_t byte) ;
uint8_t SPI_Receiver_MODE1(void);
uint32_t SPI_Re_18Data(void);
/* CPOL=1,CPHA=0, MSB first MODE2*/
uint8_t SOFT_SPI_RW_MODE2(uint8_t byte) ;
uint8_t SPI_Receiver_MODE2(void);
/* CPOL = 1, CPHA = 1, MSB first MODE3*/
uint8_t SOFT_SPI_RW_MODE3( uint8_t write_dat );
uint8_t SPI_Receiver_MODE3(void);

/*                           第二块ADS8885                          */
#define MOSI2_H  	HAL_GPIO_WritePin(MOSI2_GPIO_Port, MOSI2_Pin, GPIO_PIN_SET)
#define MOSI2_L  	HAL_GPIO_WritePin(MOSI2_GPIO_Port, MOSI2_Pin, GPIO_PIN_RESET)
#define SCLK2_H   HAL_GPIO_WritePin(SCLK2_GPIO_Port, SCLK2_Pin, GPIO_PIN_SET)
#define SCLK2_L   HAL_GPIO_WritePin(SCLK2_GPIO_Port, SCLK2_Pin, GPIO_PIN_RESET)
#define MISO2    	HAL_GPIO_ReadPin(MISO2_GPIO_Port, MISO2_Pin)

uint32_t SPI2_Re_18Data(void);

#endif
/*******************************************************************************
 * @file     ads8885.c
 * @brief    ads8885
 * @version  V1.0
 * @date     2021-10-27
 *
 * @note
 *
 ******************************************************************************/
#include "ads8885.h"

/*ADS8885 三线操作*/
uint32_t getData_3WireSoft(void)
{
	uint32_t data;
	CTL_L;
	CONVST_H;
	HAL_Delay_us(1);
	CONVST_L;
	data = SPI_Re_18Data();
	CONVST_H;
	CTL_H;
	return data;
}

uint32_t getData2_3WireSoft(void)
{
	uint32_t data;
	CTL2_L;
	CVST2_H;
	HAL_Delay_us(1);
	CVST2_L;
	data = SPI2_Re_18Data();
	CVST2_H;
	CTL2_H;
	return data;
}

/*ADS8885 四线操作*/
/*
uint32_t getData_4WireSoft(void)
{
	uint32_t data;
	CTL_L;
	DIN_H;
	CONVST_H;
	HAL_Delay_us(1);
	DIN_L;
	data = SPI_Re_18Data();
	DIN_H;
	CONVST_L;
	CONVST_H;
	return data;
}
*/

double TansformData(uint8_t mode)
{
	double transdata;
	uint32_t data;
//	if(mode == Wire3Soft_1)
//	{
//		data = getData_3WireSoft()+105;
	data = getData_3WireSoft();
		if(data & 0x20000)
		{
			transdata = ((double)(data&0x1ffff)*4.096)/131071;
			if(transdata > 8)
				return 0;
			return transdata-4.096;
		}
		else 
		{
			transdata = ((double)data*4.096)/131071;
			if(transdata > 8)
				return 0;
			return transdata;
		}
	return 0;
}

void getRData(float *data, int Avg)
{
	for(int i=0;i<Avg;i++)
	{
		data[i] = TansformData(Wire3Soft_1);
//		HAL_Delay_us(1);
	}
}




/*                           第二块ADS8885                          */
double TansformData_2ADS(uint8_t mode)
{
	double transdata;
	uint32_t data;
	data = getData2_3WireSoft();
		if(data & 0x20000)
		{
			transdata = ((double)(data&0x1ffff)*4.096)/131071;
			if(transdata > 8)
				return 0;
			return transdata-4.096;
		}
		else 
		{
			transdata = ((double)data*4.096)/131071;
			if(transdata > 8)
				return 0;
			return transdata;
		}
	return 0;
}
void getRData_2ADS(float *data, int Avg)
{
	for(int i=0;i<Avg;i++)
	{
		data[i] = TansformData_2ADS(Wire3Soft_1);
	}
}



#if 0			//硬件SPI
uint32_t getData_3Wire(void)
{
	uint32_t data;
	uint8_t dat[3]={0};
	HAL_GPIO_WritePin(CTL_GPIO_Port,CTL_Pin,GPIO_PIN_SET);		//拉低CTL引脚,保持电平
	HAL_GPIO_WritePin(CONVST_GPIO_Port,CONVST_Pin,GPIO_PIN_SET);
	HAL_Delay_us(1);
	HAL_GPIO_WritePin(CONVST_GPIO_Port,CONVST_Pin,GPIO_PIN_RESET);
	if(HAL_SPI_Receive(&hspi3,(uint8_t*)dat,3,0xff) == HAL_OK)
	{
		data = ((dat[0]<<16) | (dat[1]<<8) | dat[2]);
	}
	HAL_GPIO_WritePin(CTL_GPIO_Port,CTL_Pin,GPIO_PIN_RESET);		//拉高CTL引脚,进行下一次转换
	HAL_Delay_us(1);
	return data;
}
#endif

#include "soft_spi.h"

/*********************************************
模式零         读数据
*********************************************/
/* CPOL = 0, CPHA = 0, MSB first MODE0*/
uint8_t SOFT_SPI_RW_MODE0( uint8_t write_dat )
{
    uint8_t i, read_dat;
    for( i = 0; i < 8; i++ )
    {
        if( write_dat & 0x80 )
            MOSI_H;
        else                    
            MOSI_L;  
        write_dat <<= 1;
        HAL_Delay_us(1);	
        SCLK_H; 
        read_dat <<= 1;  
        if( MISO ) 
            read_dat++; 
				HAL_Delay_us(1);
        SCLK_L; 
        __nop();
    }
    return read_dat;
}
uint8_t SPI_Receiver_MODE0(void)
{
	uint8_t n ,dat;
	for(n=0;n<8;n++)
	{
		SCLK_L;
		dat<<=1;
		if(MISO)		//读取电平
			dat|=0x01;
		else 
			dat&=0xfe;
		SCLK_H;
	}
	SCLK_L;
	return dat;
}

/*********************************************
模式一       读数据
*********************************************/
/* CPOL=0,CPHA=1, MSB first MODE1*/
uint8_t SOFT_SPI_RW_MODE1(uint8_t byte) 
{
  uint8_t i,Temp=0;
	for(i=0;i<8;i++)     // 循环8次
	{
		SCLK_H;     //拉高时钟
		if(byte&0x80)
        {
			MOSI_H;  //若最到位为高,则输出高
        }
		else      
		{
			MOSI_L;   //若最到位为低,则输出低
		}
		byte <<= 1;     // 低一位移位到最高位
		HAL_Delay_us(1);
		SCLK_L;     //拉低时钟
		Temp <<= 1;     //数据左移
 
		if(MISO)
			Temp++;     //若从从机接收到高电平,数据自加一
		HAL_Delay_us(1);
	}
	return (Temp);     //返回数据
}

uint8_t SPI_Receiver_MODE1(void)
{
 uint8_t n ,dat=0;
 for(n=0;n<8;n++)
 {
  SCLK_H;
   dat<<=1;
  if(MISO)
		dat|=0x01;
  else 
		dat&=0xfe;
  SCLK_L;
 }
  SCLK_L;
  return dat;
}
uint32_t SPI_Re_18Data(void)
{
	uint8_t n ;
	uint32_t dat=0;
	for(n=0;n<18;n++)
 {
 #if 1
 SCLK_H;
    dat<<=1;
  if(MISO)
		dat|=0x00001;
  else 
		dat&=0x3ffff;
  SCLK_L;
 }
  SCLK_L;
 dat = (~dat) & (0x3ffff);
 #endif
  return dat;
}
 

uint32_t SPI2_Re_18Data(void)
{
	uint8_t n ;
	uint32_t dat=0;
	for(n=0;n<18;n++)
 {
 #if 1
 SCLK2_H;
    dat<<=1;
  if(MISO2)
		dat|=0x00001;
  else 
		dat&=0x3ffff;
  SCLK2_L;
 }
  SCLK2_L;
 dat = (~dat) & (0x3ffff);
 #endif
  return dat;
}


/*********************************************
模式二          读数据
*********************************************/
/* CPOL=1,CPHA=0, MSB first MODE2*/
uint8_t SOFT_SPI_RW_MODE2(uint8_t byte) 
{
    uint8_t i,Temp=0;
 
	for(i=0;i<8;i++)     // 循环8次
	{
		if(byte&0x80)
    {
			MOSI_H;  //若最到位为高,则输出高
    }
		else      
		{
			MOSI_L;   //若最到位为低,则输出低
		}
		byte <<= 1;     // 低一位移位到最高位
		HAL_Delay_us(1);
		SCLK_L;     //拉低时钟
		Temp <<= 1;     //数据左移
 
		if(MISO)
			Temp++;     //若从从机接收到高电平,数据自加一
		HAL_Delay_us(1);
		SCLK_H;     //拉高时钟
	}
	return (Temp);     //返回数据
}
 
uint8_t SPI_Receiver_MODE2(void)
{
 uint8_t n ,dat;
 for(n=0;n<8;n++)
 {
  SCLK_H;
  dat<<=1;
  if(MISO)
		dat|=0x01;
  else 
		dat&=0xfe;
  SCLK_L;
 }
  SCLK_L;
  return dat;
}
 
/************************************
模式三          读数据
************************************/
/* CPOL = 1, CPHA = 1, MSB first MODE3*/
uint8_t SOFT_SPI_RW_MODE3( uint8_t write_dat )
{
    uint8_t i, read_dat;
    for( i = 0; i < 8; i++ )
    {
			SCLK_L;
			if( write_dat & 0x80 )
					MOSI_H;  
			else
					MOSI_L;  
			write_dat <<= 1;
			HAL_Delay_us(1);	
			SCLK_H; 
			read_dat <<= 1;  
			if( MISO ) 
					read_dat++; 
			HAL_Delay_us(1);
			__nop();
    }
    return read_dat;
}

uint8_t SPI_Receiver_MODE3(void)
{
 uint8_t n ,dat;
 SCLK_L;
 for(n=0;n<8;n++)
 { 
	SCLK_L;
	dat<<=1;
	if(MISO)
		dat|=0x01;
	else 
	  dat&=0xfe;
	SCLK_H;
 }
	SCLK_H;
	return dat;
}

注意:由于是使用了两块ADS8885分别对AM和FM两路解调信号进行采样,采到的数据经过加窗,FFT处理,可以得到解调信号的频率

加窗函数

/*
*file		WindowFunction.h
*author		Vincent Cui
*e-mail		whcui1987@163.com
*version	0.3
*data		31-Oct-2014
*brief		各种窗函数的C语言实现
*/

#ifndef _WINDOWFUNCTION_H_
#define _WINDOWFUNCTION_H_

#include <stdint.h>

#define besseli_Flag	0	//缺少besseli函数
#define prod_Flag		0	//缺少prod函数
#define linSpace_Flag	0	//缺少linSpace函数

#define BESSELI_K_LENGTH 10

#define FLATTOPWIN_A0  0.215578995
#define FLATTOPWIN_A1  0.41663158
#define FLATTOPWIN_A2  0.277263158
#define FLATTOPWIN_A3  0.083578947
#define FLATTOPWIN_A4  0.006947368

#define NUTTALL_A0   0.3635819
#define NUTTALL_A1   0.4891775
#define NUTTALL_A2   0.1365995
#define NUTTALL_A3   0.0106411

#define BLACKMANHARRIS_A0 0.35875
#define BLACKMANHARRIS_A1 0.48829
#define BLACKMANHARRIS_A2 0.14128
#define BLACKMANHARRIS_A3 0.01168

#define PI 3.14159265358979323846264338327950288419717  //定义圆周率值

typedef enum
{
	DSP_ERROR = 0,
	DSP_SUCESS,
}dspErrorStatus;

dspErrorStatus triangularWin(uint16_t N, double w[]);
dspErrorStatus bartlettWin(uint16_t N, double w[]);
dspErrorStatus bartLettHannWin(uint16_t N, double w[]);
dspErrorStatus blackManWin(uint16_t N, double w[]);
dspErrorStatus blackManHarrisWin(uint16_t N, double w[]);
dspErrorStatus bohmanWin(uint16_t N, double w[]);
dspErrorStatus chebyshevWin(uint16_t N, double r, double w[]);
dspErrorStatus flatTopWin(uint16_t N, double w[]);
dspErrorStatus gaussianWin(uint16_t N, double alpha, double w[]);
dspErrorStatus hammingWin(uint16_t N, double w[]);
dspErrorStatus hannWin(uint16_t N, double w[]);
dspErrorStatus nuttalWin(uint16_t N, double w[]);
dspErrorStatus parzenWin(uint16_t N, double w[]);
dspErrorStatus rectangularWin(uint16_t N, double w[]);

#if besseli_Flag
dspErrorStatus kaiserWin(uint16_t N, double beta, double w[]);
#endif

#if prod_Flag
dspErrorStatus taylorWin(uint16_t N, uint16_t nbar, double sll, double w[]);
#endif

#if linSpace_Flag
dspErrorStatus tukeyWin(uint16_t N, double r, double w[]);
#endif

#endif
/*
*file		WindowFunction.c
*author		Vincent Cui
*e-mail		whcui1987@163.com
*version	0.3
*data		31-Oct-2014
*brief		各种窗函数的C语言实现
*/

#include "winfun.h"
#include <math.h>
#include <stdlib.h>

#if prod_Flag
/*函数名:taylorWin
*说明:计算泰勒窗。泰勒加权函数
*输入:
*输出:
*返回:
*调用:prod()连乘函数
*其它:用过以后,需要手动释放掉*w的内存空间
*        调用示例:ret = taylorWin(99, 4, 40, &w); 注意此处的40是正数 表示-40dB
*/
dspErrorStatus taylorWin(dspUint_16 N, dspUint_16 nbar, dspDouble sll, dspDouble **w)
{
	dspDouble A;
	dspDouble *retDspDouble;
	dspDouble *sf;
	dspDouble *result;
	dspDouble alpha, beta, theta;
	dspUint_16 i, j;

	/*A = R   cosh(PI, A) = R*/
	A = (dspDouble)acosh(pow((dspDouble)10.0, (dspDouble)sll / 20.0)) / PI;
	A = A * A;

	/*开出存放系数的空间*/
	retDspDouble = (dspDouble *)malloc(sizeof(dspDouble) * (nbar - 1));
	if (retDspDouble == NULL)
		return DSP_ERROR;
	sf = retDspDouble;

	/*开出存放系数的空间*/
	retDspDouble = (dspDouble *)malloc(sizeof(dspDouble) * N);
	if (retDspDouble == NULL)
		return DSP_ERROR;
	result = retDspDouble;

	alpha = prod(1, 1, (nbar - 1));
	alpha *= alpha;
	beta = (dspDouble)nbar / sqrt(A + pow((nbar - 0.5), 2));
	for (i = 1; i <= (nbar - 1); i++)
	{
		*(sf + i - 1) = prod(1, 1, (nbar - 1 + i)) * prod(1, 1, (nbar - 1 - i));
		theta = 1;
		for (j = 1; j <= (nbar - 1); j++)
		{
			theta *= 1 - (dspDouble)(i * i) / (beta * beta * (A + (j - 0.5) * (j - 0.5)));
		}
		*(sf + i - 1) = alpha * (dspDouble)theta / (*(sf + i - 1));
	}

	/*奇数阶*/
	if ((N % 2) == 1)
	{
		for (i = 0; i < N; i++)
		{
			alpha = 0;
			for (j = 1; j <= (nbar - 1); j++)
			{
				alpha += (*(sf + j - 1)) * cos(2 * PI * j * (dspDouble)(i - ((N - 1) / 2)) / N);
			}
			*(result + i) = 1 + 2 * alpha;
		}
	}
	/*偶数阶*/
	else
	{
		for (i = 0; i < N; i++)
		{
			alpha = 0;
			for (j = 1; j <= (nbar - 1); j++)
			{
				alpha += (*(sf + j - 1)) * cos(PI * j * (dspDouble)(2 * (i - (N / 2)) + 1) / N);
			}
			*(result + i) = 1 + 2 * alpha;

		}
	}
	*w = result;
	free(sf);

	return DSP_SUCESS;
}
#endif

/*
*函数名:triangularWin
*说明:计算三角窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = triangularWin(99, w);
*/
dspErrorStatus triangularWin(uint16_t N, double w[])
{
	uint16_t i;

	/*阶数为奇*/
	if ((N % 2) == 1)
	{
		for (i = 0; i < ((N - 1) / 2); i++)
		{
			w[i] = 2 * (double)(i + 1) / (N + 1);
		}
		for (i = ((N - 1) / 2); i < N; i++)
		{
			w[i] = 2 * (double)(N - i) / (N + 1);
		}
	}
	/*阶数为偶*/
	else
	{
		for (i = 0; i < (N / 2); i++)
		{
			w[i] = (i + i + 1) * (double)1 / N;
		}
		for (i = (N / 2); i < N; i++)
		{
			w[i] = w[N - 1 - i];
		}
	}

	return DSP_SUCESS;
}

#if linSpace_Flag
/*
*函数名:tukeyWin
*说明:计算tukey窗函数
*输入:
*输出:
*返回:linSpace()
*调用:
*其它:用过以后,需要手动释放掉*w的内存空间
*        调用示例:ret = tukeyWin(99, 0.5, &w);
*/
dspErrorStatus tukeyWin(dspUint_16 N, dspDouble r, dspDouble **w)
{
	dspErrorStatus retErrorStatus;
	dspUint_16        index;
	dspDouble        *x, *result, *retPtr;
	dspDouble        alpha;

	retErrorStatus = linSpace(0, 1, N, &x);
	if (retErrorStatus == DSP_ERROR)
		return DSP_ERROR;

	result = (dspDouble *)malloc(N * sizeof(dspDouble));
	if (result == NULL)
		return DSP_ERROR;

	/*r <= 0 就是矩形窗*/
	if (r <= 0)
	{
		retErrorStatus = rectangularWin(N, &retPtr);
		if (retErrorStatus == DSP_ERROR)
			return DSP_ERROR;
		/*将数据拷出来以后,释放调用的窗函数的空间*/
		memcpy(result, retPtr, (N * sizeof(dspDouble)));
		free(retPtr);
	}
	/*r >= 1 就是汉宁窗*/
	else if (r >= 1)
	{
		retErrorStatus = hannWin(N, &retPtr);
		if (retErrorStatus == DSP_ERROR)
			return DSP_ERROR;
		/*将数据拷出来以后,释放调用的窗函数的空间*/
		memcpy(result, retPtr, (N * sizeof(dspDouble)));
		free(retPtr);
	}
	else
	{
		for (index = 0; index < N; index++)
		{
			alpha = *(x + index);
			if (alpha < (r / 2))
			{
				*(result + index) = (dspDouble)(1 + cos(2 * PI * (dspDouble)(alpha - (dspDouble)r / 2) / r)) / 2;
			}
			else if ((alpha >= (r / 2)) && (alpha <(1 - r / 2)))
			{
				*(result + index) = 1;
			}
			else
			{
				*(result + index) = (dspDouble)(1 + cos(2 * PI * (dspDouble)(alpha - 1 + (dspDouble)r / 2) / r)) / 2;
			}

		}
	}

	free(x);

	*w = result;

	return DSP_SUCESS;
}
#endif

/*
*函数名:bartlettWin
*说明:计算bartlettWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = bartlettWin(99, w);
*/
dspErrorStatus bartlettWin(uint16_t N, double w[])
{
	
	uint16_t n;

	for (n = 0; n < (N - 1) / 2; n++)
	{
		w[n] = 2 * (double)n / (N - 1);
	}

	for (n = (N - 1) / 2; n < N; n++)
	{
		w[n] = 2 - 2 * (double)n / ((N - 1));
	}

	return DSP_SUCESS;
}

/*
*函数名:bartLettHannWin
*说明:计算bartLettHannWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = bartLettHannWin(99, w);
*/
dspErrorStatus bartLettHannWin(uint16_t N, double w[])
{
	uint16_t n;

	/*奇*/
	if ((N % 2) == 1)
	{
		for (n = 0; n < N; n++)
		{
			w[n] = 0.62 - 0.48 * fabs(((double)n / (N - 1)) - 0.5) + 0.38 * cos(2 * PI * (((double)n / (N - 1)) - 0.5));
		}
		for (n = 0; n < (N - 1) / 2; n++)
		{
			w[n] = w[N - 1 - n];
		}
	}
	/*偶*/
	else
	{
		for (n = 0; n < N; n++)
		{
			w[n] = 0.62 - 0.48 * fabs(((double)n / (N - 1)) - 0.5) + 0.38 * cos(2 * PI * (((double)n / (N - 1)) - 0.5));
		}
		for (n = 0; n < N / 2; n++)
		{
			w[n] = w[N - 1 - n];
		}
	}

	return DSP_SUCESS;
}

/*
*函数名:blackManWin
*说明:计算blackManWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = blackManWin(99, w);
*/
dspErrorStatus blackManWin(uint16_t N, double w[])
{
	uint16_t n;

	for (n = 0; n < N; n++)
	{
		w[n] = 0.42 - 0.5 * cos(2 * PI * (double)n / (N - 1)) + 0.08 * cos(4 * PI * (double)n / (N - 1));
	}

	return DSP_SUCESS;
}

/*
*函数名:blackManHarrisWin
*说明:计算blackManHarrisWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = blackManHarrisWin(99, w);
*  minimum 4-term Blackman-harris window -- From Matlab
*/
dspErrorStatus blackManHarrisWin(uint16_t N, double w[])
{
	uint16_t n;

	for (n = 0; n < N; n++)
	{
		w[n] = BLACKMANHARRIS_A0 - BLACKMANHARRIS_A1 * cos(2 * PI * (double)n / (N)) + \
			BLACKMANHARRIS_A2 * cos(4 * PI * (double)n / (N)) - \
			BLACKMANHARRIS_A3 * cos(6 * PI * (double)n / (N));
	}

	return DSP_SUCESS;
}

/*
*函数名:bohmanWin
*说明:计算bohmanWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = bohmanWin(99, w);
*/
dspErrorStatus bohmanWin(uint16_t N, double w[])
{
	uint16_t n;
	
	double x;

	for (n = 0; n < N; n++)
	{
		x = -1 + n *  (double)2 / (N - 1);
		/*取绝对值*/
		x = x >= 0 ? x : (x * (-1));
		w[n] = (1 - x) * cos(PI * x) + (double)(1 / PI) * sin(PI * x);
	}

	return DSP_SUCESS;
}

/*
*函数名:chebyshevWin
*说明:计算chebyshevWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = chebyshevWin(99,100, w);
*/
dspErrorStatus chebyshevWin(uint16_t N, double r, double w[])
{
	uint16_t n, index;
	
	double x, alpha, beta, theta, gama;

	/*10^(r/20)*/
	theta = pow((double)10, (double)(fabs(r) / 20));
	beta = pow(cosh(acosh(theta) / (N - 1)), 2);
	alpha = 1 - (double)1 / beta;

	if ((N % 2) == 1)
	{
		/*计算一半的区间*/
		for (n = 1; n < (N + 1) / 2; n++)
		{
			gama = 1;
			for (index = 1; index < n; index++)
			{
				x = index * (double)(N - 1 - 2 * n + index) / ((n - index) * (n + 1 - index));
				gama = gama * alpha * x + 1;
			}
			w[n] = (N - 1) * alpha * gama;
		}

		theta = w[(N - 1) / 2];
		w[0] = 1;

		for (n = 0; n < (N + 1) / 2; n++)
		{
			w[n] = (double)(w[n]) / theta;
		}

		/*填充另一半*/
		for (; n < N; n++)
		{
			w[n] = w[N - n - 1];
		}
	}
	else
	{
		/*计算一半的区间*/
		for (n = 1; n < (N + 1) / 2; n++)
		{
			gama = 1;
			for (index = 1; index < n; index++)
			{
				x = index * (double)(N - 1 - 2 * n + index) / ((n - index) * (n + 1 - index));
				gama = gama * alpha * x + 1;
			}
			w[n] = (N - 1) * alpha * gama;
		}

		theta = w[(N / 2) - 1];
		w[0] = 1;

		for (n = 0; n < (N + 1) / 2; n++)
		{
			w[n] = (double)(w[n]) / theta;
		}

		/*填充另一半*/
		for (; n < N; n++)
		{
			w[n] = w[N - n - 1];
		}
	}

	return DSP_SUCESS;
}

/*
*函数名:flatTopWin
*说明:计算flatTopWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = flatTopWin(99, w);
*/
dspErrorStatus flatTopWin(uint16_t N, double w[])
{
	uint16_t n;

	for (n = 0; n < N; n++)
	{
		w[n] = FLATTOPWIN_A0 - FLATTOPWIN_A1 * cos(2 * PI * (double)n / (N - 1)) + \
			FLATTOPWIN_A2 * cos(4 * PI * (double)n / (N - 1)) - \
			FLATTOPWIN_A3 * cos(6 * PI * (double)n / (N - 1)) + \
			FLATTOPWIN_A4 * cos(8 * PI * (double)n / (N - 1));
	}

	return DSP_SUCESS;
}


/*
*函数名:gaussianWin
*说明:计算gaussianWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = gaussianWin(99,2.5, w);
*/
dspErrorStatus gaussianWin(uint16_t N, double alpha, double w[])
{
	uint16_t n;
	double k, beta, theta;

	for (n = 0; n < N; n++)
	{
		if ((N % 2) == 1)
		{
			k = n - (N - 1) / 2;
			beta = 2 * alpha * (double)k / (N - 1);
		}
		else
		{
			k = n - (N) / 2;
			beta = 2 * alpha * (double)k / (N - 1);
		}

		theta = pow(beta, 2);
		w[n] = exp((-1) * (double)theta / 2);
	}

	return DSP_SUCESS;
}

/*
*函数名:hammingWin
*说明:计算hammingWin窗函数,汉明窗
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = hammingWin(99, w);
*/
dspErrorStatus hammingWin(uint16_t N, double w[])
{
	uint16_t n;

	for (n = 0; n < N; n++)
	{
		w[n] = 0.54 - 0.46 * cos(2 * PI *  (double)n / (N - 1));
	}

	return DSP_SUCESS;
}

/*
*函数名:hannWin
*说明:计算hannWin窗函数,汉宁窗
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = hannWin(99, w);
*/
dspErrorStatus hannWin(uint16_t N, double w[])
{
	uint16_t n;

	for (n = 0; n < N; n++)
	{
		w[n] = 0.5 * (1 - cos(2 * PI * (double)n / (N - 1)));
	}

	return DSP_SUCESS;
}

#if besseli_Flag
/*
*函数名:kaiserWin
*说明:计算kaiserWin窗函数
*输入:
*输出:
*返回:
*调用:besseli()第一类修正贝塞尔函数
*其它:用过以后,需要手动释放掉*w的内存空间
*        调用示例:ret = kaiserWin(99, 5, &w);
*/
dspErrorStatus kaiserWin(dspUint_16 N, dspDouble beta, dspDouble **w)
{
	dspUint_16 n;
	dspDouble *ret;
	dspDouble theta;

	ret = (dspDouble *)malloc(N * sizeof(dspDouble));
	if (ret == NULL)
		return DSP_ERROR;

	for (n = 0; n < N; n++)
	{
		theta = beta * sqrt(1 - pow(((2 * (dspDouble)n / (N - 1)) - 1), 2));
		*(ret + n) = (dspDouble)besseli(0, theta, BESSELI_K_LENGTH) / besseli(0, beta, BESSELI_K_LENGTH);
	}

	*w = ret;

	return DSP_SUCESS;
}
#endif

/*
*函数名:nuttalWin
*说明:计算nuttalWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = nuttalWin(99, w);
*/
dspErrorStatus nuttalWin(uint16_t N, double w[])
{
	uint16_t n;

	for (n = 0; n < N; n++)
	{
		w[n] = NUTTALL_A0 - NUTTALL_A1 * cos(2 * PI * (double)n / (N - 1)) + \
			NUTTALL_A2 * cos(4 * PI * (double)n / (N - 1)) - \
			NUTTALL_A3 * cos(6 * PI * (double)n / (N - 1));
	}

	return DSP_SUCESS;
}

/*
*函数名:parzenWin
*说明:计算parzenWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = parzenWin(99, w);
*/
dspErrorStatus parzenWin(uint16_t N, double w[])
{
	uint16_t n;
	
	double alpha, k;

	if ((N % 2) == 1)
	{
		for (n = 0; n < N; n++)
		{
			k = n - (N - 1) / 2;
			alpha = 2 * (double)fabs(k) / N;
			if (fabs(k) <= (N - 1) / 4)
			{
				w[n] = 1 - 6 * pow(alpha, 2) + 6 * pow(alpha, 3);
			}
			else
			{
				w[n] = 2 * pow((1 - alpha), 3);
			}
		}
	}
	else
	{
		for (n = 0; n < N; n++)
		{
			k = n - (N - 1) / 2;
			alpha = 2 * (double)fabs(k) / N;
			if (fabs(k) <= (double)(N - 1) / 4)
			{
				w[n] = 1 - 6 * pow(alpha, 2) + 6 * pow(alpha, 3);
			}
			else
			{
				w[n] = 2 * pow((1 - alpha), 3);
			}

		}
	}

	return DSP_SUCESS;
}

/*
*函数名:rectangularWin
*说明:计算rectangularWin窗函数
*输入:
*输出:
*返回:
*调用:
*调用示例:ret = rectangularWin(99, w);
*/
dspErrorStatus rectangularWin(uint16_t N, double w[])
{
	uint16_t n;

	for (n = 0; n < N; n++)
	{
		w[n] = 1;
	}

	return DSP_SUCESS;
}

卡尔曼滤波

#include "kalman.h"

/**
 *卡尔曼滤波器
 *@param 	Kalman *kfp 卡尔曼结构体参数
 *   			float input 需要滤波的参数的测量值(即传感器的采集值)
 *@return 滤波后的参数(最优值)
 */
float KalmanFilter(float inData)
{
		static float prevData = 0;                                 //上一个数据
		static float p = 10, q = 0.001, r = 0.001, kGain = 0;      // q 控制误差 r 控制响应速度
		p = p + q;
		kGain = p / ( p + r );                                      //计算卡尔曼增益
		inData = prevData + ( kGain * ( inData - prevData ) );      //计算本次滤波估计值
		p = ( 1 - kGain ) * p;                                      //更新测量方差
		prevData = inData;
		return inData;                                             //返回估计值

}

/* 优化后的卡尔曼滤波 
	更改Q值,响应加快,但太大会有震荡
	更改R值,响应减慢,越大稳定性会提高,但时间会增加
*/

unsigned long kalman_filter( unsigned long ADC_Value )
{
	float LastData;
	float NowData;
	float kalman_adc;
	static float kalman_adc_old = 0;
	static float PP;
	static float Q = 0.5;
	static float R = 10;
	static float Kg = 0;
	static float P = 1;
	NowData = ADC_Value;
	LastData = kalman_adc_old;
	P = PP + Q;
	Kg = P / ( P + R );
	kalman_adc = LastData + Kg * ( NowData - kalman_adc_old );
	PP = ( 1 - Kg ) * P;
	P = PP;
	kalman_adc_old = kalman_adc;
	return ( unsigned long )( kalman_adc );

}

/* 优化后的卡尔曼滤波 
	更改Q值,响应加快,但太大会有震荡
	更改R值,响应减慢,越大稳定性会提高,但时间会增加
*/

float kalman_filter_FPU( float Val )
{
	float LastData;
	float NowData;
	float kalman_adc;
	static float kalman_adc_old = 1.0;
	static float PP;
	static float Q = 0.5;
	static float R = 10;
	static float Kg = 0;
	static float P = 1;
	NowData = Val;
	LastData = kalman_adc_old;
	P = PP + Q;
	Kg = P / ( P + R );
	kalman_adc = LastData + Kg * ( NowData - kalman_adc_old );
	PP = ( 1 - Kg ) * P;
	P = PP;
	kalman_adc_old = kalman_adc;
	return ( kalman_adc );

}


主要程序

FFT的计算
void FFT_Caculate(uint16_t *adc_buf, uint16_t FFT)
{
	for(int i = 0; i < FFT; i++)
	{
		fft_inputbuf[2*i]=adc_buf[i] * 3.3 / 4096;  //实部
		fft_inputbuf[2*i+1]=0;//虚部全部为0
	}
	arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_inputbuf,0,1);
	arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT);    //把运算结果复数求模得幅值 
	
	fft_outputbuf[0] /= FFT;
	for(int i = 1; i < FFT/2 ;i++) 
	{
		fft_outputbuf[i] /= (FFT/2);
	}
	
	for(int i=0;i<FFT/2;i++)
	{
		printf("%f\n",fft_outputbuf[i]);
	}
}

void FFT_Caculate_NonePrint(uint16_t *adc_buf, uint16_t FFT)
{
	for(int i = 0; i < FFT; i++)
	{
		fft_inputbuf[2*i]=adc_buf[i] * 3.3 / 4096;  //实部
		fft_inputbuf[2*i+1]=0;//虚部全部为0
	}
	arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_inputbuf,0,1);
	arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT);    //把运算结果复数求模得幅值 
	
	fft_outputbuf[0] /= FFT;
	for(int i = 1; i < FFT/2 ;i++) 
	{
		fft_outputbuf[i] /= (FFT/2);
	}
}

unsigned long FFT_Caculate_Float(float *adc_8885_buf, uint16_t FFT)
{
	unsigned long dds_fre;
	float c_fre=0,m_fre;
	int temp_i;
	for(int i=0;i<FFT;i++)
	{
		fft_inputbuf[2*i]=adc_8885_buf[i];  //实部
		fft_inputbuf[2*i+1]=0;//虚部全部为0
	}
	arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_inputbuf,0,1);
	arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT_LENGTH);    //把运算结果复数求模得幅值
	
	for(int i=0;i<FFT_LENGTH/2;i++)
	{
		if(fft_outputbuf[i]>c_fre){
			c_fre=fft_outputbuf[i];
			temp_i = i;
		}
	}
	m_fre = (float)ADS8885_CLK/1024.0 * temp_i;			//基带频率
	dds_fre = (unsigned long)((m_fre/1000)+1)*1000;	//把频率给DDS
	return dds_fre;
}
ADS8885计算频率和幅度
void ADS8885_Calculat_Fre(double *fre)
{
	int temp_ii=0;
	float cmp_fre=0;
	getRData(adc8885_val,FFT_LENGTH);
	for(int i = 0; i < FFT_LENGTH; i++)
	{
		fft_inputbuf[2*i]=adc8885_val[i];
		fft_inputbuf[2*i+1]=0;//虚部全部为0
	}
	arm_cfft_f32(&arm_cfft_sR_f32_len1024,fft_inputbuf,0,1);
	arm_cmplx_mag_f32(fft_inputbuf,fft_outputbuf,FFT_LENGTH);    //把运算结果复数求模得幅值
	for(int i=10;i<FFT_LENGTH/2;i++)
	{
		if(fft_outputbuf[i]>cmp_fre){
			cmp_fre=fft_outputbuf[i];
			temp_ii = i;
		}
	}
	*fre = (float)ADS8885_CLK/1024.0 * temp_ii;
	*fre = (float)((int)(*fre/1000)+1)*1000;
}

void ADS8885_Calculat_Amg(float *adc8885_avgs)
{
	float adc8885_minval = 5.0;
	float adc8885_maxval = -5.0;
	for(int k=0;k<10;k++)
	{
		getRData(adc8885_val,FFT_LENGTH);
		for(int i=0;i<FFT_LENGTH/2;i++) {
			if(adc8885_val[i] > adc8885_maxval)
				adc8885_maxval=adc8885_val[i];
			if(adc8885_val[i] < adc8885_minval)
				adc8885_minval=adc8885_val[i];
		}
		*adc8885_avgs += (adc8885_maxval-(adc8885_minval));
	}
	*adc8885_avgs /= 10.0;
}

结语

main函数过于长且没整理,暂时不贴出
本次还是很可惜,没有将代码写全,若将第三部分的频率拓展到第一、二部分,那才是真真正正的将整个解决完毕,FM解调部分若是想10M-30M均能解调,使用模块的话是肯定不行的,除非至少三块或三块以上的解调模块来互补解调,所以这里的FM解调方法可能采用频谱分析仪的做工思想,用窄带滤波法,分几百Hz的带宽来在频带上一路扫过去,若只有一根则是无调制,三根则是AM调制,若干根则是FM调制。

  • 12
    点赞
  • 109
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
2022ti杯大学生电子设计竞赛的C是小车跟随行驶系统。该系统要求设计一个能够实现自主跟随行驶的小车,能够通过感知周围环境并根据控制算法进行决策,实现跟随目标物体运动的功能。 为了完成这个设计,我们可以采用以下步骤: 1. 硬件设计:设计一个小车平台,包括驱动电机、传感器和处理器等组件。可以选择使用微控制器或者单片机作为控制器,并根据需要选择适当的传感器,如红外线传感器、超声波传感器、摄像头等。 2. 环境感知:利用传感器来感知小车周围的环境。例如,使用红外线传感器来检测前方是否有障碍物,使用摄像头来识别目标物体的位置和运动状态。 3. 数据处理:将传感器获取的数据输入到处理器中进行数据处理,包括数据滤波、特征提取和目标跟踪等。可以使用图像处理算法来分析目标物体的运动轨迹。 4. 控制算法:根据处理后的数据,设计控制算法来实现小车的自主控制。可以采用模糊控制、PID控制等算法来控制车辆的转向和速度,使其能够跟随目标物体行驶。 5. 系统实现与测试:将设计好的硬件和控制算法进行组装和测试。通过实际场景下的测试,不断优化算法和参数,使小车能够准确地跟随目标物体行驶。 这是一个具有挑战性和实际应用价值的设计竞赛目。通过设计这个跟随行驶系统,可以提高学生们的电子设计能力和创新思维,同时也可以培养他们解决实际问的能力和团队合作精神。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值