打印

STM8S105K4的I2C问题

[复制链接]
3849|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yzjgod|  楼主 | 2010-10-18 14:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
今天用STM8的I2C,硬件的,我的初始化程序如下:

void I2C_Init(void)
{
    I2C_CR1_PE = 0;
    I2C_FREQR_FREQ = 0x01;
    I2C_TRISER_TRISE = 0x02;
    I2C_CCRL = 0x05;
    I2C_CCRH = 0x00;
    I2C_CR1_PE = 1;
    I2C_CR2_POS = 1;
}
我的时钟用的是内部的16M,发现BUSY位一直是1,不管是初始化前还是初始化后。当我不判断BUSY位的时候,直接置START,我在IO引脚上没有量出来有任何反应,而且SB位也一直是0。
请教各位高手这BUSY位一直是1是什么原因啊,是我频率和时钟有问题吗,PB4,PB5要设成开漏输出还是输入。
这两个引脚做IO用的时候没有问题
沙发
jgphu| | 2010-10-18 14:51 | 只看该作者
BUSY为1,说明此时总线有通信,你量一下SDA或者SCL的电平,是否为低电平。

I2C总线上是要有上拉电阻的。

使用特权

评论回复
板凳
jgphu| | 2010-10-18 14:52 | 只看该作者
#include "i2c.h"

#define DAT_I2C_DDR    PB.DDR.Bit5
#define DAT_I2C_CR1    PB.CR1.Bit5
#define DAT_I2C_CR2    PB.CR2.Bit5
#define DAT_I2C_ODR    PB.ODR.Bit5
#define DAT_I2C_IDR    PB.IDR.Bit5

#define SCL_I2C_DDR    PB.DDR.Bit4
#define SCL_I2C_CR1    PB.CR1.Bit4
#define SCL_I2C_CR2    PB.CR2.Bit4
#define SCL_I2C_ODR    PB.ODR.Bit4
#define SCL_I2C_IDR    PB.IDR.Bit4

/******************************************************************************
函数:i2c_delay()
功能:
说明:
******************************************************************************/
#define i2c_nop   nop()
void  i2c_delay( void )
{
nop();
nop();
nop();
}
/******************************************************************************
函数:I2C_init()
功能:I2C总线初始化,释放总路线;使总线处于空闲状态 (总线为输入)
说明:在main()函数的开始处,应当执行一次本函数
******************************************************************************/
void I2C_init(void)
{
SCL_I2C_DDR=1;
SCL_I2C_CR1=0;
SCL_I2C_CR2=0;
SCL_I2C_ODR=1;

DAT_I2C_DDR=1;
DAT_I2C_CR1=0;
DAT_I2C_CR2=0;
DAT_I2C_ODR=1;
}
/******************************************************************************
函数:i2c_start()
功能:起动IIC
说明:执行前后都是输出模式
******************************************************************************/
void I2C_Start(void)
{
SCL_I2C_ODR=1;
SCL_I2C_DDR=1;
i2c_nop;
DAT_I2C_ODR=1;
DAT_I2C_DDR=1;
i2c_delay();
DAT_I2C_ODR=0;
i2c_delay();
SCL_I2C_ODR=0;
i2c_delay();
}
/******************************************************************************
函数:i2c_start()
功能:起动IIC
说明:执行前后都是输出模式
******************************************************************************/
void I2C_Stop(void)
{
        SCL_I2C_ODR=0;
        i2c_nop;
        DAT_I2C_ODR=0;
  i2c_delay();
        SCL_I2C_ODR=1;
  i2c_delay();
        DAT_I2C_ODR=1;
  i2c_delay();
}
/******************************************************************************
函数:I2C_Write()
功能:向I2C总线写1个字节的数据
参数:dat是要写到总线上的数据
******************************************************************************/
unsigned char  I2C_Write(unsigned char dat)
{
        unsigned char n=8;
  while(n)
  {
  i2c_delay();
        if(dat&0x01)DAT_I2C_ODR=1;
        else        DAT_I2C_ODR=0;
  i2c_delay();
       
        SCL_I2C_ODR=1;
  i2c_delay();
        i2c_delay();
        dat=dat>>1;n--;
        SCL_I2C_ODR=0;
  }
  i2c_delay();
        DAT_I2C_DDR=0;
  i2c_delay();
        SCL_I2C_ODR=1;
  i2c_delay();
        n=DAT_I2C_IDR; //NACK or ACK;
        i2c_delay();
        SCL_I2C_ODR=0;
  i2c_delay();
        DAT_I2C_DDR=1;
  i2c_delay();
        return n;
}
//******************************************************************
//.................先发高位................................
unsigned char  I2C_WriteMSB(unsigned char dat)
{
        unsigned char n=8;
  while(n)
  {
  i2c_delay();
        if(dat&0x80)DAT_I2C_ODR=1;
        else        DAT_I2C_ODR=0;
  i2c_delay();
       
        SCL_I2C_ODR=1;
  i2c_delay();
        i2c_delay();
        dat=dat<<1;n--;
        SCL_I2C_ODR=0;
  }
  i2c_delay();
        DAT_I2C_DDR=0;
  i2c_delay();
        SCL_I2C_ODR=1;
  i2c_delay();
        n=DAT_I2C_IDR; //NACK or ACK;
        i2c_delay();
        SCL_I2C_ODR=0;
  i2c_delay();
        DAT_I2C_DDR=1;
  i2c_delay();
        return n;
}
/******************************************************************************
函数:I2C_Read()
功能:从从机读取1个字节的数据
返回:读取的1个字节数据
******************************************************************************/
unsigned char I2C_Read(unsigned char ack)
{
        unsigned char dat=0;
        unsigned char t = 8;
        DAT_I2C_DDR=0;
        while(t--)
        {
         dat <<= 1;
   i2c_delay();
         SCL_I2C_ODR=1;
         i2c_delay();
         if (DAT_I2C_IDR)dat+=0x01;
         i2c_delay();
         SCL_I2C_ODR=0;
         i2c_delay();
        }
        DAT_I2C_DDR=1;
        DAT_I2C_ODR=ack; //NACK or ACK
        i2c_delay();
        SCL_I2C_ODR=1;
        i2c_delay();
        i2c_delay();
        SCL_I2C_ODR=0;
        i2c_delay();
        return dat;
}

//**************************************************************************
//**************************************************************************

unsigned char I2C_R_2065(unsigned char index)
{
        unsigned char tmp;
       
        I2C_Start();
        tmp = I2C_WriteMSB(0x8a);
        if(tmp == 0)
        {
                tmp = I2C_WriteMSB(index);
                if(tmp == 0);
                {
                        I2C_Start();
                        tmp = I2C_WriteMSB(0x8b);
                        tmp = I2C_Read(1);
                        I2C_Stop();
                }
        }
       
        return tmp;
}

void I2C_W_2065(void)
{
        unsigned char tmp, i;
       
        for(i = 0; i < 47; i++)
        {
                I2C_Start();
                tmp = I2C_WriteMSB(0xec);
                if(tmp == 0)
                {
//                        tmp = I2C_WriteMSB(i2c_2065buf[i][0]);
//                        tmp = I2C_WriteMSB(i2c_2065buf[i][1]);
                        I2C_Stop();
                }
        }
       
}

使用特权

评论回复
地板
yzjgod|  楼主 | 2010-10-18 14:53 | 只看该作者
我的上拉电阻是4.7K,电平也一直是高电平

使用特权

评论回复
5
jgphu| | 2010-10-18 14:55 | 只看该作者
上面的I2C程序给你做参考

使用特权

评论回复
6
jgphu| | 2010-10-18 14:57 | 只看该作者
还有下面的
#include "iic.h"

void IIC_Init(void)
{
        UCHAR temp;
       
        CLK_PCKENR1 |= 0x01;

        I2C_FREQR |= 0x10;                  //输入外设时钟频率为1MHz
        I2C_CR1    = 0x00;                  //禁止I2C外设
        I2C_CCRH  &= ~0xcf;
        I2C_CCRL  &= ~0xff;  
  I2C_TRISER = 0x11;
        I2C_CCRL   = 0x10;
        I2C_CCRH   = 0x00;
        I2C_CR1   |= 0x01;                  //开启I2C外设
        I2C_CR2   |= 0x04;                  //当前接收字节返回应答
        I2C_CR2   &= 0x08;
        I2C_OARL   = 0x86;                  //自身地址
        I2C_OARH   = 0x40;
}

void Read_8816(UCHAR *pBuffer, UCHAR index, UCHAR NumByteToRead)
{
        UCHAR temp;

        while(I2C_SR3 & 0x02);             //等待总线空闲
        I2C_CR2 |= 0x01;                                //产生起始位
        while(!(I2C_SR1 & 0x01));          //等待START发送完
        I2C_DR = 0x8a;                     //发送8816器件地址
        while(!(I2C_SR1 & 0x02));          //等特7位器件地址发送完
        temp = I2C_SR1;
        temp = I2C_SR3;
        I2C_DR = (UCHAR)(index);
        while(!(I2C_SR1 & 0x84));
       
        I2C_CR2 |= 0x01;                                      //产生重复起始位
        while(!(I2C_SR1 & 0x01));          //等待START发送完
        I2C_DR = 0x8b;                     //读
        while(!(I2C_SR1 & 0x02));          //等特7位器件地址发送完
        temp = I2C_SR1;
        temp = I2C_SR3;
        while(NumByteToRead)                      //要读几个字节
        {
                if(NumByteToRead == 1)
                {
                        I2C_CR2 &= ~0x04;              //不返回应答
                        I2C_CR2 |= 0x02;               //产生停止位
                }
                if(I2C_SR1 & 0x40)
                {
                        temp = I2C_SR1;
                        *pBuffer = I2C_DR;
                        pBuffer++;
                        NumByteToRead--;
                }
        }
        I2C_CR2 |= 0x04;
        I2C_CR2 &= ~0x08;                  //为下一次接收使能应答
}

使用特权

评论回复
7
yzjgod|  楼主 | 2010-10-18 14:57 | 只看该作者
你有硬件I2C的程序吗,不是固件库的那种,固件库往IAR上弄感觉很是麻烦,谢谢

使用特权

评论回复
8
yzjgod|  楼主 | 2010-10-18 14:59 | 只看该作者
想问一下你的时钟是多少的,I2C_TRISER这个是怎么算出来的,我现在很是糊涂

使用特权

评论回复
9
jgphu| | 2010-10-18 15:15 | 只看该作者
I2C_TRISER表示在主模式下快速或标准模式下的最大上升时间。

例如: 标准模式中最大允许SCL上升时间为1000ns. 我的时间为16MHz(62.5ns),则这个值等于(1000/62.5)+1 = 17 = 0X11.

使用特权

评论回复
10
yzjgod|  楼主 | 2010-10-19 13:42 | 只看该作者
哎,硬件的还是没搞明白,刚用模拟的给调了一下,暂时就这样吧

使用特权

评论回复
11
jgphu| | 2010-10-19 13:46 | 只看该作者
不是吧,注释都这么清楚了。

使用特权

评论回复
12
yzjgod|  楼主 | 2010-10-19 13:53 | 只看该作者
我感觉我也很清楚,初始化,寄存器什么的都研究的差不多了,但是寄存器和IO脚标志位根本没反应,CLK_PCKENR1这个都是FF了,能想到的我都试过了,一个24C04这么简单的东西被ST搞的这么复杂,很是令人不解

使用特权

评论回复
13
yzjgod|  楼主 | 2010-10-19 13:57 | 只看该作者
贴一下我的模拟I2C程序吧,该程序局限性很大,但是时序没什么问题。

#define SET_SCL                (PB_ODR_ODR4 = 1)
#define CLR_SCL                (PB_ODR_ODR4 = 0)
#define SET_SDA                (PB_ODR_ODR5 = 1)
#define CLR_SDA                (PB_ODR_ODR5 = 0)
uc    I2C_DATA[2];

void delay_i2c(void)
{
  uc i;
    for(i = 0; i < 200; i ++)
        DOG_CLR();
}

void I2C_Init(void)
{
    SET_SCL;
    delay_i2c();
    SET_SDA;
    delay_i2c();
}

void I2C_Start(void)
{
        SET_SDA;
        delay_i2c();
        SET_SCL;
        delay_i2c();
        CLR_SDA;
        delay_i2c();
        CLR_SCL;
        delay_i2c();
}

void I2C_Stop(void)
{
        CLR_SDA;
        delay_i2c();
        SET_SCL;
        delay_i2c();
        SET_SDA;
        delay_i2c();
        delay_i2c();
        delay_i2c();
}

uc I2C_GetAck(void)
{
        uc ack;
        SET_SDA;
        delay_i2c();
        PB_DDR_DDR5 = 0;
        SET_SCL;
        delay_i2c();
        if(PB_IDR_IDR5)
                ack = 1;
        else
                ack = 0;
        PB_DDR_DDR5 = 1;
        CLR_SCL;
        delay_i2c();
        return ack;
}

void I2C_PutAck(uc ack)
{
        if(ack)
        {
                SET_SDA;
                delay_i2c();
        }
        else
        {
                CLR_SDA;
                delay_i2c();
        }
        SET_SCL;
        delay_i2c();
        CLR_SCL;
        delay_i2c();
}

void I2C_Write(uc j)
{
        uc i;
        for(i = 0; i < 8; i ++)
        {
                delay_i2c();
                if(j & 0x80)
                        SET_SDA;
                else
                        CLR_SDA;
                j <<= 1;
                delay_i2c();
                SET_SCL;
                delay_i2c();
                CLR_SCL;
        }
}

uc I2C_Read(void)
{
        uc i,j = 0;
        SET_SDA;
        PB_DDR_DDR5 = 0;
        for(i = 0; i < 8; i ++)
        {
                SET_SCL;
                delay_i2c();
                j <<= 1;
                delay_i2c();
                if(PB_IDR_IDR5)
                        j ++;
                delay_i2c();
                CLR_SCL;
                delay_i2c();
        }
        PB_DDR_DDR5 = 1;
        return j;
}

void Write_24c04(void)
{
        I2C_Start();
        I2C_Write(0xa0);
        if(I2C_GetAck())
        {
                I2C_Stop();
        }
        I2C_Write(0x00);
        if(I2C_GetAck())
        {
                I2C_Stop();
        }
        I2C_Write(0xaa);
        if(I2C_GetAck())
        {
                I2C_Stop();
        }
        I2C_Write(0x55);
        if(I2C_GetAck())
        {
                I2C_Stop();
        }
        I2C_Stop();
}

void Read_24c04(void)
{
        I2C_Start();
        I2C_Write(0xa0);
        if(I2C_GetAck())
        {
                I2C_Stop();
        }
        I2C_Write(0x00);
        if(I2C_GetAck())
        {
                I2C_Stop();
        }
        I2C_Start();
        I2C_Write(0xa1);
        if(I2C_GetAck())
        {
                I2C_Stop();
        }
        I2C_DATA[0] = I2C_Read();
        I2C_PutAck(0);
        I2C_DATA[1] = I2C_Read();
        I2C_PutAck(1);
        I2C_Stop();
}

使用特权

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

本版积分规则

239

主题

370

帖子

2

粉丝