说明: 本例用PIC单片机控制带感应器的直流无刷电机,通过调节RA0端口的可变电阻器可实现电机调速控制.由于当前版本PROTEUS不支持换向功能,连接RA1端口的SW1尚不能控制无刷电机的运行方向.
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
代码:
- //-----------------------------------------------------------------
- // 名称: 带位置感应器的直流无刷电机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();
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
所有资料51hei提供下载: