搜索
bottom↓
回复: 12

STC15W401AS-35I-SOP16(人民币1.6)实现四轴飞行器无刷电机的电机

[复制链接]

出45入38汤圆

发表于 2015-1-8 09:24:15 | 显示全部楼层 |阅读模式
本帖最后由 国学芯用 于 2015-1-8 09:29 编辑

STC15W401AS-35I-SOP16(人民币1.6)-实现四轴飞行器无刷电机的电调控制-参考程序和电路

/*---------------------------------------------------------------------*/
/* --- STC MCU International Limited ----------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Fax: 0513-55012956,55012947,55012969 ---------------------------*/
/* --- Tel: 0513-55012928,55012929,55012966 ---------------------------*/
/* --- Web: www.GXWMCU.com   www.stcmcu.com ---------------------------*/
/* --- QQ:  800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了宏晶科技的资料及程序   */
/*---------------------------------------------------------------------*/


/*************        功能说明        **************

本程序试验使用STC15W401AS-35I-SOP16<RMB1.6>来驱动航模用的无传感器无刷三相直流马达.

本程序参考自网上的代码(作者: 瑞生), 改良而来.

电路图见文件 "BLDC-V10-实验电路.pdf".

控制信号由P3.2输入正脉冲信号, 间隔5~20ms, 脉冲宽度1.000~1.610ms.

1.160ms开始启动, 1.610ms为最高速度, 分辨率为2us.

本程序仅仅是简单控制, 软件没有处理 过0延时30度切换 过流检测.

由于过0检测部分有RC滤波, 所以改变电容值可以大约的对应在最高速时延时30度的时间.

有意者可自行完善电路和程序.

******************************************/




#define MAIN_Fosc                24000000L        //定义主时钟

#include "STC15Fxxxx.H"

#define                MCU_PIN                16        /* 选择MCU引脚数, 只支持16或20脚(28脚或32脚跟20脚一样) */



//CMPCR1
#define        CMPEN        0x80        //1: 允许比较器, 0: 禁止,关闭比较器电源
#define        CMPIF        0x40        //比较器中断标志, 包括上升沿或下降沿中断, 软件清0
#define        PIE                0x20        //1: 比较结果由0变1, 产生上升沿中断
#define        NIE                0x10        //1: 比较结果由1变0, 产生下降沿中断
#define        PIS                0x08        //输入正极性选择, 0: 选择外部P5.5做正输入,           1: 由ADCIS[2:0]所选择的ADC输入端做正输入.
#define        NIS                0x04        //输入负极性选择, 0: 选择内部BandGap电压BGv做负输入, 1: 选择外部P5.4做输入.
#define        CMPOE        0x02        //1: 允许比较结果输出到P1.2, 0: 禁止.
#define        CMPRES        0x01        //比较结果, 1: CMP+电平高于CMP-,  0: CMP+电平低于CMP-,  只读

//CMPCR2
#define        INVCMPO        0x80        //1: 比较器输出取反,  0: 不取反
#define        DISFLT        0x40        //1: 关闭0.1uF滤波,   0: 允许
#define        LCDTY        0x00        //0~63, 比较结果变化延时周期数

#if        (MCU_PIN == 20)
        sbit PWM2_L = P3^4;
        sbit PWM1_L = P3^5;
        sbit PWM0_L = P3^6;
#endif

#if        (MCU_PIN == 16)
        sbit PWM2_L = P5^5;
        sbit PWM1_L = P3^3;
        sbit PWM0_L = P3^6;
#endif

u8        Step;
u8        PWM_Value; // 决定PWM占空比的值
u16        RxPulseWide;
bit        B_RxOk;
bit        B_RUN;
u8        PWW_Set;
u8        cnt10ms;
u8        Rx_cnt;
u8        TimeOut;        //堵转超时

#define DISABLE_CMP_INT CMPCR1 &= ~0X40                // 关闭比较器中断
#define ENABLE_CMP_INT  CMPCR1 |= 0X40                // 打开比较器中断

/*************************/

void        Delay_n_ms(u8 dly)
{
        u16        j;
        do
        {
                j = MAIN_Fosc / 13000;        //延时1ms, 主程序在此节拍下运行
                while(--j)        ;
        }while(--dly);
}


void delay_us(u8 us)
{
        do
        {
                NOP(20);        //@24MHz
        }
        while(--us);
}

void StepXL(void) // 换相序列函数
{
switch(Step)
  {
   case 0:  // AB
                        PWM0_L=0;        PWM2_L=0;
                        CCAP0H = PWM_Value;        CCAP1H=0;        CCAP2H=0;        // 打开A相的高端
                        PWM1_L = 1;                 // 打开B相的低端
                        ADC_CONTR = 0XED;        // 选择P1.5作为ADC输入 即c相电压
                        CMPCR1 = 0x9C;                //bit7=1 允许比较器, bit4=1 比较结果由1变0, 产生下降沿中断 (不能响应下降沿中断?)
                        break;
   case 1:  // AC
                        PWM0_L=0;        PWM1_L=0;
                        CCAP0H = PWM_Value;        CCAP1H=0;        CCAP2H=0;        // 打开A相的高端
                        PWM2_L = 1;                        // 打开C相的低端
                        ADC_CONTR = 0XEC;        // 选择P1.4作为ADC输入 即B相电压
                        CMPCR1 = 0xAC;                //上升沿中断
         
      break;
   case 2:  // BC
                        PWM0_L=0;        PWM1_L=0;
                        CCAP0H=0;        CCAP2H=0;        CCAP1H = PWM_Value; // 打开B相的高端
                        PWM2_L = 1;                        // 打开C相的低端
                        ADC_CONTR = 0XEB;        // 选择P1.3作为ADC输入 即a相电压
                        CMPCR1 = 0x9C;                //下降沿中断
      break;
   case 3:  // BA
                        PWM1_L=0;        PWM2_L=0;
                        CCAP0H=0;        CCAP2H=0;        CCAP1H = PWM_Value; // 打开B相的高端
                        PWM0_L = 1;                        // 打开A相的低端
                        ADC_CONTR = 0XED;        // 选择P1.5作为ADC输入 即c相电压
                        CMPCR1 = 0xAC;                //上升沿中断
                       
      break;
   case 4: // CA
                        PWM1_L=0;        PWM2_L=0;
                        CCAP0H=0;        CCAP1H=0;        CCAP2H = PWM_Value; // 打开C相的高端
                        PWM0_L = 1;                        // 打开A相的低端
                        ADC_CONTR = 0XEC;        // 选择P1.4作为ADC输入 即B相电压
                        CMPCR1 = 0x9C;                //下降沿中断
      break;
   case 5: // CB
                      PWM0_L=0;        PWM2_L=0;
                        CCAP0H=0;        CCAP1H=0;        CCAP2H = PWM_Value;// 打开C相的高端
                      PWM1_L = 1;                        // 打开B相的低端
                        ADC_CONTR = 0XEB;        // 选择P1.3作为ADC输入 即a相电压
                        CMPCR1 = 0xAC;                //上升沿中断
         
                break;
         
        default:
                break;
  }       
}



void PWM_Init(void)
{
        PWM0_L = 0;
        PWM1_L = 0;
        PWM2_L = 0;
       
#if        (MCU_PIN == 20)
        P3n_push_pull(0x70);
#endif
#if        (MCU_PIN == 16)
        P3n_push_pull(0x48);
        P5n_push_pull(0x20);
#endif

//        CMOD = 1 << 1; //选择系统时钟/2为时钟源,即PWM频率=24M/2/256=46.9K
        CMOD = 5 << 1; //选择系统时钟/4为时钟源,即PWM频率=24M/4/256=23.4K
//        CMOD = 6 << 1; //选择系统时钟/6为时钟源,即PWM频率=24M/6/256=15.6K
        CL=0;                        // PCA计数器清零
        CH=0;
       
        PCA_PWM0 = 0X00;
        CCAP0H=0;    // 初始化占空比为0% H的值装载到L中
        CCAP0L=0;
        CCAPM0=0x42;        // 设置为PWM模式
       
        PCA_PWM1 = 0X00;
        CCAP1H=0;    // 初始化占空比为0%
        CCAP1L=0;
        CCAPM1=0x42;        // 设置为PWM模式
       
        PCA_PWM2 = 0X00;
        CCAP2H=0;    // 初始化占空比为0%
        CCAP2L=0;
        CCAPM2=0x42;        // 设置为PWM模式
       
        CR = 1;
}

void ADC_Init(void)
{
        P1n_pure_input(0x38);
        P1ASF = 0X38; // 开通P1.3 P1.4 P1.5的AD输入口
}

void CMP_INT(void) interrupt 21
{
        CMPCR1 &= ~0X40; // 需软件清除中断标志位
        if(Step<5)        Step++;
        else                Step = 0;
        StepXL();
        TimeOut = 10;        //10ms超时
}

void CMP_Init(void)
{
        CMPCR1 = 0X8C;        // 1000 1100 打开比较器,P5.4作为比较器的反相输入端,ADC引脚作为正输入端
        CMPCR2 = 60;        // 60个时钟滤波
        P5n_pure_input(0x10);
}

u8 StartMotor(void)
{
        u16 timer,i;
        DISABLE_CMP_INT;        // 禁止比较器中断
        PWM_Value = 30;                // 初始占空比=16/256=6%
        Step = 0;
        StepXL();                        // 初始位置
        Delay_n_ms(5);//delay_ms(5);
        timer = 300;

        while(1)
        {
                for(i=0; i<timer; i++)        delay_us(50);  //
                timer -= timer /15 + 1;
                if(timer < 25)        return(1);
                if( Step < 5)        Step++;
                else                        Step = 0;
                StepXL();
        }
}

void T0_Iint(void)
{
        Timer0_AsTimer();        /* 时器0用做定时器        */
        Timer0_12T();                /* Timer0 clodk = fo/12        12分频,        default        */
        Timer0_16bit();
        Timer0_Gate_INT0_P32();        /* 时器0由外部INT0高电平允许定时计数 */
        TH0 = 0;
        TL0 = 0;
        TR0 = 1; // 打开定时器0
        ET0 = 1;// 允许ET0中断
}

void T0_Interrupt(void) interrupt 1
{
        Rx_cnt = 0;                        //一旦出现溢出, 则开始的n个脉冲无效
        RxPulseWide = 1000;        //停止
        B_RxOk = 1;                        //虚拟收到一个脉冲
}

/********************* INT0中断函数 *************************/
void INT0_int (void) interrupt INT0_VECTOR
{
        u16        j;
       
        TR0 = 0;
        j = ((u16)TH0 << 8) + TL0;
        TH0 = 0;
        TL0 = 0;
        TR0 = 1;

        if(++Rx_cnt >= 5)        Rx_cnt = 5;
        j >>= 1;        //为了好处理, 转成单位为us
        if((j >= 800) && (j <= 2000) && (Rx_cnt == 5))
        {
                RxPulseWide = j;
                B_RxOk = 1;                //标志收到一个脉冲
        }

}


/**********************************************/
void main(void)
{
        u16 j;

        PWM_Init();
        ADC_Init();
        CMP_Init();
        T0_Iint();

        IE0 = 0;        // 清除外中断0标志位
        EX0 = 1;        // INT0 Enable
        IT0 = 1;        //INT0 下降沿中断
       
        RxPulseWide = 1000;
        PWW_Set = 0;
        cnt10ms = 0;
        Rx_cnt  = 0;
        TimeOut = 0;

        EA  = 1; // 打开总中断
       
        while (1)
        {
                Delay_n_ms(1);        //延时1ms, 主程序在此节拍下运行

                if(TimeOut > 0)
                {
                        if(--TimeOut == 0)        //堵转超时
                        {
                                CCAP0H=0;        CCAP1H=0;        CCAP2H=0;  // 占空比为0
                                PWM0_L=0;        PWM1_L=0;        PWM2_L=0;
                                DISABLE_CMP_INT; // 关比较器中断
                                Delay_n_ms(250);        //堵转时,延时1秒再启动
                                Delay_n_ms(250);
                                Delay_n_ms(250);
                                Delay_n_ms(250);

                                RxPulseWide = 1000;
                                PWW_Set   = 0;
                                PWM_Value = 0;
                                B_RxOk = 0;
                                B_RUN  = 0;
                                Rx_cnt = 0;
                                TimeOut = 0;
                        }
                }
               
                if(B_RxOk)        //收到一个脉冲
                {
                        B_RxOk = 0;
                        j = RxPulseWide;
                        if(j >= 1100)                                // 1100~1610对应PWM占空比值0~255
                        {
                                j = (j - 1100) >> 1;        //2us对应PWM一个步进
                                if(j > 256)        j = 255;
                        }
                        else        j = 0;
                        PWW_Set = (u8)j;
                }
               
                if(!B_RUN && (PWW_Set >= 30))                // PWM_Set >= 30, 并且马达未运行, 则启动马达
                {
                        StartMotor();        // 启动马达
                        CMPCR1 &= ~0X40; // 需软件清除中断标志位
                        ENABLE_CMP_INT; // 打开比较器中断
                        B_RUN = 1;
                        TimeOut = 0;
                }
               
               
                if(++cnt10ms >= 10)                // 10ms时隙
                {
                        cnt10ms = 0;
                        if(B_RUN)
                        {
                                if(PWM_Value < PWW_Set)        PWM_Value++;
                                if(PWM_Value > PWW_Set)        PWM_Value--;
                                if(PWM_Value < 20)        // 停转
                                {
                                        PWM_Value = 0;
                                        B_RUN = 0;
                                        CCAP0H=0;        CCAP1H=0;        CCAP2H=0;  // 占空比为0
                                        PWM0_L=0;        PWM1_L=0;        PWM2_L=0;
                                        DISABLE_CMP_INT; // 关比较器中断
                                }
                        }
                }
       
        }
}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2015-1-8 09:41:14 | 显示全部楼层
¥1.6?
降价了?
什么时候的事??

出45入38汤圆

 楼主| 发表于 2015-1-8 09:58:08 | 显示全部楼层
LearningASM 发表于 2015-1-8 09:41
¥1.6?
降价了?
什么时候的事??

一直是啊

出0入0汤圆

发表于 2015-1-8 10:01:01 | 显示全部楼层
好便宜啊

出0入0汤圆

发表于 2015-1-8 10:54:58 | 显示全部楼层
以后或许会用到,收下了。

出0入0汤圆

发表于 2015-1-8 11:02:21 | 显示全部楼层
我倒是比较关心这电调做出来性能怎么样,油门信号和电机力矩的关系有没有测试过,线性度不怎么好的话估计也只能用于固定翼上面了。

出0入0汤圆

发表于 2015-1-8 12:28:48 | 显示全部楼层
挺棒的啊。

出0入0汤圆

发表于 2015-1-8 17:03:54 | 显示全部楼层
没玩过四轴飞行,谢谢分享,学习学习了。

出0入0汤圆

发表于 2015-1-8 17:12:40 | 显示全部楼层
这个51做出来的能实用?

出0入0汤圆

发表于 2015-1-8 19:30:54 | 显示全部楼层
四轴飞行51能用?

出0入0汤圆

发表于 2015-1-12 11:14:09 | 显示全部楼层
不知道楼主的电机和螺旋桨从哪里买的

出0入0汤圆

发表于 2015-1-13 00:57:25 来自手机 | 显示全部楼层
STC确实挺棒的

出0入0汤圆

发表于 2015-12-27 23:17:34 | 显示全部楼层
参考一些,谢谢分享
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-18 20:58

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表