1. 项目概述
在嵌入式通信系统中,2FSK(二进制频移键控)是一种简单高效的调制方式。最近我用STM32F103C8T6开发板配合标准库3.5版本,实现了一个完整的2FSK调制解调系统。这个项目特别适合需要低成本无线通信的场合,比如工业传感器数据采集、智能家居控制等场景。
整套系统包含发送端和接收端两部分:发送端将数字信号调制成2FSK波形,通过DAC输出;接收端则通过ADC采样,使用Goertzel算法进行频率检测。实测在波特率1200bps下,通信距离可达50米(配合简单的433MHz射频模块)。下面我就详细拆解这个项目的技术实现。
2. 硬件设计与关键参数
2.1 核心硬件选型
主控芯片选用STM32F103C8T6(蓝色pill开发板),主要考虑因素:
- 72MHz主频足够处理1200bps的2FSK信号
- 内置12位DAC和ADC,满足基础信号生成与采集需求
- 成本仅10元左右,适合批量应用
射频部分采用廉价的SYN115/SYN480R模块组:
- 发射模块SYN115:工作电压3.3-5V,发射功率10dBm
- 接收模块SYN480R:灵敏度-105dBm,支持315/433MHz频段
注意:射频模块需加装弹簧天线,实测PCB天线效果会下降30%以上
2.2 关键电路设计
发送端信号链:
code复制MCU(DAC) → RC低通滤波(截止频率3kHz) → SYN115
接收端信号链:
code复制SYN480R → 运放放大(增益20dB) → MCU(ADC)
参数计算示例:
- DAC输出采样率设为8kHz(满足奈奎斯特准则)
- 载频选择:f1=1200Hz,f2=2400Hz(符合ITU-T V.23标准)
- 每个符号采样点数=8000/1200≈6.67,取整为8点/符号
3. 软件实现详解
3.1 发送端调制实现
使用定时器触发DAC输出,核心代码如下:
c复制// 2FSK波形生成
void TIM2_IRQHandler(void) {
static uint8_t sample_count = 0;
if(sample_count++ >= samples_per_symbol) {
sample_count = 0;
current_bit = get_next_bit(); // 获取待发送数据
}
// 根据当前bit选择频率
if(current_bit) {
dac_value = 2048 + 1500 * sin(2 * PI * 2400 * t);
} else {
dac_value = 2048 + 1500 * sin(2 * PI * 1200 * t);
}
DAC_SetChannel1Data(DAC_Align_12b_R, dac_value);
t += 0.000125; // 1/8000采样率
}
关键配置:
- 定时器2配置为125us周期(8kHz)
- DAC输出范围0-3.3V,偏置1.65V
- 使用查表法优化计算效率
3.2 接收端解调算法
采用Goertzel算法检测特征频率:
c复制float goertzel(int freq) {
static float q1 = 0, q2 = 0;
float coeff = 2 * cos(2 * PI * freq / 8000);
for(int i=0; i<8; i++) {
float q0 = coeff * q1 - q2 + adc_buffer[i];
q2 = q1;
q1 = q0;
}
float magnitude = q1*q1 + q2*q2 - q1*q2*coeff;
q1 = q2 = 0;
return magnitude;
}
void demodulate() {
float f1200 = goertzel(1200);
float f2400 = goertzel(2400);
if(f2400 > f1200 * 1.5) { // 阈值检测
decoded_data = 1;
} else {
decoded_data = 0;
}
}
实测技巧:调整阈值系数1.5可优化误码率,建议通过实际测试校准
4. 系统优化与实测数据
4.1 抗干扰措施
- 软件滤波:在ADC采样后加入移动平均滤波
c复制#define FILTER_SIZE 4
uint16_t moving_avg(uint16_t new_sample) {
static uint16_t buffer[FILTER_SIZE];
static uint8_t index = 0;
buffer[index++] = new_sample;
if(index >= FILTER_SIZE) index = 0;
uint32_t sum = 0;
for(int i=0; i<FILTER_SIZE; i++) {
sum += buffer[i];
}
return sum / FILTER_SIZE;
}
- 硬件改进:
- 在DAC输出端增加π型滤波器
- 接收端使用屏蔽线连接ADC
- 电源端加装10μF+0.1μF去耦电容
4.2 性能测试数据
| 测试条件 | 误码率 | 最大距离 |
|---|---|---|
| 室内无障碍 | <0.1% | 25m |
| 室内隔墙(1堵) | 0.5%-1% | 15m |
| 室外视距 | <0.01% | 80m |
| 有WiFi干扰环境 | 0.3%-0.8% | 20m |
5. 常见问题排查
5.1 接收灵敏度低
可能原因及解决方案:
-
射频模块供电不足
- 确认电压≥3.3V
- 检查电源线压降
-
天线匹配不良
- 使用1/4波长天线(433MHz约17.3cm)
- 避免天线靠近金属物体
-
ADC采样时钟不稳定
- 检查定时器配置
- 改用DMA方式采集
5.2 误码率偏高
调试步骤:
- 先用信号发生器替代发送端,隔离问题
- 检查Goertzel算法中的频率参数是否准确
- 调整判决阈值(1.5倍系数可改为1.2-2.0范围尝试)
- 在接收端增加前导码和CRC校验
6. 项目扩展方向
这个基础框架还可以进一步优化:
- 改用HAL库版本,便于移植到其他STM32型号
- 增加曼彻斯特编码提高抗干扰能力
- 实现多节点组网(CSMA/CA协议)
- 移植到STM32F4系列,支持更高波特率
我在实际部署中发现,在电机等强干扰环境中,将载频提高到8kHz/16kHz组合能显著改善性能。另外,使用PCB环形天线时,最好通过网分仪调整匹配电路,这是提升距离的关键。