/*---------------------------------------------------------------------*/
/* --- STC MCU International Limited ----------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: 13922805190 --------------------------------------------*/
/* --- Fax: 0513-55012956,55012947,55012969 ---------------------------*/
/* --- Tel: 0513-55012928,55012929,55012966 ---------------------------*/
/* --- Web: www.GXWMCU.com www.stcmcu.com ---------------------------*/
/* --- QQ: 800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了宏晶科技的资料及程序 */
/*---------------------------------------------------------------------*/
/************* 功能说明 **************
本程序试验使用STC8H1K28-LQFP32来驱动带霍尔传感器的无刷三相直流电机.
PWM的捕捉中断功能用来检测霍尔信号.
P0.3接的电位器控制转速, 处于中间位置为停止, 逆时针旋转电位器电压降低电机为逆时针转, 顺时针旋转电位器电压升高电机为顺时针转.
关于带霍尔传感器三相无刷直流电机的原理, 用户自行学习了解, 本例不予说明.
******************************************/
#define MAIN_Fosc 24000000L //定义主时钟
#include "STC8Hxxx.h"
#define ADC_START (1<<6) /* 自动清0 */
#define ADC_FLAG (1<<5) /* 软件清0 */
#define ADC_SPEED 1 /* 0~15, ADC时钟 = SYSclk/2/(n+1) */
#define RES_FMT (1<<5) /* ADC结果格式 0: 左对齐, ADC_RES: D9 D8 D7 D6 D5 D4 D3 D2, ADC_RESL: D1 D0 0 0 0 0 0 0 */
/* 1: 右对齐, ADC_RES: 0 0 0 0 0 0 D9 D8, ADC_RESL: D7 D6 D5 D4 D3 D2 D1 D0 */
#define CSSETUP (0<<7) /* 0~1, ADC通道选择时间 0: 1个ADC时钟, 1: 2个ADC时钟, 默认0(默认1个ADC时钟) */
#define CSHOLD (1<<5) /* 0~3, ADC通道选择保持时间 (n+1)个ADC时钟, 默认1(默认2个ADC时钟) */
#define SMPDUTY 20 /* 10~31, ADC模拟信号采样时间 (n+1)个ADC时钟, 默认10(默认11个ADC时钟) */
/* ADC转换时间: 10位ADC固定为10个ADC时钟, 12位ADC固定为12个ADC时钟. */
sbit PWM1 = P1^0;
sbit PWM1_L = P1^1;
sbit PWM2 = P1^2;
sbit PWM2_L = P1^3;
sbit PWM3 = P1^4;
sbit PWM3_L = P1^5;
u8 step; //切换步骤
u8 PWM_Value; // 决定PWM占空比的值
bit B_RUN; //运行标志
u8 PWW_Set; //目标PWM设置
u8 YouMen; //油门
bit B_direct; //转向, 0顺时针, 1逆时针
bit B_4ms; //4ms定时标志
/*************************/
//========================================================================
// 函数: u16 Get_ADC10bitResult(u8 channel)) //channel = 0~15
//========================================================================
u16 Get_ADC10bitResult(u8 channel) //channel = 0~15
{
u8 i;
ADC_RES = 0;
ADC_RESL = 0;
ADC_CONTR = 0x80 | ADC_START | channel;
NOP(5); //
i = 255; //超时限制
while(i != 0)
{
i--;
if((ADC_CONTR & ADC_FLAG) != 0) break; //等待ADC结束
}
ADC_CONTR &= ~ADC_FLAG;
return ((u16)ADC_RES * 256 + (u16)ADC_RESL);
}
void Delay_500ns(void)
{
NOP(6);
}
void StepMotor(void) // 换相序列函数
{
PWMB_IER = 0;
PWMB_CCER1 = 0;
PWMB_CCER2 = 0;
step = P2 & 0x07; //P2.0-HALL_A P2.1-HALL_B P2.2-HALL_C
if(!B_direct) //顺时针
{
switch(step)
{
case 2: // 010, P2.0-HALL_A下降沿 PWM3, PWM2_L=1 //顺时针
PWMA_ENO = 0x00; PWM1_L=0; PWM3_L=0;
Delay_500ns();
PWMA_ENO = 0x10; // 打开C相的高端PWM
PWM2_L = 1; // 打开B相的低端
PWMB_CCER2 = (0x01+0x00); //P2.2 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
PWMB_IER = 0x08; //P2.2 使能中断
break;
case 6: // 110, P2.2-HALL_C上升沿 PWM3, PWM1_L=1
PWMA_ENO = 0x10; PWM2_L=0; PWM3_L=0; // 打开C相的高端PWM
Delay_500ns();
PWM1_L = 1; // 打开A相的低端
PWMB_CCER1 = (0x10+0x20); //P2.1 0x10:允许输入捕获, +0x00:上升沿, +0x20:下降沿
PWMB_IER = 0x04; //P2.1 使能中断
break;
case 4: // 100, P2.1-HALL_B下降沿 PWM2, PWM1_L=1
PWMA_ENO = 0x00; PWM2_L=0; PWM3_L=0;
Delay_500ns();
PWMA_ENO = 0x04; // 打开B相的高端PWM
PWM1_L = 1; // 打开A相的低端
PWMB_CCER1 = (0x01+0x00); //P2.0 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
PWMB_IER = 0x02; //P2.0 使能中断
break;
case 5: // 101, P2.0-HALL_A上升沿 PWM2, PWM3_L=1
PWMA_ENO = 0x04; PWM1_L=0; PWM2_L=0; // 打开B相的高端PWM
Delay_500ns();
PWM3_L = 1; // 打开C相的低端
PWMB_CCER2 = (0x01+0x02); //P2.2 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
PWMB_IER = 0x08; //P2.2 使能中断
break;
case 1: // 001, P2.2-HALL_C下降沿 PWM1, PWM3_L=1
PWMA_ENO = 0x00; PWM1_L=0; PWM2_L=0;
Delay_500ns();
PWMA_ENO = 0x01; // 打开A相的高端PWM
PWM3_L = 1; // 打开C相的低端
PWMB_CCER1 = (0x10+0x00); //P2.1 0x10:允许输入捕获, +0x00:上升沿, +0x20:下降沿
PWMB_IER = 0x04; //P2.1 使能中断
break;
case 3: // 011, P2.1-HALL_B上升沿 PWM1, PWM2_L=1
PWMA_ENO = 0x01; PWM1_L=0; PWM3_L=0; // 打开A相的高端PWM
Delay_500ns();
PWM2_L = 1; // 打开B相的低端
PWMB_CCER1 = (0x01+0x02); //P2.0 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
PWMB_IER = 0x02; //P2.0 使能中断
break;
default:
break;
}
}
else //逆时针
{
switch(step)
{
case 4: // 100, P2.0-HALL_A下降沿 PWM1, PWM2_L=1 //逆时针
PWMA_ENO = 0x00; PWM1_L=0; PWM3_L=0;
Delay_500ns();
PWMA_ENO = 0x01; // 打开A相的高端PWM
PWM2_L = 1; // 打开B相的低端
PWMB_CCER1 = (0x10+0x00); //P2.1 0x10:允许输入捕获, +0x00:上升沿, +0x20:下降沿
PWMB_IER = 0x04; //P2.1 使能中断
break;
case 6: // 110, P2.1-HALL_B上升沿 PWM1, PWM3_L=1
PWMA_ENO = 0x01; PWM1_L=0; PWM2_L=0; // 打开A相的高端PWM
Delay_500ns();
PWM3_L = 1; // 打开C相的低端
PWMB_CCER2 = (0x01+0x02); //P2.2 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
PWMB_IER = 0x08; //P2.2 使能中断
break;
case 2: // 010, P2.2-HALL_C下降沿 PWM2, PWM3_L=1
PWMA_ENO = 0x00; PWM1_L=0; PWM2_L=0;
Delay_500ns();
PWMA_ENO = 0x04; // 打开B相的高端PWM
PWM3_L = 1; // 打开C相的低端
PWMB_CCER1 = (0x01+0x00); //P2.0 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
PWMB_IER = 0x02; //P2.0 使能中断
break;
case 3: // 011, P2.0-HALL_A上升沿 PWM2, PWM1_L=1
PWMA_ENO = 0x04; PWM2_L=0; PWM3_L=0; // 打开B相的高端PWM
Delay_500ns();
PWM1_L = 1; // 打开A相的低端
PWMB_CCER1 = (0x10+0x20); //P2.1 0x10:允许输入捕获, +0x00:上升沿, +0x20:下降沿
PWMB_IER = 0x04; //P2.1 使能中断
break;
case 1: // 001, P2.1-HALL_B下降沿 PWM3, PWM1_L=1
PWMA_ENO = 0x00; PWM2_L=0; PWM3_L=0;
Delay_500ns();
PWMA_ENO = 0x10; // 打开C相的高端PWM
PWM1_L = 1; // 打开A相的低端
PWMB_CCER2 = (0x01+0x00); //P2.2 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
PWMB_IER = 0x08; //P2.2 使能中断
break;
case 5: // 101, P2.2-HALL_C上升沿 PWM3, PWM2_L=1
PWMA_ENO = 0x10; PWM1_L=0; PWM3_L=0; // 打开C相的高端PWM
Delay_500ns();
PWM2_L = 1; // 打开B相的低端
PWMB_CCER1 = (0x01+0x02); //P2.0 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
PWMB_IER = 0x02; //P2.0 使能中断
break;
default:
break;
}
}
}
void PWMA_config(void)
{
P_SW2 |= 0x80; //SFR enable
PWM1 = 0;
PWM1_L = 0;
PWM2 = 0;
PWM2_L = 0;
PWM3 = 0;
PWM3_L = 0;
P1n_push_pull(0x3f);
PWMA_PSCR = 3; // 预分频寄存器, 分频 Fck_cnt = Fck_psc/(PSCR[15:0}+1), 边沿对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)), 中央对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)*2).
PWMA_DTR = 24; // 死区时间配置, n=0~127: DTR= n T, 0x80 ~(0x80+n), n=0~63: DTR=(64+n)*2T,
// 0xc0 ~(0xc0+n), n=0~31: DTR=(32+n)*8T, 0xE0 ~(0xE0+n), n=0~31: DTR=(32+n)*16T,
PWMA_ARR = 255; // 自动重装载寄存器, 控制PWM周期
PWMA_CCER1 = 0;
PWMA_CCER2 = 0;
PWMA_SR1 = 0;
PWMA_SR2 = 0;
PWMA_ENO = 0;
PWMA_PS = 0;
PWMA_IER = 0;
// PWMA_ISR_En = 0;
PWMA_CCMR1 = 0x68; // 通道模式配置, PWM模式1, 预装载允许
PWMA_CCR1 = 0; // 比较值, 控制占空比(高电平时钟数)
PWMA_CCER1 |= 0x05; // 开启比较输出, 高电平有效
PWMA_PS |= 0; // 选择IO, 0:选择P1.0 P1.1, 1:选择P2.0 P2.1, 2:选择P6.0 P6.1,
// PWMA_ENO |= 0x01; // IO输出允许, bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P, bit3: ENO2N, bit2: ENO2P, bit1: ENO1N, bit0: ENO1P
// PWMA_IER |= 0x02; // 使能中断
PWMA_CCMR2 = 0x68; // 通道模式配置, PWM模式1, 预装载允许
PWMA_CCR2 = 0; // 比较值, 控制占空比(高电平时钟数)
PWMA_CCER1 |= 0x50; // 开启比较输出, 高电平有效
PWMA_PS |= (0<<2); // 选择IO, 0:选择P1.2 P1.3, 1:选择P2.2 P2.3, 2:选择P6.2 P6.3,
// PWMA_ENO |= 0x04; // IO输出允许, bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P, bit3: ENO2N, bit2: ENO2P, bit1: ENO1N, bit0: ENO1P
// PWMA_IER |= 0x04; // 使能中断
PWMA_CCMR3 = 0x68; // 通道模式配置, PWM模式1, 预装载允许
PWMA_CCR3 = 0; // 比较值, 控制占空比(高电平时钟数)
PWMA_CCER2 |= 0x05; // 开启比较输出, 高电平有效
PWMA_PS |= (0<<4); // 选择IO, 0:选择P1.4 P1.5, 1:选择P2.4 P2.5, 2:选择P6.4 P6.5,
// PWMA_ENO |= 0x10; // IO输出允许, bit7: ENO4N, bit6: ENO4P, bit5: ENO3N, bit4: ENO3P, bit3: ENO2N, bit2: ENO2P, bit1: ENO1N, bit0: ENO1P
// PWMA_IER |= 0x08; // 使能中断
PWMA_BKR = 0x80; // 主输出使能 相当于总开关
PWMA_CR1 = 0x81; // 使能计数器, 允许自动重装载寄存器缓冲, 边沿对齐模式, 向上计数, bit7=1:写自动重装载寄存器缓冲(本周期不会被打扰), =0:直接写自动重装载寄存器本(周期可能会乱掉)
PWMA_EGR = 0x01; //产生一次更新事件, 清除计数器和与分频计数器, 装载预分频寄存器的值
// PWMA_ISR_En = PWMA_IER; //设置标志允许通道1~4中断处理
}
// PWMA_PS = (0<<6)+(0<<4)+(0<<2)+0; //选择IO, 4项从高到低(从左到右)对应PWM1 PWM2 PWM3 PWM4, 0:选择P1.x, 1:选择P2.x, 2:选择P6.x,
// PWMA_PS PWM4N PWM4P PWM3N PWM3P PWM2N PWM2P PWM1N PWM1P
// 00 P1.7 P1.6 P1.5 P1.4 P1.3 P1.2 P1.1 P1.0
// 01 P2.7 P2.6 P2.5 P2.4 P2.3 P2.2 P2.1 P2.0
// 02 P6.7 P6.6 P6.5 P6.4 P6.3 P6.2 P6.1 P6.0
// 03 P3.3 P3.4 -- -- -- -- -- --
//========================================================================
// 函数: void PWMB_config(void)
// 描述: PPWM配置函数。
// 参数: noe.
// 返回: none.
// 版本: V1.0, 2021-5-10
// 备注:
//========================================================================
void PWMB_config(void)
{
P_SW2 |= 0x80; //SFR enable
PWMB_PSCR = 11; // 预分频寄存器, 分频 Fck_cnt = Fck_psc/(PSCR[15:0]+1), 边沿对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)), 中央对齐PWM频率 = SYSclk/((PSCR+1)*(AAR+1)*2).
PWMB_DTR = 0; // 死区时间配置, n=0~127: DTR= n T, 0x80 ~(0x80+n), n=0~63: DTR=(64+n)*2T,
// 0xc0 ~(0xc0+n), n=0~31: DTR=(32+n)*8T, 0xE0 ~(0xE0+n), n=0~31: DTR=(32+n)*16T,
PWMB_CCER1 = 0;
PWMB_CCER2 = 0;
PWMB_CR1 = 0; // 使能计数器, 允许自动重装载寄存器缓冲, 边沿对齐模式, 向上计数, bit7=1:写自动重装载寄存器缓冲(本周期不会被打扰), =0:直接写自动重装载寄存器本(周期可能会乱掉)
PWMB_CR2 = 0;
PWMB_SR1 = 0;
PWMB_SR2 = 0;
PWMB_ENO = 0; //IO禁止输出PWM, bit6: ENO8P, bit4: ENO7P, bit2: ENO5P, bit0: ENO4P
PWMB_PS = 0;
PWMB_IER = 0;
PWMB_CCMR1 = 0x31; // 通道5模式配置, 配置成输入通道, 8个时钟滤波
// PWMB_CCER1 |= (0x01+0x02); // 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
PWMB_PS |= 0; // 选择IO, 0:选择P2.0, 1:选择P1.7, 2:选择P0.0, 3:选择P7.4,
// PWMB_IER |= 0x02; // 使能中断
PWMB_CCMR2 = 0x31; // 通道6模式配置, 配置成输入通道, 8个时钟滤波
// PWMB_CCER1 |= (0x10+0x20); // 0x10:允许输入捕获, +0x00:上升沿, +0x20:下降沿
PWMB_PS |= (0<<2); // 0:选择P2.1, 1:选择P5.4, 2:选择P0.1, 3:选择P7.5,
// PWMB_IER |= 0x04; // 使能中断
PWMB_CCMR3 = 0x31; // 通道7模式配置, 配置成输入通道, 8个时钟滤波
// PWMB_CCER2 |= (0x01+0x02); // 0x01:允许输入捕获, +0x00:上升沿, +0x02:下降沿
PWMB_PS |= (0<<4); // 选择IO, 0:选择P2.2, 1:选择P3.3, 2:选择P0.2, 3:选择P7.6,
// PWMB_IER |= 0x08; // 使能中断
PWMB_EGR = 0x01; //产生一次更新事件, 清除计数器和预分频计数器, 装载预分频寄存器的值
PWMB_SMCR = 0x60;
PWMB_BKR = 0x00; //主输出使能 相当于总开关
PWMB_CR1 |= 0x01; // 使能计数器, 允许自动重装载寄存器缓冲, 边沿对齐模式, 向上计数, bit7=1:写自动重装载寄存器缓冲(本周期不会被打扰), =0:直接写自动重装载寄存器本(周期可能会乱掉)
// P2n_standard(0x07); //通道5 6 7输出IO设置为准双向口
}
// PWMB_PS = (0<<6)+(0<<4)+(0<<2)+0; //选择IO, 4项从高到低(从左到右)对应PWM8 PWM7 PWM6 PWM5
// PWMB_PS PWM8 PWM7 PWM6 PWM5
// 00 P2.3 P2.2 P2.1 P2.0
// 01 P3.4 P3.3 P5.4 P1.7
// 02 P0.3 P0.2 P0.1 P0.0
// 03 P7.7 P7.6 P7.5 P7.4
//========================================================================
// 函数: void PWMB_ISR(void) interrupt PWMB_VECTOR
// 描述: PWMB中断处理程序. 捕获数据通过 TIM1-> CCRnH / TIM1-> CCRnL 读取
// 参数: None
// 返回: none.
// 版本: V1.0, 2021-6-1
//========================================================================
void PWMB_ISR(void) interrupt PWMB_VECTOR
{
PWMB_SR1 = 0; //清除中断标志
PWMB_SR2 = 0; //清除中断标志
if(B_RUN) StepMotor(); //换相
}
void ADC_config(void) //ADC初始化函数
{
P1n_pure_input(0xc0); //P1.7 P1.6设置为高阻输入
P0n_pure_input(0x0f); //P0.3~P0.0设置为高阻输入
ADC_CONTR = 0x80 + 6; //ADC on + channel
ADCCFG = RES_FMT + ADC_SPEED;
P_SW2 |= 0x80; //访问XSFR
ADCTIM = CSSETUP + CSHOLD + SMPDUTY;
}
void Timer0_config(void) //Timer0初始化函数
{
Timer0_16bitAutoReload(); // T0工作于16位自动重装
Timer0_12T();
TH0 = (65536UL-MAIN_Fosc/12 / 250) / 256; //4ms
TL0 = (65536UL-MAIN_Fosc/12 / 250) % 256;
TR0 = 1; // 打开定时器0
ET0 = 1;// 允许ET0中断
}
void Timer0_ISR(void) interrupt 1 //Timer0中断函数
{
B_4ms = 1; //4ms定时标志
// if(B_RUN) StepMotor(); //换相, 增加定时器里换相可以保证启动成功.
}
/**********************************************/
void main(void)
{
P2n_standard(0xf8);
P3n_standard(0xbf);
P5n_standard(0x10);
PWMA_config();
PWMB_config();
ADC_config();
Timer0_config(); //Timer0初始化函数
PWW_Set = 0;
EA = 1; // 打开总中断
while (1)
{
if(B_4ms) // 4ms时隙
{
B_4ms = 0;
YouMen = (u8)(Get_ADC10bitResult(11) >> 2); //油门是8位的, P0.3 ADC11-->控制电位器输入
if(YouMen >= 128) PWW_Set = YouMen - 128, B_direct = 0; //顺时针
else PWW_Set = 127 - YouMen, B_direct = 1; //逆时针
PWW_Set *= 2; //PWM设置值0~254
if(!B_RUN && (PWW_Set >= 30)) // PWM_Set >= 30, 并且电机未运行, 则启动电机
{
PWM_Value = 30; //启动电机的最低PWM, 根据具体电机而定
PWMA_CCR1L = PWM_Value; //输出PWM
PWMA_CCR2L = PWM_Value;
PWMA_CCR3L = PWM_Value;
B_RUN = 1; //标注运行
StepMotor(); //启动换相
}
if(B_RUN) //正在运行中
{
if(PWM_Value < PWW_Set) PWM_Value++; //油门跟随电位器, 调速柔和
if(PWM_Value > PWW_Set) PWM_Value--;
if(PWM_Value < 20) // 停转
{
B_RUN = 0;
PWMB_IER = 0;
PWMB_CCER1 = 0;
PWMB_CCER2 = 0;
PWM_Value = 0;
PWMA_ENO = 0;
PWMA_CCR1L = 0;
PWMA_CCR2L = 0;
PWMA_CCR3L = 0;
PWM1_L=0;
PWM2_L=0;
PWM3_L=0;
}
else
{
PWMA_CCR1L = PWM_Value;
PWMA_CCR2L = PWM_Value;
PWMA_CCR3L = PWM_Value;
}
}
}
}
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !