打印

新人学习MSP430G2553开发板,扩展PCF8574时遇到问题

[复制链接]
2159|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
adamxx00|  楼主 | 2015-12-16 23:44 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
使用I2C模拟时序,希望实现功能为开发板自带I2C扩展的1个按键控制点亮PCF8574外扩的1盏LED灯,PCF8574地址为0x42,SDA和SCL已经上拉,现在的问题是无法发送数据到PCF8574。

求大牛们帮助啊!! 下面是代码:



1.png (86.85 KB )

1.png

2.png (67.45 KB )

2.png

3.png (72.1 KB )

3.png

4.png (73.72 KB )

4.png

5.png (73.86 KB )

5.png

6.png (71.97 KB )

6.png

7.png (75.07 KB )

7.png

8.png (73.95 KB )

8.png

9.png (78.66 KB )

9.png

10.png (82.11 KB )

10.png

11.png (69.79 KB )

11.png

12.png (68.44 KB )

12.png

13.png (68.05 KB )

13.png

相关帖子

沙发
adamxx00|  楼主 | 2015-12-16 23:47 | 只看该作者
这样会不会比较好看一些

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();
        }
}

使用特权

评论回复
板凳
dirtwillfly| | 2015-12-17 08:02 | 只看该作者
这类问题主要是时序问题,建议用逻辑分析仪或者示波器观察一下时序

使用特权

评论回复
地板
adamxx00|  楼主 | 2015-12-17 22:40 | 只看该作者
dirtwillfly 发表于 2015-12-17 08:02
这类问题主要是时序问题,建议用逻辑分析仪或者示波器观察一下时序

已经解决了,原因是设置的频率太高,我改成1MH之后就可以了,但是这是为什么我还是不太清楚

使用特权

评论回复
5
dirtwillfly| | 2015-12-18 08:12 | 只看该作者
adamxx00 发表于 2015-12-17 22:40
已经解决了,原因是设置的频率太高,我改成1MH之后就可以了,但是这是为什么我还是不太清楚 ...

频率变了,时序也会跟着变

使用特权

评论回复
6
adamxx00|  楼主 | 2015-12-19 21:35 | 只看该作者
dirtwillfly 发表于 2015-12-18 08:12
频率变了,时序也会跟着变

嗯嗯,今天用示波器看了一下波形,确实是时序有变化,学习了,谢谢

使用特权

评论回复
7
smilingangel| | 2015-12-20 11:03 | 只看该作者
这个还是足以地址的访问与总线自身的信号传输的稳定性。

使用特权

评论回复
8
mmbs| | 2015-12-21 22:48 | 只看该作者
时序存在问题吧

使用特权

评论回复
9
mmbs| | 2015-12-21 22:48 | 只看该作者
使用单步调试。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

31

帖子

1

粉丝