TCA6416A进行IO口扩展实验

/ 0评 / 0

(1)main.c
/* ****警告:由于G2 LaunchPad上的LED2使用了P1.6(I2C引脚),所以所有涉及到I2C的实验都必须把P1.6跳线拔除*** */
#include"MSP430G2553.h"
#include"TCA6416A.h"

void WDT_init();
void I2C_IODect() ; //检测事件确实发生了

void main(void)
{
WDTCTL = WDTPW + WDTHOLD; //关狗
BCSCTL1 = CALBC1_12MHZ; /* Set DCO to 8MHz */
DCOCTL = CALDCO_12MHZ;
TCA6416A_Init(); // 初始化IO扩展口
//----提示初始化成功----
PinOUT(0,1); // 指定0号管脚输出为1
PinOUT(1,0); // 指定1号管脚输出为0
PinOUT(2,1); // 指定0号管脚输出为1
PinOUT(3,0); // 指定1号管脚输出为0
PinOUT(4,1); // 指定0号管脚输出为1
PinOUT(5,0); // 指定1号管脚输出为0
PinOUT(6,1); // 指定0号管脚输出为1
PinOUT(7,0); // 指定1号管脚输出为0
WDT_init();
while(1)
{
PinIN();
I2C_IODect();
__bis_SR_register(LPM0_bits);
}

}
void WDT_init()
{ //-----设定WDT为-----------
WDTCTL=WDT_ADLY_16;
//-----WDT中断使能----------------------
IE1 |= WDTIE;
}
#pragma vector=WDT_VECTOR
__interrupt void WDT_ISR(void)
{
// PinIN();
// I2C_IODect();
__bic_SR_register_on_exit(LPM0_bits );
}
void I2C_IO10_Onclick()
{
static unsigned char turn = 1;
turn ^= BIT0;
PinOUT(0,turn); //指定0号管脚输出为0&1
PinOUT(1,turn); //指定1号管脚输出为0&1
}
void I2C_IO11_Onclick()
{
static unsigned char turn = 1;
turn ^= BIT0;
PinOUT(2,turn); //指定2号管脚输出为0&1
PinOUT(3,turn); //指定3号管脚输出为0&1
}
void I2C_IO12_Onclick()
{
static unsigned char turn = 1;
turn ^= BIT0;
PinOUT(5,turn); //指定5号管脚输出为0&1
PinOUT(4,turn); //指定4号管脚输出为0&1
}
void I2C_IO13_Onclick()
{
static unsigned char turn = 1;
turn ^= BIT0;
PinOUT(6,turn); //指定6号管脚输出为0&1
PinOUT(7,turn); //指定7号管脚输出为0&1
}
void I2C_IODect() //检测事件确实发生了
{
static unsigned char KEY_Now=0;
unsigned char KEY_Past;
KEY_Past=KEY_Now;
//----判断I2C_IO10所连的KEY1按键是否被按下------
if((TCA6416A_InputBuffer&BIT8) == BIT8)
KEY_Now |=BIT0;
else
KEY_Now &=~BIT0;
if(((KEY_Past&BIT0)==BIT0)&&(KEY_Now&BIT0) !=BIT0)
I2C_IO10_Onclick();
//----判断I2C_IO11所连的KEY2按键是否被按下------
if((TCA6416A_InputBuffer&BIT9)== BIT9)
KEY_Now |=BIT1;
else
KEY_Now &=~BIT1;
if(((KEY_Past&BIT1)==BIT1)&&(KEY_Now&BIT1)!=BIT1)
I2C_IO11_Onclick();
//----判断I2C_IO12所连的KEY3按键是否被按下------
if((TCA6416A_InputBuffer&BITA) == BITA)
KEY_Now |=BIT2;
else
KEY_Now &=~BIT2;
if(((KEY_Past&BIT2)==BIT2)&&(KEY_Now&BIT2) ==0)
{
I2C_IO12_Onclick();
}
//----判断I2C_IO13所连的KEY4按键是否被按下------
if((TCA6416A_InputBuffer&BITB) == BITB)
KEY_Now |=BIT3;
else
KEY_Now &=~BIT3;
if(((KEY_Past&BIT3) == BIT3)&& (KEY_Now&BIT3) == 0)
{
I2C_IO13_Onclick();
}
}

(2)TCA6416A.c
#include "I2C.h"
#include "MSP430G2553.h"

//-----控制寄存器定义-----
#define In_CMD0 0x00 //读取管脚输入状态寄存器;只读
#define In_CMD1 0x01
#define Out_CMD0 0x02 //控制管脚输出状态寄存器;R/W
#define Out_CMD1 0x03
#define PIVS_CMD0 0x04 //反向控制管脚输出状态寄存器;R/W
#define PIVS_CMD1 0x05
#define CFG_CMD0 0x06 //管脚方向控制:1:In;0::Out。
#define CFG_CMD1 0x07
volatile unsigned int TCA6416A_InputBuffer=0;

void TCA6416_Tx_Frame(unsigned char *p_Tx,unsigned char num)
{
unsigned char temp=0;
do{
temp=I2C_TxFrame(p_Tx, num);
}while(temp==0);
}

void TCA6416_Rx_Frame(unsigned char *p_Rx,unsigned char num)
{
unsigned char temp=0;
do {
temp=I2C_RxFrame(p_Rx, num);
}while(temp==0);
}

void TCA6416A_Init(void)
{
unsigned char conf[3]={0};
__delay_cycles(100000); //TCA6416的复位时间比单片机长,延迟确保可靠复位
I2C_Init();
I2C_Tx_Init(); //永远默认发模式
//----根据扩展板的引脚使用,将按键所在管脚初始化为输入,其余管脚初始化为输出
conf[0] = CFG_CMD0; //TCA6416控制寄存器
conf[1] = 0x00; // 0 0 0 0_0 0 0 0 (LED0~LED7)
TCA6416_Tx_Frame(conf,2); // 写入命令字

conf[0] = CFG_CMD1;
conf[1] = 0x0f; // 0 0 0 0_1 1 1 1 (按键)
TCA6416_Tx_Frame(conf,2); // 写入命令字

//----上电先将管脚输出为高(此操作对输入管脚无效)
conf[0] = Out_CMD0;
conf[1] = 0xff; // 某位置1,输出为高,0为低
TCA6416_Tx_Frame(conf,2); // 写入命令字

conf[0] = Out_CMD1;
conf[1] = 0xff;
TCA6416_Tx_Frame(conf,2); // 写入命令字
}

void PinOUT(unsigned char pin,unsigned char status)
{
static unsigned char pinW0 = 0xff; //用于缓存已写入相应管脚的状态信息,此操作避免读回TCA6416A中当前寄存器的值
static unsigned char pinW1 = 0xff; //用于缓存已写入相应管脚的状态信息,此操作避免读回TCA6416A中当前寄存器的值

unsigned char out0_7[2]={0}; //管脚 pin0~pin7输出状态缓存
unsigned char out10_17[2] = {0}; //管脚 pin10~pin17输出状态缓存
if(pin<=7) //所选管脚为pin0~pin7 ,刷新所要操作的输出缓存pinW0 状态
{
if(status == 0)
pinW0 &= ~(1<<pin);
else
pinW0 |= 1<<pin;
out0_7[0] = Out_CMD0;
out0_7[1] = pinW0;
TCA6416_Tx_Frame(out0_7,2); // 将更新后的数据包,写入芯片寄存器

}
else if(pin>=10 && pin<=17) //所选管脚为pin10~pin17 ,刷新所要操作的输出缓存pinW1 状态
{
if(status == 0)
pinW1 &= ~(1<<(pin%10));
else
pinW1 |= 1<<(pin%10);
out10_17[0] = Out_CMD1;
out10_17[1] = pinW1 ;
TCA6416_Tx_Frame(out10_17,2); // 将更新后的数据包,写入芯片寄存器
}
else
{
__no_operation(); // Set breakpoint >>here<<
}

}

void PinIN()
{
unsigned char temp[2]={0};
unsigned char conf[1]={0};
conf[0]=In_CMD1;
TCA6416_Tx_Frame(conf,1); // 写入要读取的寄存器地址命令
I2C_Rx_Init(); // 将I2C切换到Rx模式 初始化
TCA6416_Rx_Frame(&temp[0],1); // 读取IO输入寄存器
TCA6416_Rx_Frame(&temp[1],1); // 读取IO输入寄存器,用不上也要读
//----将最新键值,更新到输入缓存----
TCA6416A_InputBuffer = TCA6416A_InputBuffer&0x00ff;
TCA6416A_InputBuffer |=(((unsigned int)temp[0])<<8 )&0xff00;
I2C_Tx_Init();
}

(3)TCA6416A.h
#ifndef TCA6416A_H_
#define TCA6416A_H_

extern void PinIN();
extern void PinOUT(unsigned char pin,unsigned char status);
extern void TCA6416A_Init(void);
extern volatile unsigned int TCA6416A_InputBuffer;

#endif

(4)I2C.c

#include"MSP430G2553.h"
#include"I2C.h"

#ifdef HARD_I2C //Begin of Hard I2C

#define TX_STATE 0 /*I2C发送状态*/
#define RX_STATE 1 /*I2C接收状态*/
//-----对SMCLK分频产生I2C通信波特率-----
#define I2C_BAUDRATE_DIV 14 /*I2C波特率控制*/
#define SLAVE_ADDR 0x20 /*从机TCA6416A的地址*/
static unsigned char TxByteCnt=0; //剩余发送数据
static unsigned char RxByteCnt=0; //剩余接收数据
static unsigned char *pTxData; // 待发送TX 数据的指针
static unsigned char *pRxData; // Rx接收存放数据的指针
unsigned char I2C_State = 0; //收发状态指示变量

void I2C_Init()
{
_disable_interrupts();
P1SEL |= BIT6 + BIT7; // GPIO 配置为USCI_B0功能
P1SEL2|= BIT6 + BIT7; // GPIO 配置为USCI_B0功能
UCB0CTL1 |= UCSWRST; // 软件复位状态
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // 同步通信I2C主机状态
UCB0CTL1 = UCSSEL_2 + UCSWRST; // 使用SMCLK,软件复位状态
UCB0BR0 =I2C_BAUDRATE_DIV ; // 除了分频系数,实际波特率还与SMCLK有关
UCB0BR1 = 0; //这一级别的分频一般不启用
UCB0I2CSA = SLAVE_ADDR; // I2C从机地址,可在宏定义中修改
UCB0CTL1 &= ~UCSWRST; // 开启I2C
_enable_interrupts();
}

void I2C_Tx_Init()
{
_disable_interrupts();
while ((UCB0STAT & UCBUSY)||UCB0CTL1 & UCTXSTP); // 确保总线空闲
IE2 &= ~UCB0RXIE; //关闭Rx中断
I2C_State=TX_STATE;
IE2 |= UCB0TXIE; //允许Tx中断
_enable_interrupts(); // 开总中断
}

void I2C_Rx_Init()
{
_disable_interrupts();
while ((UCB0STAT & UCBUSY)||UCB0CTL1 & UCTXSTP); // 确保总线空闲
IE2 &= ~UCB0TXIE; //关闭Rx中断
I2C_State=RX_STATE;
IE2 |= UCB0RXIE; //允许Tx中断
_enable_interrupts(); // 开总中断
}

unsigned char I2C_TxFrame(unsigned char *p_Tx,unsigned char num)
{
if ((UCB0STAT & UCBUSY)||(UCB0CTL1 & UCTXSTP)) return(0);
pTxData = (unsigned char *)p_Tx; // 更新数据指针
TxByteCnt = num; // 更新剩余发送数据个数
UCB0CTL1 |= UCTR + UCTXSTT; // I2C Tx位, 软件start condition
_bis_SR_register(CPUOFF+GIE); // 进LPM0模式,开总中断
return(1);
}

unsigned char I2C_RxFrame(unsigned char *p_Rx,unsigned char num)
{
if ((UCB0STAT & UCBUSY)||(UCB0CTL1 & UCTXSTP)) return(0);
pRxData = (unsigned char *)p_Rx; // 更新数据指针
RxByteCnt= num; // 更新剩余接收数据个数
UCB0CTL1 &= ~UCTR;
UCB0CTL1 |= UCTXSTT; // I2C Rx位, 软件start condition
_bis_SR_register(CPUOFF+GIE); // 进LPM0模式,开总中断
return(1);
}
void I2C_TxFrame_ISR(void);
void I2C_RxFrame_ISR(void);

#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
_disable_interrupts(); //等同_DINT
if(I2C_State==TX_STATE) //判断是收状态还是发状态
I2C_TxFrame_ISR(); // 事件:发送帧
else
I2C_RxFrame_ISR(); // 事件:接收帧
//-------预留给主循环中唤醒CPU用途-------
if(RxByteCnt == 0 || TxByteCnt == 0) //如果没有待发送或待接收数据
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
_enable_interrupts(); //等同_ENIT
}

void I2C_TxFrame_ISR(void)
{
if (TxByteCnt) // 检查数据是否发完
{
UCB0TXBUF = *pTxData; // 装填待发送数据
pTxData++; //数据指针移位
TxByteCnt--; // 待发送数据个数递减
}
else //数据发送完毕
{
UCB0CTL1 |= UCTXSTP; // 置停止位
IFG2 &= ~UCB0TXIFG; // 人工清除标志位(由于没有写Buffer,MCU不会自动清除)
}
}

void I2C_RxFrame_ISR(void)
{
if (RxByteCnt == 1) // 只剩1字节没接收时(实际已经在RxBuff里了)
UCB0CTL1 |= UCTXSTP; // 软件产生停止位
RxByteCnt--; // 待接收字节数递减
*pRxData = UCB0RXBUF; // 存储已接收的数据
*pRxData++; //数据指针移位
}
#endif //End of Hard I2C

#ifdef SOFT_I2C //Begin of Soft I2C
#define MCLK_FREQ 1000000 // 此处填写实际时钟频率
//-----屏蔽硬件差异,对I2C的IO操作进行宏定义-----
#define I2C_CLK_HIGH P1DIR &=~BIT6;
#define I2C_CLK_LOW P1DIR |= BIT6; P1OUT &=~BIT6
#define I2C_DATA_HIGH P1DIR &=~BIT7
#define I2C_DATA_LOW P1DIR |= BIT7; P1OUT &=~BIT7
#define I2C_DATA_IN P1IN&BIT7
#define I2C_START Start()
#define I2C_STOP Stop()
//-----从机地址宏定义
#define SLAVE_ADDR 0x20 //填写实际的从机地址
#define SLAVE_ADDR_W SLAVE_ADDR<<1 //自动生成,不用修改
#define SLAVE_ADDR_R (SLAVE_ADDR<<1)+1 //自动生成,不用修改

//-----为兼容硬件I2C编写的空函数
void I2C_Tx_Init(){}
void I2C_Rx_Init(){}

static void delay_us()
{
// _delay_cycles(MCLK_FREQ/1000); //1000us延时
// _delay_cycles(MCLK_FREQ/10000); //100us延时
// _delay_cycles(MCLK_FREQ/100000); //10us延时
// _delay_cycles(MCLK_FREQ/1000000); //1us延时
}

void Start()
{
I2C_DATA_HIGH;
delay_us();
I2C_CLK_HIGH;
delay_us();
I2C_DATA_LOW;
delay_us();
I2C_CLK_LOW;
delay_us();
}

void Stop()
{
I2C_CLK_LOW;
delay_us();
I2C_DATA_LOW;
delay_us();
I2C_CLK_HIGH;
delay_us();
I2C_DATA_HIGH;
delay_us();
}

void I2C_Init()
{
P1DIR |= BIT6; //SCL管脚为输出
P1DIR &= ~BIT7; //SDA管脚为输入
I2C_CLK_LOW;
I2C_STOP;
}

void Send_Char(unsigned char data)
{
unsigned char i=0;
for(i=0;i<8;i++)
{
if((data<<i)&BIT7)
I2C_DATA_HIGH;
else
I2C_DATA_LOW;
I2C_CLK_HIGH;
delay_us();
I2C_CLK_LOW ;
delay_us();
}
//----最后1个CLK,接收从机应答位,但不作判断----
I2C_CLK_HIGH ;
delay_us();
I2C_CLK_LOW;
delay_us();
}

void Master_Ack()
{
I2C_DATA_LOW; //主机控制数据线,给0信号
delay_us();
I2C_CLK_HIGH; //主机发出应答位0
delay_us();
//-----释放总线-----
I2C_CLK_LOW;
delay_us();
I2C_DATA_HIGH;
}

unsigned char Get_Char()
{
unsigned char i=0;
unsigned char Temp=0;
I2C_DATA_HIGH;
for(i=0;i<8;i++)
{
I2C_CLK_HIGH;
delay_us();
Temp=Temp<<1;
if((I2C_DATA_IN )== BIT7) //先收高位
Temp |=BIT0;
delay_us();
I2C_CLK_LOW ;
delay_us();
}
//-----应答位-----
Master_Ack();
return(Temp);
}

unsigned char I2C_TxFrame(unsigned char *p_Tx,unsigned char num)
{
_disable_interrupts();
unsigned char i=0;
I2C_START;
Send_Char(SLAVE_ADDR_W); //先发送器件地址和写标志
for(i=0;i<num;i++) //然后依次发送各字节数据
{
Send_Char(*p_Tx);
p_Tx++;
}
I2C_STOP;
_enable_interrupts();
return 1;
}

unsigned char I2C_RxFrame(unsigned char *p_Tx,unsigned char num)
{
unsigned char i=0;
_disable_interrupts();;
I2C_START;
Send_Char(SLAVE_ADDR_R); //先发送器件地址和读标志
for(i=0;i<num;i++) //然后依次接收各个字节数据
{
*p_Tx=Get_Char();
p_Tx++;
}
I2C_STOP;
_enable_interrupts();
return 1;
}
#endif //End of Soft I2C

(5)I2C.h

#ifndef I2C_H_
#define I2C_H_
//#define HARD_I2C //编译硬件I2C代码
#define SOFT_I2C //编译软件I2C代码
extern void I2C_Init();
extern void I2C_Tx_Init();
extern void I2C_Rx_Init();
extern unsigned char I2C_TxFrame(unsigned char *p_Tx,unsigned char num);
extern unsigned char I2C_RxFrame(unsigned char *p_Tx,unsigned char num);

#endif

评论已关闭。

jQuery.adamsOverload();