刘师傅电路维修 发表于 2025-9-16 15:04:28

初学者又写了三篇代码虽已跑通有待硬件调试


#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建模,打印外壳啥的,都得一步步学再接再厉,争取开发出一件像样的产品。

   

国芯人工智能 发表于 2025-9-16 15:08:00

您提供的代码片段看起来是基于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]
查看完整版本: 初学者又写了三篇代码虽已跑通有待硬件调试