解读以下这个利用proteus绘制的直流电机控制系统的c语言程序。

解读一下这个直流电机控制程序

img



/*******************************************************************************
************                 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控制
    }
 }   



![img](https://img-mid.csdnimg.cn/release/static/image/mid/ask/442498132686183.png "#left")


#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中实现的整数计算器的样例设计代码。下面是代码的解释:

  1. 代码包含了两个头文件:"calc.h"和"board.h"。

  2. 它定义了各种全局变量和常量,用于程序中,例如输出缓冲区、控制信号、电机参数、PID变量等等。

  3. main()函数初始化变量、初始化LCD显示,并设置电机方向和速度。

  4. 在主循环中,代码从PC端口读取输入,控制电机方向,并检查是否存在阶跃信号。

  5. 如果存在阶跃信号,代码进行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)  //正反转控制
        {            //if1为正转
            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控制
    }
}


要解读啥,是具体哪里不明白