51单片机 28BYJ-48步进电机的细分驱动方式 Test

#include <reg52.h>

typedef unsigned char uint8_t;
typedef unsigned int uint16_t;
typedef unsigned long uint32_t;

uint32_t periodCnt = 0;  //PWM周期计数值
uint8_t highRH = 0;  //高电平重载值的高字节
uint8_t highRL = 0;  //高电平重载值的低字节
uint8_t lowRH  = 0;  //低电平重载值的高字节
uint8_t lowRL  = 0;  //低电平重载值的低字节
uint8_t T1RH = 0;    //T1重载值的高字节
uint8_t T1RL = 0;    //T1重载值的低字节
//1-2相励磁
uint8_t code beatCode[8] = {
    0xE, 0xC, 0xD, 0x9, 0xB, 0x3, 0x7, 0x6
};
uint8_t code dutyCycle[4] = {  //占空比调整表
	25, 50, 75, 100
};
uint8_t hRHi[5], hRLi[5], lRHi[5], lRLi[5];
uint32_t beats = 0;
 
void configTmr1(uint16_t ms);
void configPWM(uint16_t fr, uint8_t dc);
void calcRldVal(uint8_t idx);
void setTurningAngle(uint32_t angle);

void main() {
	uint8_t i;

    EA = 1;     //开总中断
	configPWM(10000, dutyCycle[3]);  //配置并启动PWM
	for (i = 0; i < 13; i++)
    	calcRldVal(i);
    configTmr1(1);    //用T1定时调整占空比
    setTurningAngle(2 * 360 + 180);
    while (1);
}
/* 配置并启动PWM,fr-频率,dc-占空比 */
void configPWM(uint16_t fr, uint8_t dc) {
    uint16_t high, low;

    periodCnt = 11059200 / 12 / fr; //计算一个周期所需的计数值
    high = periodCnt * dc / 100;    //计算高电平所需的计数值
    low  = periodCnt - high;        //计算低电平所需的计数值
    high = 65536 - high + 12;       //计算高电平的定时器重载值并补偿中断延时
    low  = 65536 - low  + 12;       //计算低电平的定时器重载值并补偿中断延时
    highRH = high >> 8; //高电平重载值拆分为高低字节
    highRL = high;
    lowRH  = low >> 8;  //低电平重载值拆分为高低字节
    lowRL  = low;

    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = highRH;   //加载T0重载值
    TL0 = highRL;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
}
/* 配置并启动T1,定时调整占空比,ms-定时时间 */
void configTmr1(uint16_t ms) {
    uint32_t tmp;  //临时变量

    tmp = 11059200 / 12;      //定时器计数频率
    tmp = (tmp * ms) / 1000;  //计算所需的计数值
    tmp = 65536 - tmp;        //计算定时器重载值
    tmp = tmp + 12;           //补偿中断响应延时造成的误差
    T1RH = tmp >> 8;  //定时器重载值拆分为高低字节
    T1RL = tmp;

    TMOD &= 0x0F;   //清零T1的控制位
    TMOD |= 0x10;   //配置T1为模式1
    TH1 = T1RH;     //加载T1重载值
    TL1 = T1RL;
    ET1 = 1;        //使能T1中断
	PT1 = 1;		//设置T1抢占优先
    TR1 = 1;        //启动T1
}
/* 占空比调整函数,频率不变只调整占空比 */
void calcRldVal(uint8_t idx) {
    uint16_t high, low;

    high = periodCnt * dutyCycle[idx] / 100;    //计算高电平所需的计数值
    low  = periodCnt - high;        //计算低电平所需的计数值
    high = 65536 - high + 12;       //计算高电平的定时器重载值并补偿中断延时
    low  = 65536 - low  + 12;       //计算低电平的定时器重载值并补偿中断延时
    hRHi[idx] = high >> 8; //高电平重载值拆分为高低字节
    hRLi[idx] = high;
    lRHi[idx] = low >> 8;  //低电平重载值拆分为高低字节
    lRLi[idx] = low;
}
void setTurningAngle(uint32_t angle) {
    EA = 0;		//关总中断
    beats = angle * 4076 / 360;
    EA = 1;
}
uint8_t now = 0, next = 1;      //当前哪两拍调制PWM
/************************************************************ 
	T0中断服务函数,根据重载值产生PWM输出(控制电枢电流的大小),
	根据now和next的值将PWM输出到对应的两相电枢上
************************************************************/
void tmr0IntSrv() interrupt 1 {
    static bit flag = 0;
    uint8_t tmp;

    if (flag == 0) {
        TH0 = lowRH;
        TL0 = lowRL;
        tmp = P1;
        tmp &= 0xF0;
        tmp |= beatCode[now];
    } else {
        TH0 = highRH;
        TL0 = highRL;
        tmp = P1;
        tmp &= 0xF0;
        tmp |= beatCode[next];
    }
    P1 = tmp;
    flag = ~flag;
}
/************************************************************** 
	T1中断服务函数,定时动态调整占空比,并驱动电机换相 
**************************************************************/
void tmr1IntSrv() interrupt 3 {
    static uint8_t index = 3;   //细分精度为4,细分内拍子的索引

    TH1 = T1RH;  //重新加载T1重载值
    TL1 = T1RL;
    highRH = hRHi[index];
	highRL = hRLi[index];
	lowRH = lRHi[index];
	lowRL = lRLi[index];
	if (beats == 0)
        return;
    if (index == 0) {
        index = 3;
        now = next;
        next = (next + 1) % 8;  //8拍
        beats--;
    } else {
        index--;
    }
}



你可能感兴趣的:(51单片机 28BYJ-48步进电机的细分驱动方式 Test)