早上搞了就一个选通开关
为什么说就呢?因为我觉得自己的效率是可以提高的。
我想展开来具体说说:
我一开始是在想,我有了昨天的基础我有必要再去研究单通道fft吗?然后花花公子撒肠子一样看了昨天的fft代码(这个半小时其实啥收获都没有)
所以,下次出现这个的时候,就不要犹豫,花点时间回想一下自己对这个东西的理解。
后面自己看了看74HC4067的数据手册,发现这个全英文不想看,然后在CSDN上面找文章,看看能不能找到现成的(这一点倒是做到了昨天的想法了),确实也找到了相关的文章。
我抄代码的时候居然不知道这个GPIO是要初始化的
就是那一瞬间,我自己想到了自己对这些东西的理解:
不能平白无故用这些东西,我要对其进行相关的初始化
//初始化4051引脚用来控制相关的选通
//PB12 13 14
void CD4051_Init(void)
{
//定义一个结构体变量
GPIO_InitTypeDef GPIO_InitStructure;
//开始时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//初始化结构体
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14; //端口配置三个引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//pb12 13 14:输出低
GPIO_ResetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14);// 初始全部设置成0,也就是y0导通
}
后面一下子搞出来自己想法的选通开关,那个时候的正反馈嘎嘎推着我。
下午问别人问出来了第三问的思路
下午其实就是在研究这个多路识别选通要怎么做?
后面发现可以基于现阶段的出来的单通道fft改成单ADC多通道fft采样
(短短几个字,硬控了我半天)
前面看解析的文章和看参考手册注意不到细节的小缺点又出现了!!!
这种东西,其实就是看看原有的例程,然后理解一下其中关键的代码是哪些?
好的,这下我展开说说:
1.下次碰到这种建立在类似的例程的基础上的代码,先去理解一下例程;紧接着,去看一遍参考手册中的配置指南重点是什么;最后一点点移植代码,要可以一步步观察的代码过程。
(先熟悉,再陌生)
2.具体例子:
先看了一遍例程:
(详见stm32精英手册)
然后看了看野火的代码:
static void ADCx_Mode_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
// 打开DMA时钟
RCC_AHBPeriphClockCmd(ADC_DMA_CLK, ENABLE);
// 打开ADC时钟
ADC_APBxClock_FUN ( ADC_CLK, ENABLE );
// 复位DMA控制器
DMA_DeInit(ADC_DMA_CHANNEL);
// 配置 DMA 初始化结构体
// 外设基址为:ADC 数据寄存器地址
DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 ) ( & ( ADC_x->DR ) );
// 存储器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;
// 数据源来自外设
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
// 缓冲区大小,应该等于数据目的地的大小
DMA_InitStructure.DMA_BufferSize = NOFCHANEL;
// 外设寄存器只有一个,地址不用递增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 存储器地址递增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// 外设数据大小为半字,即两个字节
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
// 内存数据大小也为半字,跟外设数据大小相同
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
// 循环传输模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// 禁止存储器到存储器模式,因为是从外设到存储器
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// 初始化DMA
DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);
// 使能 DMA 通道
DMA_Cmd(ADC_DMA_CHANNEL , ENABLE);
// ADC 模式配置
// 只使用一个ADC,属于单模式
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
// 扫描模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE ;
// 连续转换模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// 不用外部触发转换,软件开启即可
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// 转换结果右对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
// 转换通道个数
ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL;
// 初始化ADC
ADC_Init(ADC_x, &ADC_InitStructure);
// 配置ADC时钟N狿CLK2的8分频,即9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置ADC 通道的转换顺序和采样时间
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL1, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL2, 2, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL3, 3, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL4, 4, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL5, 5, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL6, 6, ADC_SampleTime_55Cycles5);
// 使能ADC DMA 请求
ADC_DMACmd(ADC_x, ENABLE);
// 开启ADC ,并开始转换
ADC_Cmd(ADC_x, ENABLE);
// 初始化ADC 校准寄存器
ADC_ResetCalibration(ADC_x);
// 等待校准寄存器初始化完成
while(ADC_GetResetCalibrationStatus(ADC_x));
// ADC开始校准
ADC_StartCalibration(ADC_x);
// 等待校准完成
while(ADC_GetCalibrationStatus(ADC_x));
// 由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
}
然后大概对这个东西有一个了解
(划重点,这个大概真的就是大概,没有细节的大概,我后面就是花大量的时间在这个细节上)
然后基础的移植代码,这个大家其实都会,我呢小毛病就出现了。
// 缓冲区大小,应该等于数据目的地的大小
DMA_InitStructure.DMA_BufferSize = NOFCHANEL;
// 扫描模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE ;
// 连续转换模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
// 不用外部触发转换,软件开启即可
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
// 转换通道个数
ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL;
// 配置ADC 通道的转换顺序和采样时间
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL1, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL2, 2, ADC_SampleTime_55Cycles5);
// 由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
1.这个缓冲区大小,应该等于数据目的地大小。
我一开始的理解还是SRAM中的转移数组大小:256,后面意识到这个要和fft处理的256练习起来,而且我是双通道,我就要改成512
2.扫描方式和连续转化
这俩就是主观觉得无所谓,就这样,但是深究去看参考手册发现这个也是很有讲究的。这里填一个坑,我还是没研究明白。
3.这个触发转化
我是直接根据DMA+FFT+ADC,我才知道要配置成TIM3,这个也是没理解进去
4.转化通道
这个就是看你自己要开几个通道了,这个也是要配置一边才知道。
5.这个配置规则通道
GPIO不能乱来的,要根据32规定的引脚进行初始化,才可以。
6.触发
这个也是看了别人的代码才知道是这样的。
讲讲我对fft的进一步了解。
cr4_fft_256_stm32(FFT_OutData, FFT_SourceData, SAMPLS_NUM);
这个256!!!
是规定了,这个FFT_SourceData中的数据要有256个,然后系统对他进行转化。
256要来自一个波形,并且不能出现。
基于上面的进一步理解,今天双通道的思路就是:
初始化相关引脚,ADC配置双通道(规则通道)、根据fft特征(采样处理256个点)把数组大小改成512、利用分离把采集到的数组分别进入到fft中处理。
还是要进一步对所用的知识有一个理解(再次感谢陈同学救我一命)