这样会不会比较好看一些
I2C.c
#include"MSP430G2553.h"
#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 //自动生成,不用修改
#define SLAVE_ADDR_PW (SLAVE_ADDR+1)<<1 //自动生成,不用修改
#define SLAVE_ADDR_PR ((SLAVE_ADDR+1)<<1)+1 //自动生成,不用修改
//-----为兼容硬件I2C编写的空函数
void I2C_Tx_Init(){}
void I2C_Rx_Init(){}
/******************************************************************************************************
* 名 称:delay_us()
* 功 能:us级精确延时
* 入口参数:无
* 出口参数:无
* 说 明:实际延时值与CPU时钟频率有关,所以使用了MCLK_FREQ宏定义实现自动调整
* 不同的I2C设备的速度不一样,并不一定遵守100kHz和400kHz的规范。所以延时
* 参数可视情况添加。
* 范 例:无
******************************************************************************************************/
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延时
}
/******************************************************************************************************
* 名 称:Start()
* 功 能:模拟I2C的起始位
* 入口参数:无
* 出口参数:无
* 说 明:无
* 范 例:无
******************************************************************************************************/
void Start()
{
I2C_DATA_HIGH;
delay_us();
I2C_CLK_HIGH;
delay_us();
I2C_DATA_LOW;
delay_us();
I2C_CLK_LOW;
delay_us();
}
/******************************************************************************************************
* 名 称:Stop()
* 功 能:模拟I2C的停止位
* 入口参数:无
* 出口参数:无
* 说 明:无
* 范 例:无
******************************************************************************************************/
void Stop()
{
I2C_CLK_LOW;
delay_us();
I2C_DATA_LOW;
delay_us();
I2C_CLK_HIGH;
delay_us();
I2C_DATA_HIGH;
delay_us();
}
/******************************************************************************************************
* 名 称:I2C_Init()
* 功 能:兼容硬件I2C的格式,给一个初始化函数
* 入口参数:无
* 出口参数:无
* 说 明:无
* 范 例:无
******************************************************************************************************/
void I2C_Init()
{
P1DIR |= BIT6; //SCL管脚为输出
P1DIR &= ~BIT7; //SDA管脚为输入
I2C_CLK_LOW;
I2C_STOP;
}
/******************************************************************************************************
* 名 称:Send_Char()
* 功 能:主机向从机发送1个字节数据
* 入口参数:无
* 出口参数:无
* 说 明:发完了8位后,从机有一个应答位。
* 范 例:无
******************************************************************************************************/
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();
}
/******************************************************************************************************
* 名 称: Master_Ack()
* 功 能:主机的接收应答
* 入口参数:无
* 出口参数:无
* 说 明:当主机接收完从机8个字节数据后,主机要控制数据线发出0应答信号。之后再释放总线。
* 范 例:无
******************************************************************************************************/
void Master_Ack()
{
I2C_DATA_LOW; //主机控制数据线,给0信号
delay_us();
I2C_CLK_HIGH; //主机发出应答位0
delay_us();
//-----释放总线-----
I2C_CLK_LOW;
delay_us();
I2C_DATA_HIGH;
}
/******************************************************************************************************
* 名 称:Get_Char()
* 功 能:主机接收从机1个字节数据
* 入口参数:无
* 出口参数:无
* 说 明:接受完最后一位数据后,主机要给出应答位
* 范 例:无
******************************************************************************************************/
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);
}
/******************************************************************************************************
* 名 称:I2C_TxFrame(unsigned char *p_Tx,unsigned char num)
* 功 能:主机发送若干字节的1帧数据
* 入口参数:无
* 出口参数:无
* 说 明:无
* 范 例:无
******************************************************************************************************/
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_TxFrame_P(unsigned char *p_Tx,unsigned char num)
{
_disable_interrupts();
unsigned char i=0;
I2C_START;
Send_Char(0x42); //先发送器件地址和写标志
for(i=0;i<num;i++) //然后依次发送各字节数据
{
Send_Char(*p_Tx);
p_Tx++;
}
I2C_STOP;
_enable_interrupts();
return 1;
}
/******************************************************************************************************
* 名 称:I2C_RxFrame(unsigned char *p_Tx,unsigned char num)
* 功 能:主机接收若干字节的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;
}
unsigned char I2C_RxFrame_P(unsigned char *p_Tx,unsigned char num)
{
unsigned char i=0;
_disable_interrupts();;
I2C_START;
Send_Char(0x43); //先发送器件地址和读标志
for(i=0;i<num;i++) //然后依次接收各个字节数据
{
*p_Tx=Get_Char();
p_Tx++;
}
I2C_STOP;
_enable_interrupts();
return 1;
}
PCF.c
#include"I2C.h"
volatile unsigned int PCF8574_InputBuffer=0;
/******************************************************************************************************
* 名 称:PCF8574_Tx_Frame()
* 功 能:给PCF8574发送一帧数据
* 入口参数:*p_Tx:待发送数据的头指针
* num:数据字节数
* 出口参数:无
* 说 明:调用底层驱动实现。发成功为止。
* 范 例:无
******************************************************************************************************/
void PCF8574_Tx_Frame(unsigned char *p_Tx,unsigned char num)
{
unsigned char temp=0;
do
{
temp=I2C_TxFrame_P(p_Tx, num);
}
while(temp==0);
}
/******************************************************************************************************
* 名 称:PCF8574_Rx_Frame()
* 功 能:从PCF8574接收一帧函数
* 入口参数: *p_Rx:待存放数据的头指针
* num:待接收字节数
* 出口参数:无
* 说 明:调用底层驱动函数实现。收成功为止。
* 范 例:无
******************************************************************************************************/
void PCF8574_Rx_Frame(unsigned char *p_Rx,unsigned char num)
{
unsigned char temp=0;
do {
temp=I2C_RxFrame_P(p_Rx, num);
}while(temp==0);
}
/******************************************************************************************************
* 名 称:PCF8574_Init()
* 功 能:PCF8574
* 入口参数:无
* 出口参数:无
* 说 明:类似读FIFO操作,但指针无需循环
* 范 例:无
******************************************************************************************************/
void PCF8574_Init()
{
__delay_cycles(10000);
I2C_Init();
I2C_Tx_Init();
}
/******************************************************************************************************
* 名 称:PinOUT()
* 功 能:I2C的Rx事件处理函数,读取UCB0RXBUF写入指定缓存数组中
* 入口参数:无
* 出口参数:无
* 说 明:类似读FIFO操作,但指针无需循环
* 范 例:无
******************************************************************************************************/
void PinOUT_P(unsigned char pin,unsigned char status)
{
static unsigned char PinW = 0xff;
unsigned char out[1] = {0};
if(pin<=7)
{
if(status == 0)
PinW &= ~(1<<pin);
else
PinW |= 1<<pin;
out[0] = PinW;
PCF8574_Tx_Frame(out,1);
}
else
{
__no_operation();
}
}
/******************************************************************************************************
* 名 称:PinIN()
* 功 能:I2C的Rx事件处理函数,读取UCB0RXBUF写入指定缓存数组中
* 入口参数:无
* 出口参数:无
* 说 明:类似读FIFO操作,但指针无需循环
* 范 例:无
******************************************************************************************************/
void PinIN_P()
{
unsigned char temp[1] = {0};
unsigned char cof[1] = {0};
cof[0] = 0x41;
PCF8574_Tx_Frame(cof,1);
I2C_Rx_Init();
PCF8574_Rx_Frame(temp,1);
PCF8574_InputBuffer = PCF8574_InputBuffer & 0x00ff;
PCF8574_InputBuffer |=(((unsigned int)temp[0])<<8 )&0xff00;
I2C_Tx_Init();
}
main.c
#include"MSP430G2553.h"
#include"TCA6416A.h"
#include"PCF8574.h"
void WDT_init();
void I2C_IODect() ; //检测事件确实发生了
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; //关狗
BCSCTL1 = CALBC1_16MHZ; /* Set DCO to 8MHz */
DCOCTL = CALDCO_16MHZ;
TCA6416A_Init(); // 初始化IO扩展口
PCF8574_Init();
//----提示初始化成功----
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);
}
}
/******************************************************************************************************
* 名 称:WDT_init()
* 功 能:初始化WDT定时中断为16ms
* 入口参数:无
* 出口参数:无
* 说 明:无
* 范 例:无
******************************************************************************************************/
void WDT_init()
{
//-----设定WDT为-----------
WDTCTL=WDT_ADLY_16;
//-----WDT中断使能----------------------
IE1 |= WDTIE;
}
/******************************************************************************************************
* 名 称:WDT_ISR()
* 功 能:WDT定时中断服务
* 入口参数:无
* 出口参数:无
* 说 明:无
* 范 例:无
******************************************************************************************************/
#pragma vector=WDT_VECTOR
__interrupt void watchdog_timer(void)
{
// PinIN();
// I2C_IODect();
__bic_SR_register_on_exit(LPM0_bits );
}
/******************************************************************************************************
* 名 称: I2C_IO10_Onclick()
* 功 能:TCA6416A的扩展IO1.0的按下事件处理函数
* 入口参数:无
* 出口参数:无
* 说 明:无
* 范 例:无
******************************************************************************************************/
void I2C_IO10_Onclick()
{
static unsigned char turn = 1;
turn ^= BIT0;
PinOUT(0,turn); //指定0号管脚输出为0&1
PinOUT(1,turn); //指定1号管脚输出为0&1
}
/******************************************************************************************************
* 名 称: I2C_IO11_Onclick()
* 功 能:TCA6416A的扩展IO1.1的按下事件处理函数
* 入口参数:无
* 出口参数:无
* 说 明:无
* 范 例:无
******************************************************************************************************/
void I2C_IO11_Onclick()
{
static unsigned char turn = 1;
turn ^= BIT0;
PinOUT(2,turn); //指定2号管脚输出为0&1
PinOUT(3,turn); //指定3号管脚输出为0&1
__delay_cycles(1000);
PinOUT_P(3,turn);
}
/******************************************************************************************************
* 名 称: I2C_IO12_Onclick()
* 功 能:TCA6416A的扩展IO1.2的按下事件处理函数
* 入口参数:无
* 出口参数:无
* 说 明:无
* 范 例:无
******************************************************************************************************/
void I2C_IO12_Onclick()
{
static unsigned char turn = 1;
turn ^= BIT0;
PinOUT(5,turn); //指定5号管脚输出为0&1
PinOUT(4,turn); //指定4号管脚输出为0&1
}
/******************************************************************************************************
* 名 称: I2C_IO13_Onclick()
* 功 能:TCA6416A的扩展IO1.3的按下事件处理函数
* 入口参数:无
* 出口参数:无
* 说 明:无
* 范 例:无
******************************************************************************************************/
void I2C_IO13_Onclick()
{
static unsigned char turn = 1;
turn ^= BIT0;
PinOUT(6,turn); //指定6号管脚输出为0&1
PinOUT(7,turn); //指定7号管脚输出为0&1
}
/******************************************************************************************************
* 名 称: I2C_IODect()
* 功 能:TCA6416A的扩展IO事件检测函数
* 入口参数:无
* 出口参数:无
* 说 明:检测具体哪个扩展IO被按下
* 范 例:无
******************************************************************************************************/
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();
}
} |