1. 项目概述
最近在做一个基于STM32的通信系统项目,需要生成伪随机序列用于信号调制。调研发现M序列(最大长度线性反馈移位寄存器序列)非常适合这个场景,但网上现成的C语言实现方案很少。于是自己动手实现了一个轻量级的M序列发生器,可以直接集成到STM32工程中使用。
M序列在通信系统、加密算法、雷达信号处理等领域都有广泛应用。它的特点是实现简单、周期长、统计特性接近白噪声。这个项目完整实现了M序列的生成算法,并通过串口将生成的序列发送到MATLAB进行可视化验证。
2. M序列原理详解
2.1 线性反馈移位寄存器结构
M序列的核心是一个线性反馈移位寄存器(LFSR)。以4级LFSR为例,它包含:
- 4个串联的D触发器(移位寄存器)
- 若干异或门组成的反馈网络
- 时钟驱动信号
每次时钟上升沿到来时:
- 所有寄存器值向右移动一位
- 最左边寄存器的新值由反馈网络计算得到
- 最右边寄存器的值作为序列输出
2.2 反馈系数与序列周期
反馈系数决定了哪些寄存器的输出会参与反馈计算。对于n级LFSR,当反馈多项式是本原多项式时,可以产生周期为2^n-1的M序列。
例如4级LFSR的典型反馈系数是(23)₈,对应二进制00010011,表示:
- 第1、2、4级寄存器参与反馈(从右数第0位开始)
- 反馈逻辑:新值 = Reg1 ⊕ Reg2 ⊕ Reg4
2.3 M序列特性
- 平衡性:一个周期内"1"的个数比"0"多1个
- 游程特性:连续"1"或"0"的长度满足特定分布
- 自相关特性:具有尖锐的自相关峰
- 线性复杂度:n级LFSR产生的序列复杂度为n
3. 代码实现解析
3.1 数据结构设计
c复制typedef struct {
uint8_t Degree; // 寄存器级数
uint32_t FeedBack; // 反馈系数
uint32_t Value; // 当前寄存器状态
} MSeqInitTypeDef;
这个结构体封装了M序列生成器的核心参数:
Degree:移位寄存器级数(n)FeedBack:反馈系数,每个bit表示对应寄存器是否参与反馈Value:当前寄存器状态,LSB对应最后一级寄存器
3.2 初始化函数
c复制void MSeqInit(MSeqInitTypeDef* MSeqInitStruct, uint32_t FB, uint32_t InitVal)
{
// 计算寄存器级数
uint8_t DegAdd1 = MAX_DEGREE / 2;
for (; FB >> DegAdd1 == 0; DegAdd1 /= 2);
for (; FB >> DegAdd1 != 0; DegAdd1++);
// 初始化结构体
MSeqInitStruct->Degree = DegAdd1 - 1;
MSeqInitStruct->FeedBack = FB;
MSeqInitStruct->Value = InitVal;
}
初始化过程的关键是自动计算寄存器级数。这里采用二分查找法确定反馈系数的有效位数,比直接循环移位更高效。
3.3 序列生成函数
c复制uint8_t MSeqUpdate(MSeqInitTypeDef* MSeqInitStruct)
{
uint8_t ret = 0;
for (uint8_t i = 0; i < MSeqInitStruct->Degree; i++)
{
if ((MSeqInitStruct->FeedBack & (0x0001 << i)) == 0x0000)
continue;
ret = XOR((MSeqInitStruct->Value & (0x0001 << i)), ret);
}
MSeqInitStruct->Value >>= 1;
if (ret)
MSeqInitStruct->Value |= (0x0001 << (MSeqInitStruct->Degree - 1));
return ret;
}
这个函数实现了M序列生成的核心逻辑:
- 遍历所有寄存器,计算反馈值(异或和)
- 寄存器整体右移一位
- 根据反馈值设置最高位
- 返回移出的最低位
提示:使用XOR宏定义实现了逻辑异或运算,比直接使用^运算符更直观。
4. STM32集成与验证
4.1 硬件连接
- STM32F103C8T6核心板
- USB转串口模块(CH340)
- 连接方式:
- PA9(TX) → RXD
- PA10(RX) → TXD
- 共地
4.2 测试代码
c复制MSeqInitTypeDef MSeqInitStruct = {0};
int main(void)
{
Serial_Init(); // 串口初始化
MSeqInit(&MSeqInitStruct, 37, 4); // 5级LFSR,反馈系数37₈
while (Serial_GetRxFlag() == 0); // 等待MATLAB启动信号
uint8_t cnt = 0;
while (1)
{
uint8_t mseq = MSeqUpdate(&MSeqInitStruct);
Serial_SendByte(cnt++); // 发送序号
Serial_SendByte(mseq); // 发送M序列值
Delay_ms(100); // 控制发送速率
}
}
4.3 MATLAB接收与分析
matlab复制s = serialport("COM12", 9600);
write(s, uint8(1), "uint8"); % 发送启动信号
data = zeros(100,2);
for i = 1:100
data(i,:) = read(s, 2, 'uint8');
end
figure;
stairs(data(:,1), data(:,2));
title('M序列波形');
xlabel('序号'); ylabel('值');
5. 实际应用中的注意事项
5.1 反馈系数选择
不同级数LFSR对应的典型反馈系数:
| 级数 | 反馈系数(八进制) | 序列周期 |
|---|---|---|
| 3 | 13 | 7 |
| 4 | 23 | 15 |
| 5 | 37 | 31 |
| 6 | 103 | 63 |
| 7 | 203 | 127 |
注意:必须选择本原多项式对应的反馈系数,否则无法产生最大长度序列。
5.2 初始值问题
- 全零状态会导致序列停滞(反馈值恒为0)
- 建议初始值设为1或其他非零值
- 可以通过读取硬件随机源(如ADC噪声)设置初始值
5.3 性能优化技巧
- 查表法:预计算反馈值表,用查表代替实时计算
- 并行计算:使用位操作同时处理多个bit
- DMA传输:结合DMA实现序列的自动发送
6. 扩展应用场景
6.1 通信系统
- 直接序列扩频(DSSS)
- 跳频序列生成
- 加扰/解扰器
6.2 测试测量
- 噪声信号模拟
- 系统激励信号
- 误码率测试
6.3 安全加密
- 流密码密钥流生成
- 随机数生成器
- 身份认证挑战码
我在实际项目中使用这个M序列发生器实现了简单的扩频通信系统。发现当寄存器级数大于10时,建议改用查表法优化性能。另外,通过组合多个不同级数的M序列,可以产生更复杂的伪随机序列。
