#include <msp430f448.h>
#include "Spi.h"
/***********************************宏定义*********************************/
#define UxCTL U0CTL
#define UxRCTL U0RCTL
#define UxTCTL U0TCTL
#define UxBR0 U0BR0
#define UxBR1 U0BR1
#define UxMCTL U0MCTL
#define UxRXBUF U0RXBUF
#define UxTXBUF U0TXBUF
#define UxME U0ME
#define UxIE U0IE
#define UxIFG U0IFG
#define USPIEx USPIE0
#define URXIEx URXIE0
#define UTXIEx UTXIE0
#define USARTxTX_VECTOR USART0TX_VECTOR
#define USARTxRX_VECTOR USART0RX_VECTOR
#define USPI3ON P3SEL |= 0X0E //SPI 0的第二功能打开(三线模式)
#define USPI4ON P3SEL |= 0X0F //SPI 0的第二功能打开(四线模式)
#define SSN0 P3OUT &= 0xFE //P3.0=0
#define SSN1 P3OUT |= 0x01 //P3.0=1
/**************************************************************************/
char TxFlag_Spi=1;
char RxFlag_Spi=0;
/****************************************************************************
* 名 称:SpiMasterInit
* 功 能:初始化SPI。设置波特率等,主机模式
* 入口参数:
* baud: 波特率 (300~500k)
只能是串口使用时钟的整数分频,spi模式UxMCTL寄存器无效
若为整数分频,将分频系数设为 整数部分,将不支持小数分
频
datsBits: 数据位位数 (7或8)
mode: 停止位位数 (3或4)
3:三线模式 4:四线模式
clkMode 时钟模式 (0-3) 控制时钟的极性和相位
0: 上升沿发送,下降沿接收 正常UCLK
1: 下降沿发送,上升沿接收 正常UCLK
2: 下降沿发送,上升沿接收 延时半个周期UCLK
3: 上升沿发送,下降沿接收 延时半个周期UCLK
****************************************************************************/
char SpiMasterInit(long baud,char dataBits,char mode,char clkMode)
{
long int brclk; //波特率发生器时钟频率
UxCTL |= SWRST; //初始
//反馈选择位,为1,发送的数被自己接收,用于测试,正常使用时注释掉
//UxCTL |= LISTEN;
UxCTL |= SYNC + MM; //SPI 主机模式
//时钟源设置
UxTCTL &=~ (SSEL0+SSEL1); //清除之前的时钟设置
if(baud>=300 && baud<=115200) //
{
UxTCTL |= SSEL0; //ACLK,降低功耗
brclk = 32768; //波特率发生器时钟频率=ACLK(32768)
}
//————————设置波特率————————- else if(baud < 300||baud > 115200) //波特率超出范围
{
return 0;
}
//设置波特率寄存器
int fen = brclk / baud; //分频系数
//if(fen<2)return (0); //分频系数必须大于2
if(fen>=2)
{
UxBR0 = fen / 256;
UxBR1 = fen % 256;
}
//————————设置数据位————————- switch(dataBits)
{
case 7:case'7': UxCTL &=~ CHAR; break; //7位数据
case 8:case'8': UxCTL |= CHAR; break; //8位数据
default : return(0); //参数错误
} //————————设置模式————————— switch(mode)
{
case 3:case'3': //三线模式 P3.1-P3.3分别接SPI的SI、SO和SCK
UxTCTL |= STC; P3SEL |= BIT1+BIT2+BIT3;
P3SEL &= ~BIT0; //P3.0=SSN
P3DIR |= BIT0+BIT2+BIT3; break; case 4:case'4': //四线模式 P3.0-P3.3分别接SPI的SSN、SI、SO和SCK
UxTCTL &=~ STC; P3SEL = 0x0f;
P3DIR = 0x0b; break; default : return(0); //参数错误
}
//————————设置UCLK模式———————– switch(clkMode)
{
case 0:case'0': UxTCTL &=~ CKPH; UxTCTL &=~ CKPL; break; //模式0
case 1:case'1': UxTCTL &=~ CKPH; UxTCTL |= CKPL; break; //模式1
case 2:case'2': UxTCTL |= CKPH; UxTCTL &=~ CKPL; break; //模式2
case 3:case'3': UxTCTL |= CKPH; UxTCTL |= CKPL; break; //模式3
default : return(0); //参数错误
}
UxME |= USPIEx; //模块使能
UCTL0 &= ~SWRST; // Initialize USART state machine
//UxIE |= URXIEx + UTXIEx; // Enable USART0 TX RX interrupt return(1); //设置成功
}
/****************************************************************************
* 名 称:UartLpm
* 功 能:串口收/发等待过程中,将时钟系统的部分时钟该关掉,休眠省电
* 入口参数:无
* 出口参数:无
* 说 明: 若与其他外设的时钟冲突,可注释掉该函数,但会增加功耗。
****************************************************************************/
void SpiLpm()
{
if(UxTCTL&SSEL0) LPM3; //若以ACLK 作时钟,进入LPM3休眠(仅打开ACLK)
else LPM0; //若以SMCLK作时钟,进入LPM0休眠(不关闭SMCLK)
}
/****************************************************************************
* 名 称:UartWriteChar
* 功 能:向串口写一个字节数据
* 入口参数:c: 待发送的一字节数据
* 出口参数:无
* 说 明: 在等待发送完毕的过程中,CPU会休眠
****************************************************************************/
void SpiWriteDat(char c)
{ SSN0;
while (TxFlag_Spi==0) SpiLpm(); // 等待上一字节发完,并休眠
//TxFlag_Spi=0; //
UxTXBUF=c;
//while((UxIFG&UTXIFG0)==0);//等待发送缓冲器为空
SSN1;
}
/****************************************************************************
* 名 称:UartReadChar
* 功 能:从串口读取1字节数据
* 入口参数:无 * 出口参数:收到的一字节数据
* 说 明: 如果串口没有数据,会一直等待。等待过程中,CPU会休眠
****************************************************************************/
char SpiReadDat()
{ SSN0;
while (RxFlag_Spi==0) {}; // 收到一字节?
//RxFlag_Spi=0;
//while((UxIFG&URXIFG0)==0);//等待接收缓冲器为满
return(UxRXBUF);
SSN1;
}
/****************************************************************************
* 名 称:SpiWriteData
* 功 能:有返回的写入
* 入口参数:c: 待发送的一字节数据
* 出口参数:char:写入的同时收到的字节
* 说 明: SPI是全双工通信,每次发送,接收时钟也在接收,发送完成后的半个时钟
* 周期后,读到一个字符,这个字符也许不是从设备返回的,仅仅是信号线
* 的默认电平,根据实际情况判断;当只需读数据时,也要用此函数,否则
* 没有时钟提供给从设备,不能读到数据;强烈建议使用时,发送接收只调
* 此函数,否则读取的可能是上一次采样的字符 \0(默认电平)
****************************************************************************/
char SpiWriteData(char c)
{
char i;
SpiWriteDat(c);
for (i = 0xFFFF; i > 0; i–); // Delay
return SpiReadDat();
}
/****************************************************************************
* 名 称:UartRx
* 功 能:串口接收中断,每接收到1字节会发生一次中断
****************************************************************************/
#pragma vector=USARTxRX_VECTOR
__interrupt void SpiRx()
{
char a;
//RxFlag=1;
RxFlag_Spi=1;
a=UxRXBUF;
//__low_power_mode_off_on_exit();
}
/****************************************************************************
* 名 称:UartTx
* 功 能:串口发送中断,每发完1字节会发生一次中断
****************************************************************************/
#pragma vector=USARTxTX_VECTOR
__interrupt void SpiTx()
{
//TxFlag=1;
TxFlag_Spi=1;
//__low_power_mode_off_on_exit();
}
用以上程序对GP21进行配置时出现以下问题:
(1)当UxCTL |= LISTEN时,发送和接收数据相同,但是不能进入发送和接收中断
(2)当注释掉UxCTL |= LISTEN时,用while((UxIFG&URXIFG0)==0)判断是否有接收中断时,可通过while语句,但是接收数据为0
(3)当注释掉UxCTL |= LISTEN,并开启中断时,不能进入中断
请工程师回答我的问题,谢谢
灰小子:
“可通过while语句”是什么意思?这一句能执行过去?
Zhao Li2:
回复 灰小子:
是的,while可执行过去,但是收到的数为0