OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4516|回复: 7

80C51F240和5158tuner版之间用硬件i2c通信的问题

[复制链接]

2

主题

9

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2015-1-5
在线时间
0 小时
发表于 2015-1-5 10:24:53 | 显示全部楼层 |阅读模式
5金钱
最近在弄单片机的硬件i2c,tuner小板的硬件i2c有两个,i2c0和i2c1。但是80c51f340的i2c和他们又有区别,所以我将其对接的时候用i2c0写没问题,但是i2c0读的时候少了一个nack的操作(stop反而有,费解),导致每次读完操作以后下次读或者写发chipid的时候都会nack。现在连i2c1发完chipid给个nack都死机了,我真的无力了,求助,下面是时序图和程序
C8051F340的时序是
write:
    start| chipid(7:1)+write(写0) | Ack | address(7:0) | Ack | data(7:0) | Ack | stop;
read:
    start | chipid(7:1)+write(写0) | Ack | address(7:0) | Ack | Restart | chipid(7:1)+read(写1) | Ack | data(7:0) | Nack;
    start | chipid(7:1)+write(写0) | Ack | address(7:0) | Ack | Restart | chipid(7:1)+read(写1) | Ack | data1(7:0) | Ack | data2(7:0) | Ack |……| dataN(7:0) | Nack;
而5158的是这样的
I2c0:
    
I2c1:


#include "c8051f340.h"
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define chip5158_I2C0 0xC4    //Device address for slave 5158_chip in i2c0
#define chip5158_I2C1 0xC2    //Device address for slave 5158_chip in i2c1
#define SYSCLS 12000000
//#define SMB_FQ 50000        //Target SCL clock rate

#define WRITE 0x00            //SMBUS WRITE command
#define READ  0x01            //SMBUS READ command
typedef struct
{
    uchar TARGET;            //从地址(读或写时要先写入它的值)
    uchar SMB_RW;
}I2C_DATA;

void Wait(int x)
{
    while(x--);
}
void SMBUS_Init()
{
    SMB0CF = 0x5D;                       // Use Timer1 overflows as SMBus clock
                                       // source;
                                       // Disable slave mode;
                                       // Enable setup & hold time extensions;
                                       // Enable SMBus Free timeout detect;
                                       // Enable SCL low timeout detect;
    SMB0CF &= ~0x80;
    SMB0CF |= 0x80;                        //Enable SMBUS
    EIE1 &= 0xFE;
    SMB0CN &= 0xCC;                //Init SMB0CN
}


void Timer1_Init(ulong SMB_FQ)
{
//    uchar SCALE;
    if ((SYSCLS/SMB_FQ/3) < 255)
    {
//        SCALE = 1;
        CKCON |= 0x08 ;
    }
    else if ((SYSCLS/SMB_FQ/3/4) < 255)//使用4分频
    {
//        SCALE = 4;
        CKCON |= 0x01;
        CKCON &= ~0x0A;
    }
    else if ((SYSCLS/SMB_FQ/3/8) < 255)//使用8分频
    {
//        SCALE = 8;
        CKCON |= 0x03;
        CKCON &= ~0x08;
    }
    else if ((SYSCLS/SMB_FQ/3/12) < 255)//使用12分频
    {
//        SCALE = 12;
        CKCON |= 0x03;
        CKCON &= ~0x0B;
    }
    else if ((SYSCLS/SMB_FQ/3/48) < 255)//使用48分频
    {
//        SCALE = 48;
        CKCON |= 0x03;
        CKCON &= ~0x09;
    }
    TMOD = 0x20;
    TH1  = 256 -(SYSCLS/SMB_FQ/3);
    TL1  = TH1;
    TR1  = 1;
}
#if 0
void Timer3_Init()
{
    TMR3CN = 0x00;        //16位时钟,低字节中断
    CKCON &= ~0x40;        //使用12分频时钟信号
    TMR3RLL = -(SYSCLS/12/40);
    TMR3L = TMR3RLL;        //25ms之后时钟3执行溢出重载
    EIE1 |= 0x80;            //时钟3中断使能
    TMR3CN |= 0x04;            //打开时钟3
}
#endif
void PORT_Init()
{
    0MDIN = 0xff;
    0MDOUT = 0x00;

    0SKIP = 0x00;

    XBR0 = 0x04;
    XBR1 = 0x40;
    0 = 0xFF;
}

void Send_Start(void)
{
    STA = 1;
    SI = 0;
}
void Send_Stop(void)
{
    STO = 1;
    SI = 0;
}
void Send_Addr(uchar target_addr,uchar smb_rw)
{
    uchar dat;
    dat = target_addr;
    dat &= 0xFE;
    dat |= smb_rw;
    SMB0DAT = dat;
    STA = 0;
    SI = 0;
}
void Send_Data(uchar dat)
{
    SMB0DAT = dat;
    SI = 0;
}
void Receive_Data()
{
    uchar dat;
    dat = SMB0DAT;
    ACK = 0;
    SI = 0;
}
void Rec_Last_Data()
{
    uchar dat;
    dat = SMB0DAT;
    ACK = 1;
    SI = 0;
}
uchar get_SMBDAT()
{
    return SMB0DAT;
}
void Reset_I2C(void)
{
    SMB0CF &= ~0x80;
    Wait(50);
    SMB0CF |= 0x80; //重启SMBUS
    SMB0CN &= 0xCC;
}
uchar Return_I2C_Status()
{
    return SI;
}

void I2c0_Write(uchar dest_addr,uint src_data)
{
//    I2C_DATA temp;
//    SPI0CN &= ~0x01;
//    temp.TARGET = chip5158_I2C0;
//    temp.SMB_RW = WRITE;
    uchar src_buf[2];
    src_buf[0] = src_data>>8;
    src_buf[1] = src_data;
    Send_Start();
    while(!Return_I2C_Status());
    Send_Addr(chip5158_I2C0,WRITE);
    while(!Return_I2C_Status());
    Send_Data(dest_addr);
    while(!Return_I2C_Status());
    Send_Data(src_buf[0]);
    while(!Return_I2C_Status());
    Send_Data(src_buf[1]);
//    STO = 1;
    while(!Return_I2C_Status());
    Send_Stop();
//    while(!Return_I2C_Status());
    Reset_I2C();
//    SPI0CN |= 0x01;
}

void I2c0_Read(uchar *dest_buf,uchar src_addr)
{
//    I2C_DATA temp;
//    SPI0CN &= ~0x01;
//    temp.TARGET = chip5158_I2C0;
//    temp.SMB_RW = WRITE;
    Send_Start();
    while(!Return_I2C_Status());
    Send_Addr(chip5158_I2C0,WRITE);

    while(!Return_I2C_Status());
    Send_Data(src_addr);

    while(!Return_I2C_Status());
    Send_Start();

    while(!Return_I2C_Status());
    Send_Addr(chip5158_I2C0,READ);

    while(!Return_I2C_Status());
    Receive_Data();

    while(!Return_I2C_Status());
    dest_buf[0] = get_SMBDAT();
    Rec_Last_Data();

    while(!Return_I2C_Status());
    dest_buf[1] = get_SMBDAT();
//    ACK = 1;
//    ACK = 1;
//    ACK = 1;
    Send_Stop();
//    while(!Return_I2C_Status());
    Reset_I2C();
//    SPI0CN |= 0x01;
}

void I2c1_Readbyte(uchar *dest_buf,ulong src_addr)
{
    uchar temp[4];
    temp[0] = (uchar)(src_addr<<1);
    temp[0] |= 0x01;                //get ADDR[6:0],1;
    temp[1] = (uchar)(src_addr>>16);//get ADDR[23:16];
    temp[2] = (uchar)(src_addr>>24);//get ADDR[31:24];
    temp[3] = (uchar)(src_addr>>7); //get ADDR[14:7];
    Send_Start();
    while(!Return_I2C_Status());
    Send_Addr(chip5158_I2C1,WRITE);

    while(!Return_I2C_Status());
    Send_Data(temp[0]);

    while(!Return_I2C_Status());
    Send_Data(temp[1]);

    while(!Return_I2C_Status());
    Send_Data(temp[2]);

    while(!Return_I2C_Status());
    Send_Data(temp[3]);

    while(!Return_I2C_Status());
    Send_Start();

    while(!Return_I2C_Status());
    Send_Addr(chip5158_I2C0,READ);

    while(!Return_I2C_Status());
    Receive_Data();

    while(!Return_I2C_Status());
    dest_buf[0] = get_SMBDAT();
    Rec_Last_Data();

    while(!Return_I2C_Status());
    dest_buf[1] = get_SMBDAT();
    Send_Stop();

    while(!Return_I2C_Status());
    Reset_I2C();
}
void I2c1_Writebyte(ulong dest_addr,uint src_data)
{
    uchar temp[4],src_buf[2];
    temp[0] = (uchar)(dest_addr<<1);
    temp[0] |= 0x01;                //get ADDR[6:0],1;
    temp[1] = (uchar)(dest_addr>>16);//get ADDR[23:16];
    temp[2] = (uchar)(dest_addr>>24);//get ADDR[31:24];
    temp[3] = (uchar)(dest_addr>>7); //get ADDR[14:7];
    src_buf[0] = src_data;
    src_buf[1] = src_data>>8;
    Send_Start();
    while(!Return_I2C_Status());
    Send_Addr(chip5158_I2C1,WRITE);

    while(!Return_I2C_Status());
    Send_Data(temp[0]);

    while(!Return_I2C_Status());
    Send_Data(temp[1]);

    while(!Return_I2C_Status());
    Send_Data(temp[2]);

    while(!Return_I2C_Status());
    Send_Data(temp[3]);

    while(!Return_I2C_Status());
    Send_Data(src_buf[0]);
    while(!Return_I2C_Status());
    Send_Data(src_buf[1]);

    while(!Return_I2C_Status());
    Send_Stop();

//    while(!Return_I2C_Status());
    Reset_I2C();
}
void I2c1_Start(void)
{
//    uchar buff[2];
//    I2c0_Write(0xea,0xccda);
//    I2c0_Write(0xea,0x69c4);
//    I2c0_Write(0xea,0xffff);
//    I2c0_Read(buff,0xea);
//    I2c0_Read(buff,0xea);
//    I2c0_Read(buff,0xea);
#if 1    
    I2c0_Write(0xe2,0xccda);
//    I2c0_Read(buff,0xe2);
    I2c0_Write(0xe4,0x69c4);
//    I2c0_Read(buff,0xe4);
    I2c0_Write(0xf6,0x0000);
//    I2c0_Read(buff,0xf6);
    I2c0_Write(0xf2,0x0000);
//    I2c0_Read(buff,0xf2);
    I2c0_Write(0xf2,0x0001);    //dsp reset
//    I2c0_Read(buff,0xf2);
#endif    
    Wait(10);
    
    I2c0_Write(0xea,0x8000);
//    I2c0_Read(buff,0xea);
    Wait(10);
}
#if 0
void I2c1_Stop()
{
    ;
}
#endif
void main(void)
{
//    char in_buff[9];
//    char out_buff[8]="ABCDEFGH";
//    uchar in_buff0[2];
    uchar in_buff1[2];
    uint out_data0=0x4142;
    uint out_data1=0x4143;
    CA0MD &= ~0x40;    //stop WDT
    OSCICN |= 0x03;        //SYSCLK为内部高频正当期输出
    RSTSRC = 0x04;        //使能丢失时钟监测器
    ORT_Init();
    Timer1_Init(30000);//Sumbus's frequence
//    Timer3_Init();
    SMBUS_Init();
    EA = 1;
    while(1)
    {
//        I2c0_Read(in_buff,0xe0);            //read 2byte from 0xe0
//        I2c0_Write(0xE2,out_data0);
//        I2c0_Read(in_buff0,0xE2);
        I2c1_Start();
        I2c1_Writebyte(0x13145210,out_data1);
        I2c1_Readbyte(in_buff1,0x13145210);
//        I2c1_Stop();
    }
}


最佳答案

查看完整内容[请看2#楼]

我去,原来程序是对的,只是因为clock太快了!!!所以不给反应啊.............谢谢了~~
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2015-1-5
在线时间
0 小时
 楼主| 发表于 2015-1-5 10:24:54 | 显示全部楼层
我去,原来程序是对的,只是因为clock太快了!!!所以不给反应啊.............谢谢了~~
回复

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2015-1-5
在线时间
0 小时
 楼主| 发表于 2015-1-5 10:34:33 | 显示全部楼层
@正点原子,原子哥,求助啊,i2c0读的时候差一个clock,最好我回nack的时候没有clock来,只有最后stop的时候有响应,这样的话对应就会出错,能不能控制clock,让它多发一个clock信号,把我的nack采集进去啊。还有,i2c1现在写的时候写入chipid就挂了..............头疼了两天了,为这个.........真的求助
回复

使用道具 举报

120

主题

7877

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12010
金钱
12010
注册时间
2013-9-10
在线时间
427 小时
发表于 2015-1-5 12:36:31 | 显示全部楼层
用模拟的路过。。。
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2015-1-5
在线时间
0 小时
 楼主| 发表于 2015-1-5 12:44:18 | 显示全部楼层
回复【3楼】八度空间:
---------------------------------
模拟的我之前用过了,没有硬件I2C来的快,我想用硬件i2c来实现,现在问题得不到解决啊,整个人都不好了...........
回复

使用道具 举报

120

主题

7877

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12010
金钱
12010
注册时间
2013-9-10
在线时间
427 小时
发表于 2015-1-5 13:27:44 | 显示全部楼层
回复【4楼】进击的小菜鸟:
---------------------------------
硬件的话不是配置好之后自己通讯的么,怎么还要多发一个clock呢
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2015-1-5
在线时间
0 小时
 楼主| 发表于 2015-1-5 15:38:12 | 显示全部楼层
回复【5楼】八度空间:
---------------------------------
clock应该是自己发的啊,我改了一下,read的时候还是少一个stop,刚才那两个read都有问题
void I2c0_Read(uchar *dest_buf,uchar src_addr)
{
// I2C_DATA temp;
// SPI0CN &= ~0x01;
// temp.TARGET = chip5158_I2C0;
// temp.SMB_RW = WRITE;
Send_Start();
while(!Return_I2C_Status());

Send_Addr(chip5158_I2C0,WRITE);
while(!Return_I2C_Status());

Send_Data(src_addr);
while(!Return_I2C_Status());

Send_Start();
while(!Return_I2C_Status());

Send_Addr(chip5158_I2C0,READ);
while(!Return_I2C_Status());
Clear_SI();

while(!Return_I2C_Status());
dest_buf[0] = Receive_Data();

while(!Return_I2C_Status());
dest_buf[1] = Rec_Last_Data();

while(!Return_I2C_Status());
// Send_Stop();

Reset_I2C();
// SPI0CN |= 0x01;
}
stop应该是5158tuner发给我的,可是不知道为什么没有,我用中断来写的时候都有的,换成现在这种写法就不行了
回复

使用道具 举报

120

主题

7877

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12010
金钱
12010
注册时间
2013-9-10
在线时间
427 小时
发表于 2015-1-5 17:50:27 | 显示全部楼层
回复【6楼】进击的小菜鸟:
---------------------------------
IIC里面,单片机永远都是主机,不管发送还是读取,停止信号是主机发出的,你不发出stop信号怎么产生,从设备只是被动接收
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 07:59

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表