本程序主要特点是发送与接收所用的是不同定时器的不同通道,刚接触到这个问题,在网上没有找着例程,连官网的也是发送与接收用的同一定时器,就自己开始编写调试了 现把调通的代码贴上
/*
由于此处发送为P5.0/TA1.1,接收引脚为P7.6/TA0.2,发送接收是不同的定时器,可同时用接收产生捕获和定时,故发送接收可以进同一个中断
标志位Flag_RX是由于发送接收产生中断方式不同,故用标志位来判断是发送还是接收
*/
//利用捕捉比较功能实现异步串行通信。
//芯片型号:MSP430F4152 p7.6---RX P5.0--TX
//Timer_A TACLK=ACLK
//波特率为 2400BIT/S TBIT1=14 TBIT0_5=6
//帧格式:(0)XXXXXXXX(1),0为起始位,1为结束位,XXXXXXXXX为8位数据
#include <msp430f4152.h>
#define TBIT1 14; //TBIT1 为1 位时间
#define TBIT0_5 6; //TBIT0_5 为半位时间
#define TBIT1_5 20;
#define TXD BIT0 //使用P1.0作为发送,特殊功能脚,用CCI0A做比较输出
#define TXD_DIR P5DIR
#define TXD_SEL P5SEL
#define TXD_OUT P5OUT
#define RXD BIT6 //使用P1.1作为接收,特殊功能脚,用CCI0B做捕获输入
#define RXD_DIR P7DIR
#define RXD_SEL P7SEL
unsigned char Flag_RX;
unsigned int TR_COUNT; //发收计数器
unsigned int T_DATA=0x00; //发送缓冲器
unsigned int R_DATA=0x00; //接收缓冲器
void init(void); //初始化
void txd (unsigned char byte); //发送一字节数据
void rxd(void); //接收准备子程序
main()
{
init();
while(1)
{
rxd(); //准备接收
LPM3; //进入休眠状态,收到数据后在唤醒
txd(R_DATA); //把收到的数据重发
}
}
void init(void)
{
WDTCTL=WDTPW+WDTHOLD; //停止WDT
RXD_SEL|=RXD; //选择为外部模块功能
RXD_DIR&=~RXD; //设置接收引脚为输入模式
TXD_SEL&=~TXD; // 关键点1:此处发送用的是定时器的比较功能,在发送阶段使其输出数据,所以需要设为I/O功能
TXD_DIR|=TXD;
Flag_RX = 1; //关键点2:由于不需要用发送的捕获,所以不能用CCISx来判断是发送接收,故需要一个标志位
TACTL|=TASSEL_1+MC_2; //设定时器A 时钟源ACLK,设定时器为连续模式
_EINT(); //开中断允许
}
//******************************************************
//发送一字节数据子程序
//输入参量:unsigned char 类型字节
// *****************************************************
void txd(unsigned char byte)
{
T_DATA=byte;
CCR2=TAR; //将TAR 时间存入CCR2,确定第一位 长度。
CCR2+=TBIT1; //将每1 位时间周期加入CCR2。
TR_COUNT=0x0A; //发送计数器。
CCTL2=CCIE;
while(CCIE&CCTL2); //等待CCIE 是否为0?为0 则表示发送完数据。
}
// *****************************************************
//接收准备子程序
//依赖TA0 中断来接收一字节数据。
// *****************************************************
void rxd(void)
{
TR_COUNT=8; //接收数据位 位数
CCTL2 = SCS + CCIS_0 + CM_2 + CAP + CCIE;
// 比较捕获为输出模式+比较捕获模块为中断允许+下降沿捕获+设置为捕获模式
//+选择CCI2A 为捕获源+同步捕获
}
//*******************************************************************************
#pragma vector=TIMER0_A1_VECTOR
__interrupt void TIMER0_A1(void)
{
switch(TA0IV)
{
case TA0IV_TACCR1: break;
case TA0IV_TACCR2:
if(Flag_RX == 1) //发送和接收用的分别是TA1和TA0的中断 //接收处理
// if(((CCTL2 & CCIS0)||(CCTL2 & CCIS1)) == 0) //是处于接收中还是发送中? 关键点3:发送不用捕获,不用此语句判断
{
if(CCTL2&CAP) //是捕获模式还是比较模式?
{
CCTL2&=~CAP; //是-开始捕获,将捕获功能改为比较功能
CCR2+=TBIT1_5; //开始捕获位再加半位时间
}
else
{
R_DATA=R_DATA>>1; //处于比较功能,将前面 那位向低位移.
if(CCTL2&SCCI) //这句等效于(P1IN&RXD)==1,如果RXD管脚是高电平
{
R_DATA|=BIT7; //则R_DATA的最高位置1
}
TR_COUNT--; //计数器减1
CCR2+=TBIT1;
if(TR_COUNT==0) //是否接收完8 位?
{
CCTL2&=~CCIE; //是接收完,捕获/ 比较块停止中断充许
Flag_RX = 0;
LPM3_EXIT; //退出低功率模式(一般,在进入LPM3 时才使用)
}
}
} //接收结束
//----------------------------------------------------------------
else //发送处理
{
switch(TR_COUNT)
{
case 0x0a: TA0CCR2+=TBIT1; TXD_OUT&=~TXD; TR_COUNT--; break; //起始位
case 0x09: TA0CCR2+=TBIT1; if(T_DATA&0x01){TXD_OUT|=TXD;} else{TXD_OUT&=~TXD;} TR_COUNT--; break;
case 0x08: TA0CCR2+=TBIT1; if(T_DATA&0x02){TXD_OUT|=TXD;} else{TXD_OUT&=~TXD;} TR_COUNT--; break;
case 0x07: TA0CCR2+=TBIT1; if(T_DATA&0x04){TXD_OUT|=TXD;} else{TXD_OUT&=~TXD;} TR_COUNT--; break;
case 0x06: TA0CCR2+=TBIT1; if(T_DATA&0x08){TXD_OUT|=TXD;} else{TXD_OUT&=~TXD;} TR_COUNT--; break;
case 0x05: TA0CCR2+=TBIT1; if(T_DATA&0x10){TXD_OUT|=TXD;} else{TXD_OUT&=~TXD;} TR_COUNT--; break;
case 0x04: TA0CCR2+=TBIT1; if(T_DATA&0x20){TXD_OUT|=TXD;} else{TXD_OUT&=~TXD;} TR_COUNT--; break;
case 0x03: TA0CCR2+=TBIT1; if(T_DATA&0x40){TXD_OUT|=TXD;} else{TXD_OUT&=~TXD;} TR_COUNT--; break;
case 0x02: TA0CCR2+=TBIT1; if(T_DATA&0x80){TXD_OUT|=TXD;} else{TXD_OUT&=~TXD;} TR_COUNT--; break;
case 0x01: TA0CCR2+=TBIT1; TXD_OUT|=TXD; TR_COUNT--; break; //停止位
case 0x00: CCTL2&=~CCIE; Flag_RX = 1; break;
}
}
break;
}
} |