资源描述
实验406.DSP直流电机控制实验
———————————————————————————————— 作者:
———————————————————————————————— 日期:
17
个人收集整理 勿做商业用途
姓名
吴 镌
樊 想
孙 璐
陈玉枫
学号
0816070110
0816070202
0816070201
0816070203
专业
自动化
时间
2011/12/7
成绩
实验名称
直流电机控制实验
实验内容
通过C 语言编程控制控制I/O 管脚产生不同占空比的PWM 信号,从而控制直流电机的转速
实验目的和要求
1.学习用C 语言编制中断程序,控制F2812 DSP 通用I/O 管脚产生不同占空比的PWM 信号。
2.学习F2812DSP 的通用I/O 管脚的控制方法。
3.学习直流电机的控制原理和控制方法。
实验设备
计算机,ICETEK-F2812—EDU 实验箱(或ICETEK 仿真器+ICETEK–F2812—A 系统板+相关连线及电源)。
实验原理
1.TMS320F2812DSP 的McBSP 引脚
通过设置 PWM11 和PWM5 的工作方式和状态,可以实现将它们当成通用I/O 引脚使用.
2.直流电机控制
直流电动机是最早出现的电动机,也是最早能实现调速的电动机。近年来,直流电动机的结构和控制方式都发生了很大的变化。随着计算机进入控制领域,以及新型的电力电子功率元器件的不断出现,使采用全控型的开关功率元件进行脉宽调制(Puls Width Modulation,简称PWM)控制方式已成为绝对主流.PWM 调压调速原理
直流电动机转速 n 的表达式为:
Φ−=Kn U IR
其中,U 为电枢端电压;I 为电枢电流;R 为电枢电路总电阻;Φ为每极磁通量;K 为电动机结构参数.所以直流电动机的转速控制方法可分为两类:对励磁磁通进行控制的励磁控制法和对电枢电压进行控制的电枢控制法。其中励磁控制法在低速时受磁极饱和的限制,在高速时受换向火花和换向器结构强度的限制,并且励磁线圈电感较大,动态响应较差,所以这种控制方法用得很少。现在,大多数应用场合都使用电枢控制法。绝大多数直流电机采用开关驱动方式.开关驱动方式是使半导体功率器件工作在开关状态,通过脉宽调制PWM 来控制电动机电枢电压,实现调速。
上图是利用开关管对直流电动机进行 PWM 调速控制的原理图和输入输出电压波形.图中,
当开关管MOSFET 的栅极输入高电平时,开关管导通,直流电动机电枢绕组两端有电压Us。
t1 秒后,栅极输入变为低电平,开关管截止,电动机电枢两端电压为0。t2 秒后,栅极输入重
新变为高电平,开关管的动作重复前面的过程。这样,对应着输入的电平高低,直流电动机电
枢绕组两端的电压波形如图中所示。电动机的电枢绕组两端的电压平均值Uo 为
S S
S
O U U
T
t
t t
t U
U = =α
+
+
= 1
1 2
1 0
式中α为占空比,α=t1/T
占空比α表示了在一个周期 T 里,开关管导通的时间与周期的比值.α的变化范围为0
≤α≤1。由此式可知,当电源电压Us 不变的情况下,电枢的端电压的平均值Uo 取决于占
空比α的大小,改变α值就可以改变端电压的平均值,从而达到调速的目的,这就是PWM
调速原理。
PWM 调速方法:
在 PWM 调速时,占空比α是一个重要参数。以下3 种方法都可以改变占空比的值:
(1)定宽调频法:这种方法是保持t1 不变,只改变t2,这样使周期T(或频率)也随之改变。
(2)调宽调频法:这种方法是保持t2 不变,只改变t1,这样使周期T(或频率)也随之改变。
(3)定频调宽法:这种方法是使周期T(或频率)保持不变,而改变t1 和t2。
前两种方法由于在调速时改变了控制脉冲的周期(或频率),当控制脉冲的频率与系统的
固有频率接近时,将会引起震荡,因此这两种方法用得很少。目前,在直流电动机的控制中,
主要使用定频调宽法
图中 PWM 输入对应ICETEK–F2812-A 评估板上P4 外扩插座第26 引脚的PWM11 信
号,DSP 将在此引脚上给出PWM 信号用来控制直流电机的转速;图中的DIR 输入对应
ICETEK–F2812—A 评估板上P1 外扩插座第6 引脚的P4 信号,DSP 将在此引脚上给出高电
平或低电平来控制直流电机的方向。从DSP 输出的PWM 信号和转向信号先经过2 个与门和
1 个非门再与各个开关管的栅极相连。
控制原理
当电动机要求正转时,PWM11 给出高电平信号,该信号分成3 路:第1 路接与门Y1
的输入端,使与门Y1 的输出由PWM 决定,所以开关管V1 栅极受PWM 控制;第2 路直接
与开关管V4 的栅极相连,使V4 导通;第3 路经非门F1 连接到与门Y2 的输入端,使与门
Y2 输出为0,这样使开关管V3 截止;从非门F1 输出的另一路与开关管V2 的栅极相连,其
低电平信号也使V2 截止。
同样,当电动机要求反转时,PWM5 给出低电平信号,经过2 个与门和1 个非门组成的
逻辑电路后,使开关管V3 受PWM 信号控制,V2 导通,V1、V4 全部截止。
4.程序编制
程序中采用定时器中断产生固定频率的 PWM 波,在每个中断中根据当前占空比判断应
输出波形的高低电平。
主程序用轮询方式读入键盘输入,得到转速和方向控制命令.
在改变电机方向时为减少电压和电流的波动采用先减速再反转的控制顺序。
实验设计及调试:
(1)对实验内容和实验原理进行分析,理出完成实验的设计思路。
通过C语言编程改变pwm波的占空比,将此pwm波从I/O口输出到直流电动机,从而改变其转速,通过引脚上给出高电平或低电平和逻辑电路来控制直流电机的方向。
(2)列出设计所需的特殊环节…
1。pwm初始化
2.电机使能
3.键盘实时监测
4。中断调用
(3)画出设计流程图。
(4)调试程序
#include "DSP281x_Device.h" // DSP281x Headerfile Include File
#include "DSP281x_Examples.h” // DSP281x Examples Include File
// Prototype statements for functions found within this file.
interrupt void cpu_timer0_isr(void);
void Delay(unsigned int nTime);
void Gpio_select(void);
void error(int);
void program_stop();
void Gpio_PortA(void);
void Gpio_PortB(void);
void Gpio_PortF(void);
void Gpio_PortDEG(void);
char ConvertScanToChar(unsigned char cScanCode);
void RefreshLEDArray(); // 刷新显示
void SetLEDArray(int nNumber); // 修改显示内容
#define T46uS 0x0d40
#define SCANCODE_0 0x70
#define SCANCODE_1 0x69
#define SCANCODE_2 0x72
#define SCANCODE_3 0x7A
#define SCANCODE_4 0x6B
#define SCANCODE_5 0x73
#define SCANCODE_6 0x74
#define SCANCODE_7 0x6C
#define SCANCODE_8 0x75
#define SCANCODE_9 0x7D
#define SCANCODE_Del 0x49
#define SCANCODE_Enter 0x5A
#define SCANCODE_Plus 0x79
#define SCANCODE_Minus 0x7B
#define SCANCODE_Mult 0x7C
#define SCANCODE_Divid 0x4A
#define SCANCODE_Num 0x77
#define CTRGR *(int *)0x108000
#define CTRLCDCMDR *(int *)0x108001
#define CTRKEY *(int *)0x108001
#define CTRLCDCR *(int *)0x108002
#define CTRCLKEY *(int *)0x108002
#define CTRLCDLCR *(int *)0x108003
#define CTRLCDRCR *(int *)0x108004
#define CTRLA *(int *)0x108005
#define CTRLR *(int *)0x108007
Uint16 var1 = 0;
Uint16 var2 = 0;
Uint16 var3 = 0;
Uint16 test_count = 0;
Uint16 Test_flag = 0;
Uint16 Test_var = 0;
Uint16 Test_status[32];
Uint16 PASS_flag = 0;
unsigned int uWork;
int jishu=0;
unsigned int uWork,nCount=0,uN,uN1,nCount1,nDir;
unsigned int uPort8000;
unsigned int nScreenBuffer[1024];
unsigned char ledbuf[8],ledx[8];
unsigned char ledkey[10][8]=
{
{0x00,0x00,0x7C,0x82,0x82,0x82,0x7C,0x00},
{0x00,0x00,0x00,0x84,0xFE,0x80,0x00,0x00}, //1
{0x00,0x00,0x84,0xC2,0xA2,0x92,0x8C,0x00}, //2
{0x00,0x00,0x44,0x92,0x92,0x92,0x6C,0x00},
{0x00,0x00,0x30,0x28,0x24,0xFE,0x20,0x00},
{0x00,0x00,0x4E,0x92,0x92,0x92,0x62,0x00},
{0x00,0x00,0x7C,0x92,0x92,0x92,0x64,0x00},
{0x00,0x00,0x02,0xC2,0x32,0x0A,0x06,0x00},
{0x00,0x00,0x6C,0x92,0x92,0x92,0x6C,0x00},
{0x00,0x00,0x4C,0x92,0x92,0x92,0x7C,0x00}
};
void main(void)
{
//int nCount=0;
char cKey,cOldKey;
unsigned int nScanCode,nKeyCode;
unsigned int nSpeed;
// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the DSP281x_SysCtrl.c file。
InitSysCtrl();
// Step 2. Initalize GPIO:
// This example function is found in the DSP281x_Gpio。c file and
// illustrates how to set the GPIO to it's default state。
// InitGpio(); // Skipped for this example
// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
DINT;
// Initialize the PIE control registers to their default state。
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the DSP281x_PieCtrl。c file。
InitPieCtrl();
StopCpuTimer0();
// Disable CPU interrupts and clear all CPU interrupt flags:
IER = 0x0000;
IFR = 0x0000;
// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
// This will populate the entire table, even if the interrupt
// is not used in this example. This is useful for debug purposes.
// The shell ISR routines are found in DSP281x_DefaultIsr.c。
// This function is found in DSP281x_PieVect.c。
InitPieVectTable();
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
EALLOW; // This is needed to write to EALLOW protected registers
PieVectTable。TINT0 = &cpu_timer0_isr;
EDIS; // This is needed to disable write to EALLOW protected registers
// Step 4。 Initialize all the Device Peripherals:
// This function is found in DSP281x_InitPeripherals.c
// InitPeripherals(); // Not required for this example
/////InitCpuTimers(); // For this example, only initialize the Cpu Timers
CpuTimer0.RegsAddr = &CpuTimer0Regs;
// Initialize timer period to maximum:
//CpuTimer0Regs。PRD。all = music[nCount][0]*450;
CpuTimer0Regs。PRD。all = 0x3000;
// Initialize pre-scale counter to divide by 1 (SYSCLKOUT):
CpuTimer0Regs。TPR.all = 0;
CpuTimer0Regs。TIM.all = 0;
CpuTimer0Regs.TPRH.all = 0;
// Make sure timer is stopped:
CpuTimer0Regs.TCR。bit.TSS = 1;
CpuTimer0Regs。TCR.bit.SOFT = 1;
CpuTimer0Regs.TCR.bit。FREE = 1;
// Reload all counter register with period value:
CpuTimer0Regs。TCR。bit。TRB = 1;
CpuTimer0Regs。TCR.bit。TIE = 1;
// Reset interrupt counters:
CpuTimer0.InterruptCount = 0;
// Step 5。 User specific code, enable interrupts:
// Enable CPU INT1 which is connected to CPU-Timer 0:
IER |= M_INT1;
// Enable TINT0 in the PIE: Group 1 interrupt 7
PieCtrlRegs.PIEIER1。bit.INTx7 = 1;
// Enable global Interrupts and higher priority real-time debug events:
EINT; // Enable Global interrupt INTM
ERTM; // Enable Global realtime interrupt DBGM
CTRGR=0x80; // 初始化ICETEK-CTR
CTRGR=0x0;
CTRGR=0x80;
CTRLR=0; // 关闭东西方向的交通灯
CTRLR=0x40; // 关闭南北方向的交通灯
CTRLR=0xC0;
CTRGR=0x81;
uPort8000=CTRCLKEY;
Gpio_PortA();
Gpio_PortB();
nSpeed=T46uS;
uN=60; nCount=nCount1=0; nDir=0; cKey=cOldKey=0;
StartCpuTimer0(); //启动定时器
while (1)
{
nScanCode=*(int *)0x108001; // 读扫描码
nScanCode&=0x0ff; // 低8位
uPort8000=*(int *)0x108002;
//Delay(5);
if ( nScanCode!=0 )
{
if ( nScanCode==9 ) break;
else
{
cKey=nScanCode;
if ( cKey!=0 && cOldKey!=cKey )
{
cOldKey=cKey;
switch ( cKey )
{
case 1: uN=10; break;
case 2: uN=50; break;
case 3: uN=60; break;
case 4: uN=70; break;
case 5: uN=80; break;
case 6: uN=100; break;
case 7:
uN1=uN;
uN=60; // 降速
Delay(128);
GpioDataRegs.GPADAT.bit。GPIOA4 = 1;
////CpuTimer0Regs。PRD.all = nSpeed;
//CpuTimer0Regs。PRD。all = 182*50;
nDir=0;
Delay(128);
uN=uN1;
break;
case 8:
uN1=uN;
uN=60; // 降速
Delay(128);
GpioDataRegs.GPADAT.bit.GPIOA4 = 0;
Delay(128);
//CpuTimer0Regs。PRD。all=nSpeed;
nDir=1;
Delay(128);
uN=uN1;
break;
}
}
}
}
//Delay(4);
}
StopCpuTimer0();
CTRGR=0;
}
interrupt void cpu_timer0_isr(void)
{
CpuTimer0。InterruptCount++;
// Acknowledge this interrupt to receive more interrupts from group 1
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
CpuTimer0Regs.TCR.bit.TIF = 1;
CpuTimer0Regs。TCR.bit.TRB = 1;
GpioDataRegs。GPBSET.bit。GPIOB4=1;
GpioDataRegs.GPBDAT。bit。GPIOB4=( nCount1<uN )?1:0;
nCount1++; nCount1%=100;
}
void Delay(unsigned int nDelay)
{
int ii,jj,kk=0;
for ( ii=0;ii〈nDelay;ii++ )
{
for ( jj=0;jj〈64;jj++ )
{
//RefreshLEDArray();
kk++;
}
}
}
void RefreshLEDArray()
{
int i;
for ( i=0;i〈8;i++ )
{
CTRGR=ledx[i];
CTRLA=ledbuf[i];
}
}
void Gpio_PortA(void)
{
// GPIO Test #2:
// Configure Upper 8 bits of Port as inputs and lower 8 bits as outputs
// Loop back bits [7:0] to bits [15:8]
// Don't set any input qualifier
var1= 0x0000; // sets GPIO Muxs as I/Os
var2= 0x00FF; // sets GPIO 15-8 DIR as inputs, 7—0 DIR as outputs
var3= 0x0000; // Don't set any input qualifier
Gpio_select();
test_count = 0;
Test_status[Test_var] = 0x0002;
Test_var++;
Test_status[Test_var] = 0xD0BE; // Set the default value of status
// to "PASSED”
GpioDataRegs。GPACLEAR.all = 0x00FF; // Test Clear
asm(” RPT #5 ||NOP");
GpioDataRegs。GPASET。bit.GPIOA4=1;
}
void Gpio_PortB(void)
{
// GPIO Test #2:
// Configure Upper 8 bits of Port as inputs and lower 8 bits as outputs
// Loop back bits [7:0] to bits [15:8]
// Don’t set any input qualifier
var1= 0x0000; // sets GPIO Muxs as I/Os
var2= 0x00FF; // sets GPIO 15—8 DIR as inputs, 7-0 DIR as outputs
var3= 0x0000; // Don't set any input qualifier
Gpio_select();
test_count = 0;
Test_status[Test_var] = 0x0002;
Test_var++;
Test_status[Test_var] = 0xD0BE; // Set the default value of status
// to "PASSED”
GpioDataRegs。GPBCLEAR.all = 0x00FF; // Test Clear
asm(" RPT #5 ||NOP”);
GpioDataRegs.GPBSET。bit。GPIOB4=1;
}
void Gpio_select(void)
{
EALLOW;
GpioMuxRegs。GPAMUX.all=var1; // Configure MUXs as digital I/Os or
GpioMuxRegs。GPBMUX.all=var1; // peripheral I/Os
GpioMuxRegs。GPDMUX。all=var1;
GpioMuxRegs.GPFMUX。all=var1;
GpioMuxRegs。GPEMUX。all=var1;
GpioMuxRegs。GPGMUX。all=var1;
GpioMuxRegs。GPADIR.all=var2; // GPIO PORTs as output
GpioMuxRegs。GPBDIR.all=var2; // GPIO DIR select GPIOs as output
GpioMuxRegs。GPDDIR。all=var2;
GpioMuxRegs.GPEDIR.all=var2;
GpioMuxRegs.GPFDIR.all=var2;
GpioMuxRegs.GPGDIR。all=var2;
GpioMuxRegs。GPAQUAL.all=var3; // Set GPIO input qualifier values
GpioMuxRegs.GPBQUAL.all=var3;
GpioMuxRegs。GPDQUAL。all=var3;
GpioMuxRegs.GPEQUAL。all=var3;
EDIS;
}
char ConvertScanToChar(unsigned char cScanCode)
{
char cReturn;
cReturn=0;
switch ( cScanCode )
{
case SCANCODE_0: cReturn=’0'; break;
case SCANCODE_1: cReturn=’1’; break;
case SCANCODE_2: cReturn=’2’; break;
case SCANCODE_3: cReturn=’3'; break;
case SCANCODE_4: cReturn=’4’; break;
case SCANCODE_5: cReturn='5'; break;
case SCANCODE_6: cReturn=’6’; break;
case SCANCODE_7: cReturn=’7'; break;
case SCANCODE_8: cReturn=’8'; break;
case SCANCODE_9: cReturn=’9’; break;
// case SCANCODE_F1:
case SCANCODE_Plus: cReturn=’+'; break;
// case SCANCODE_F2:
case SCANCODE_Minus: cReturn='-’; break;
}
return cReturn;
}
调试过程中所遇到的问题及解决思路和方法。
1. 调试时电机不运转,复位cpu重新写入程序运行,检查程序,观察是否有存在错误。
2。点按键后电机运转没变化,长按按键观察或检查程序是否有问题。
实验后的经验教训总结.
实验前需熟悉实验仪器,了解实验要求和内容,熟悉程序的逻辑关系,再进行试验.在程序创作上,必须保证结构严谨、关键字正确和逻辑准确等,开始的认真是为了之后程序调试能更快更准确.
教师评语
展开阅读全文