#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. UED Landing 页 - 定时抓取掘金文章

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:琉易 https://liuxianyu.cn 本次分享基 ...

  2. windows 搭建iis文件服务器

    1.运行打开控制面板->程序->启用或关闭Windows功能,勾选下面所有的选项. 注意,必须安装功能所需文件. 等待 关闭即可. 2.在控制面板找到管理工具,不同版本的Windows不尽 ...

  3. json与字符串的互转

    在spring框架中当ajax请求需要返回json数据时,我们只需要在@RequestMapping后面加上@ResponseBody,即可为我们返回想要的json. 下面我们讲解json与字符串的互 ...

  4. 使用pycharm or vscode来编写python代码?

    pycharm社区版可用于商业项目 pycharm社区版可用于商业项目,来源于官方的回答:Can I use Community Editions of JetBrains IDEs for deve ...

  5. C++进阶(哈希)

    vector容器补充(下面会用到) 我们都知道vector容器不同于数组,能够进行动态扩容,其底层原理:所谓动态扩容,并不是在原空间之后接续新空间,因为无法保证原空间之后尚有可配置的空间.而是以原大小 ...

  6. PRIx64:uint64_t类型输出为十六进制格式

    #include <stdio.h> #include <stdint.h> #include <inttypes.h> int main(void) { uint ...

  7. 万万没想到,go的数据库操作,也能像php一样溜了

    Hi,各位go的小伙伴. 很多人都是从php转过来的吧,不知道你们有没有发现,go界的orm并没有像php的orm一样好用.这篇文章里,我们认真的讨论下这个问题,并且会在后面提出解决方案. php的方 ...

  8. [编程基础] Python数据生成库Faker总结

    Python Faker教程展示了如何使用Faker软件包在Python中生成伪数据.我们使用joke2k/faker包. 1 介绍 Faker是一个生成假数据的Python库.伪数据通常用于测试或用 ...

  9. css预处理器scss/sass语法以及使用

    scss scss在css基础语法上面增加了变量 (variables).嵌套 (nested rules).混合 (mixins).导入 (inline imports) 等高级功能,使用scss可 ...

  10. 洛谷P1496 火烧赤壁【题解】

    事先声明 本题解文字比较多,较为详细,算法为离散化和差分,如会的大佬可以移步去别处看这道题的思路(因为作者比较懒,不想新开两个专题). 题目简要 给定每个起火部分的起点和终点,请你求出燃烧位置的长度之 ...