开发环境:WIN10
开发软件:STM32CubeIDE
使用硬件:STM32F03C6T6开发板
准备TTF软件:是 GCC版本的。
1.新建项目:TTF_Simulate_data_f103c6
打开STM32CubeIDE-->文件-->新建-->STM32 project
选择器件: 搜索103c6,选择STM32F03A,-->下一步
--- 输入项目名称,点击“完成”,自动进入STM32CubeMX界面
二,coudMX设置:
1.项目使用单片机资源:
(1)外部时钟72MH 、
(2)TIM3
(3)USART1
(4)PC13
--- 外部时钟72MH
RCC设置:
--- HCLK(MHz) 位置输入 72 ,回车,点击OK, 自动完成设置。
--- TIM3 设置
--- USART1设置:
--- 中断设置:打开TIM3,USART中断
---PC13设置:
--- 保存,确认
至此,项目初始化完成。
三,导入FFT软件,选择文件系统导入,浏览到FFT软件所在文件夹
--- stm32_dsp.h,table_fft.h 导入 Inc 文件夹
--- cr4_fft_256_stm32.s,cr4_fft_1024_stm32.s 导入Src 文件夹
也可以分别直接复制,粘贴到 Inc 和 Src 这两个文件夹内。
四、添加自己的程序到main.c 找到绿色代码对应位置,复制范围内的代码到自己的main.c。
添加头文件声明
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "math.h"
#include "stm32_dsp.h"
#include "table_fft.h"
/* USER CODE END Includes */
添加变量声明:
/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim3;
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */
//串口printf重定向
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
PUTCHAR_PROTOTYPE {
/* Place your implementation of fputc here */
/* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
HAL_UART_Transmit(&huart1, (uint8_t*) &ch, 1, 0xFFFF);
return ch;
}
int display_on = 1;
char frequency_domain_value = 0;
char frequency_domain = 1;
char simulate_data = 2;
//串口输出使用
#define FQV frequency_domain_value //频谱
//串口绘图使用
#define FQD frequency_domain //频谱
#define SMD simulate_data //仿真数据
#define SPT 256 //Sample points 采样点
long simulate_data_array[SPT]; //模拟数据数组simulate_data_array
long FFT_out_array[SPT / 2]; //FFT运算结果
long Frequency_amplitude_array[SPT / 2]; //频谱 FFT运算结果转换
float PI2 = 6.28318530717959;
uint32_t SPF = 10240; //采样率
/* USER CODE END PV */
添加函数声明:
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM3_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
void simulate_data_generation(void); //Generate analog sampling data 生成模拟采样数据
void FFT_256(void);
void get_Frequency_amplitude(void); Frequency amplitude 频率幅度
//打印绘图
char print_drawing(char str); //频谱值
/* USER CODE END PFP */
主程序初始化 :复位后只执行一次
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim3); //启动定时器3
simulate_data_generation(); //仿真数据生成 //Generate analog sampling data 生成模拟采样数据
FFT_256(); //
get_Frequency_amplitude(); Frequency amplitude 频率幅度
//打印绘图
print_drawing(FQV); //频谱值
/* USER CODE END 2 */
主程序循环
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (display_on == 1) {
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); //LED灯状态反转
//打印绘图
print_drawing(FQD); //频谱
//打印绘图
//需要看频谱,将注释掉下一行代码
// print_drawing(SMD); //仿真数据
display_on = 0;
}
//----------------
}
/* USER CODE END 3 */
添加自己的函数:
//仿真数据生成 SPT是采样点:256,SPF是采样频率:10.240KHz
/* USER CODE BEGIN 4 */
//生成FFT需要的仿真数据
void simulate_data_generation(void) {
unsigned short i;
float Signal;
for (i = 0; i < SPT; i++) {
Signal = 100 * sin(PI2 * i * 60.0 / SPF) //频率60
+ 100 * sin(PI2 * i * 1280.0 / SPF) //频率1280
+ 100 * sin(PI2 * i * 5000.0 / SPF); //频率5000
simulate_data_array[i] = ((signed short) Signal) << 16;
}
}
//FFT
void FFT_256() {
cr4_fft_256_stm32(FFT_out_array, simulate_data_array, SPT);
}
//频谱
void get_Frequency_amplitude() {
signed short lX, lY;
float X, Y, Mag;
for (uint16_t i = 0; i < SPT / 2; i++) {
lX = (FFT_out_array[i] << 16) >> 16;
lY = (FFT_out_array[i] >> 16);
X = SPT * ((float) lX) / 32768;
Y = SPT * ((float) lY) / 32768;
Mag = sqrt(X * X + Y * Y) / SPT;
if (i == 0)
Frequency_amplitude_array[i] = (unsigned long) (Mag * 32768);
else
Frequency_amplitude_array[i] = (unsigned long) (Mag * 65536);
}
}
//打印绘图
char print_drawing(char str) {
for (int i = 0; i < SPT / 2; i++) {
switch (str) {
case 0: //FQV串口输出使用 频谱
printf("i = %d", i); //\r\n
printf(" F = %ld", ((SPF / 256) * i)); //175\r\n
printf(" V = %ld\r\n", Frequency_amplitude_array[i]); //\r\n
break;
//串口绘图使用
case 1: //FQD频谱
printf("%ld\r\n", Frequency_amplitude_array[i]); //
break;
case 2: //SMD仿真数据
printf("%ld\r\n", simulate_data_array[i]); //
break;
}
printf("\r\n");
}
return 0;
}
/* USER CODE END 4 */
中断设置:打开 stm32f1xx_it.c 找到对应位置
添加变量:
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
extern int display_on;
/* USER CODE END PV */
定时器3
void TIM3_IRQHandler(void) {
/* USER CODE BEGIN TIM3_IRQn 0 */
/* USER CODE END TIM3_IRQn 0 */
HAL_TIM_IRQHandler(&htim3);
/* USER CODE BEGIN TIM3_IRQn 1 */
display_on = 1;
/* USER CODE END TIM3_IRQn 1 */
}
程序部分结束。
构建项目成功:
下载程序:
STM32F03C6T6开发板 运行:
代码:print_drawing(FQV); //频谱值
//FQV串口输出 打印结果:i = 系列 与FFT采样点有关,F = 频率,V = 频率对应的值。
FFT采样点,采样率确定后,频谱的频率就固定下来了,去看SPF = 10240; //采样率,函数 simulate_data_generation(void) 中的生成频率,60Hz,1280Hz,5000Hz。
10240(采样率) / 256(采样点) = 40 ,很明显生成频率60Hz不在40的整数倍上,看不到60Hz的峰值点,但是邻居频率点幅值是递减的;1280Hz,5000Hz能看到峰值。
i = 0 F = 0 V = 17
i = 1 F = 40 V = 70
i = 2 F = 80 V = 60
i = 3 F = 120 V = 24
i = 4 F = 160 V = 13
i = 5 F = 200 V = 11
i = 6 F = 240 V = 10
i = 7 F = 280 V = 8
i = 8 F = 320 V = 8
i = 9 F = 360 V = 8
i = 10 F = 400 V = 10
i = 11 F = 440 V = 10
i = 12 F = 480 V = 8
i = 13 F = 520 V = 7
i = 14 F = 560 V = 10
i = 15 F = 600 V = 10
i = 16 F = 640 V = 7
i = 17 F = 680 V = 4
i = 18 F = 720 V = 2
i = 19 F = 760 V = 6
i = 20 F = 800 V = 2
i = 21 F = 840 V = 6
i = 22 F = 880 V = 6
i = 23 F = 920 V = 6
i = 24 F = 960 V = 6
i = 25 F = 1000 V = 6
i = 26 F = 1040 V = 2
i = 27 F = 1080 V = 6
i = 28 F = 1120 V = 4
i = 29 F = 1160 V = 4
i = 30 F = 1200 V = 6
i = 31 F = 1240 V = 2
i = 32 F = 1280 V = 96
i = 33 F = 1320 V = 4
i = 34 F = 1360 V = 4
i = 35 F = 1400 V = 6
i = 36 F = 1440 V = 4
i = 37 F = 1480 V = 6
i = 38 F = 1520 V = 4
i = 39 F = 1560 V = 4
i = 40 F = 1600 V = 4
i = 41 F = 1640 V = 4
i = 42 F = 1680 V = 6
i = 43 F = 1720 V = 6
i = 44 F = 1760 V = 4
i = 45 F = 1800 V = 6
i = 46 F = 1840 V = 6
i = 47 F = 1880 V = 6
i = 48 F = 1920 V = 2
i = 49 F = 1960 V = 2
i = 50 F = 2000 V = 2
i = 51 F = 2040 V = 2
i = 52 F = 2080 V = 2
i = 53 F = 2120 V = 2
i = 54 F = 2160 V = 2
i = 55 F = 2200 V = 2
i = 56 F = 2240 V = 4
i = 57 F = 2280 V = 4
i = 58 F = 2320 V = 5
i = 59 F = 2360 V = 4
i = 60 F = 2400 V = 2
i = 61 F = 2440 V = 4
i = 62 F = 2480 V = 2
i = 63 F = 2520 V = 2
i = 64 F = 2560 V = 0
i = 65 F = 2600 V = 0
i = 66 F = 2640 V = 2
i = 67 F = 2680 V = 2
i = 68 F = 2720 V = 2
i = 69 F = 2760 V = 2
i = 70 F = 2800 V = 2
i = 71 F = 2840 V = 0
i = 72 F = 2880 V = 2
i = 73 F = 2920 V = 2
i = 74 F = 2960 V = 2
i = 75 F = 3000 V = 4
i = 76 F = 3040 V = 0
i = 77 F = 3080 V = 2
i = 78 F = 3120 V = 4
i = 79 F = 3160 V = 2
i = 80 F = 3200 V = 2
i = 81 F = 3240 V = 4
i = 82 F = 3280 V = 2
i = 83 F = 3320 V = 4
i = 84 F = 3360 V = 0
i = 85 F = 3400 V = 2
i = 86 F = 3440 V = 4
i = 87 F = 3480 V = 2
i = 88 F = 3520 V = 2
i = 89 F = 3560 V = 4
i = 90 F = 3600 V = 4
i = 91 F = 3640 V = 2
i = 92 F = 3680 V = 2
i = 93 F = 3720 V = 4
i = 94 F = 3760 V = 4
i = 95 F = 3800 V = 2
i = 96 F = 3840 V = 2
i = 97 F = 3880 V = 4
i = 98 F = 3920 V = 4
i = 99 F = 3960 V = 4
i = 100 F = 4000 V = 0
i = 101 F = 4040 V = 4
i = 102 F = 4080 V = 2
i = 103 F = 4120 V = 0
i = 104 F = 4160 V = 2
i = 105 F = 4200 V = 4
i = 106 F = 4240 V = 4
i = 107 F = 4280 V = 2
i = 108 F = 4320 V = 0
i = 109 F = 4360 V = 4
i = 110 F = 4400 V = 4
i = 111 F = 4440 V = 4
i = 112 F = 4480 V = 2
i = 113 F = 4520 V = 2
i = 114 F = 4560 V = 2
i = 115 F = 4600 V = 2
i = 116 F = 4640 V = 2
i = 117 F = 4680 V = 2
i = 118 F = 4720 V = 0
i = 119 F = 4760 V = 2
i = 120 F = 4800 V = 2
i = 121 F = 4840 V = 2
i = 122 F = 4880 V = 4
i = 123 F = 4920 V = 2
i = 124 F = 4960 V = 0
i = 125 F = 5000 V = 96
i = 126 F = 5040 V = 2
i = 127 F = 5080 V = 0
函数 get_Frequency_amplitude() 转换的数据,打印绘图结果:
代码:print_drawing(FQD); //频谱
函数 simulate_data_generation(void) 生成的数据,打印绘图结果:
代码:print_drawing(SMD); //仿真数据
不同采样率,不同生成频率:
参考链接:
【玩转单片机系列002】 如何使用STM32提供的DSP库进行FFT - 知乎 (zhihu.com)
串口 printf 重定向参考:
STM32CubeIDE 利用自带HAL库 串口收发_stm32cube实现串口接收数据_zateper的博客-优快云博客