打印
[STM8]

STM8 I/O口模拟I2C所读数据不正确

[复制链接]
6908|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lo_xiaohua_ve|  楼主 | 2010-4-27 16:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM8 I/O口模拟I2C

#define I2C_ERR   0
#define I2C_CRR   1
#define  I2CDataIn  1
#define  I2CDataOut 0
#define I2C_PORT  (GPIOC)
#define I2CSCL   (GPIO_PIN_7)
#define I2CSDA   (GPIO_PIN_6)

//***************************************************************
// I2C Data input/output
// 0-Output, 1-Input
//***************************************************************
void I2CDataInOut(bool InOut)
{
if(InOut)
  {
  GPIO_Init(I2C_PORT,I2CSDA,GPIO_MODE_IN_FL_NO_IT);
  }
else
  {
  GPIO_Init(I2C_PORT,I2CSDA,GPIO_MODE_OUT_OD_LOW_FAST);
  }
}
//***************************************************************
//  Send start condition
//  ensure data is high then issue a start condition
//  see also i2c_Start() macro
//***************************************************************
void I2C_Start (void)
{
GPIO_WriteHigh(I2C_PORT, I2CSDA);
_delay_5us(5);
GPIO_WriteHigh(I2C_PORT, I2CSCL);
_delay_5us(5);
GPIO_WriteLow(I2C_PORT, I2CSDA);
_delay_5us(5);
}
//***************************************************************
//   Send stop condition
//   data low-high while clock high
//***************************************************************
void I2C_Stop (void)
{
GPIO_WriteLow(I2C_PORT, I2CSDA);
_delay_5us(5);
GPIO_WriteHigh(I2C_PORT, I2CSCL);
_delay_5us(5);
GPIO_WriteHigh(I2C_PORT, I2CSDA);
}
//***************************************************************
//ROUTINE NAME : I2C_Ack
//INPUT/OUTPUT : None.
//DESCRIPTION  : Acknoledge generation from now.
//COMMENTS     : Transfer sequence = DATA, ACK.
//***************************************************************
void I2C_Rack(void)
{
GPIO_WriteLow(I2C_PORT, I2CSDA);
_delay_5us(5);
GPIO_WriteHigh(I2C_PORT, I2CSCL);
_delay_5us(5);
GPIO_WriteLow(I2C_PORT, I2CSCL);
_delay_5us(5);
}

//***************************************************************
//ROUTINE NAME : I2C_nAck
//INPUT/OUTPUT : None.
//DESCRIPTION  : Non acknoledge generation from now.
//COMMENTS     : Transfer sequence = DATA, NACK.
//***************************************************************
void I2C_nAck (void)
{
GPIO_WriteHigh(I2C_PORT, I2CSDA);
_delay_5us(5);
GPIO_WriteHigh(I2C_PORT, I2CSCL);
_delay_5us(5);
GPIO_WriteLow(I2C_PORT, I2CSCL);
_delay_5us(5);
}
//***************************************************************
//  Send a byte to the slave 写一个数据没有应答
//  return I2C_ERR OR I2C_CRR
//***************************************************************
bool SendByte(UCHAR I2cData)
{
UCHAR i;
bool I2CStatus;

for(i=0; i<8; i++)
  {
  GPIO_WriteLow(I2C_PORT, I2CSCL);
  _delay_5us(5);
  if(I2cData & 0x80)
   {GPIO_WriteHigh(I2C_PORT, I2CSDA);}
  else
   {GPIO_WriteLow(I2C_PORT, I2CSDA);}
  GPIO_WriteHigh(I2C_PORT, I2CSCL);
  _delay_5us(5);
  I2cData <<= 1;
  }
  GPIO_WriteLow(I2C_PORT, I2CSCL);
  GPIO_WriteHigh(I2C_PORT, I2CSDA);//发送完一字节,接收应答
  
  I2CDataInOut(I2CDataIn);

  GPIO_WriteHigh(I2C_PORT, I2CSCL);
  _delay_5us(5);
  if(GPIO_ReadInputPin(I2C_PORT,I2CSDA) == 0)
   {
   I2CStatus = I2C_CRR;
   }
  else
   {
   I2CStatus = I2C_ERR;
   }
  I2CDataInOut(I2CDataOut);
  return I2CStatus;
}

//***************************************************************
//ROUTINE NAME : I2Cm_RxData
//INPUT/OUTPUT : Last byte to receive flag (active high)/Received data byte.
//DESCRIPTION  : Receive a data byte.
//COMMENTS     : Transfer sequence = DATA, ACK, EV7...
//***************************************************************
UCHAR RcvByte(void)
{   
    UCHAR i;
    UCHAR ReadByte=0;
   GPIO_WriteHigh(I2C_PORT, I2CSDA);

I2CDataInOut(I2CDataIn);
_delay_5us(10);
for(i=0; i<8; i++)
  {
   ReadByte <<= 1;
   GPIO_WriteLow(I2C_PORT, I2CSCL);
   _delay_5us(5);
   GPIO_WriteHigh(I2C_PORT, I2CSCL);
   _delay_5us(5);

   if(GPIO_ReadInputPin(I2C_PORT,I2CSDA) == 1)
    {ReadByte |= 0x01;}
   _delay_5us(5);
  }  
GPIO_WriteLow(I2C_PORT, I2CSCL);
I2CDataInOut(I2CDataOut);
_delay_5us(10);
   return ReadByte;
}

/*******************************************************
  读N个数据,参数:
   wrDAdr: write device-address 写器件地址
   wordAdr: word address 读数据的寄存器地址
   rdDAdr: read device-address 读器件地址
   *pRdDat: p->read data 读数据指针
   num: number 需要读数据的个数
*******************************************************/
bool I2C_Read(UCHAR wrDAdr,UCHAR wordAdr,UCHAR *pRdDat,UCHAR num)
{
bool I2CAck;
UCHAR i=0;
UCHAR rdDAdr;
rdDAdr = wrDAdr+1; //读器件地址为写地址加1
I2C_Start();  /*启动I2C*/
_delay_5us(5);
I2CAck = SendByte(wrDAdr); /*发写器件地址*/
if(!I2CAck)
  {
   return I2C_ERR;
  }
I2CAck = SendByte(wordAdr); /*发寄存器地址*/
if(!I2CAck)
  {
   return I2C_ERR;
  }

I2C_Start();   /*重启I2C*/
  I2CAck = SendByte(rdDAdr); /*发读器件地址*/
if(!I2CAck)
  {
   return I2C_ERR;
  }
_delay_5us(5);
for(i=0;i<num-1;i++)
  {
  *(pRdDat+i) = RcvByte();
  I2C_Rack();
   }
if(i==num-1)
  {
  *(pRdDat+i) = RcvByte();
  I2C_nAck();
  }
I2C_Stop();
return I2C_CRR;
}

/*******************************************************
写N个数据,前N-1个要应答,最后一个不要应答
wrDAdr: write device-address 写器件地址
  wordAdr: word address 写数据的寄存器地址
  *pWrDat: p->write data 写数据指针
  num: number  需要写入的数据个数
*******************************************************/
bool I2C_Write(UCHAR wrDAdr,UCHAR wordAdr,UCHAR *pWrDat,UCHAR num)
{
bool I2CAck;
unsigned char i;

I2C_Start();      /*启动I2C*/
_delay_5us(5);
I2CAck = SendByte(wrDAdr); /*发写器件地址*/
if(!I2CAck)
  {
   return I2C_ERR;
  }
I2CAck = SendByte(wordAdr);  /*发要写的寄存器地址*/
if(!I2CAck)
  {
   return I2C_ERR;
  }
for(i=0;i<num-1;i++)
  {
  I2CAck = SendByte(*(pWrDat+i));
  if(!I2CAck)
   {return I2C_ERR;}
  }
if(i==num-1)
  {
  I2CAck = SendByte(*(pWrDat+num-1));
  if(!I2CAck)
   {return I2C_ERR;}
  }
I2C_Stop();
return I2CAck;
}

以上代码不知为何读出数据不正确,用示波器看我发送的器件地址,寄存器地址这些都对,器件输出的数据是0xFF,程序中读出返回的数据是0x00,弄了一天没对相当郁闷,同志们指点下
沙发
lo_xiaohua_ve|  楼主 | 2010-5-4 11:38 | 只看该作者
终于搞定了, 应该跟我的器件有关,另外if(GPIO_ReadInputPin(I2C_PORT,I2CSDA) == 1)这种不能写成==1,要直接写成if(GPIO_ReadInputPin(I2C_PORT,I2CSDA)),太郁闷了

使用特权

评论回复
板凳
shizhewen| | 2010-5-4 12:01 | 只看该作者
呵呵

使用特权

评论回复
地板
yybj| | 2010-5-4 20:43 | 只看该作者
还会有2楼所说的问题。两种写法应该是一样的呀

使用特权

评论回复
5
txcy| | 2010-5-4 20:51 | 只看该作者
有些编译器是这样的,奇怪的问题

使用特权

评论回复
6
snowdpq| | 2010-5-11 23:19 | 只看该作者
终于搞定了, 应该跟我的器件有关,另外if(GPIO_ReadInputPin(I2C_PORT,I2CSDA) == 1)这种不能写成==1,要直接写成if(GPIO_ReadInputPin(I2C_PORT,I2CSDA)),太郁闷了
lo_xiaohua_ve 发表于 2010-5-4 11:38
你去看看GPIO_ReadInputPin这个程序你就知道为什么不能这样写了,想当然的想法

使用特权

评论回复
7
IJK| | 2010-5-12 09:05 | 只看该作者
你去看看GPIO_ReadInputPin这个程序你就知道为什么不能这样写了,想当然的想法
snowdpq 发表于 2010-5-11 23:19


是的,不看、不调试,而想当然,这种做法不太好

使用特权

评论回复
8
sxmilovebb| | 2012-7-31 18:37 | 只看该作者
切,
BitStatus GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin)
{
  return ((BitStatus)(GPIOx->IDR & (uint8_t)GPIO_Pin));
}

typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus, BitStatus, BitAction;

我用==1 和用 == SET 都不行,就必须像楼主那种解决办法。
我看了函数原型,仍然不知道为什么不行
编译器 IAR FOR STM8 1.3

使用特权

评论回复
9
lo_xiaohua_ve|  楼主 | 2012-8-15 23:40 | 只看该作者
楼上可以调试跟踪看一下,ST提供的这个库函数在端口数据不问0的时候,返回的是一个不为0的任意值,所以一定不能写成“==1 和用 == SET“ ,写成 "!= RESET"就没问题。我想应该是这里的强制类型转换引起的。

使用特权

评论回复
10
捡漏王子| | 2012-8-16 09:54 | 只看该作者
楼上可以调试跟踪看一下,ST提供的这个库函数在端口数据不问0的时候,返回的是一个不为0的任意值,所以一定不能写成“==1 和用 == SET“ ,写成 "!= RESET"就没问题。我想应该是这里的强制类型转换引起的。 ...
lo_xiaohua_ve 发表于 2012-8-15 23:40
应该是的

使用特权

评论回复
11
weikezhi| | 2012-10-16 15:22 | 只看该作者
那这强制类转换有点奇怪

使用特权

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

本版积分规则

6

主题

33

帖子

1

粉丝