⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tri_emc.c

📁 用80c196kc单片机实现的直流无刷电机控制程序
💻 C
字号:

#pragma model(kc)
#include <kc_sfrs.h>
#include <kc_funcs.h>

#define   ENABLE_HSI1_INPUT            0x04   //IOC0
#define   ENABLE_TIMER1_OVERFLOW_INT   0x04   //IOC1
#define   ENABLE_ACH7_INTERRUPT        0x02   //IOC1 EXTINT P0.7
#define   DOU_PWM_PERIOD               0x04   //IOC2
#define   ENABLE_PWM1                  0x04   //IOC3(HWIN1)
#define   ENABLE_TIMEROVF_INTERRUPT    0x01   //INT_MASK (timer)
#define   ENABLE_HSIDATA_INTERRUPT     0x04   //INT_MASK (hsi)
#define   ENABLE_EXT_INT1              0x20   //INT_MASK1 P2.2 (can)

#define   CAN_BASEADDR                 0x8000
#define   LOCK_BASEADDR                0x9000
#define   DIR_BASEADDR                 0xA000
#define   PWM_EN_BASEADDR              0xB000
#define   F1_EN_BASEADDR               0xC000
#define   SW_BASEADDR                  0xD000

#define   PWM_VALUE1                   20  //导致模块保护的PWM差值
#define   PWM_VALUE2                   10  //加载的PWM差值,此值要小于上值
#define   PWM_VALUE3                   20//换向的最大PWM值,应大于步进初始值

#define   TIME_CONST1                  3  //发送信息
#define   TIME_CONST2                  50    //保护时PWM增加时间

#define   CAN_ID1                      0x22
#define   CAN_ID2                      0x2F
#define   TMS_INFO_ID                  0xF1

unsigned char can_mode[32];
#pragma   locate(can_mode=CAN_BASEADDR)
unsigned char lock;
#pragma   locate(lock=LOCK_BASEADDR)
unsigned char motor_switch;
#pragma   locate(motor_switch=DIR_BASEADDR)
unsigned char pwm_en;
#pragma   locate(pwm_en=PWM_EN_BASEADDR)
unsigned char f1_status;
#pragma   locate(f1_status=F1_EN_BASEADDR)
unsigned char sw_status;
#pragma   locate(sw_status=SW_BASEADDR)

unsigned char send_data_buffer[8]={0x01,0x34,0x56,0x78,0x90,0xAB,0xCD,0xEF}; //发送数据缓冲,8个字节
unsigned char send_data_length;    //发送数据的长度,半个字节为单位
unsigned char received_data_buffer[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //接收数据缓冲
unsigned char received_data_length=0;     //接收数据长度

unsigned char wsr_image;
unsigned char motor_pwm=0;
unsigned char motor_direction=0x00;
unsigned char function;
unsigned int  motor_pulse=0;
unsigned int  motor_rotate_speed=0;
unsigned char time_ref=0;

void wait_ms(unsigned int x )
{
        unsigned int   i,j;
        for(i = x; i > 0; i--)
              for(j = 187; j > 0; j--);
}

void set_motor_pwm1(unsigned char pwm_value)
{
  wsr_image=wsr;
  disable();
  wsr=1;
  pwm1_control=pwm_value;
  wsr=wsr_image;
  enable();
  motor_pwm = pwm_value;
}

void set_motor_pwm(unsigned char pwm_value)
{
  unsigned char m;
  if (pwm_value > motor_pwm)
  {
     while((pwm_value - motor_pwm) > PWM_VALUE1)
     {
       set_motor_pwm1(motor_pwm + PWM_VALUE2);
       wait_ms(TIME_CONST2);
     }
     set_motor_pwm1(pwm_value);
  }

  if(pwm_value < motor_pwm)
  {
     if((motor_pwm - pwm_value ) > PWM_VALUE1)
     {
       m=motor_pwm;
       set_motor_pwm1(pwm_value);
       wait_ms(m*3);
     }
     set_motor_pwm1(pwm_value);
  }

  set_motor_pwm1(pwm_value);
}

//===============================================
// 控制电机方向
//===============================================
void set_motor_direction(unsigned char direction)
{
  unsigned char m;
  if(direction!= motor_direction)
  {
    if (motor_pwm > PWM_VALUE3)
    {
      m=motor_pwm;               //转向保护
      set_motor_pwm1(0);          //直接调用set_motor_pwm1,减少延时
      wait_ms(m*4);
      motor_switch = direction;
      set_motor_pwm(m);
    }
    else
      motor_switch = direction;

    //更新方向信息
    motor_direction=direction;
  }
}

//===============================================
// 使用面板控制
//===============================================
void control_by_panel()
{
  unsigned char ad_temp;

  //控制电机方向
  if (sw_status == 0x00)
    set_motor_direction(0x00);
  else set_motor_direction(0x80);

  //控制电机转速
  ad_command=0x0A;
  zero_reg=zero_reg+zero_reg;
  zero_reg=zero_reg+zero_reg;
  while(ad_result_lo & 0x08);
  ad_temp=ad_result_hi;
  set_motor_pwm(ad_temp);
}

void init_can()
{
  do
  {
    can_mode[0]=0x01;
  }
  while (can_mode[0] & 0x01 !=0x01);  //复位sja1000

  can_mode[4]=0x09;         //enable receive int 数据溢出中断使能
  can_mode[2]=0x00;         //status reg
  can_mode[31]=0xc8;        //clock div

  can_mode[30]=0x00;      //RX缓冲区起始地址
  can_mode[14]=0x00;      //RX error count
  can_mode[15]=0x00;      //Tx error count

  can_mode[16]=0x22;      //验收代码 00100010001
  can_mode[17]=0x2F;
  can_mode[18]=0xFF;
  can_mode[19]=0xFF;

  can_mode[20]=0xFF;      //验收屏蔽 0时比较
  can_mode[21]=0xFF;
  can_mode[22]=0xFF;
  can_mode[23]=0xFF;

  can_mode[6]=0x40;       //总线时序
  can_mode[7]=0x6F;

  can_mode[8]=0x1A;       //输出控制

  do
  {
    can_mode[0]=0x04;
  }
  while(can_mode[0]!=0x04);

  can_mode[4]=0x01;      //输出中断使能
}

//===============================================
// CAN处理
//===============================================
void can_process()
{
  unsigned char state;
  unsigned char direction;
  unsigned char pwm;

  if (received_data_buffer[0]==0xC1)
    function=received_data_buffer[1];

  if (received_data_buffer[0]==0xC2)
  {
    state=received_data_buffer[1];
    pwm=received_data_buffer[2];
    if ((state & 0x10) ==0x10)
      direction=0x80;
    else
      direction=0x00;

    if ((state & 0x40)==0x40)  set_motor_direction(direction);
    if ((state & 0x80)==0x80)  set_motor_pwm(pwm);
  }
}

//===============================================
// can发送程序
//===============================================
void can_send()
{
    unsigned char i;
    //等待发送缓冲器释放
    while(can_mode[2]&0x04!=0x04);
    //填充数据
    can_mode[16]=send_data_length;            //数据个数
    can_mode[17]=CAN_ID1;
    can_mode[18]=CAN_ID2;

    for(i=0;i<send_data_length;i++)
    {
      can_mode[19+i]=send_data_buffer[i];
    }
    //发送数据
    can_mode[1]=0x01;
}

//===============================================
//发送速度信息
//===============================================
void send_motor_info()
{
  unsigned char dir=0;
  unsigned int  *p;
  send_data_length=8;
  send_data_buffer[0]=TMS_INFO_ID;
  if (motor_direction==0x80)  dir = 0x10;
  send_data_buffer[1]=dir;
  p=(unsigned int *)&send_data_buffer[2];
  *p= motor_rotate_speed;

  can_send();
}

//===============================================
// 定时中断
//===============================================
#pragma interrupt(TIMER_isr=0)
void  TIMER_isr(void)
{
   //22.8881* 脉冲数
   disable();
   //////////////////////////
   //测速
   /////////////////////////

   motor_rotate_speed=23 * motor_pulse;
   motor_pulse=0;

   /////////////////////////
   //发送电机运行信息
   /////////////////////////
   if (time_ref==TIME_CONST1)
   {
     time_ref=0;
     send_motor_info();
   }
   else
    time_ref++;

   enable();
}

//===============================================
// 高速输入中断
//===============================================
#pragma interrupt(HSI_isr=2)  //中断矢量地址2004
void  HSI_isr(void)
{
   //22.8881* 脉冲数
   disable();

   zero_reg=hsi_time;
   motor_pulse++;

   enable();
}

//===============================================
// CAN中断
//===============================================
#pragma interrupt(CanInt_isr=29) //中断矢量地址203A
void  CanInt_isr(void)
{
  unsigned char i;

  disable();

  if ((can_mode[3]& 0x01) ==0x01)  //判断是否为接收中断
  {
    while((can_mode[2]& 0x01)==0x01)    //判断接收缓冲器是否有报文
    {
      received_data_length=can_mode[16];
      for(i=0;i<received_data_length;i++)
      {
        received_data_buffer[i]=can_mode[19+i];
      }
      can_process();
      can_mode[1]=0x04;
    }
  }

  enable();
}

void main()
{
        disable();

        //清HSI
        while((ios1 & 0x80) ==0x80)
        zero_reg=hsi_time;
        hsi_mode=0xFF;

        hsi_mode=0xFF;  //hsi输入全部是每次跳变(正和负)

        ioc0=ENABLE_HSI1_INPUT;
        ioc1=ENABLE_TIMER1_OVERFLOW_INT|ENABLE_ACH7_INTERRUPT;
        ioc2=DOU_PWM_PERIOD;
        wsr_image=wsr;
        wsr=1;
        ioc3=ENABLE_PWM1;
        wsr=wsr_image;

        //设置中断
        int_mask=ENABLE_HSIDATA_INTERRUPT|ENABLE_TIMEROVF_INTERRUPT  ;
        int_mask1=ENABLE_EXT_INT1;
        int_pend=0x00;
        int_pend1=0x00;

        lock=0x80;  //解除锁定
        pwm_en=0x00;  //PWM使能
        f1_status=0x00;  //F2灭
        function=0xF1;
        set_motor_pwm(0x00);
        init_can();

        enable();

        while(1)
        {
          if (function==0xF1)
            control_by_panel();
        }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -