|
本帖最后由 国学芯用 于 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
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|