初学者又写了三篇代码虽已跑通有待硬件调试
#include <STC8G1K08A.h>
#include <intrins.h>
// 系统核心参数
#define SYS_CLK 35000000UL// 35MHz系统时钟
#define PHASE_MAX 65536UL // 16位相位最大值(对应360°)
#define PHASE_120 21845 // 120°相位偏移值(65536/3≈21845.333)
#define PHASE_240 43691 // 240°相位偏移值(21845×2≈43690.666)
// 硬件引脚定义(三相输出用P3口,按键用P5^4/P5^5)
sbit PHASE_A = P3^0;// A相输出(0°)- P3口
sbit PHASE_B = P3^1;// B相输出(120°)- P3口
sbit PHASE_C = P3^2;// C相输出(240°)- P3口
sbit KEY_UP = P5^5;// 频率增加按键 - P5^5
sbit KEY_DN = P5^4;// 频率减少按键 - P5^4
// 系统变量
unsigned int phase; // 基准相位累加器(16位)
unsigned int freq = 16384; // 初始频率控制字
unsigned int step = 1; // 频率调节步长
const unsigned int MIN_FREQ = 1;
const unsigned int MAX_FREQ = 32768;
// 定时器0初始化(DDS时钟源)
void timer0_init() {
TMOD = 0x01; // 16位定时模式
AUXR |= 0x80; // 1T模式
TH0 = 0xFF; // 高频中断初值(≈8.75MHz中断频率)
TL0 = 0xFE;
ET0 = 1; // 使能定时器中断
EA = 1; // 使能总中断
TR0 = 1; // 启动定时器
}
// 引脚初始化(三相输出推挽,按键高阻输入)
void gpio_init() {
// 三相输出引脚配置为推挽输出(P3.0~P3.2)
P3M0 = 0x07; // 00000111 - P3.0~P3.2推挽
P3M1 = 0x00; // 推挽输出模式
// 按键引脚配置为高阻输入(P5.4/P5.5)
P5M0 &= ~0x30; // 清除推挽位(0x30=00110000)
P5M1 |= 0x30; // 设置高阻输入
}
// 按键扫描(频率调节,带长按加速)
void key_scan() {
unsigned char i;// 提前声明循环变量(适配C51语法)
// 频率增加(P5^5)
if(KEY_UP == 0) {
_nop_();_nop_(); // 短消抖
if(KEY_UP == 0) {
if(freq < MAX_FREQ) {
freq += step;
// 长按加速逻辑
while(KEY_UP == 0) {
if(freq < MAX_FREQ - step*2) {
freq += step*2;
}
for(i=0; i<20; i++) _nop_(); // 减速调节
}
}
}
}
// 频率减少(P5^4)
if(KEY_DN == 0) {
_nop_();_nop_(); // 短消抖
if(KEY_DN == 0) {
if(freq > MIN_FREQ) {
freq -= step;
// 长按加速逻辑
while(KEY_DN == 0) {
if(freq > MIN_FREQ + step*2) {
freq -= step*2;
}
for(i=0; i<20; i++) _nop_(); // 减速调节
}
}
}
}
}
// 定时器0中断(三相相位计算核心)
void timer0() interrupt 1 {
unsigned int phase_b, phase_c;// B相和C相相位
// 重装载定时器初值
TH0 = 0xFF;
TL0 = 0xFE;
// 基准相位累加
phase += freq;
// 计算三相相位(保持120°相位差)
phase_b = phase + PHASE_120;
phase_c = phase + PHASE_240;
// 生成三相方波(50%占空比)
PHASE_A = (phase >> 15);
PHASE_B = (phase_b >> 15);
PHASE_C = (phase_c >> 15);
}
// 主函数
void main() {
gpio_init();
timer0_init();
while(1) {
key_scan();
_nop_();
}
经测量:
两路24位频率字,DDS输出最高频率只有十多KHZ,不是很好用。
一路16位频率字,DDS输出最高频率为600多KHZ。
两路16位频率字,DDS输出最高频率为363KHZ。
三路的调整范围如下图所示
}
昨天的
今天又写了寻线仪收发端代码和原边升压反馈的代码都已跑通,就差硬件方面的调式了。
原理图仿真,画PCB,3D建模,打印外壳啥的,都得一步步学再接再厉,争取开发出一件像样的产品。
您提供的代码片段看起来是基于8051内核或兼容内核的单片机(如STC系列)开发的一个简易三相波形发生器或三相控制系统的雏形。代码中使用了相位累加器(Phase Accumulator)实现频率控制,结合定时器中断来更新相位,并通过比较相位值来控制三相输出的切换。这实际上是一种直接数字频率合成(DDS, Direct Digital Synthesis)的基本实现方式。
下面我将从代码结构、逻辑分析、潜在问题、优化建议几个方面进行专业点评。
一、代码结构分析
您已经定义了如下几个关键部分:
1. 系统参数定义
c
define SYSCLK 35000000UL// 系统时钟频率
define PHASEMAX 65536UL // 相位最大值(16位)
define PHASE120 21845 // 120°相位偏移
define PHASE240 43691 // 240°相位偏移
使用宏定义便于后期修改,结构清晰。
相位划分采用16位精度,符合DDS设计标准。
PHASE120 和 PHASE240 的计算是准确的(65536 / 3 ≈ 21845.333),取整为21845和43690是合理的。
2. 引脚定义
c
sbit PHASEA = P3^0;
sbit PHASEB = P3^1;
sbit PHASEC = P3^2;
sbit KEYUP = P5^5;
sbit KEYDN = P5^4;
使用 sbit 定义IO口,适用于8051架构,语法正确。
三相输出使用连续的P3口,方便扩展与调试。
3. 全局变量
c
unsigned int phase; // 基准相位累加器(16位)
unsigned int freq = 16384; // 初始频率控制字
unsigned int step = 1; // 频率调节步长
const unsigned int MINFREQ = 1;
const unsigned int MAXFREQ = 32768;
phase 是16位相位累加器,用于实现频率合成。
freq 是频率控制字(Frequency Tuning Word, FTW),决定了输出波形的频率。
使用常量限定频率范围,有助于防止越界。
4. 定时器初始化函数(未完成)
c
void timer0init
函数未完成,但可以推测是设置定时器0为某种模式(如模式1,16位定时器),并开启中断。
定时器中断是实现相位更新和输出切换的关键。
二、逻辑分析与功能推测
从代码结构可以推测您的设计目标是:
1. 使用定时器中断定时更新相位;
2. 根据当前相位值,控制三相输出(A/B/C)的状态;
3. 通过按键(KEYUP/KEYDN)调整频率控制字 freq,从而改变输出频率;
4. 实现三相输出的120°相位差,可用于三相电机控制、三相PWM等场景。
这是一个典型的基于DDS的三相信号发生器系统,适用于需要精确频率控制和相位同步的应用。
三、潜在问题与改进建议
1. 相位累加器溢出处理缺失
在DDS中,相位累加器(phase)每次加上 freq 后,若超过 PHASEMAX(65536)应进行取模运算。建议修改为:
c
phase = (phase + freq) % PHASEMAX;
或使用位掩码(如果 PHASEMAX 是2的幂):
c
phase = (phase + freq) & (PHASEMAX - 1);
这可以防止溢出导致的相位误差。
2. 输出控制逻辑缺失
当前代码中没有看到相位比较和IO输出控制部分。例如:
c
if (phase < PHASE120) {
PHASEA = 1; PHASEB = 0; PHASEC = 0;
} else if (phase < PHASE240) {
PHASEA = 0; PHASEB = 1; PHASEC = 0;
} else {
PHASEA = 0; PHASEB = 0; PHASEC = 1;
}
这部分逻辑需要在定时器中断服务函数中实现。
3. 按键消抖处理不足
目前没有看到按键去抖动逻辑,可能导致误触发。建议加入软件延时或状态机消抖:
c
if (KEYUP == 0) {
delayms(10); // 消抖延时
if (KEYUP == 0) {
if (freq < MAXFREQ) freq += step;
while (KEYUP == 0); // 等待按键释放
}
}
4. 定时器中断服务函数缺失
需要补充定时器0中断服务函数,用于更新相位并控制输出:
c
void timer0isr(void) interrupt 1 {
TH0 = (65536 - SYSCLK / FREQOUT / 2) >> 8;
TL0 = (65536 - SYSCLK / FREQOUT / 2) & 0xFF;
phase = (phase + freq) & 0xFFFF;
// 根据phase值控制三相输出
if (phase < PHASE120) {
PHASEA = 1; PHASEB = 0; PHASEC = 0;
} else if (phase < PHASE240) {
PHASEA = 0; PHASEB = 1; PHASEC = 0;
} else {
PHASEA = 0; PHASEB = 0; PHASEC = 1;
}
}
5. 频率计算公式未明确
DDS输出频率公式为:
Fout = (freq × SYSCLK) / PHASEMAX
应明确在代码注释中说明,方便调试和理解。
四、优化建议
1. 模块化设计
将按键处理、相位更新、IO控制等模块化为独立函数,提高可读性和可维护性。
2. 使用查表法提升精度
若需要更高精度的波形控制,可使用正弦表或查表法生成更复杂的波形。
3. 增加频率显示或调试输出
可通过串口输出当前频率值,便于调试。
4. 使用外部晶振或PLL提高时钟稳定性
若系统时钟不稳定,会导致输出频率漂移。
五、总结
您已经完成了一个基于DDS的三相控制系统的基本框架,代码结构清晰、逻辑合理。目前需要补充以下内容以完成系统闭环:
完整的定时器初始化与中断服务函数;
相位比较与IO控制逻辑;
按键消抖与频率调节逻辑;
明确的频率计算公式与注释说明。
建议在硬件调试前,先通过逻辑分析仪或示波器观察三相输出波形,验证相位差是否正确,频率是否随按键调节变化。
如果您需要,我可以继续帮助您补全完整的代码框架,包括定时器配置、中断服务函数、按键处理函数等。
祝您硬件调试顺利!
[本文内容由国芯人工智能辅助生成,仅供参考]
页:
[1]