- 打卡等级:初来乍到
- 打卡总天数:8
- 最近打卡:2025-06-16 10:28:49
注册会员
- 积分
- 94
|
发表于 2025-5-27 13:29:03
|
显示全部楼层
#include "STC32G.h"
#include <math.h>
// 系统配置
#define SYS_CLK 32768000UL // 使用STC出厂预校准的22.1184MHz时钟
#define PWM_PERIOD 1420 // 中心对齐模式计数器值
#define DEAD_TIME 70 // 死区时间(约1uS@22.1184MHz)
#define PI 3.141592653589793
#define PWM1_1 0x00 //P:P1.0 N:P1.1
#define PWM1_2 0x01 //P:P2.0 N:P2.1
#define PWM1_3 0x02 //P:P6.0 N:P6.1
#define PWM2_1 0x00 //P:P1.2/P5.4 N:P1.3
#define PWM2_2 0x04 //P:P2.2 N:P2.3
#define PWM2_3 0x08 //P:P6.2 N:P6.3
#define PWM3_1 0x00 //P:P1.4 N:P1.5
#define PWM3_2 0x10 //P:P2.4 N:P2.5
#define PWM3_3 0x20 //P:P6.4 N:P6.5
#define PWM4_1 0x00 //P:P1.6 N:P1.7
#define PWM4_2 0x40 //P:P2.6 N:P2.7
#define PWM4_3 0x80 //P:P6.6 N:P6.7
#define PWM4_4 0xC0 //P:P3.4 N:P3.3
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long
// 全局变量
volatile float freq = 50.0; // 输出频率(5~100Hz可调)
volatile float theta = 0.0; // 当前角度
volatile float delta_theta; // 角度增量
unsigned char r_f[100];
unsigned char r_c;
unsigned char r_t[30];
#define voltage_power_supply 90.0 // 最高电压限制
#define _constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
float Ualpha, Ubeta = 0, Ua = 0, Ub = 0, Uc = 0;
void send(unsigned char d[],unsigned int m);
// PWM初始化
void PWMA_Init(void)
{
PWMA_ENO = 0x00;
PWMA_CCER1 = 0x00; //写 CCMRx 前必须先清零 CCxE 关闭通道
PWMA_CCER2 = 0x00;
PWMA_CCMR1 = 0x68; //通道模式配置
PWMA_CCMR2 = 0x68;
PWMA_CCMR3 = 0x68;
PWMA_ARRH = 1410/256;
PWMA_ARRL = 1410%256;
PWMA_DTR = 70; // 设置死区时间
PWMA_CCER1 = 0x55; //配置通道输出使能和极性
PWMA_CCER2 = 0x05;
PWMA_CCMR1 = 0x60; // 通道模式配置, PWM模式1, 预装载允许
PWMA_CCMR2 = 0x60;
PWMA_CCMR3 = 0x60;
PWMA_ENO = 0x3F; //IO输出PWM允许
//高级PWM输出脚会自动设置为推挽输出模式
PWMA_PS = 0x00; //高级 PWM 通道输出脚选择位
PWMA_PS |= PWM1_2; //选择 PWM1_3 通道
PWMA_PS |= PWM2_2; //选择 PWM2_3 通道
PWMA_PS |= PWM3_2; //选择 PWM3_3 通道
PWMA_BKR = 0x80; //使能主输出
PWMA_CR1 = 0x81; //使能ARR预装载,开始计时
}
// 定时器0初始化(1ms中断)
void Timer0_Init(void)
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x00; //设置定时初始值
TH0 = 0x80; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
void ledcWrite(u8 in, u16 Dat)
{
switch (in)
{
case 0:
{
PWMA_CCR1H = (u8)(Dat >> 8); // 设置占空比
PWMA_CCR1L = (u8)(Dat);
}
break;
case 1:
{
PWMA_CCR2H = (u8)(Dat >> 8); // 设置占空比
PWMA_CCR2L = (u8)(Dat);
}
break;
case 2:
{
PWMA_CCR3H = (u8)(Dat >> 8); // 设置占空比
PWMA_CCR3L = (u8)(Dat);
}
break;
default:
break;
}
}
// 设置PWM到控制器输出
void setPwm(float Ua, float Ub, float Uc)
{
// 变量声明
float dc_a, dc_b, dc_c;
u16 dutyA,dutyB,dutyC,ty;
// 限制上限
Ua = _constrain(Ua, 0.0f, voltage_power_supply);
Ub = _constrain(Ub, 0.0f, voltage_power_supply);
Uc = _constrain(Uc, 0.0f, voltage_power_supply);
// 计算占空比
// 限制占空比从0到1
dc_a = _constrain(Ua / voltage_power_supply, 0.0f, 1.0f);
dc_b = _constrain(Ub / voltage_power_supply, 0.0f, 1.0f);
dc_c = _constrain(Uc / voltage_power_supply, 0.0f, 1.0f);
dutyA=(u16)(dc_a * 1420);dutyB=(u16)(dc_b *1420);dutyC=(u16)(dc_c * 1420);
// 写入PWM到PWM 0 1 2 通道
ledcWrite(0, dutyA);
ledcWrite(1, dutyB);
ledcWrite(2, dutyC);
ty=(u16)(theta*180/PI);
r_t[0]='a';r_t[1]=dutyA/1000+0x30;r_t[2]=(dutyA%1000)/100+0x30;r_t[3]=(dutyA%100)/10+0x30;r_t[4]=dutyA%10+0x30;
r_t[5]='b';r_t[6]=dutyB/1000+0x30;r_t[7]=(dutyB%1000)/100+0x30;r_t[8]=(dutyB%100)/10+0x30;r_t[9]=dutyB%10+0x30;
r_t[10]='c';r_t[11]=dutyC/1000+0x30;r_t[12]=(dutyC%1000)/100+0x30;r_t[13]=(dutyC%100)/10+0x30;r_t[14]=dutyC%10+0x30;
r_t[15]='t';r_t[16]=ty/100+0x30;r_t[17]=(ty%100)/10+0x30;r_t[18]=ty%10+0x30;
r_t[19]=0x0d;r_t[20]=0x0a;
send(r_t,21);
}
// 归一化角度到 [0,2PI]
float _normalizeAngle(float angle)
{
float a = fmod(angle, 2 * PI); // 取余运算可以用于归一化,列出特殊值例子算便知
return a >= 0 ? a : (a + 2 * PI);
// 三目运算符。格式:condition ? expr1 : expr2
// 其中,condition 是要求值的条件表达式,如果条件成立,则返回 expr1 的值,否则返回 expr2 的值。可以将三目运算符视为 if-else 语句的简化形式。
// fmod 函数的余数的符号与除数相同。因此,当 angle 的值为负数时,余数的符号将与 _2PI 的符号相反。也就是说,如果 angle 的值小于 0 且 _2PI 的值为正数,则 fmod(angle, _2PI) 的余数将为负数。
// 例如,当 angle 的值为 -PI/2,_2PI 的值为 2PI 时,fmod(angle, _2PI) 将返回一个负数。在这种情况下,可以通过将负数的余数加上 _2PI 来将角度归一化到 [0, 2PI] 的范围内,以确保角度的值始终为正数。
}
#define _Conv 1.15470053838f
// 2023年9月22日添加SVPWM
void setTorque(float Uq, float Ud, float angle_el)
{
float Max = 0, Min = 0, Adder = 0;
// 幅值限位
Uq = _constrain(Uq, -(voltage_power_supply) / 2, (voltage_power_supply) / 2);
Ud = _constrain(Ud, -(voltage_power_supply) / 2, (voltage_power_supply) / 2);
angle_el = _normalizeAngle(angle_el);
//angle_el=theta;
// 帕克逆变换
Ualpha = (Ud * cos(angle_el)) - (Uq * sin(angle_el));
Ubeta = (Uq * cos(angle_el)) + (Ud * sin(angle_el));
// 克拉克逆变换
Ua = Ualpha + voltage_power_supply / 2;
Ub = (sqrt(3) * Ubeta - Ualpha) / 2 + voltage_power_supply / 2;
Uc = (-Ualpha - sqrt(3) * Ubeta) / 2 + voltage_power_supply / 2;
// Fast_Svpwm实现
Max = Ua > Ub ? (Ua > Uc ? Ua : Uc) : (Ub > Uc ? Ub : Uc);
Min = Ua < Ub ? (Ua < Uc ? Ua : Uc) : (Ub < Uc ? Ub : Uc);
Adder = -(Max + Min) / 2;
Ua = (Ua + Adder) * _Conv, Ub = (Ub + Adder) * _Conv, Uc = (Uc + Adder) * _Conv;
setPwm(Ua, Ub, Uc);
}
//////////串口1通信初始化
void serial_init()
{
unsigned int i;
for(i=0;i<100;i++) r_f=0;
r_c=0;
}
void send(unsigned char d[],unsigned int m)
{
unsigned int i;
for(i=0;i<m;i++)
{
SBUF = d; //发一个字节
while(!TI);
TI=0;
}
}
/********************* UART1中断函数************************/
void UART1_int ( ) interrupt 4
{
if(RI)
{
r_f[r_c] = SBUF;//保存一个字节
if(r_c>=100) r_c=0;
else r_c++;
RI = 0;
}
}
void UartInit(void) //115200bps@32.768MHz
{
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x01; //串口1选择定时器2为波特率发生器
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0xB9; //设置定时初始值
T2H = 0xFF; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
}
// 主函数
void main()
{
WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P2M0=0x00;P2M1=0x00;
PWMA_Init();
Timer0_Init();
UartInit();
ET0=1;
EA = 1;
serial_init();
while(1)
{
delta_theta = 2 * PI * freq * 0.002; // 1ms中断对应角度增量
}
}
// 定时器0中断服务函数
void Timer0_ISR() interrupt 1
{
theta += delta_theta; // 更新角度
if(theta >= 2*PI) theta = 0;
setTorque(0,70,theta);
}
辛苦王工帮我看看,这个程序有无问题?更改70的数值,改变幅度(还没有去写这部分程序)。谢谢。 |
|