//-----------------------------------------------------------------
// 名称: 带位置感应器的直流无刷电机PMW控制仿真
//-----------------------------------------------------------------
// 说明: 本例用PIC单片机控制带感应器的直流无刷电机,通过调节RA0端口的
// 可变电阻器可实现电机调速控制.
// 由于当前版本PROTEUS不支持换向功能,连接RA1端口的SW1尚不能控制
// 无刷电机的运行方向.
//
//-----------------------------------------------------------------
#include <xc.h>
#define INT8U unsigned char
#define INT16U unsigned int
#define _XTAL_FREQ 20000000UL //20MHz
#define BLDC_StopMask 0B11010101 //关闭电机的掩码(高边设为全0)
#define BLDC_DrivePort PORTC //无刷直流电机驱动方向控制端口(6位)
#define BLDC_DrivePortTris TRISC //无刷直流电机驱动方向控制端口方向设置
#define BLDC_Direction RA1 //无刷直流电机当前方向检测位
#define BLDC_SensorPORT PORTE //无刷直流电机感应器输入端口
#define BLDC_SensorTRIS TRISE //无刷直流电机感应器输入端口方向寄存器
volatile INT8U ADC_Result; //控制PWM的AN0通道A/D转换数据
volatile INT8U DriveByte; //电机驱动字节(低6位有效)
//-----------------------------------------------------------------
// 驱动表设置(更详细说明可参阅本书相关章节)
//-----------------------------------------------------------------
//1.6个驱动器共为3对,每2个为一对
//2.每一对驱动线由一个高边和一个低边构成
//3.三个驱动器对应于三个电机绕组A,B,C
//4.绕组 A 由RC[1..0]两位驱动,其中RC1是 A 绕组的高边
//5.绕组 B 由RC[3..2]两位驱动,其中RC3是 B 绕组的高边
//6.绕组 C 由RC[5..4]两位驱动,其中RC5是 C 绕组的高边
//7.三个感应器位构成了驱动表的偏移地址,感应器位[0..2]分别对应于绕组A,B,C
//正向驱动数据表,第1-6字节对应于相位6,4,5,2,1,3的驱动位,各字节中仅低6位有效
//驱动表中第0,7两字节无效
const INT8U FwdTable[] =
{
};
//反向驱动数据表,第1-6字节对应于相位/6,/4,/5,/2,/1,/3的驱动位,0,7两字节无效
//表中每个字节后6位中,相邻两位为一组,与上表的差别是每组中的两位颠倒
const INT8U RevTable[] =
{
};
//-----------------------------------------------------------------
// 换向控制
//-----------------------------------------------------------------
void Get_Drive_Byte()
{
//读取PORTE端口输入的感应器当前数据(三位)
INT8U CurrentSensor = PORTE & 0B00000111;
//根据RA1端口的方向位及当前位置感应器输出,从正向或反向驱动表中读取驱动字节
if (BLDC_Direction == 0)
DriveByte = FwdTable[CurrentSensor];
else
DriveByte = RevTable[CurrentSensor];
}
//-----------------------------------------------------------------
// 初始化程序
//-----------------------------------------------------------------
void Initialize()
{
Get_Drive_Byte(); //根据当前电机位置取得驱动字节
ADC_Result= 0x00; //初始速度控制值为0
BLDC_DrivePort = 0x00; //关闭BLDC驱动端口
BLDC_DrivePortTris = 0x00; //BLDC驱动方向端口设为输出
BLDC_SensorTRIS = 0xFF; //无刷直流电机感应器端口设为输入
TRISA = 0B00000011; //AN0为模拟量输入,RA1为电机方向控制
T0CS = 0; //TMR0时钟选择:内部时钟
PSA = 0; //前分频器分配给TMR0
PS2 = 1; PS1 = 1; PS0 = 1; //256分频(OPTION低3位为111,4M,256us)
ADCON1 = 0B00001110; //A/D转换结果左对齐,AN0为模拟端口,其余为数字端口
ADCON0 = 0B11000001; //A/D时钟源:RC,ADON置位,使能A/D模块
GO_nDONE = 1; //启动ADC
}
//-----------------------------------------------------------------
// 读取A/D转换结果的高8位
//-----------------------------------------------------------------
void ReadADC()
{
//如果模/数转换已经就绪则读取速度控制值并重新启ADC,以便读取一次ADC结果
if (GO_nDONE) return;
ADC_Result = ADRESH; //读取A/D结果的高8位
GO_nDONE = 1; //重启A/D模块
}
//-----------------------------------------------------------------
// 主程序
//-----------------------------------------------------------------
void main()
{
Initialize();
while (1)
{
ReadADC();//从模/数转换端口读取速度控制值
//如果A/D转换值为最大值则电机全速运行,否则调节PWM
//占空比 = ADC_Result / 255
if (ADC_Result != 0xFF)
{
if (TMR0 + ADC_Result <= 0xFF) DriveByte &= BLDC_StopMask;
}
//发送电机驱动字节(6位),驱动电机运行
BLDC_DrivePort = DriveByte;
//根据电机位置感应器输出的当前位置取得新的驱动字节
Get_Drive_Byte();
}
}