#include "public.h"

#define FFT_POINT 	(256)

static uint16_t _DmaBuffer[FFT_POINT];
static uint16_t _AdcBuffer[FFT_POINT];
static uint8_t F_DMA_TC; static int32_t FFT_InBuffer[FFT_POINT];
static int32_t FFT_OutBuffer[FFT_POINT];
#define FFT_MagBuffer _AdcBuffer static void _InitClk(void) {
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
} static void _InitGpio(void) {
SocGpio_SetMode(SocGpio_GetPinIndex(0<<4|1), INPUT_MODE_AIN);
SocGpio_SetMode(SocGpio_GetPinIndex(0<<4|0), OUTPUT_MODE_PUSH_PULL);
} static void _InitDMA(void) {
DMA_InitTypeDef def; // 初始化
def.DMA_PeripheralBaseAddr = (uint32_t)(&ADC1->DR); // 外设地址
def.DMA_MemoryBaseAddr = (uint32_t)(&_DmaBuffer[0]); // 内存地址
def.DMA_DIR = DMA_DIR_PeripheralSRC; // 从外设复制到内存
def.DMA_BufferSize = ASIZE(_DmaBuffer); // 内存元素个数
def.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址固定
def.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址递增
def.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 外设元素大小16字节
def.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 内存元素大小16字节
def.DMA_Mode = DMA_Mode_Circular; // 循环采集
def.DMA_Priority = DMA_Priority_High; // 循环
def.DMA_M2M = DMA_M2M_Disable; // 外设到内存
DMA_Init(DMA1_Channel1, &def); // 中断
NVIC_SetPriority(DMA1_Channel1_IRQn, 0);
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
DMA_ClearFlag(DMA1_FLAG_TC1);
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); DMA_Cmd(DMA1_Channel1, ENABLE);
} static void _InitAdc(void) {
ADC_InitTypeDef def; // 初始化
ADC_StructInit(&def);
def.ADC_Mode = ADC_Mode_Independent; // 独立模式
def.ADC_ScanConvMode = DISABLE; // 单通道
def.ADC_ContinuousConvMode = DISABLE; // 定时器触发,不连续转换
def.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;// 转换不受外界决定
def.ADC_DataAlign = ADC_DataAlign_Right; // 右对齐
def.ADC_NbrOfChannel = 1; // 扫描通道数
ADC_Init(ADC1, &def); // 通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_1Cycles5);
ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); // 校准
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1)); } static void _InitTim(void) {
TIM_TimeBaseInitTypeDef def;
TIM_TimeBaseStructInit(&def); def.TIM_Period = 100-1;
def.TIM_Prescaler = 72-1;
def.TIM_ClockDivision = TIM_CKD_DIV1;
def.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &def); TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update); TIM_Cmd(TIM3, ENABLE);
} void cr4_fft_256_stm32(void *pssOUT, void *pssIN, u16 Nbin); static void _FFT_Proc(void) {
for (uint16_t i = 0; i < FFT_POINT; i++) {
FFT_InBuffer[i] = (_AdcBuffer[i]-1990) << 16;
}
#if 0
printf("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",
FFT_InBuffer[1], FFT_InBuffer[2], FFT_InBuffer[3], FFT_InBuffer[4],
FFT_InBuffer[5], FFT_InBuffer[6], FFT_InBuffer[7], FFT_InBuffer[8],
FFT_InBuffer[9], FFT_InBuffer[10], FFT_InBuffer[11], FFT_InBuffer[12]);
#endif
cr4_fft_256_stm32(FFT_OutBuffer, FFT_InBuffer, FFT_POINT); #if 0
printf("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",
_AdcBuffer[1], _AdcBuffer[2], _AdcBuffer[3], _AdcBuffer[4],
_AdcBuffer[5], _AdcBuffer[6], _AdcBuffer[7], _AdcBuffer[8],
_AdcBuffer[9], _AdcBuffer[10], _AdcBuffer[11], _AdcBuffer[12]);
#endif
} #if 0
void GetPowerMag(void)
{
signed short lX,lY;
float X,Y,Mag;
unsigned short i; for(i=0; i<NPT; i++)
{
lX = (lBufOutArray[i] << 16) >> 16;
lY = (lBufOutArray[i] >> 16); //除以32768再乘65536是为了符合浮点数计算规律
X = NPT * ((float)lX) / 32768;
Y = NPT * ((float)lY) / 32768;
Mag = sqrt(X * X + Y * Y)*1.0/ NPT;
if(i == 0)
lBufMagArray[i] = (unsigned long)(Mag * 32768);
else
lBufMagArray[i] = (unsigned long)(Mag * 65536);
}
}
#endif static void _Send(uint8_t ch) {
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
USART_SendData(USART1, ch);
} // STEP:39Hz
static void _FFT_GetMag(void) {
int16_t x, y;
for (uint16_t i = 1; i <= 64; i++) {
x = FFT_OutBuffer[i]&0xFFFF;
y = FFT_OutBuffer[i]>>16;
//printf("%d: %d, %d\n", i, x, y);
FFT_MagBuffer[i] = sqrt(x*x + y*y); // 存在超过25为有信号, 需要连续好几个周期的判断,以便防抖
}
} void SocAdc_Init(void) {
_InitClk();
_InitGpio();
_InitDMA();
_InitAdc();
_InitTim(); ADC_SoftwareStartConvCmd(ADC1, ENABLE);
} void SocAdc_Main(void) {
if (F_DMA_TC) {
F_DMA_TC = 0;
memcpy(_AdcBuffer, _DmaBuffer, sizeof(_DmaBuffer));
GPIOA->BSRR = GPIO_Pin_0;
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
_FFT_Proc();
_FFT_GetMag(); #if 1
_Send(0xFF);
for (uint16_t i = 1; i <= 64; i++) { // 不要第一个分量
if (FFT_MagBuffer[i] > 0xFE) {
_Send(0xFE);
} else {
_Send(FFT_MagBuffer[i]);
}
}
#endif #if 0
printf("%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d\n",
FFT_MagBuffer[1], FFT_MagBuffer[2], FFT_MagBuffer[3], FFT_MagBuffer[4],
FFT_MagBuffer[5], FFT_MagBuffer[6], FFT_MagBuffer[7], FFT_MagBuffer[8],
FFT_MagBuffer[9], FFT_MagBuffer[10], FFT_MagBuffer[11], FFT_MagBuffer[12]);
#endif
}
} // DMA的ADC通道中断
void DMA1_Channel1_IRQHandler(void) {
if (DMA_GetFlagStatus(DMA1_FLAG_TC1)) {
DMA_ClearFlag(DMA1_FLAG_TC1);
ADC_SoftwareStartConvCmd(ADC1, DISABLE);
F_DMA_TC = 1;
GPIOA->BRR = GPIO_Pin_0;
}
}

TIM + DMA + ADC的更多相关文章

  1. STM32F103ZET6 之 ADC+TIM+DMA+USART 综合实验

    1.实验目的 1)使用 TIM1 触发 ADC,ADC 采集的数据通过DMA 传至内存,然后通过串口打印出采集的数据: 2)学会 DMA 传输数据并将数据进行保存: 3)验证ADC 的采样率与实际设置 ...

  2. STM32之DMA+ADC

    借用小甲鱼的经典:各位互联网的广大网友们.大家早上中午晚上好..(打下小广告,因为小甲鱼的视频真的很不错).每次看小甲鱼的视频自学都是比较轻松愉快的..我在想,如果小甲鱼出STM32的视频,我会一集不 ...

  3. ADC-单通道DMA到多通道DMA ADC采集修改事项

    1. 使能通道IO,因为从单通道到多通道,需要添加规则转换通道数,故需要使能扫描模式,否则只能扫描第一个通道: 2. DMA模式配置需修改为循环传输模式,否则只转换一次: 3. 开启ADC规则转换通道 ...

  4. 案例 stm32单片机,adc的双通道+dma 内部温度

    可以这样理解 先配置adc :有几个通道就配置几个通道. 然后配置dma,dma是针对adc的,而不是针对通道的. 一开始我以为一个adc通道对应一个dma通道.(这里是错的,其实是我想复杂了) 一个 ...

  5. STM32F103VET6 ADC采集64点做FFT变换

    http://www.stmcu.org/module/forum/thread-598459-1-11.html http://bbs.21ic.com/icview-589756-1-1.html ...

  6. 关于STM32 DMA相关总结[概述知识点]

    关于DMA相关知识的总结,写给未来的自己,希望有帮助.立个Flag[坚持写博客总结自己工作或学习记录自己的生活] ------------------------------------------- ...

  7. 【STM32H7教程】第32章 STM32H7的TIM定时器基础知识和HAL库API

    完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第32章       STM32H7的TIM定时器基础知识和H ...

  8. 9. DMA

    9.1 介绍 Direct memory access(DMA) 直接存储器访问. 这两个DMA控制器总共有16个流(每个控制器8个),每个流用于管理来自一个或多个外围设备的内存访问请求.每个流总共可 ...

  9. ADC配置成定时器触发的启发

    百度文库:https://wenku.baidu.com/view/99d39413f78a6529647d5344.html STM32关于使用定时器触发ADC转换的解决办法和详细说明 本人在使用S ...

  10. DMA Stream/Channel Outputting via GPIOC[0..7]

    Ok, so quickly mashing up another example using a different TIM, DMA Stream/Channel for illustration ...

随机推荐

  1. telnet 退出失败

    1. 根据提示,使用ctrl+] ,退出到telnet >界面 2. 使用quit退出 3. 最简单的退出方式,强制退出: ] + Enter键

  2. ArcObjects SDK开发 006 ICommand和ITool接口

    1.ICommand接口 ICommand接口是插件协议之一,继承该接口的类都可以成为命令.即点击一下执行,不主动与宿主发生鼠标和键盘交互.该接口包含的重要成员如下表所示. 序号 名称 类型 描述 1 ...

  3. day28-jQuery01

    jQuery01 参考文档1:jQuery API 中文文档 | jQuery API 中文在线手册 | jquery api 下载 | jquery api chm (cuishifeng.cn) ...

  4. linux常用指令记录

    给目标文件夹执行权限:chmod -R 777 html du -sh .  [对当前目录下所有的目录和文件的大小进行汇总,-s表示汇总,-h表示以KB, MB, GB, TB格式进行人性化显示]du ...

  5. 【笔面试题目】Java集合相关的面试题-List、Map、Set等

    一.List 1.subList 不会返回新的list对象--与String的subString不同 返回原来list的从[fromIndex,toIndex)之间这一部分的视图,实际上,返回的lis ...

  6. 【算法总结】【队列均LinkedList】栈和队列、双端队列的使用及案例

    1.栈 初始化:Stack<E> stack = new Stack<>(); 出栈:stack.pop() 或 stack.remove(stack.size() - 1) ...

  7. MySQL的select for update用法

    MySQL中的select for update大家应该都有所接触,但什么时候该去使用,以及有哪些需要注意的地方会有很多不清楚的地方,我把我如何使用和查询到的文档在此记录. 作用 select本身是一 ...

  8. 个人电脑公网IPv6配置

    一.前言 自己当时以低价买的阿里ECS云服务器马上要过期了,对于搭建个人博客.NAS这样服务器的需求购买ECS服务器成本太高了,刚好家里有台小型的桌面式笔记本,考虑用作服务器,但是公网IPv4的地址实 ...

  9. ping localhost时出现::1的原因以及解决办法

    ping localhost时出现: 在cmd中ping localhost解析出来的是ipv6的::1的原因是windows有个优先解析列表,当ipv6的优先级高于ipv4时,就会出现这种情况. 具 ...

  10. 从面试题入手,畅谈 Vue 3 性能优化

    前言 今年又是一个非常寒冷的冬天,很多公司都开始人员精简.市场从来不缺前端,但对高级前端的需求还是特别强烈的.一些大厂的面试官为了区分候选人对前端领域能力的深度,经常会在面试过程中考察一些前端框架的源 ...