解读一下这个直流电机控制程序
/*******************************************************************************
************ LABCENTER ELECTRONICS ************
************ Proteus VSM Sample Design Code ************
************ Integer Calculator ( 2K Code Limit) ************
*******************************************************************************/
#include "calc.h"
#include "board.h"
//Variables
static CHAR outputbuffer[MAX_DISPLAY_CHAR]; //没用
char AD_Result;
unsigned char Sample_Mark = 0;
unsigned char Step_mark = 0; //阶跃信号标志
unsigned char TK=0x02,IBAND=0x20,TC,gate,DCZ=0X02,DCF=0X03,rot=0;
long int KP=0xFFFF,TI=0x10,TD=0x08; //KP放大65536倍,TI,TD的单位是10ms KP=0xC000,TI=0x18,TD=0x08
char EK,EK_1,AEK;
int ZEK,UK;
int speed;
int P,I,D,temp;
unsigned long int fre=0;
unsigned char tranfre=0;
unsigned char typeNMI;
unsigned char L;
unsigned char H;
VOID main (VOID)
//Initialise our variables and call the
//Assembly routine to initialise the LCD display.
{
char motorstatus=0;
char MotorDirection = 0;
UK=EK=EK_1=AEK=0;
ZEK=0;
Sample_Mark = 0;
initialise(); // Initialize the LCD 初始化
outp(IO7,0x03); //停止电机转动
MotorDirection = 1; //电机运行方向
if (MotorDirection)
{
speed = 400;
}
else
{
speed = 100;
}
while(1)
{
rot=inp(ADR_PPI_PORTC); //读PC口的地址
if((rot&0x10)==0) //正反转控制
{ //if 后1为正转
DCZ=0X02; //A口动
DCF=0X03;
}
else
{
DCZ=0X01; //DIR动
DCF=0X03;
}
Step_mark = inp(ADR_PPI_PORTC) & 0x80; //读取开关位置
if (Step_mark > 0)
{
// calc_display(calc_decascii(1)); //显示1,表示没有给阶跃信号
EK=EK_1=AEK=0;
ZEK=UK=0;
TC=0x01;
speed=0;
outp(IO7,0x03);//电机停转
}
else
{
if (Sample_Mark == 1)
{
Sample_Mark = 0; //清除采样标志
/* PID */
TC--; //采样周期
if(TC==0)
{
typeNMI=inp(ADR_PPI_PORTC); //初始化
outp(ADR_TIMER_CONTROL, TIMER_COUNTER0 | TIMER_MODE0 | TIMER_LSB);//定时器0初始化
outp(ADR_TIMER_DATA0, 0x2);
outp(ADR_TIMER_CONTROL, TIMER_COUNTER2 | TIMER_MODE0 | TIMER_LSB_MSB);//定时器2初始化
outp(ADR_TIMER_DATA2, 0x50);
outp(ADR_TIMER_DATA2, 0xC3); //初始化停止
typeNMI=inp(ADR_PPI_PORTC);
while((typeNMI&0x60)==0)
{//outp(IO6,0xFF);
typeNMI=inp(ADR_PPI_PORTC);
if((typeNMI&0x40)==0x40)//SIGN0=1
{
L=inp( ADR_TIMER_DATA2);
H=inp( ADR_TIMER_DATA2);
fre=(100000/(50000-H*256-L));
}
if((typeNMI&0x20)==0x20)
{
fre=0;
}
}
fre=(fre*255)/346;//;;
tranfre=fre/2;
P=I=D=0;
outp(IO5,1); //启动AD转换器 ********改动
td_delay(20); //延时
AD_Result=inp(IO5); //读AD转换结果*******改动
EK=AD_Result-tranfre;
AEK=EK-EK_1; /*△EK*/
if(ABS(EK)> IBAND) //开始PID调节
{
I=0;
}
else
{
ZEK=EK+ZEK;
I=(ZEK*TK)/TI;
}
P=EK;
D=(AEK*TD)/TK;
temp=(P+I+D)*KP/65536;
EK_1=EK;
TC=TK;
speed = (int)(temp*10);
if (speed >600)
{
speed = 600;
}
if (speed <1)
{
speed = 0;
}
}
}
// Drive a PWM signal out.
//speed=600;
outp(IO7,DCZ);//***********改动
td_delay(speed);
outp(IO7,DCF);//***********改动
td_delay(600-speed);
}
// calc_display(calc_decascii(speed)); //显示8,表示有给阶跃信号,开始PID控制
}
}

#include "calc.h"
#include "board.h"
static CHAR outputbuffer[MAX_DISPLAY_CHAR];
char AD_Result;
unsigned char Sample_Mark = 0;
unsigned char Step_mark = 0;
unsigned char TK=0x02,IBAND=0x20,TC,gate,DCZ=0X02,DCF=0X03,rot=0;
long int KP=0xFFFF,TI=0x10,TD=0x08;
char EK,EK_1,AEK;
int ZEK,UK;
int speed;
int P,I,D,temp;
unsigned long int fre=0;
unsigned char tranfre=0;
unsigned char typeNMI;
unsigned char L;
unsigned char H;
这段代码中calc.h和board.h是一些库文件,用于调用相关函数。变量定义中有一些很关键的参数,例如KP、TI和TD,它们是PID控制中比例项、积分项和微分项的系数,分别对应P、I、D三个控制量的权重,需要不断调整以达到最佳控制效果。
主函数中initialise()函数用于初始化LCD显示屏和相关的寄存器。之后将电机停止转动,并根据电机运行方向设置初速度。接着进入一个无限循环,不断地读取IO口的地址来获取各种信号。如果没有接收到阶跃信号,电机将根据PID控制进行调节;否则会停止电机运行,清空相关标志量。最后通过IO口驱动电机,实现对其转速的调节。
#include "calc.h"
#include "board.h"
//包含所需的头文件
//Variables
static CHAR outputbuffer[MAX_DISPLAY_CHAR];
//定义字符数组输出缓冲区,用于暂存要显示的字符
char AD_Result;
//AD转换结果
unsigned char Sample_Mark = 0;
//采样标志,初始值为0
unsigned char Step_mark = 0;
//阶跃信号标志
unsigned char TK=0x02,IBAND=0x20,TC,gate,DCZ=0X02,DCF=0X03,rot=0;
//TK为采样周期,IBAND为允许误差带宽,TC为计数器
long int KP=0xFFFF,TI=0x10,TD=0x08;
//KP为比例增益,放大65536倍,TI为积分时间,TD为微分时间
char EK,EK_1,AEK;
//EK为速度误差,EK_1为上次速度误差,AEK为速度误差变化
int ZEK,UK;
//ZEK为积分误差,UK为输出
int speed;
//速度
int P,I,D,temp;
//比例、积分、微分项及临时变量
unsigned long int fre=0;
//频率
unsigned char tranfre=0;
//频率转为AD值
unsigned char typeNMI;
//中断类型
unsigned char L;
//低8位
unsigned char H;
//高8位
VOID main (VOID)
{
char motorstatus=0;
//电机状态
char MotorDirection = 0;
//电机转动方向
UK=EK=EK_1=AEK=0;
ZEK=0;
Sample_Mark = 0;
initialise();
// 初始化LCD
outp(IO7,0x03);
//电机停转
MotorDirection = 1;
//电机运行方向
if (MotorDirection)
{
speed = 400;
}
else
{
speed = 100;
}
while(1)
{
rot=inp(ADR_PPI_PORTC);
//读PC口输入
if((rot&0x10)==0)
//正反转控制
{
DCZ=0X02;
//A口动
DCF=0X03;
}
else
{
DCZ=0X01;
//DIR动
DCF=0X03;
}
Step_mark = inp(ADR_PPI_PORTC) & 0x80;
//读取开关状态
if (Step_mark > 0)
{
EK=EK_1=AEK=0;
ZEK=UK=0;
TC=0x01;
speed=0;
outp(IO7,0x03);//电机停转
}
else
{
if (Sample_Mark == 1)
{
Sample_Mark = 0;
//清除采样标志
TC--;
//采样周期减1
if(TC==0)
{
typeNMI=inp(ADR_PPI_PORTC);
//初始化
//定时器及AD初始化
fre=(100000/(50000-H*256-L));
//计算频率
fre=(fre*255)/346;
//频率转化为AD值
tranfre=fre/2;
P=I=D=0;
outp(IO5,1);
//启动AD转换
td_delay(20);
//延时
AD_Result=inp(IO5);
//读AD转换结果
EK=AD_Result-tranfre;
//速度误差
AEK=EK-EK_1; /△EK/
if(ABS(EK)> IBAND) //开始PID调节
{
I=0;
}
else
{
ZEK=EK+ZEK;
I=(ZEK*TK)/TI;
}
P=EK;
D=(AEK*TD)/TK;
temp=(P+I+D)*KP/65536;
EK_1=EK;
TC=TK;
speed = (int)(temp*10);
if (speed >600)
{
speed = 600;
}
if (speed <1)
{
speed = 0;
}
}
}
// 输出PWM信号
outp(IO7,DCZ);
//选择PWM波输出端口
td_delay(speed);
//PWM周期
outp(IO7,DCF);
td_delay(600-speed);
}
// calc_display(calc_decascii(speed));
//显示速度
}
}
//计算速度误差变化、积分误差、PID控制量及速度
//限制速度最大值及最小值
//输出PWM控制电机
//这是一个基于PIC单片机的PWM速度闭环控制代码示例。
建议你说一下到底哪部分不明白,实际上这个代码的注释已经够详细了。
直流电机控制的Proteus仿真及C语言程序设计
可以借鉴下
https://blog.csdn.net/fanjufei123456/article/details/127522497
你给的这段代码是一个用于 实现Proteus VSM 的代码,主函数 main 中定义了一些变量,包括 motorstatus 和 MotorDirection。程序首先初始化 LCD 显示器,然后停止电机转动。接下来,程序进入一个循环,在循环中读取 PC 口的地址和开关位置,并根据这些信息控制电机转动方向和速度。
这段代码是一个在Proteus VSM中实现的整数计算器的样例设计代码。下面是代码的解释:
代码包含了两个头文件:"calc.h"和"board.h"。
它定义了各种全局变量和常量,用于程序中,例如输出缓冲区、控制信号、电机参数、PID变量等等。
main()
函数初始化变量、初始化LCD显示,并设置电机方向和速度。
在主循环中,代码从PC端口读取输入,控制电机方向,并检查是否存在阶跃信号。
如果存在阶跃信号,代码进行PID调节;否则,代码根据速度驱动PWM信号输出控制电机。
参考GPT
#include "calc.h"
#include "board.h"
//Variables
static CHAR outputbuffer[MAX_DISPLAY_CHAR]; //没用
char AD_Result;
unsigned char Sample_Mark = 0;
unsigned char Step_mark = 0; //阶跃信号标志
unsigned char TK = 0x02, IBAND = 0x20, TC, gate, DCZ = 0X02, DCF = 0X03, rot = 0;
long int KP = 0xFFFF, TI = 0x10, TD = 0x08; //KP放大65536倍,TI,TD的单位是10ms KP=0xC000,TI=0x18,TD=0x08
char EK, EK_1, AEK;
int ZEK, UK;
int speed;
int P, I, D, temp;
unsigned long int fre = 0;
unsigned char tranfre = 0;
unsigned char typeNMI;
unsigned char L;
unsigned char H;
VOID main(VOID)
//Initialise our variables and call the
//Assembly routine to initialise the LCD display.
{
char motorstatus = 0;
char MotorDirection = 0;
UK = EK = EK_1 = AEK = 0;
ZEK = 0;
Sample_Mark = 0;
initialise(); // Initialize the LCD 初始化
outp(IO7, 0x03); //停止电机转动
MotorDirection = 1; //电机运行方向
if (MotorDirection)
{
speed = 400;
}
else
{
speed = 100;
}
while (1)
{
rot = inp(ADR_PPI_PORTC); //读PC口的地址
if ((rot & 0x10) == 0) //正反转控制
{ //if 后1为正转
DCZ = 0X02; //A口动
DCF = 0X03;
}
else
{
DCZ = 0X01; //DIR动
DCF = 0X03;
}
Step_mark = inp(ADR_PPI_PORTC) & 0x80; //读取开关位置
if (Step_mark > 0)
{
//calc_display(calc_decascii(1)); //显示1,表示没有给阶跃信号
EK = EK_1 = AEK = 0;
ZEK = UK = 0;
TC = 0x01;
speed = 0;
outp(IO7, 0x03);//电机停转
}
else
{
if (Sample_Mark == 1)
{
Sample_Mark = 0; //清除采样标志
/* PID */
TC--; //采样周期
if (TC == 0)
{
typeNMI = inp(ADR_PPI_PORTC); //初始化
outp(ADR_TIMER_CONTROL, TIMER_COUNTER0 | TIMER_MODE0 | TIMER_LSB);//定时器0初始化
outp(ADR_TIMER_DATA0, 0x2);
outp(ADR_TIMER_CONTROL, TIMER_COUNTER2 | TIMER_MODE0 | TIMER_LSB_MSB);//定时器2初始化
outp(ADR_TIMER_DATA2, 0x50);
outp(ADR_TIMER_DATA2, 0xC3); //初始化停止
typeNMI = inp(ADR_PPI_PORTC);
while ((typeNMI & 0x60) == 0)
{//outp(IO6,0xFF);
typeNMI = inp(ADR_PPI_PORTC);
if ((typeNMI & 0x40) == 0x40)//SIGN0=1
{
L = inp(ADR_TIMER_DATA2);
H = inp(ADR_TIMER_DATA2);
fre = (100000 / (50000 - H * 256 - L));
}
if ((typeNMI & 0x20) == 0x20)
{
fre = 0;
}
}
fre = (fre * 255) / 346;//;;
tranfre = fre / 2;
P = I = D = 0;
outp(IO5, 1); //启动AD转换器 ********改动
td_delay(20); //延时
AD_Result = inp(IO5); //读AD转换结果*******改动
EK = AD_Result - tranfre;
AEK = EK - EK_1; /*△EK*/
if (ABS(EK) > IBAND) //开始PID调节
{
I = 0;
}
else
{
ZEK = EK + ZEK;
I = (ZEK * TK) / TI;
}
P = EK;
D = (AEK * TD) / TK;
temp = (P + I + D) * KP / 65536;
EK_1 = EK;
TC = TK;
speed = (int)(temp * 10);
if (speed > 600)
{
speed = 600;
}
if (speed < 1)
{
speed = 0;
}
}
}
// Drive a PWM signal out.
//speed=600;
outp(IO7, DCZ);//***********改动
td_delay(speed);
outp(IO7, DCF);//***********改动
td_delay(600 - speed);
}
//calc_display(calc_decascii(speed)); //显示8,表示有给阶跃信号,开始PID控制
}
}
要解读啥,是具体哪里不明白