OpenEdv-开源电子网

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

iic 通讯,读写异常,麻烦有高手可以帮忙看看,谢谢!!

[复制链接]

2

主题

9

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2014-2-7
在线时间
0 小时
发表于 2014-2-7 15:14:41 | 显示全部楼层 |阅读模式

头文件如下:
 #ifndef __IIC_H__
#define __IIC_H__

#include "stm8l15x_gpio.h"

#define SCL_OUT_INIT()    GPIO_Init(GPIOC,GPIO_Pin_1,GPIO_Mode_Out_OD_Low_Fast)
#define SCL_OUT_HIGH()    GPIO_WriteBit(GPIOC,GPIO_Pin_1,SET)
#define SCL_OUT_LOW()     GPIO_WriteBit(GPIOC,GPIO_Pin_1,RESET)

#define SDA_OUT_INIT()    GPIO_Init(GPIOC,GPIO_Pin_0,GPIO_Mode_Out_OD_Low_Fast)
#define SDA_OUT_HIGH()    GPIO_WriteBit(GPIOC,GPIO_Pin_0,SET)
#define SDA_OUT_LOW()     GPIO_WriteBit(GPIOC,GPIO_Pin_0,RESET)

#define SDA_IN_INIT()     GPIO_Init(GPIOC,GPIO_Pin_0,GPIO_Mode_In_FL_No_IT)
#define SDA_IN_DATA()     GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_0)


#define IIC_HIGH  0x80
#define IIC_LOW  0

extern void iic_init();
extern  void iic_single_byte_write(unsigned char Daddr, unsigned char addr, unsigned char data);
extern unsigned char iic_single_byte_read(unsigned char Daddr, unsigned char addr);


#endif /* __IIC_H__ */


函数定义如下:

#include "IIC.h"
extern void delay(uint32_t);


//IIC初始化函数
void iic_init(){
        //初始化引脚为输出
 SCL_OUT_INIT();
 SDA_OUT_INIT();
        delay(20);
        //初始化状态为高电平
 SCL_OUT_HIGH();
 SDA_OUT_HIGH();
        delay(20);
}

//IIC起始信号
void iic_start() {
    SCL_OUT_INIT();
 SDA_OUT_INIT();

        //SDA = 1
 SDA_OUT_HIGH();
 delay(2);

        //SCL = 1
 SCL_OUT_HIGH();
 delay(2);

        //SDA = 0
 SDA_OUT_LOW();
 delay(2);

         //SCL = 0
// SCL_OUT_LOW();
// delay(2);
}

//IIC终止信号
void iic_stop() {
   SCL_OUT_INIT();
 SDA_OUT_INIT();
        //SDA = 0
 SDA_OUT_LOW();
 delay(2);

        //SCL = 1
 SCL_OUT_HIGH();
 delay(2);

        //SDA = 1
 SDA_OUT_HIGH();
 delay(2);
}

//IIC应答信号
void iic_respons(){
 
 unsigned char i=0;

 SCL_OUT_INIT();
// SDA_OUT_INIT();
 
    //SCL = 1
 SCL_OUT_HIGH();
 delay(2);

    //SDA初始化为输入
 SDA_IN_INIT();

 while((SDA_IN_DATA()==1)&& (i<250))i++;
 
 SDA_OUT_INIT();
 
    //SCL = 0
 SCL_OUT_LOW();
 delay(2);

}

//void respons()  //应答
//{ 
//uchar i; 
//scl = 1; 
//delay(); 
//while((sda==1)&&(i<250))i++;
//scl = 0; 
//delay();
//}

//void NoRespons()//不应答
//{ sda=1; 
//delay();
//scl=1;
//delay();
//scl=0;
//delay();
//}


void iic_no_respons(){
 SCL_OUT_INIT();
 SDA_OUT_INIT();


  //SDA=1
 SDA_OUT_HIGH();
 delay(2);
 
    //SCL = 1
 SCL_OUT_HIGH();
 delay(2);
 
    //SCL = 0
  SCL_OUT_LOW();
 delay(2);

}


void iic_write_byte(unsigned char data) {
 unsigned char i, temp;

 SCL_OUT_INIT();
 SDA_OUT_INIT();
 
 for (i = 0; i < 8; i++) {
  temp = data;
  temp = temp & 0x80;
  
  SCL_OUT_LOW();
  delay(2);
  
  if(IIC_HIGH == temp) {
   SDA_OUT_HIGH();
  }
  else {
   SDA_OUT_LOW();
  }
  delay(2);
  
  SCL_OUT_HIGH();
  delay(2);

  data = data<<1;
 }
        SCL_OUT_LOW();
       delay(2);
       SDA_OUT_HIGH();
        delay(2);

}


unsigned char iic_read_byte() {
 unsigned char i, temp=0, data=0;

 SCL_OUT_INIT();
 SDA_OUT_INIT();
 
 SCL_OUT_LOW();
 delay(2);
 SDA_OUT_HIGH();
 delay(2);

    //SDA初始化为输入
 SDA_IN_INIT();
    delay(2);
 
 for (i = 0; i < 8; i++) {
  SCL_OUT_HIGH();
  delay(5);
  
  temp = SDA_IN_DATA();
  data = (data << 1) | temp;
  
  SCL_OUT_LOW();
  delay(5);
 }

    //SDA重新初始化为输出
 SDA_OUT_INIT();
   delay(5);

 
 return data;
}

void iic_single_byte_write(unsigned char Daddr, unsigned char addr, unsigned char data){
   iic_start();

   iic_write_byte(Daddr);
   iic_respons();

   iic_write_byte(addr);
   iic_respons();

   iic_write_byte(data);
   iic_respons();

   iic_stop();
}


unsigned char iic_single_byte_read(unsigned char Daddr, unsigned char addr){
   unsigned char data;

   iic_start();
   iic_write_byte(Daddr);
   iic_respons();

   iic_write_byte(addr);
   iic_respons();

   iic_start();
   iic_write_byte(Daddr+1);
   iic_respons();

   data = iic_read_byte();
   iic_no_respons();

   iic_stop();

   return data;
}



当前问题是:
读取数据部分非0xff,且固定,应该可以判定读正常;
写新数据后读出的数据仍为写入前的数据,
波形均正常。麻烦有高手帮忙解决下,谢谢!!

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

17

主题

470

帖子

1

精华

高级会员

Rank: 4

积分
718
金钱
718
注册时间
2013-11-23
在线时间
0 小时
发表于 2014-2-7 16:17:15 | 显示全部楼层
数据没写进去,STM8做主机?从机是什么?仿真看看
回复 支持 反对

使用道具 举报

120

主题

7881

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12010
金钱
12010
注册时间
2013-9-10
在线时间
427 小时
发表于 2014-2-8 08:37:05 | 显示全部楼层
回复【楼主位】magni:
---------------------------------
你的写入一个字节数据的代码好像有点错误,我的是这样的,你可以参考下
u8 IIC_Write_Byte(u8 dat)
{
u8 i;
u8 iic_ack=0; //iic应答标志

IIC_SDA_OUT(); //设置成输出

for(i = 0;i < 8;i++)
{
if(dat & 0x80) IIC_SDA = 1; //判断发送位,先发送高位
else IIC_SDA = 0;

IIC_SCL = 1; //为SCL下降做准备
IIC_SCL = 0; //突变,将数据位发送过去
dat<<=1; //数据左移一位
} //字节发送完成,开始接收应答信号

IIC_SDA = 1; //释放数据线

IIC_SDA_IN(); //设置成输入

IIC_SCL = 1; //为SCL下降做准备
iic_ack |= IN_SDA; //读入应答位
IIC_SCL = 0;
return iic_ack; //返回应答信号
}
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2014-2-7
在线时间
0 小时
 楼主| 发表于 2014-2-8 08:53:57 | 显示全部楼层
回复【2楼】hechao3225:
数据没写进去,STM8做主机?从机是什么?仿真看看
---------------------------------
stm8做主机,at24c做从机,读的数据应该是正常的,写入数据失败。
回复 支持 反对

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2014-2-7
在线时间
0 小时
 楼主| 发表于 2014-2-8 09:11:03 | 显示全部楼层
回复【3楼】Badu_Space:
回复【楼主位】magni: --------------------------------- 你的写入一个字节数据的代码好像有点错误,我的是这样的,你可以参考下 u8 IIC_Write_Byte(u8 dat) { u8 i; u8 iic_ack=0; //iic应答标志 IIC_SDA_OUT(); //设置成输出 for(i = 0;i < 8;i++) { if(dat & 0x80) IIC_SDA = 1; //判断发送位,先发送高位 else IIC_SDA = 0; IIC_SCL = 1; //为SCL下降做准备 IIC_SCL = 0; //突变,将数据位发送过去 dat<<=1; //数据左移一位 } //字节发送完成,开始接收应答信号 IIC_SDA = 1; //释放数据线 IIC_SDA_IN(); //设置成输入 IIC_SC
......
---------------------------------
你好,感谢你的回复。
你能不能具体指出可能出错的地方?
是不是指数据发出的阶段需要SCL的突变才能发送数据出去呢?
我按照这个理解修改代码后,效果比原来还差,读的数据也不正确。
麻烦有空的时候给我解答下,
谢谢!!
回复 支持 反对

使用道具 举报

120

主题

7881

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12010
金钱
12010
注册时间
2013-9-10
在线时间
427 小时
发表于 2014-2-8 11:22:45 | 显示全部楼层
回复【5楼】magni:
---------------------------------
void iic_write_byte(unsigned char data)?{
?unsigned char i, temp;

?SCL_OUT_INIT();
?SDA_OUT_INIT();
?
?for (i = 0; i < 8; i++) {
??temp = data;
??temp = temp & 0x80;
??
??SCL_OUT_LOW();
??delay(2);
??
??if(IIC_HIGH == temp) {
???SDA_OUT_HIGH();
??}
??else {
???SDA_OUT_LOW();
??}
??delay(2);
??
??SCL_OUT_HIGH();
??delay(2);

??data = data<<1;
?}
??????? SCL_OUT_LOW();
?????? delay(2);
?????? SDA_OUT_HIGH();
??????? delay(2);

}
以上代码改为这样看下
void iic_write_byte(unsigned char data)?
{
unsigned char i, temp;
SCL_OUT_INIT();
SDA_OUT_INIT();

for (i = 0; i < 8; i++)
{
temp = data;
temp = temp & 0x80;

SCL_OUT_LOW();
delay(2);
if(IIC_HIGH == temp) 
{ SDA_OUT_HIGH(); }
else { SDA_OUT_LOW(); }
delay(2);
SCL_OUT_HIGH();
delay(2);
data = data<<1;
}
SCL_OUT_LOW();
// delay(2); //去掉以下三句,防止读取应答信号出错
// SDA_OUT_HIGH();
// delay(2);
}
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

120

主题

7881

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12010
金钱
12010
注册时间
2013-9-10
在线时间
427 小时
发表于 2014-2-8 11:32:33 | 显示全部楼层
回复【5楼】magni:
---------------------------------
接收函数代码改为这样看下
unsigned char iic_read_byte()
{
unsigned char i, temp=0, data=0;
// SCL_OUT_INIT(); //感觉没必要这样
// SDA_OUT_INIT();
SCL_OUT_LOW(); //置SCL低电平,允许数据改变
// delay(2);
SDA_OUT_HIGH();
// delay(2); //这个延时没必要
SDA_IN_INIT(); //SDA初始化为输入
// delay(2); //这个延时没必要

for (i = 0; i < 8; i++)
{
SCL_OUT_HIGH();
// delay(5); //这个延时可以去掉
temp = SDA_IN_DATA(); //这句改为这样好点 --> if(SDA_IN_DATA()) data |= 0x01; //收到高电平
data = (data << 1) | temp; //这句就改为 --> data <<= 1; //否则收到低电平
SCL_OUT_LOW();
// delay(5); //这个延时也可以去掉
}
//SDA重新初始化为输出
SDA_OUT_INIT();
delay(5);

return data;
}
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2014-2-7
在线时间
0 小时
 楼主| 发表于 2014-2-8 14:41:03 | 显示全部楼层
回复【7楼】Badu_Space:
---------------------------------
感谢花时间耐心回复。
完全按照你的修改意见修改完毕之后,读出以及写新数据后读出的情况和修改前基本一样。
不同点在于:
1:修改前绝大部分读出为0xff, 修改后为0xfe
2:其他数据也有类是变化。
回复 支持 反对

使用道具 举报

120

主题

7881

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12010
金钱
12010
注册时间
2013-9-10
在线时间
427 小时
发表于 2014-2-8 15:56:10 | 显示全部楼层
回复【8楼】magni:
---------------------------------
我的IIC驱动就是这样的,现在已经用在项目上了,呵呵

我的代码比你的简洁
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2014-2-7
在线时间
0 小时
 楼主| 发表于 2014-2-8 16:17:42 | 显示全部楼层
回复【9楼】Badu_Space:
回复【8楼】magni:---------------------------------我的IIC驱动就是这样的,现在已经用在项目上了,呵呵我的代码比你的简洁
---------------------------------
谢谢你的回复,
问题现在基本搞定了。
我用的是AT24C128,需要写入的地址需要注意。
即主要的问题在以下两个函数中:
void iic_single_byte_write(unsigned char Daddr, 【unsigned char addr】 unsigned char data){}

unsigned char iic_single_byte_read(unsigned char Daddr, 【unsigned int addr】){}

其他函数暂时还没有发现问题。

现在的新问题是写入的数据读出之后被左移了一位,即乘以了2,具体原因还在调查中。
回复 支持 反对

使用道具 举报

2

主题

9

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2014-2-7
在线时间
0 小时
 楼主| 发表于 2014-2-8 16:25:47 | 显示全部楼层
temp = SDA_IN_DATA(); //这句改为这样好点 --> if(SDA_IN_DATA()) data |= 0x01; //收到高电平 
data = (data << 1) | temp; //这句就改为 --> data <<= 1; //否则收到低电平 

把上述你的指出的修改,修改为我最原始的代码,读写数据正常。

感谢你的多次回复,谢谢!!
你也看看你的代码是不是存在瑕疵。
回复 支持 反对

使用道具 举报

120

主题

7881

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12010
金钱
12010
注册时间
2013-9-10
在线时间
427 小时
发表于 2014-2-8 16:56:29 | 显示全部楼层
回复【11楼】magni:
---------------------------------
没有吧,我用来操作24c02、24c32都没问题呀,还控制这PCF8563时钟芯片在运行呢
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

120

主题

7881

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12010
金钱
12010
注册时间
2013-9-10
在线时间
427 小时
发表于 2014-2-8 16:58:07 | 显示全部楼层
回复【11楼】magni:
---------------------------------
我的写字节函数
u8 IIC_Write_Byte(u8 dat)
{
u8 i;
u8 iic_ack=0; //iic应答标志

IIC_SDA_OUT(); //设置成输出

for(i = 0;i < 8;i++)
{
if(dat & 0x80) IIC_SDA = 1; //判断发送位,先发送高位
else IIC_SDA = 0;

IIC_Delay();
IIC_SCL = 1; //为SCL下降做准备
IIC_Delay();
IIC_SCL = 0; //突变,将数据位发送过去
dat<<=1; //数据左移一位
} //字节发送完成,开始接收应答信号

IIC_SDA = 1; //释放数据线

IIC_SDA_IN(); //设置成输入

IIC_Delay();
IIC_SCL = 1; //为SCL下降做准备
IIC_Delay();
iic_ack |= IN_SDA; //读入应答位
IIC_SCL = 0;
return iic_ack; //返回应答信号
}

我的读取字节函数

u8 IIC_Read_Byte(void)
{
u8 i;
u8 x=0;

IIC_SDA = 1; //首先置数据线为高电平

IIC_SDA_IN(); //设置成输入

for(i = 0;i < 8;i++)
{
x <<= 1; //读入数据,高位在前

IIC_Delay();
IIC_SCL = 1; //突变
IIC_Delay();

if(IN_SDA) x |= 0x01; //收到高电平

IIC_SCL = 0;
IIC_Delay();
} //数据接收完成
IIC_SCL = 0;

return x; //返回读取到的数据
}
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

5

主题

33

帖子

0

精华

初级会员

Rank: 2

积分
199
金钱
199
注册时间
2015-10-11
在线时间
45 小时
发表于 2016-2-19 16:22:55 | 显示全部楼层
回复 支持 反对

使用道具 举报

4

主题

8

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2016-3-30
在线时间
9 小时
发表于 2016-3-31 22:53:27 | 显示全部楼层
学习了
回复 支持 反对

使用道具 举报

30

主题

705

帖子

1

精华

新手上路

积分
21
金钱
21
注册时间
2013-3-14
在线时间
52 小时
发表于 2016-4-1 14:39:04 | 显示全部楼层
试试我写的这个吧。我这个亲测能用哦。

stm8_虚拟IIC.rar

2.59 KB, 阅读权限: 10, 下载次数: 41

iic

原子哥是不是又要出黑科技了呀。^_^...
回复 支持 反对

使用道具 举报

2

主题

6

帖子

0

精华

新手上路

积分
45
金钱
45
注册时间
2017-8-28
在线时间
6 小时
发表于 2017-8-28 17:39:14 | 显示全部楼层
fanghuiopenedv 发表于 2016-4-1 14:39
试试我写的这个吧。我这个亲测能用哦。

延时函数发来看看
回复 支持 反对

使用道具 举报

10

主题

232

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2265
金钱
2265
注册时间
2012-8-24
在线时间
246 小时
发表于 2017-8-28 20:15:50 | 显示全部楼层
用示波器看一下波形
单片机技术交流请加127034610
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-6-26 07:58

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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