/* 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 "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//#include "ssd1306_tests.h"
#include "PID_Control.h"
//#include "ssd1306.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 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/* 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 // 采樣率
#define N 640 // 數據塊大小
uint16_t adc_buffer[N]; // ADC數據存放的數組
float energy[4];
int max_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);
}
/////////////////////* LFM檢測 *///////////////////////////////
//#define LFM_FS 100000.0f // ADC采樣率:100 kHz
//#define LFM_F0 25000.0f // 起始頻率:25 kHz
//#define LFM_F1 30000.0f // 結束頻率:30 kHz
//#define LFM_TIME 0.01f // LFM持續時間:10 ms
//#define LFM_SAMPLE_NUM 1000U // 100 kHz × 10 ms
//#define ADC_MID_VALUE 2048.0f // 12位ADC中點
///*
// * 理想匹配時歸一化相關值約為0.5。
// * 實際可在0.15~0.35之間調整。
// */
//#define LFM_THRESHOLD 0.20f
//#define PI_F 3.14159265358979323846f
///**
// * @brief 在ADC數據中查找25 kHz->30 kHz的LFM信號
// * @param adc_data ADC采樣數組
// * @param adc_length ADC數組長度,必須大于1000
// * @param peak_score 輸出最大相關值,可以傳NULL
// * @return >=0:LFM起始采樣點
// * -1 :未檢測到LFM
// * 例如返回500:
// * 表示LFM從adc_data[500]開始,
// * LFM結束位置約為adc_data[1499],
// * 后續數據從adc_data[1500]附近開始。
// */
//int32_t LFM_Find25To30k(const uint16_t *adc_data, uint32_t adc_length, float *peak_score)
//{
// static float template_cos[LFM_SAMPLE_NUM];
// static float template_sin[LFM_SAMPLE_NUM];
// static uint8_t template_initialized = 0U;
// float best_score = 0.0f;
// int32_t best_position = -1;
// uint32_t offset;
// uint32_t n;
//
// if ((adc_data == 0) || (adc_length < LFM_SAMPLE_NUM))
// {
// if (peak_score != 0)
// {
// *peak_score = 0.0f;
// }
// return -1;
// }
// /* 本地LFM模板只生成一次。* f(t) = f0 + μt * μ = (f1-f0)/T
// * phase(t) = 2π[f0*t + 0.5*μ*t²]*/
// if (template_initialized == 0U)
// {
// const float sweep_rate =
// (LFM_F1 - LFM_F0) / LFM_TIME;
//
// for (n = 0U; n < LFM_SAMPLE_NUM; n++)
// {
// float t;
// float phase;
// t = (float)n / LFM_FS;
// phase = 2.0f * PI_F * (LFM_F0 * t + 0.5f * sweep_rate * t * t);
// template_cos[n] = cosf(phase);
// template_sin[n] = sinf(phase);
// }
// template_initialized = 1U;
// }
// /*滑動匹配濾波/互相關*/
// for (offset = 0U;offset <= adc_length - LFM_SAMPLE_NUM; offset++)
// {
// float correlation_i = 0.0f;
// float correlation_q = 0.0f;
// float signal_energy = 0.0f;
// float score;
// for (n = 0U; n < LFM_SAMPLE_NUM; n++)
// {
// float x;
// /*將12位無符號ADC轉換為以0為中心的信號 */
// x = (float)adc_data[offset + n] - ADC_MID_VALUE;
// correlation_i += x * template_cos[n];
// correlation_q += x * template_sin[n];
// signal_energy += x * x;
// }
//
// /* * 信號過小時不進行判斷。
// * 此處相當于要求ADC信號RMS大于約10個碼 */
// if (signal_energy < (float)LFM_SAMPLE_NUM * 100.0f)
// {
// continue;
// }
//
// /*歸一化非相干相關能量,使用I²+Q²避免未知初始相位造成相關結果下降 */
// score = (correlation_i * correlation_i + correlation_q * correlation_q) / (signal_energy * (float)LFM_SAMPLE_NUM);
// if (score > best_score)
// {
// best_score = score;
// best_position = (int32_t)offset;
// }
// }
// if (peak_score != 0)
// {
// *peak_score = best_score;
// }
// if (best_score >= LFM_THRESHOLD)
// {
// return best_position;
// }
// return -1;
//}
/////////////////////* LFM檢測 *///////////////////////////////
/////////////////////* SPI *///////////////////////////////
//void NRF24_GPIO_Init(void)
//{
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); //CSN
// HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET); //CE
// HAL_Delay(100);
//}
//
//uint8_t NRF24_SPI_ReadWriteByte(uint8_t tx_data)
//{
// uint8_t rx_data = 0;
// HAL_SPI_TransmitReceive(&hspi1, &tx_data, &rx_data, 1, HAL_MAX_DELAY);
//
// //HAL_SPI_Receive(&hspi1, &rx_data, 1, HAL_MAX_DELAY);
// return rx_data;
//}
///**
// * @brief 向NRF24L01的指定寄存器寫入一個值
// * @param reg: 寄存器地址
// * @param value: 要寫入的值
// */
//void NRF24_Write_Reg(uint8_t reg, uint8_t value)
//{
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); // 1. 片選信號拉低CSN,開始SPI事務
// NRF24_SPI_ReadWriteByte(reg); // 2. 發送寄存器地址(寫入命令)
// NRF24_SPI_ReadWriteByte(value); // 3. 發送要寫入的數據
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); // 4. 拉高CSN,結束事務
//}
//
///**
// * @brief 讀取NRF24L01的指定寄存器
// * @param reg: 寄存器地址
// * @retval 寄存器的值
// */
//uint8_t NRF24_Read_Reg(uint8_t reg)
//{
// uint8_t value;
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); // 1. 拉低CSN,開始SPI事務
// NRF24_SPI_ReadWriteByte(reg); // 發送寄存器地址(讀取命令)
// value = NRF24_SPI_ReadWriteByte(0xFF); // 發送0xFF,讀取數據
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); // 4. 拉高CSN,結束事務
// return value;
//}
//
//// 向指定寄存器寫入多字節數據
//void NRF24_Write_Buf(uint8_t reg, uint8_t *pBuf, uint8_t len)
//{
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); // 1. 拉低CSN,開始SPI事務
// NRF24_SPI_ReadWriteByte(reg); // 發送寄存器地址(含指令)
// for (uint8_t i = 0; i < len; i++)
// {
// NRF24_SPI_ReadWriteByte(pBuf[i]); // 連續寫入數據
// }
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); // 4. 拉高CSN,結束事務
//}
//
//// 從指定寄存器讀取多字節數據
//void NRF24_Read_Buf(uint8_t reg, uint8_t *pBuf, uint8_t len)
//{
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); // 1. 拉低CSN,開始SPI事務
// NRF24_SPI_ReadWriteByte(reg); // 發送寄存器地址(讀指令)
// for (uint8_t i = 0; i < len; i++)
// {
// pBuf[i] = NRF24_SPI_ReadWriteByte(0xFF); // 發送0xFF讀數據
// }
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); // 4. 拉高CSN,結束事務
//}
//
///**
// * @brief 檢查NRF24L01是否存活(通信是否建立)
// * @retval 1: 通信正常, 0: 通信失敗
// */
//uint8_t NRF24_Check(void)
//{
// uint8_t tx_buf[5] = {0x01, 0x02, 0x03, 0x04, 0x05};
// uint8_t rx_buf[5] = {0};
// uint8_t i;
// uint8_t NRF24_WRITE_REG=0x20; //0010 0000
// uint8_t TX_ADDR=0x10;
// // 向TX_ADDR寄存器寫入5字節數據
//// NRF24_Write_Buf(NRF24_WRITE_REG + 0x00, tx_d, 1); //寫指令:001A AAAA
//// NRF24_Read_Buf(0x00, rx_buf, 5); //讀指令:000A AAAA
// HAL_Delay(1000);
// NRF24_Write_Buf(NRF24_WRITE_REG + TX_ADDR, tx_buf, 5); //寫指令:001A AAAA
// // 從TX_ADDR寄存器讀取5字節數據
// NRF24_Read_Buf(TX_ADDR, rx_buf, 5); //讀指令:000A AAAA
// for(i = 0; i < 5; i++)
// {
// if(rx_buf[i] != tx_buf[i])
// return 0; // 數據不一致,通信失敗,231 = 0xE7常是SPI總線空閑狀態或模塊處于復位/掉電模式時讀出的默認數據。
// }
// return 1; // 通信正常
//}
/////////////////////* SPI *///////////////////////////////
/////////////////////模擬boost測試////////////////////////////////
//float Vin = 12.0f; /* 假設固定輸入電壓 12V */
//float Vout = 0.f;
//float duty = 0.f;
//void boost_simulate(float duty,float Vin)
//{
// int r = (rand() % 7) - 3;
// if (duty >= 1.0f) duty = 0.99f; /* 防止分母為零 */
// if (duty < 0.0f) duty = 0.0f;
// Vout = Vin / (1.0f - duty)+r;
//}
/////////////////////模擬boost////////////////////////////////
/* 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_TIM1_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
GTZL_init();
// HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, N);
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_2); //啟動 PWM 通道2信號輸出
// 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(&htim3);
HAL_TIM_Base_Start_IT(&htim2); //啟動定時器中斷
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 占空比
/////////////////////* PID *///////////////////////////////
// PID_Init();
// PID_Control_Caculate(&PID_Voltage, target_value, ture_value);
/////////////////////* PID *///////////////////////////////
/////////////////////* 陀螺儀操作 *///////////////////////////
// a=HAL_I2C_IsDeviceReady(&hi2c1,104<<1,10,10000); //I2C connect right
// data=0b10000000; //Init zero
// HAL_I2C_Mem_Write(&hi2c1,104<<1,0x6b,1,&data,1,10000);//
// HAL_Delay(10);
// data=0b00000000; //Wake up
// HAL_I2C_Mem_Write(&hi2c1,104<<1,0x6b,1,&data,1,10000);//
// HAL_Delay(10);
// data=0b00011000; //Precision
// HAL_I2C_Mem_Write(&hi2c1,104<<1,0x1b,1,&data,1,10000);//
// HAL_Delay(10);
// HAL_I2C_Mem_Read(&hi2c1,104<<1,0x3F,1,data_out,2,10000);//前:實際寄存器地址大小,后:讀取數據量
// Z_A=data_out[0]<<8|data_out[1]; //合并高8位和低8位
// HAL_I2C_Mem_Read(&hi2c1,104<<1,0x3F,1,&data1,1,10000);//
// HAL_I2C_Mem_Read(&hi2c1,104<<1,0x40,1,&data2,1,10000);//
/////////////////////* 陀螺儀操作 *///////////////////////////
/////////////////////* OLED操作 *///////////////////////////
// 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();
/////////////////////* OLED操作 *///////////////////////////
/////////////////////* SPI操作 *///////////////////////////
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); //CSN
// HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET); //CE
// NRF24_GPIO_Init();
// a=NRF24_Check();
// spi_state=HAL_SPI_GetState(&hspi1); //0:外設未初始化 1:外設已初始化并可使用
// spi_error=HAL_SPI_GetError(&hspi1); //0x00:函數執行成功。 0x01:發生錯誤。 0x02:SPI外設正在忙。 0x03:操作超時
// HAL_SPI_Transmit(&hspi1, &data_spi, 1, 10000);
// HAL_SPI_TransmitReceive(&hspi1, &tx_data, &rx_data, 1, HAL_MAX_DELAY);
// if (tx_data == rx_data)
// {
// a=0; // 回環測試通過
// } else
// {
// a=1; // 回環測試失敗
// }
/////////////////////* SPI操作 *///////////////////////////
/////////////////////* GPIO操作 *///////////////////////////
// HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);
// HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8);
// HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
/////////////////////* GPIO操作 *///////////////////////////
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//printf("Hello, STM32F4!\r\n");
caculate_data_code(single_data); //編碼
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==1)
{
tx_flag=1;
HAL_Delay(1000);
}
HAL_Delay(100);
////////////////* 位操作 *///////////////////////////
// buf[0] = test_data & 0xFF; // 提取低8位
// buf[1] = (test_data >> 8) & 0xFF; // 提取高8位
// a &= ~(0b00000100); //第三位置0 a |= (1<<2);
// a ^= 0b00000100; //第三位異或操作取反 a ^=(1<<2);
// a |= 0b00000100; //第三位置1 a |=(1<<2);
// if((a >> n) & 0b00000001); //n位判定
// (a & ~(0x01 << n)) | (x << n); //修改n位為x a |=(1<<2);
////////////////* 位操作 *///////////////////////////
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {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();
}
}
/* 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;
}
#define START_FREQ 25000.0f // 起始頻率
#define END_FREQ 30000.0f // 終止頻率
#define STEP_COUNT 20-1 // 步數(20ms / 1ms)-1
#define FREQ_STEP ((END_FREQ - START_FREQ) / STEP_COUNT) // 每步變頻
uint32_t newARR = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //定時器中斷回調函數
{
if (htim->Instance == TIM2) // TIM2觸發中斷
{
if(tx_flag!=0) //發送判定
{
if(time_count<20) //LFM起始幀--20ms
{
fs=START_FREQ + time_count*FREQ_STEP;
newARR=Period/fs;
__HAL_TIM_SET_AUTORELOAD(&htim1, newARR); // 1. 修改自動重裝載值 (改變頻率)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, (newARR + 1) / 2); // 2. 同時修改比較值,保持 50% 占空比 (針對通道1)
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3); //啟動 PWM 通道3信號輸出
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3); //啟動 PWM 通道3互補信號輸出
}
if(time_count==20) //LFM起始幀--20ms
{
HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_3); //關閉PWM通道3信號輸出
HAL_TIMEx_PWMN_Stop(&htim1,TIM_CHANNEL_3); //關閉啟動PWM通道3互補信號輸出
}
if(time_count>=40 && time_count<=200) //數據幀--x ms
{
if(time_count % 10==0)
{
if(tx_count==data_count)
{
tx_flag=2; //數據發送完畢
tx_count=0;
HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_3); //關閉PWM通道3信號輸出
HAL_TIMEx_PWMN_Stop(&htim1,TIM_CHANNEL_3); //關閉啟動PWM通道3互補信號輸出
//return; //搭配下面if使用
}
if(tx_flag!=2)
{
newARR=caculate_data_ARR(tx_count % NUM_FREQ,fs_tx_buff[tx_count]); // 計算頻率
__HAL_TIM_SET_AUTORELOAD(&htim1, newARR); // 1. 修改自動重裝載值 (改變頻率)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, (newARR + 1) / 2); // 2. 同時修改比較值,保持 50% 占空比 (針對通道1)
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3); //啟動 PWM 通道3信號輸出
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3); //啟動 PWM 通道3互補信號輸出
tx_count+=1; //發送數據編號+1 關閉則定頻發送
}
}
}
if(time_count>=220 && time_count<240) //數據幀--x ms
{
fs=START_FREQ + (time_count-220)*FREQ_STEP;
newARR=Period/fs;
__HAL_TIM_SET_AUTORELOAD(&htim1, newARR); // 1. 修改自動重裝載值 (改變頻率)
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, (newARR + 1) / 2); // 2. 同時修改比較值,保持 50% 占空比 (針對通道1)
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3); //啟動 PWM 通道3信號輸出
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3); //啟動 PWM 通道3互補信號輸出
}
if(time_count==240) //數據幀--x ms
{
tx_flag=0;
HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_3); //關閉PWM通道3信號輸出
HAL_TIMEx_PWMN_Stop(&htim1,TIM_CHANNEL_3); //關閉啟動PWM通道3互補信號輸出
}
time_count += 1; //x次數清零,發波時間x次中斷
}
else
time_count=0;
// if(rx_flag==0) //修改則關閉接收
// {
// 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次中斷
// }
/////////////////////* 實時解調 *///////////////////////////////
/////////////////////* 延時解調 *///////////////////////////////
// if(rx_flag!=0) //接收判定
// {
// if(time_count_rx==0)
// {
// HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);
// if(rx_count==4)
// {
// rx_flag=0;
// rx_count=0;
// time_count_rx=0;
// return;
// }
//
// for (int i = 0; i < 4; i++)
// {
// Demodulation_buffer[i][N]=adc_buffer[N];
// }
// 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) % 10; //x次數清零,接收時間x次中斷
// }
/////////////////////* 延時解調 *///////////////////////////////
}
}
/////////////////////* CRC-8校驗*///////////////////////////
//unsigned char Crc8_Array[] = {
// 0x0, 0x2f, 0x5e, 0x71, 0xbc, 0x93, 0xe2, 0xcd, 0x57, 0x78, 0x9, 0x26, 0xeb, 0xc4, 0xb5, 0x9a,
// 0xae, 0x81, 0xf0, 0xdf, 0x12, 0x3d, 0x4c, 0x63, 0xf9, 0xd6, 0xa7, 0x88, 0x45, 0x6a, 0x1b, 0x34,
// 0x73, 0x5c, 0x2d, 0x2, 0xcf, 0xe0, 0x91, 0xbe, 0x24, 0xb, 0x7a, 0x55, 0x98, 0xb7, 0xc6, 0xe9,
// 0xdd, 0xf2, 0x83, 0xac, 0x61, 0x4e, 0x3f, 0x10, 0x8a, 0xa5, 0xd4, 0xfb, 0x36, 0x19, 0x68, 0x47,
// 0xe6, 0xc9, 0xb8, 0x97, 0x5a, 0x75, 0x4, 0x2b, 0xb1, 0x9e, 0xef, 0xc0, 0xd, 0x22, 0x53, 0x7c,
// 0x48, 0x67, 0x16, 0x39, 0xf4, 0xdb, 0xaa, 0x85, 0x1f, 0x30, 0x41, 0x6e, 0xa3, 0x8c, 0xfd, 0xd2,
// 0x95, 0xba, 0xcb, 0xe4, 0x29, 0x6, 0x77, 0x58, 0xc2, 0xed, 0x9c, 0xb3, 0x7e, 0x51, 0x20, 0xf,
// 0x3b, 0x14, 0x65, 0x4a, 0x87, 0xa8, 0xd9, 0xf6, 0x6c, 0x43, 0x32, 0x1d, 0xd0, 0xff, 0x8e, 0xa1,
// 0xe3, 0xcc, 0xbd, 0x92, 0x5f, 0x70, 0x1, 0x2e, 0xb4, 0x9b, 0xea, 0xc5, 0x8, 0x27, 0x56, 0x79,
// 0x4d, 0x62, 0x13, 0x3c, 0xf1, 0xde, 0xaf, 0x80, 0x1a, 0x35, 0x44, 0x6b, 0xa6, 0x89, 0xf8, 0xd7,
// 0x90, 0xbf, 0xce, 0xe1, 0x2c, 0x3, 0x72, 0x5d, 0xc7, 0xe8, 0x99, 0xb6, 0x7b, 0x54, 0x25, 0xa,
// 0x3e, 0x11, 0x60, 0x4f, 0x82, 0xad, 0xdc, 0xf3, 0x69, 0x46, 0x37, 0x18, 0xd5, 0xfa, 0x8b, 0xa4,
// 0x5, 0x2a, 0x5b, 0x74, 0xb9, 0x96, 0xe7, 0xc8, 0x52, 0x7d, 0xc, 0x23, 0xee, 0xc1, 0xb0, 0x9f,
// 0xab, 0x84, 0xf5, 0xda, 0x17, 0x38, 0x49, 0x66, 0xfc, 0xd3, 0xa2, 0x8d, 0x40, 0x6f, 0x1e, 0x31,
// 0x76, 0x59, 0x28, 0x7, 0xca, 0xe5, 0x94, 0xbb, 0x21, 0xe, 0x7f, 0x50, 0x9d, 0xb2, 0xc3, 0xec,
// 0xd8, 0xf7, 0x86, 0xa9, 0x64, 0x4b, 0x3a, 0x15, 0x8f, 0xa0, 0xd1, 0xfe, 0x33, 0x1c, 0x6d, 0x42,
//};
//
//unsigned char Cal_Crc_LookupTable(unsigned char *ptr, unsigned char len)
//{
// unsigned char crc = 0x00;
//
// while (len--)
// {
// crc = Crc8_Array[crc ^ *ptr++];
// }
// return (crc);
//}
//
//int main()
//{
// unsigned char crc, data = 0xc5;
// crc = Crc8_Array[data];
// printf("單字節查表:0x%x \n", crc);
// crc = Cal_Crc_LookupTable(&data, sizeof(data));
// printf("多字節查表:0x%x", crc);
// return 0;
//}
/////////////////////* CRC-8校驗*///////////////////////////
/* 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 */
|