资源描述
第四讲 定时器A的使用
MSP430F413芯片中含有TimerA3模块,如图1-2所示。其常用的外引线有三条:TACLK、TA1和TA2。
TACLK:定时器_A输入时钟(48脚),与P1.6和ACLK输出共用同一引脚。
TA1:定时器_A的第一通道输入、输出引脚(51脚)。捕获方式:CCI1A输入;比较方式:OUT1输出。
TA2:定时器_A的第二通道输入、输出引脚(45脚)。捕获方式:CCI2A输入;比较方式:OUT2输出。
1.定时器A功能及结构
定时器A基本结构是一个十六位计数器,由时钟信号驱动工作,结构框图如图4-1所示。
图4-1 定时器A结构图
定时器A具有多种功能,其特性如下:
(1)输入时钟可以有三种选择,可以是慢时钟(ACLK)、快时钟(SMCLK与单片机主时钟同频)和外部时钟。
(2)能产生的定时中断、定时脉冲和 PWM(脉宽调制)信号,没有软件带来的误差。
(3)不仅能捕获外部事件发生的时间,还可选择触发脉冲沿(由上升沿或下降沿触发)。
定时器A功能模块主要包括:
(1)计数器部分:输入的时钟源具有4种选择,所选定的时钟源又可以1、2、4或8分频作为计数频率,Timer_A可以通过选择4种工作模式灵活的完成定时/计数功能。
(2)捕获/比较器:用于捕获事件发生的时间或产生时间间隔,捕获比较功能的引入主要是为了提高I/O 端口处理事务的能力和速度。不同的MSP430单片机,Timer_A模块中所含有的捕获/比较器的数量不一样,每个捕获/比较器的结构完全相同,输入和输出都取决于各自所带控制寄存器的控制字,捕获/比较器相互之间完全独立工作。
(3)输出单元:具有可选的8种输出模式,用于产生用户需要的输出信号,支持PWM输出。
2.定时器工作模式
(1)停止模式:停止模式用于定时器暂停,并不发生复位,所有寄存器现行的内容在停止模式结束后都可用。当定时器暂停后重新计数时,计数器将从暂停时的值开始以暂停前的计数方向计数。例如,停止模式前,Timer_A工作于增/减计数模式并且处于下降计数方向,停止模式后,Timer_仍然工作于增/减计数模式,从暂停前的状态开始继续沿着下降方向开始计数。如果不需这样,则可通过TACTL中的CLR控制位来清除定时器的方向记忆特性。
(2)增计数模式:捕获/比较寄存器CCR0用作Timer_A增计数模式的周期寄存器,因为CCR0为16位寄存器,所以该模式适用于定时周期小于65536的连续计数情况。计数器TAR可以增计数到CCR0的值,当计数值与CCR0的值相等(或定时器值大于CCR0的值)时,定时器复位并从0开始重新计数。增计数模式的计数过程如图4-2所示。通过改变CCR0值,可重置计数周期。
图4-2增计数模式示意图
(3)连续计数模式:在需要65536个时钟周期的定时应用场合常用连续计数模式。定时器从当前值计数到单增到0FFFFH后,又从0开始重新计数如图4-3所示。
图4-3 连续计数模式
(4)增/减计数模式
需要对称波形的情况经常可以使用增/减计数模式,该模式下,定时器先增计数到CCR0的值,然后反向减计数到0。计数周期仍由CCR0定义,它是CCR0计数器数值的2倍。计数器的计数过程如图4-4所示。
图4-4增/减计数模式
3.增计数模式应用举例
增计数最大值存储器在CCR0,该值计算方法如下:选用辅助时钟时,ACLK频率f=32768Hz,周期T=1/32768,若选用250ms中断,则CCR0值应为:
转换成十六进制数后N=2000(H)
MSP430F413单片机定时器A构成的时钟小系统程序清单如下:
/***************************************************
* 文件名称:MSP413C语言定时程序
* 文件说明:用MSP430F413定时器A作为定时中断源。
***************************************************/
#include <msp430x41x.h>
/*****************************************************
* 文件说明:LCD 模块
*****************************************************/
#define LCD_IN_USE 10
/******************************************************
* 数据定义七段译码表
*****************************************************/
const unsigned char NUM_LCD[17]={
0xd7, 0x06, 0xe3, 0xa7, 0x36, //'0'~ '4'
0xb5, 0xf5, 0x07, 0xf7, 0xb7, //'5' ~ '9'
0x77, 0xf4, 0xd1, 0xe6, 0xf1, // 'A'~ 'E'
0x71, 0x00}; // 'F','全熄'
unsigned char lcd_Buf[LCD_IN_USE]; // 自定义显示缓冲区,用于要显示的数据
unsigned int cont,y0,y1,y2; //秒、时、分存储变量
/*******************************************************
* LCD模块初始化
*******************************************************/
void init_LCD(void)
{
char tmpv;
BTCTL = BT_fLCD_DIV32; // set LCD 时钟
P5SEL = 0xfc; // 置为外围模块
LCDCTL = LCDON+LCD4MUX+LCDP1; // 4Mux 模式
for (tmpv = 0;tmpv<10;tmpv++)
{
LCDMEM[tmpv] = 0x00; //clear LCD
}
}
/*******************************************************
* LCD清零模块
*******************************************************/
void cl_LCD(void)
{
char tmpv;
for (tmpv = 0;tmpv<10;tmpv++)
{
LCDMEM[tmpv] = 0x00; //clear LCD
}
}
/****************************************************
* 更新LCD缓冲区的内容,把数据显示到LCD
****************************************************/
void lcd_Display(void)
{
char tmpv;
lcd_Buf[0]=y2/10; lcd_Buf[1]=y2%10;
lcd_Buf[2]=16;
lcd_Buf[3]=y1/10; lcd_Buf[4]=y1%10;
lcd_Buf[5]=16;
lcd_Buf[6]=y0/10; lcd_Buf[7]=y0%10;
lcd_Buf[8]=16; lcd_Buf[9]=16;
for(tmpv=0;tmpv<LCD_IN_USE-1;tmpv++)
{
LCDMEM[tmpv] = NUM_LCD[lcd_Buf[tmpv]]; //更新LCDMEM中的内容
}
}
/***********************************************************
*定时器A中断服务程序
************************************************************/
#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A(void)
//interrupt[TIMERA0_VECTOR] void Timer_A (void)
{
cont=cont+1;
if(cont==4)
{
cont=0;
y0=y0+1; //秒加1
if(y0==60)
{
y0=0; y1=y1+1; //60秒为1分,分加1
if(y1==60)
{
y1=0; y2=y2+1; //60分为1小时,小时加1
if(y2==24)
{y2=0 ; //24小时再清零
}
}
}
cl_LCD();
lcd_Display();
_NOP();
}
}
void init_TA(void) //初始化定时器A
{
TACCR0 = 0x2000;
TACTL = TASSEL0 + TACLR; // ACLK, 清零Tar
TACCTL0 = CCIE; // 中断使能CCR0
TACTL |= MC0; // 设置增模式启动定时器A
}
/***********************************************************
*主程序
************************************************************/
void main(void)
{
WDTCTL = WDTPW +WDTHOLD; // 关WDT
SCFQCTL |= SCFQ_4M; // 设定主时钟为4MHz
init_LCD();
init_TA() ;
_EINT(); // 使能中断
cont=0; y0=0; y1=0; y2=0;
for (;;)
{
_BIS_SR(CPUOFF); //关CPU
_NOP(); // 调试程序使用
}
}
4.输出单元
定时器A的输出单元输出模式有8种,增计数模式下输出模式如图4-5所示。
图4-5输出模式示意图
各模式说明如下:
(1)输出模式0—输出模式:输出信号OUTx由每个捕获/比较模块的控制寄存器CCTLx中的OUTx位定义,并在写入该寄存器后立即更新。最终位OUTx直通。
(2)输出模式1—置位模式:输出信号在TAR等于CCRx时置位,并保持置位到定时器复位或选择另一种输出模式为止。
(3)输出模式2—PWM翻转/复位模式:输出在TAR的值等于CCRx时翻转,当TAR的值等于CCR0时复位。
(4)输出模式3—PWM置位/复位模式:输出在TAR的值等于CCRx时置位,当TAR的值等于CCR0时复位。
(5)输出模式4—翻转模式:输出电平在TAR的值等于CCRx时翻转,输出周期是定时器周期的2倍。
(6)输出模式5—复位模式:输出在TAR的值等于CCRx时复位,并保持低电平直到选择另一种输出模式。
(7)输出模式6—PWM翻转/置位模式:输出电平在TAR的值等于CCRx时翻转,当TAR值等于CCR0时置位。
(8)输出模式7—PWM复位/置位模式:输出电平在TAR的值等于CCRx时复位,当TAR的值等于CCR0时置位。
选用增计数模式、输出模式7产生的PWM输出波形如图4-6所示。
图4-6 输出模式7产生PWM输出波形
5.输出单元应用举例
例1.Timer_A用增模式在P1.2/2.0产生两路PWM输出。CCR0计数值为512,通过设定CCR1和CCR2值,定义两路输出脉宽。使用32kHz ACLK作为TACLK,定时器周期为15.625ms,P1.2占空比为75%、P2.0占空比为25%。 ACLK = TACLK = LFXT1 = 32768Hz, MCLK = SMCLK = DCO = 32xACLK = 1.048576Mhz。外部晶振接于XIN和XOUT。
#include <msp430x41x.h>
void main(void)
{
WDTCTL = WDTPW +WDTHOLD; // 关WDT
TACTL = TASSEL0 + TACLR; // ACLK, 清零Tar
CCR0 = 512; // PWM 周期
CCTL1 = OUTMOD_7; // CCR1 reset/set模式
CCR1 = 384; // CCR1 PWM 任务周期
CCTL2 = OUTMOD_7; // CCR2 reset/set模式
CCR2 = 128; // CCR2 PWM 任务周期
P1DIR |= 0x04; // P1.2 输出
P1SEL |= 0x04; // P1.2 TA1模式
P2DIR |= 0x01; // P2.0 输出
P2SEL |= 0x01; // P2.0 TA2模式
TACTL |= MC0; // 增模式启动Timer_A
for (;;)
{
_BIS_SR(LPM3_bits); // 进入LPM3省电模式
_NOP(); // C-spy使用
}
}
第五讲 直流电机控制与电动小车制作
一、直流电机驱动电路工作原理
1)直流电机转向原理
直流电机一般采用H桥驱动电路,如图5-1所示。
图5-1 直流电机驱动原理图
同步改变对角开关管通断状态,就改变了流过电机的电流方向,也就改变了直流电机的转动方向,达到了控制正、反转的目的。电路工作状态表如表5-1所示。
表5-1H桥电机控制状态表
PWM
A
B
电机运行状态
0
×
×
停转
1
0
0
停转
1
0
1
反转
1
1
0
正转
1
1
1
停转
注:“0”代表低电平;“1”代表高电平。
由表5-1可知,H桥电路将电机转动方向控制转化为A、B两端的电平控制,便于与单片机接口实现电机转向控制。
2)直流电机转速控制原理
控制直流电动机所加电压即可控制电机转速。直接调整图5-1中直流电机所加电压VDD虽然可调整电机转速,但其主要缺点是效率低。为了提高效率,通常采用占空比可调矩形波控制电机转速,即PWM(脉冲宽度调制)波调速。PWM信号示意如图5-2所示,图中T为设定的脉冲周期,在驱动电机过程中确定不变;t为脉冲的高电平时间,占空比d = t /T。 将其加于图5-1电路的PWM端,电机转速与PWM信号占空比成正比。
图5-2PWM信号示意图
PWM波产生方法有多种,本设计中为了简化电路,直接使用单片机内定时器A产生PWM控制电机转速。
3)电机驱动专用芯片L293D简介
图5-1所示H桥电路仅是原理电路,要转化为实用电路还要做许多工作,因此实际应用中很少采用。
L293D是集成电路芯片,片内含有双H 桥驱动器,引脚图如图5-3所示。输入小电流控制信号,输出高电压、大电流驱动信号。用逻辑电平控制、驱动感性负载(比如继电器,直流电机和步进电机等)。通过改变芯片控制端的输入电平,即可以对电机进行正反转操作。芯片具有1.2A峰值输出电流通道,使用简易便。其额定工作电流为1A,最大可达1.5A,Vss电压最小4.5V,最大可达36V;Vs电压最大值也是36V。
L293D是16引脚塑料封装,中间的4个引脚是短路的(为了散热), L293D的Vss和Vs电源端可分别接入芯片电源和电机驱动电源。
图5-3 L293D引脚图 图5-4 L293D功能示意图
L293D功能示意图如图5-4所示(对应20引脚芯片)。
L293D使能、输入引脚和输出引脚的逻辑关系如表5-2所示。
表5-2 引脚和输出引脚的逻辑关系
EN A(B)
IN1(IN3)
IN2(IN4)
电机运行情况
H
H
L
正转
H
L
H
反转
H
同IN2(IN4)
同IN1(IN3)
快速停止
L
X
X
停止
H-桥电路的输入量可以用来设置电机转动方向,使能信号可以用于脉宽调整(PWM),实现电机转速控制。L293D将2个H-桥电路集成到1片芯片上,这就意味着用1片芯片可以同时控制2个直流电机。每1个直流电机需要3个控制信号EN1、IN1、IN2,其中EN1是使能信号,IN1、IN2为电机转动方向控制信号,IN1、IN2分别为1,0时,电机正转,反之,电机反转。选用一路PWM连接EN1引脚,通过调整PWM的占空比可以调整电机的转速。
4)直流电机驱动电路
驱动电路如图5-5所示,单片机PIO端口线P1.0、P1.1驱动光电隔离器中发光二极管,控制光电三极管。输入为高电平时,三极管饱和导通,反之截止。当P1.0为高电平、P1.1位低电平时,L293D的IN4为高、IN3为低电平,OUT4为高、OUT3位低电平,电机正转;反之,当P1.0位低、P1.1为高电机反转;当P1.0、P1.1电平同时为高或低时,电机停转,实现了电机转向控制。
E2是OUT4、OUT3的使能端,高电平有效。当在E2端加PWM信号时,可实现调速。高速转动对应的PWM信号占空比为1;次高速占空比为0.75;中速转动占空比为0.5;低速转动占空比为0.25。
PWM信号由MSP430F413单片机定时器A产生。光电隔离器在传送信号同时实现了电平转换,将高电压(6-9V)电机驱动电路与低电压(4.5V)单片机电路隔离,消除了干扰。注意两电路地线标志不同,焊接时不能连接。
图5-5直流电机驱动电路
二、直流电机控制系统硬件设计
直流电机控制系统电路如图5-6所示,是在时钟小系统基础上加入直流电机驱动电路、按键和功能选择开关电路。功能选择开关在上是电机驱动功能,在下是时钟计时功能。
图5-6直流电机控制系统
当开关拨到时钟计时功能时,可以通过秒、分、时三个按键来调节时钟显示固定数字,然后按确定键,时钟便可以在设定时间的基础上开始计时,另外还可以按左侧的复位键,给时钟清零。
当开关拨到电机驱动功能时,电机默认为正转,占空比为0.5,然后通过按键可分别实现:占空比为1的正转,占空比为0.5的正转,占空比为0.5的反转,占空比为1的反转。注意由于按键的局限性,实现电机以上四种旋转的情况要长按按键,一旦松手电机将按默认的占空比为0.5的正传旋转。
本系统中使用两套电源供电,其一是单片机系统电源,考虑到时钟的低功耗,使用3.6伏手机电池供电;其二是直流电机电源,直流电机工作时比较耗电,所以可大容量电池或5V直流电源供电。
5V直流稳压电源电路如图5-7所示。
图5-7 直流稳压电源电路
三、程序设计
1)电机控制程序
直流电机变速驱动小系统程序是在时钟小系统程序基础上增加了相应的初始化和电机驱动控制程序。初始化部分加于_EINT()语句之后,电机驱动部分加于定时中断程序中y0=y0+1语句之后。程序清单如下所示:
/***************************************************
* 文件名称:MSP413C语言定时和直流电机控制程序
* 文件说明:用MSP413看门狗定时器作为定时中断源。
***************************************************/
#include <msp430x41x.h>
/*****************************************************
* 文件说明:LCD 模块
*****************************************************/
#define LCD_IN_USE 10
/******************************************************
* 数据定义七段译码表
*****************************************************/
const unsigned char NUM_LCD[17]={
0xd7, 0x06, 0xe3, 0xa7, 0x36, //'0'~ '4'
0xb5, 0xf5, 0x07, 0xf7, 0xb7, //'5' ~ '9'
0x77, 0xf4, 0xd1, 0xe6, 0xf1, // 'A'~ 'E'
0x71, 0x00}; // 'F','全熄'
unsigned char lcd_Buf[LCD_IN_USE]; // 自定义显示缓冲区,用于要显示的数据
unsigned int cont,y0,y1,y2,s_num; //秒、时、分存储变量
/*******************************************************
* LCD模块初始化
*******************************************************/
void init_LCD(void)
{
char tmpv;
BTCTL = BT_fLCD_DIV32; // set LCD 时钟
P5SEL = 0xfc; // 置为外围模块
LCDCTL = LCDON+LCD4MUX+LCDP1; // 4Mux 模式
for (tmpv = 0;tmpv<10;tmpv++)
{
LCDMEM[tmpv] = 0x00; //clear LCD
}
}
/*******************************************************
* LCD清零模块
*******************************************************/
void cl_LCD(void)
{
char tmpv;
for (tmpv = 0;tmpv<10;tmpv++)
{
LCDMEM[tmpv] = 0x00; //clear LCD
}
}
/****************************************************
* 更新LCD缓冲区的内容,把数据显示到LCD
****************************************************/
void lcd_Display(void)
{
char tmpv;
lcd_Buf[0]=y2/10;
lcd_Buf[1]=y2%10;
lcd_Buf[2]=16;
lcd_Buf[3]=y1/10;
lcd_Buf[4]=y1%10;
lcd_Buf[5]=16;
lcd_Buf[6]=y0/10;
lcd_Buf[7]=y0%10;
lcd_Buf[8]=16;
lcd_Buf[9]=16;
for(tmpv=0;tmpv<LCD_IN_USE-1;tmpv++)
{
LCDMEM[tmpv] = NUM_LCD[lcd_Buf[tmpv]]; //更新LCDMEM中的内容
}
}
/***********************************************************
*WDT中断服务程序
************************************************************/
interrupt[WDT_VECTOR] void watchdog_timer(void)
{
cont=cont+1;
if(cont==4)
{
cont=0;
y0=y0+1; //秒加1
s_num = (y0+7)/7; //以秒计数为敏感量
switch (s_num)
{
case 1: //高速正转
P1OUT = 0x40;
CCR1 = 511; //占空比 511/512≈1
break;
case 2: //次高速正转
P1OUT = 0x40;
CCR1 = 384; //占空比 384/512=0.75
break;
case 3: //中速正转
P1OUT = 0x40;
CCR1 = 256; //占空比 256/512=0.5
break;
case 4: //低速正转
P1OUT = 0x40;
CCR1 = 128; //占空比 128/512=0.25
break;
case 5: //高速反转
P1OUT = 0x80;
CCR1 = 511; //占空比 511/512≈1
break;
case 6: //次高速反转
P1OUT = 0x80;
CCR1 = 384; //占空比 384/512=0.75
break;
case 7: //中速反转
P1OUT = 0x80;
CCR1 = 256; //占空比 256/512=0.5
break;
case 8: //低速反转
P1OUT = 0x80;
CCR1 = 128; //占空比 128/512=0.25
break;
default : P1OUT = 0x00; //其余状态停转
break;
}
if(y0==60)
{
y0=0;
y1=y1+1; //60秒为1分,分加1
if(y1==60)
{
y1=0;
y2=y2+1; //60分为1小时,小时加1
if(y2==24)
{y2=0 ; //24小时再清零
}
}
}
cl_LCD();
lcd_Display();
_NOP();
}
}
/***********************************************************
*主程序
************************************************************/
void main(void)
{
WDTCTL = WDT_ADLY_250; // WDT间隔时间为250ms(ACLK)
IE1 |= WDTIE; // 使能WDT中断
SCFQCTL |= SCFQ_4M; // 设定主时钟为4MHz
init_LCD();
_EINT(); // 使能中断
cont=0;
y0=0;
y1=0;
y2=0;
P1DIR |= 0xC4; // P1.2 输出
P1SEL |= 0x04; // P1.2 TA1
TACTL = TASSEL0 + TACLR; // ACLK, 清除 TAR
CCR0 = 512-1; // PWM周期
CCTL1 = OUTMOD_7; // 设定输出模式7
CCR1 = 256; //占空比 256/512=0.5
TACTL |= MC0; // Timer_A 增计数模式
for (;;)
{
_BIS_SR(CPUOFF); //关CPU
_NOP(); // 调试程序使用
}
}
2)带调时按键的时钟与电机控制程序流程设计
程序流程框图如图5-8所示。
图5-8程序流程框图
2)程序设计
直流电机变速驱动小系统程序是在时钟小系统程序基础上增加了相应的初始化、按键读入、处理和电机驱动程序。程序清单如下:
#include <msp430x41x.h>
/*****************************************************
* 文件说明:时钟与直流电机控制程序
*****************************************************/
#define LCD_IN_USE 10
/******************************************************
* 数据定义七段译码表
*****************************************************/
const unsigned char NUM_LCD[17]={
0xd7, 0x06, 0xe3, 0xa7, 0x36, //'0'~ '4'
0xb5, 0xf5, 0x07, 0xf7, 0xb7, //'5' ~ '9'
0x77, 0xf4, 0xd1, 0xe6, 0xf1, // 'A'~ 'E'
0x71, 0x00};
展开阅读全文