/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "dma.h"
#include "i2c.h"
#include "tim.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "math.h"
#include <stdio.h>
#include <string.h>
#include "ssd1306.h"
#include "ssd1306_tests.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#define M_PI 3.14159265358979323846f
int a=1;
uint8_t data=0;
uint8_t data1=0;
uint8_t data2=0;
uint8_t data_spi=0;
uint8_t data_out[2]={0};
uint8_t tx_data = 0xA5;
uint8_t rx_data = 0;
uint32_t spi_error;
uint32_t spi_state;
float target_value,ture_value;
float fs,duty;
int count=0;
uint16_t Z_A=0;
char buff[64];
//FHSS--4FSK
#define NUM_FREQ 5
#define NUM_BIAS 4
#define data_count 16 //频率信号发送数量,发送位数➗️2
int Period = 64000000; //MCU主频率
int tx_count = 0; //发送数据计数
int time_count = 0; //发送时间数据计数
int f_base[NUM_FREQ] = {25500, 26500, 25000, 26000, 27000}; //基频
int f_bias[NUM_BIAS] = {0, 100, 200 ,300}; //信号偏置频率
uint8_t fs_tx_buff[data_count] = {0}; //信号的偏置频率编码
uint32_t single_data=0x35; //单次发送数据
uint8_t tx_flag=0; //发送判定符号
void caculate_data_code(uint32_t single_data);
uint8_t rx_flag=0; // 接收判定符号
int rx_count=0; // 发送数据计数
#define Fs 64000 // 采样率 100kHz
#define N 640 // 数据块大小
uint16_t adc_buffer[N]; // ADC数据存放的数组
float energy[4];
int max_idx = 0;
int second_idx = 0;
int time_count_rx=0; // 接收时间数据计数
uint32_t receive_data=0x00; // 单次发送数据
typedef struct {
int16_t coeff_Q15; // 2*cos(omega) / 2 (范围 [-1,1])
int16_t cos_Q15; // cos(omega)
int16_t sin_Q15; // sin(omega)
} GTZLParam;
static GTZLParam g_params[NUM_FREQ][NUM_BIAS];
void GTZL_init(void)
{
const float Q15_SCALE = 32768.0f;
for (int i = 0; i < NUM_FREQ; i++)
{
for (int j = 0; j < NUM_BIAS; j++)
{
float k = (N * (f_base[i]+f_bias[j])) / Fs;
float omega = (2.0f * 3.141592653589793f * k) / N;
float coeff = 2.0f * cosf(omega);
// 存储 coeff/2 以适应 Q15 范围 [-1, 1)
g_params[i][j].coeff_Q15 = (int16_t)((coeff * 0.5f) * Q15_SCALE + 0.5f);
g_params[i][j].cos_Q15 = (int16_t)(cosf(omega) * Q15_SCALE + 0.5f);
g_params[i][j].sin_Q15 = (int16_t)(sinf(omega) * Q15_SCALE + 0.5f);
}
}
}
int32_t GTZL_energy_fixed(uint16_t *samples, const GTZLParam *param) //定点GTZL
{
int32_t q0 = 0, q1 = 0, q2 = 0;
int16_t coeff_half = param->coeff_Q15;
int16_t cosv = param->cos_Q15;
int16_t sinv = param->sin_Q15;
// 循环展开 (手动展开可进一步加速)
for (int i = 0; i < N; i++)
{
// 将采样值转为 Q15 格式(0~4095 -> 0~32760)
int32_t x = (int32_t)samples[i] << 3; // 乘以 8
// 2 * (coeff_half * q1) >> 15
int32_t mul = (int32_t)((int64_t)coeff_half * q1 >> 15);
q0 = (mul << 1) - q2 + x; // q0 = 2*coeff_half*q1 - q2 + x
q2 = q1;
q1 = q0;
}
// 计算实部与虚部
int32_t real = q1 - (int32_t)((int64_t)q2 * cosv >> 15);
int32_t imag = (int32_t)((int64_t)q2 * sinv >> 15);
// 返回能量:real^2 + imag^2 (缩放调整)
int64_t real2 = (int64_t)real * real;
int64_t imag2 = (int64_t)imag * imag;
return (int32_t)((real2 + imag2) >> 15); // 右移 15 调整量级
}
int compute_energies(uint16_t *samples,int rx_count, int bias)
{
return GTZL_energy_fixed(samples, &g_params[rx_count][bias]);
}
float GTZL_magnitude_squared(uint16_t *samples, int target_freq) // 浮点GTZL
{
float k = (N * target_freq) / Fs;
float omega = (2.0f * M_PI * k) / (float)N; //调用math.h的pi
float coeff = 2.0f * cosf(omega);
float q0 = 0, q1 = 0, q2 = 0;
for (int i = 0; i < N; i++)
{
q0 = coeff * q1 - q2 + samples[i];//4096.f*3.3;
q2 = q1;
q1 = q0;
}
// 计算能量(幅度的平方),用于比较
float real = (q1 - q2 * cosf(omega));
float imag = (q2 * sinf(omega));
return (real * real + imag * imag);
}
//#define FS 64000U
//#define LFM_N 1280U
//#define PI 3.14159265358979323846f
///* LFM粗检测频率 */
//static const float lf[4] = { 25500.0f, 26500.0f, 28500.0f, 29500.0f};
///* LFM正交模板存放在Flash */
//static int16_t lfm_cos_q15[LFM_N];
//static int16_t lfm_sin_q15[LFM_N];
//#define LFM_FS 64000.0f
//#define LFM_F0 25000.0f
//#define LFM_F1 30000.0f
//#define LFM_T 0.020f //持续时间
//#define LFM_N 1280U
//#define PI_F 3.14159265358979323846f
//static float lc[4];
//static uint32_t pe = 0; /* 当前处理窗口终点 */
//static uint32_t first = 0; /* 第一次低频窗口终点 */
//static uint32_t approx = 0; /* LFM近似起点 */
//static uint8_t state = 0; /* 0搜索,1精定位,2完成 */
//static uint8_t stage = 0; /* LFM低频段检测状态 */
//void LFM_Template_Init(void)
//{
// const float mu = (LFM_F1 - LFM_F0) / LFM_T;
// uint32_t n;
// for (n = 0; n < LFM_N; n++)
// {
// float t = (float)n / LFM_FS;
// float phase = 2.0f * PI_F * (LFM_F0 * t + 0.5f * mu * t * t);
// lfm_cos_q15[n] = (int16_t)(32767.0f * cosf(phase));
// lfm_sin_q15[n] = (int16_t)(32767.0f * sinf(phase));
// }
//}
///* 检测结果 */
//volatile uint8_t lfm_ok = 0;
//volatile uint32_t lfm_pos = 0;
//static float Coef(float f)
//{
// return 2.0f * cosf(2.0f * PI * f / FS);
//}
///*================ LFM粗搜索 =================*/
//float e[4];
//float lo, hi;
//static uint8_t LFM_Search(uint32_t end, uint32_t *pos) //窗口终点,LFM初步判定起点 双能量判定LFM粗边界
//{
// uint32_t d;
// if (end < 640U)
// return 0;
// Get640(end - 640U);
//
// e[0]=GTZL_energy_fixed(win, &g_params[2][0]); //能量计算
// e[1]=GTZL_energy_fixed(win, &g_params[0][0]);
// e[2]=GTZL_energy_fixed(win, &g_params[3][0]);
// e[3]=GTZL_energy_fixed(win, &g_params[1][0]);
// lo = e[0] + e[1]; //低频能量
// hi = e[2] + e[3]; //高频能量
//
// if (!stage)
// {
// if (lo > hi * 1.5f && lo>10000) //低频能量>高频能量
// {
// stage = 1;
// first = end; //记录低频扫描点终点窗口坐标
// }
// return 0;
// }
// d = end - first; //下一次LFM检测计数
// if (d >= 320U && d <= 960U && hi > lo * 1.5f && end >= LFM_N && hi>10000) //高频能量>低频能量
// {
// *pos = end - LFM_N; //记录粗略LFM终止点
// stage = 0;
// return 1;
// }
// if (d > 960U) //误判跳出记录粗略LFM终止点
// stage = 0;
// return 0;
//}
//
///*================ LFM相关 =================*/
//static uint64_t LFM_Corr(uint32_t start, uint8_t step)
//{
// int64_t i = 0, q = 0;
// uint32_t n;
//
// for (n = 0; n < LFM_N; n += step)
// {
// int32_t x = RG(start + n);
//
// i += (int64_t)x * lfm_cos_q15[n];
// q += (int64_t)x * lfm_sin_q15[n];
// }
// i >>= 15;
// q >>= 15;
// return (uint64_t)(i * i) + (uint64_t)(q * q);
//}
//
///* 在近似位置附近寻找LFM准确起点 */
//static uint32_t LFM_Find(uint32_t a)
//{
// uint32_t now = wr; // 已经采样点数
// uint32_t old = now > RING_N ? now - RING_N : 0U; // old 表示环形缓冲区中当前仍然有效的最早采样点。
// uint32_t best = a; // 迭代最优解
// uint64_t max = 0, v; // v:当前候选位置的相关能量 max:目前找到的最大相关能量。
// int32_t p; // p 是当前正在测试的候选起点。
//
// /* 粗搜索:±320点,每32点检测一次 */
// for (p = (int32_t)a - 320; p <= (int32_t)a + 320; p += 32)
// {
// if (p < 0 ||(uint32_t)p < old || (uint32_t)p + LFM_N > now)
// continue;
//
// v = LFM_Corr((uint32_t)p, 8);
// if (v > max)
// {
// max = v;
// best = (uint32_t)p;
// }
// }
//
// /* 精搜索:最佳位置附近±8点 */
// max = 0;
// for (p = (int32_t)best - 8; p <= (int32_t)best + 8; p++)
// {
// if (p < 0 ||(uint32_t)p < old || (uint32_t)p + LFM_N > now)
// continue;
// v = LFM_Corr((uint32_t)p, 1);
// if (v > max)
// {
// max = v;
// best = (uint32_t)p;
// }
// }
// return best;
//}
//
///*================ 状态处理 =================*/
//static void LFM_Process(uint32_t end)
//{
// switch (state)
// {
// case 0: /* 搜索LFM */
// {
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
// if (LFM_Search(end, &lfm_pos))//approx
// {
// lfm_ok = 1;
// state = 2;
// }
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
// }
// break;
// case 1: /* 等待足够数据并精定位 */
// if (wr >= approx + LFM_N + 320U)
// {
// lfm_pos = LFM_Find(approx);
// lfm_ok = 1;
// state = 2;
// }
// break;
// default: /* 已检测完成 */
// break;
// }
//}
///* 重新搜索下一帧LFM */
//void LFM_Reset(void)
//{
// lfm_ok = 0;
// stage = 0;
// state = 0;
//}
///*================ 4FSK检测 =================*/
//#define FSK_GAP_N 640U
//
//static uint8_t fsk_run = 0; /* 正在解调 */
//static uint8_t fsk_step = 0; /* 当前计算第几个频率 */
//static uint8_t fsk_base = 0; /* 当前跳频基频编号 */
//static uint32_t fsk_pos = 0; /* 当前码元起点 */
//
//static int32_t fsk_e[4]; /* 四个频率能量 */
//volatile uint8_t fsk_done = 0;
//
///*
// * 当前ADC_Save()把原始ADC值直接存入ring[],
// * 所以这里不加MID,直接复制。
// */
//static void FSK_Load640(uint32_t start)
//{
// uint16_t i;
// for (i = 0; i < N; i++)
// win[i] = (uint16_t)RG(start + i);
//}
//
///* 找到头LFM后启动4FSK解调 */
//static void FSK_RT_Start(void)
//{
// /* 20ms LFM + 10ms间隔 */
// fsk_pos = lfm_pos + LFM_N + FSK_GAP_N;
// receive_data = 0;
// rx_count = 0;
// fsk_step = 0;
// fsk_run = 1;
// fsk_done = 0;
// /* 暂停继续搜索LFM */
// state = 2;
// lfm_ok = 0;
//
// /* 防止原TIM2解调逻辑同时运行 */
// rx_flag = 0;
//}
//
///*
// * 每次调用最多运行一次GTZL_energy_fixed()。
// * 单次最长阻塞时间约等于一个Goertzel的执行时间。
// */
//volatile uint8_t fsk_dbg = 0;
//volatile uint32_t fsk_age = 0;
//void FSK_RT_Task(void)
//{
// uint8_t i, max;
//
// /* 1:等待LFM检测成功 */
//// if (!fsk_run)
//// {
//// if (!lfm_ok)
//// {
//// fsk_dbg = 1;
//// return;
//// }
//// FSK_RT_Start();
//// fsk_dbg = 2; /* FSK已经启动 */
//// }
//
// if (lfm_ok == 1)
// {
// fsk_pos = lfm_pos + LFM_N + FSK_GAP_N;
// fsk_age = (uint32_t)(wr - fsk_pos);
// /* 3:当前码元的640点还未采完 */
// if (fsk_age < N)
// {
// fsk_dbg = 3;
// return;
// }
//
// /* 4:当前码元已经被环形缓存覆盖 */
// if (fsk_age > RING_N)
// {
// fsk_dbg = 4;
// fsk_run = 0U;
// LFM_Reset();
// return;
// }
//
// FSK_Load640(fsk_pos);
// fsk_base = (uint8_t)(rx_count % NUM_FREQ);
// fsk_step = 1U;
// /* * 此处不能return* 直接继续计算第一个频率。 */
// }
//
// /* 5:正在执行第1~4路Goertzel */
// fsk_dbg = 5;
// i = fsk_step - 1U;
// fsk_e[i] = GTZL_energy_fixed(win, &g_params[fsk_base][i]);
// fsk_step++;
//
// /* 还没有计算完四个频率 */
// if (fsk_step <= NUM_BIAS)
// return;
//
// /* 四路计算完成,选择能量最大者 */
// max = 0U;
//
// for (i = 1U; i < NUM_BIAS; i++)
// {
// if (fsk_e[i] > fsk_e[max])
// max = i;
// }
//
// receive_data |=
// (uint32_t)max << (rx_count * 2U);
//
// rx_count++;
// fsk_pos += N;
// fsk_step = 0U;
//
// fsk_dbg = 6; /* 一个码元完成 */
//
// if (rx_count >= data_count)
// {
// fsk_run = 0U;
// fsk_done = 1U;
// LFM_Reset();
// }
//}
/*================ 对外函数 =================*/
///* 初始化并启动ADC DMA */
//void LFM_Init(void)
//{
// for (uint8_t i = 0; i < 4U; i++)
// lc[i] = Coef(lf[i]);
// wr = pe = 0;
// pend = stage = state = lfm_ok = 0;
// HAL_ADCEx_Calibration_Start(&hadc1); //adc自校准;
// LFM_Template_Init();
// HAL_ADC_Start_DMA(&hadc1, (uint32_t *)adc_buffer, DMA_N);
// HAL_TIM_Base_Start(&htim3);
//}
/*================ DMA数据保存 =================*/
#define DMA_N 640U //全DMA数据量
#define HALF 320U //半DMA数据量
#define RING_N 2048U //
uint16_t adc_buffer[DMA_N];
static int16_t ring[RING_N];
static volatile uint32_t wr = 0; // ADC总采样点数
static volatile uint8_t pend = 0; //待处理数据块数量
#define SEG_N 320U //过零检测范围
#define ZERO_TH 50 //噪声滞环
int LFM_pos=0;
uint32_t LFM_Flag=0;
uint32_t test=0;
static uint16_t win[N];
/*================ 基础函数 =================*/
static void Uint32ToBinary(uint32_t value, char *str) //打印二进制数
{
int i = 0;
do
{
str[i++] = (value & 1U) ? '1' : '0';
value >>= 1U;
} while (value != 0U);
str[i] = '\0';
for (int j = 0; j < i / 2; j++)
{
char temp = str[j];
str[j] = str[i - 1 - j];
str[i - 1 - j] = temp;
}
}
static int16_t RG(uint32_t n)
{
return ring[n & (RING_N - 1U)];
}
static void Get640(uint32_t start)
{
for (uint32_t i = 0; i < N; i++)
win[i] = (uint16_t)RG(start + i);
}
static void ADC_Save(const uint16_t *src)
{
uint32_t i, s = wr;
for (i = 0; i < HALF; i++)
ring[(s + i) & (RING_N - 1U)] =(int16_t)src[i];//前面为余除RING_N, - MID可减去偏置
wr += HALF; //更新保留当前位
if (pend < 6U)
pend++; //待处理半数据块数量增加
}
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc) //DMA半中断
{
if (hadc->Instance == ADC1)
{
ADC_Save(&adc_buffer[0]);
}
}
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) //DMA全中断
{
if (hadc->Instance == ADC1)
{
ADC_Save(&adc_buffer[HALF]);
}
}
/*================ 过零LFM检测 =================*/
/* 统计320点内的正向过零次数 */
static uint16_t ZeroCnt(uint32_t start)
{
uint16_t i, cnt = 0;
int8_t state = 0;
for (i = 0; i < SEG_N; i++)
{
int16_t x = RG(start + i)-1990; //偏置,需要修改
if (x > ZERO_TH)
{
if (state < 0)
cnt++;
state = 1;
}
else if (x < -ZERO_TH)
{
state = -1;
}
// if(x>200 && test==0)
// {
// test=1;
// //HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8); //频率测试,可注释
// }
}
return cnt;
}
/* 检验1280点是否为25kHz→30kHz上扫LFM */
int t=0;
static void LFM_Detect(uint32_t start)
{
if(LFM_Flag==0)
{
uint16_t c;
c = ZeroCnt(start);
if (c>5 && HAL_GetTick()-t>50) //完毕后间隔50ms检测
{
LFM_pos=start+(1-c/128.f)*SEG_N;
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8); //频率测试,可注释
LFM_Flag = 1;
receive_data=0x00;
}
}
}
void FSK_Task(void)
{
if(LFM_Flag!=0) //接收判定
{
if(LFM_Flag<=10)
{
LFM_Flag+=1;
return;
}
if(time_count_rx==0)
{
if(rx_count==data_count)
{
count=receive_data; //写入数字
snprintf(buff, sizeof(buff), "RX:%d", count); //最多写入 size - 1 个字符(保留一个位置给字符串结束符 \0)count = 2026; // 某个值
// snprintf(buff, sizeof(buff), "RX:0x%X", count); // 十六进制大写
//------------------二进制------------------//
// count=receive_data; //写入数字
// char bin[48];
// Uint32ToBinary((uint32_t)count, bin);
// snprintf(buff, sizeof(buff), "Receive:%s", bin);
//------------------二进制------------------//
ssd1306_Fill(White);
ssd1306_SetCursor(2, 18);
ssd1306_WriteString(buff,Font_11x18, Black);
ssd1306_UpdateScreen();
// char *msg = "Hello"; // 可变字符串,可任意修改
// snprintf(buff, sizeof(buff), "%d%s", count, msg);
// ssd1306_Fill(White);
// ssd1306_SetCursor(2, 18);
// ssd1306_WriteString(buff, Font_11x18, Black);
// ssd1306_UpdateScreen();
LFM_Flag=0;
rx_count=0;
time_count_rx=0;
t=HAL_GetTick();
return;
}
Get640(LFM_pos+640*(rx_count+4));
for (int i = 0; i < NUM_BIAS; i++)
{
//energy[i] = GTZL_magnitude_squared(adc_buffer, f_base[0]+f_bias[i]);
//energy[i] = GTZL_magnitude_squared(adc_buffer, f_base[rx_count]+f_bias[i]);
//HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8); //频率测试,可注释
energy[i]=compute_energies(win,rx_count % NUM_FREQ,i) ;
//HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8); //频率测试,可注释
}
max_idx=0;
for (int i = 1; i < 4; i++)
{
if (energy[i] > energy[max_idx]) max_idx = i;
}
second_idx = (max_idx == 0) ? 1 : 0;
for (int i = 0; i < NUM_BIAS; i++)
{
if ((i != max_idx) && (energy[i] > energy[second_idx]))
{
second_idx = i;
}
}
if( energy[max_idx]<2*energy[second_idx]) //判决比
{
receive_data=0x00;
LFM_Flag=0;
rx_count=0;
time_count_rx=0;
t=HAL_GetTick();
return;
}
receive_data= (max_idx<<(rx_count*2)) | receive_data;
// if(rx_count==2)
// test=1;
rx_count+=1; //固定接收注释
}
time_count_rx = (time_count_rx + 1) % 2; //x次数清零,接收时间x次中断
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_TIM4_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
GTZL_init();
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, N);
// __HAL_DMA_ENABLE_IT(&hdma_adc1, DMA_IT_HT); //hdma_spi_rx
// __HAL_DMA_ENABLE_IT(&hdma_adc1, DMA_IT_TC);
// HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3); //启动 PWM 通道3信号输出
// HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3); //启动 PWM 通道3互补信号输出
// HAL_TIM_Base_Start(&htim1);
HAL_TIM_Base_Start_IT(&htim2); //启动定时器中断
HAL_TIM_Base_Start(&htim3);
HAL_TIM_Base_Start_IT(&htim4); //启动定时器中断
HAL_Delay(100);
// __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,1300); //设置 PWM 通道2 占空比
// __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,1300); //设置 PWM 通道3 占空比
// a=HAL_I2C_IsDeviceReady(&hi2c1,60<<1,10,10000); //I2C connect right
// ssd1306_TestFPS();
ssd1306_Init();
// count=2026; //写入数字2026
// snprintf(buff, sizeof(buff), "%dWelcome", count); //最多写入 size - 1 个字符(保留一个位置给字符串结束符 \0)
// ssd1306_Fill(White);
// ssd1306_SetCursor(2, 18);
// ssd1306_WriteString(buff, Font_11x18, Black);
// ssd1306_UpdateScreen();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
while (pend>0)
{
//HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8); //频率测试,可注释
__disable_irq(); //关闭中断防止冲突
pend--;
__enable_irq();
LFM_Detect(wr - HALF);
FSK_Task();
}
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV8;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
void caculate_data_code(uint32_t single_data) //8位信号,信号分解数量
{
for (int i=0;i<data_count;i++)
{
fs_tx_buff[i]= (single_data>>(i*2)) & 0x03; // 提取低2位,从低位到高位写入buff
//fs_tx_buff[i]= ((single_data<<(i*2)) & 0b11000000)>>6; // 提取高2位,从高位到低位写入buff
}
}
int caculate_data_ARR(uint8_t fr_num, uint8_t data) //基础频率编号,信号频率编码
{
int ARR,f_tx;
f_tx = f_base[fr_num] + f_bias[data];
ARR=Period/f_tx;
return ARR;
}
//定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2) // TIM2触发中断
{
if(rx_flag==1) //修改则关闭接收
{
for (int i=0;i<50;i++)
{
if(adc_buffer[i]>2100) //ADC判定接收阈值
{
rx_flag=1; //启动接收
receive_data=0x00;
time_count_rx=1;//第一周期半抛弃,存储新值|------------|---===(提取的数据)------|
//HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8); //频率测试,可注释
}
}
}
/////////////////////* 实时解调 *///////////////////////////////
if(rx_flag!=0) //接收判定
{
if(time_count_rx==0)
{
if(rx_count==data_count)
{
rx_flag=0;
rx_count=0;
time_count_rx=0;
return;
}
for (int i = 0; i < 4; i++)
{
//energy[i] = GTZL_magnitude_squared(adc_buffer, f_base[0]+f_bias[i]);
//energy[i] = GTZL_magnitude_squared(adc_buffer, f_base[rx_count]+f_bias[i]);
//HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8); //频率测试,可注释
energy[i]=compute_energies(adc_buffer,rx_count % 4,i) ;
//HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8); //频率测试,可注释
}
max_idx=0;
for (int i = 1; i < 4; i++)
{
if (energy[i] > energy[max_idx]) max_idx = i;
}
receive_data= (max_idx<<(rx_count*2)) | receive_data;
rx_count+=1; //固定接收注释
}
time_count_rx = (time_count_rx + 1) % 2; //x次数清零,接收时间x次中断
}
/////////////////////* 实时解调 *///////////////////////////////
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
|