📄 main.c
字号:
///========================================================
// 工程名称: DC_SpeedCtrl
// 功能描述: 直流电机速度测量与调节
//========================================================
#include "SPCE061A.h"
#include "DCMotor.h"
#include "Dig.h"
#include "Key.h"
#include "a2000.h"
#define SPEED_MAX 62 // 最高设定速度
#define SPEED_MIN 10 // 最低设定速度
#define SPEED_STEP 2 // 速度设定步进值
#define CP 8 // 比例常数 Proportional Const
#define CI 3 // 积分常数 Integral Const
#define CD 1 // 微分常数 Derivative Const
unsigned int g_Direction, g_Speed; // 全局变量,保存设定的转动方向和速度
void playspeed(unsigned int TempNum);
//========================================================================
// 语法格式: void System_Init(void)
// 系统初始化(时钟、变量等)
//========================================================================
void System_Init(void)
{
*P_SystemClock = C_Fosc_49M|C_StrongMode; // 系统时钟
DCMotor_Init();
Key_Init();
DIG_Init();
g_Direction = 1; // 初始设置为正转
g_Speed = 40;
}
//========================================================================
// 语法格式: void DispNum(unsigned int Num)
//========================================================================
const unsigned int DigNum[]={ // 0~9十个数字对应的数码管显示编码
0x3f,0x06,0x5b,0x4f,0x66,
0x6d,0x7d,0x27,0x7f,0x6f
};
void DispNum(unsigned int Num)
{
unsigned int TempNum = Num, k;
DIG_Clear(); // 清除数码管显示
if(Num>=10) // 十位
{
k = TempNum/10;
DIG_Set(3,DigNum[k]);
TempNum = TempNum - k * 10;
}
DIG_Set(4,DigNum[TempNum]); // 个位
}
//========================================================================
// 语法格式: void DelayMS(unsigned ms)
// 参数: ms - 毫秒数@49MHz
//========================================================================
void DelayMS(unsigned ms)
{
unsigned i;
while(ms--)
{
for(i = 0; i < 1044; i++)
*P_Watchdog_Clear = 1;
}
}
//========================================================================
// 语法格式: int DCMotor_Speed_PID(int SetSpeed, int CurSpeed)
// 实现功能: 增量式PID计算: u0 = u1 + CP*(e0-e1) + CI*e0 + CD*(e0-2*e1+e2)
//========================================================================
int DCMotor_Speed_PID(int SetSpeed, int CurSpeed)
{
int e0, u0;
static int u1 = 0; // 前一次输出值(为避免浮点运算将该值扩大16倍)
static int e1 = 0, e2 = 0;
e0 = SetSpeed - CurSpeed; // 当前速度偏差
u0 = u1
+ CP * (e0 - e1) // 比例项
+ CI * e0 // 积分项
+ CD * (e0 - e1 - e1 + e2); // 微分项
if(u0 > 1023) u0 = 1023; // 输出值应小于64(扩大16倍)
if(u0 < 16) u0 = 16; // 输出值应不小于1(扩大16倍)
u1 = u0; // 更新u1、e1和e2
e2 = e1;
e1 = e0;
return u0>>4; // 返回u0/16
}
//========================================================================
// 语法格式: void SetSpeed(void)
// 设定转速
//========================================================================
void SetSpeed(void)
{
unsigned int KeyCode;
while(1)
{
DispNum(g_Speed); // 闪烁显示当前设定的转速
DelayMS(300);
DIG_Clear();
DelayMS(300);
KeyCode = Key_Get();
switch(KeyCode)
{
case KEY_1: // Key1, 设定值增加
g_Speed += SPEED_STEP;
if(g_Speed > SPEED_MAX)g_Speed = SPEED_MIN;
break;
case KEY_2: // Key2, 设定值减小
g_Speed -= SPEED_STEP;
if(g_Speed < SPEED_MIN)g_Speed = SPEED_MAX;
break;
case KEY_3: // Key3, 确定
return;
default:
}
}
}
//========================================================================
// 语法格式: void SetDirection(void)
//========================================================================
void SetDirection(void)
{
unsigned int KeyCode;
unsigned int i;
i = 1;
while(1)
{
/// 在数码管上显示滚动的"-",表示电机转动方向
DIG_Clear(); // 清除显示
DIG_Set(i,0x40);
DelayMS(200);
i += g_Direction;
if(i>4)i=1;
if(i<1)i=4;
KeyCode = Key_Get();
switch(KeyCode)
{
case KEY_1: // Key1, 正转
g_Direction = 1;
break;
case KEY_2: // Key2, 反转
g_Direction = -1;
break;
case KEY_3: // Key3, 确定
return;
default:
break;
}
}
}
//========================================================================
// 语法格式: void StartMotor(void)
// 直流电机转动控制
//========================================================================
void StartMotor(void)
{
unsigned int KeyCode;
unsigned int SpeedLevel, CurSpeed=0, PreSpeed=0;
if(g_Direction==1) // 确定转动方向
DCMotor_Forward(MOTOR_1+MOTOR_2);
else
DCMotor_Backward(MOTOR_1+MOTOR_2);
DispNum(CurSpeed);
while(1)
{
if(CurSpeed != PreSpeed) // 如果转速改变则更新显示
{
DispNum(CurSpeed); // 显示当前转速
PreSpeed = CurSpeed;
}
if(DCMotor_IsSpeedRdy()) // 如果已完成一次测速
{
CurSpeed = DCMotor_GetSpeed(); // 获取转速
SpeedLevel = DCMotor_Speed_PID(g_Speed, CurSpeed); // PID计算,得到新的PWM占空比
DCMotor_SetSpeed(MOTOR_1+MOTOR_2, SpeedLevel); // 更新PWM占空比,调节转速
}
KeyCode = Key_Get();
switch(KeyCode)
{
case KEY_1: // Key1,速度增加
g_Speed += SPEED_STEP;
if(g_Speed > SPEED_MAX)g_Speed = SPEED_MIN;
break;
case KEY_2: // Key2,速度减小
g_Speed -= SPEED_STEP;
if(g_Speed < SPEED_MIN)g_Speed = SPEED_MAX;
break;
case KEY_3: // Key3,停止
DCMotor_Stop(MOTOR_1+MOTOR_2);
return;
case KEY_4: // Key,播报转速
playspeed(g_Speed);
break;
default:
break;
}
}
}
//========================================================================
// 语法格式: int main(void)
//========================================================================
int main(void)
{
unsigned int KeyCode, Flag_KeyEvent;
System_Init(); // 系统初始化
Flag_KeyEvent = 1;
while(1)
{
if(Flag_KeyEvent==1)
{
DispNum(g_Speed); // 显示当前设定的转速
Flag_KeyEvent = 0;
}
KeyCode = Key_Get();
switch(KeyCode)
{
case KEY_1: // Key1, 转速设定
SetSpeed();
Flag_KeyEvent = 1;
break;
case KEY_2: // Key2, 方向设定
SetDirection();
Flag_KeyEvent = 1;
break;
case KEY_3: // Key3, 启动电机
StartMotor();
Flag_KeyEvent = 1;
break;
default:
break;
}
}
}
//===============================================================================
//语法格式:void PlaySnd_Auto(unsigned int uiSndIndex)
//自动播放语音函数
//==============================================================================
void PlaySnd_Auto(unsigned int uiSndIndex)
{
SACM_A2000_Initial(1); //初始化为自动播放方式
SACM_A2000_Play(uiSndIndex,3,3); //播放
while((SACM_A2000_Status() & 0x0001) != 0)
{ //判断播放状态,如还在播放则继续循环
SACM_A2000_ServiceLoop(); //播放系统服务程序
*P_Watchdog_Clear = 0x0001;
}
SACM_A2000_Stop(); //停止播放
}
//===============================================================================
// 播报语音
//===============================================================================
void playspeed(unsigned int TempNum)
{
int iShow[4];
unsigned int KeyCode;
iShow[3]=TempNum/1000; //计算转速的千位数
iShow[2]=(TempNum/100)%10; //计算转速的百位数
iShow[1]=(TempNum/10)%10; //计算转速的十位数
iShow[0]=TempNum%10; //计算转速的个位数
KeyCode = Key_Get();
PlaySnd_Auto(12);
PlaySnd_Auto(iShow[1]);
PlaySnd_Auto(10);
if (iShow[0]!=0)
PlaySnd_Auto(iShow[0]);
PlaySnd_Auto(14);
*P_Watchdog_Clear = 0x0001;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -