OpenEdv-开源电子网

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

找不到原因

[复制链接]

25

主题

82

帖子

0

精华

高级会员

Rank: 4

积分
520
金钱
520
注册时间
2018-8-15
在线时间
85 小时
发表于 2018-8-29 17:22:08 | 显示全部楼层 |阅读模式
/* 定义I2C总线连接的GPIO端口, 用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚 */
#define EEPROM_GPIO_PORT_I2C        GPIOB                        /* GPIO端口 */
#define EEPROM_RCC_I2C_PORT         RCC_AHBPeriph_GPIOB                /* GPIO端口时钟 */
#define EEPROM_I2C_SCL_PIN                GPIO_Pin_8                        /* 连接到SCL时钟线的GPIO */
#define EEPROM_I2C_SDA_PIN                GPIO_Pin_9                        /* 连接到SDA数据线的GPIO */


/* 定义读写SCL和SDA的宏,已增加代码的可移植性和可阅读性 */
#if 0        /* 条件编译: 1 选择GPIO的库函数实现IO读写 */
        #define EEPROM_I2C_SCL_1()  GPIO_SetBits(EEPROM_GPIO_PORT_I2C, EEPROM_I2C_SCL_PIN)                /* SCL = 1 */
        #define EEPROM_I2C_SCL_0()  GPIO_ResetBits(EEPROM_GPIO_PORT_I2C, EEPROM_I2C_SCL_PIN)                /* SCL = 0 */
       
        #define EEPROM_I2C_SDA_1()  GPIO_SetBits(EEPROM_GPIO_PORT_I2C, EEPROM_I2C_SDA_PIN)                /* SDA = 1 */
        #define EEPROM_I2C_SDA_0()  GPIO_ResetBits(EEPROM_GPIO_PORT_I2C, EEPROM_I2C_SDA_PIN)                /* SDA = 0 */
       
        #define EEPROM_I2C_SDA_READ()  GPIO_ReadInputDataBit(EEPROM_GPIO_PORT_I2C, EEPROM_I2C_SDA_PIN)        /* 读SDA口线状态 */
#else        /* 这个分支选择直接寄存器操作实现IO读写 */
    /* 注意:如下写法,在IAR最高级别优化时,会被编译器错误优化 */
        #define EEPROM_I2C_SCL_1()  EEPROM_GPIO_PORT_I2C->BSRR = EEPROM_I2C_SCL_PIN                                /* SCL = 1 */
        #define EEPROM_I2C_SCL_0()  EEPROM_GPIO_PORT_I2C->BRR = EEPROM_I2C_SCL_PIN                                /* SCL = 0 */
       
        #define EEPROM_I2C_SDA_1()  EEPROM_GPIO_PORT_I2C->BSRR = EEPROM_I2C_SDA_PIN                                /* SDA = 1 */
        #define EEPROM_I2C_SDA_0()  EEPROM_GPIO_PORT_I2C->BRR = EEPROM_I2C_SDA_PIN                                /* SDA = 0 */
       
        #define EEPROM_I2C_SDA_READ()  ((EEPROM_GPIO_PORT_I2C->IDR & EEPROM_I2C_SDA_PIN) != 0)        /* 读SDA口线状态 */
#endif
void delay_us(uint32_t nus)
{
        uint32_t temp;
        SysTick->LOAD=6*nus;      //设置重装数值, 48MHZ时
        SysTick->CTRL=0X01;        //使能,减到零是无动作,采用外部时钟源
        SysTick->VAL=0;            //清零计数器
        do
        {
                temp=SysTick->CTRL;       //读取当前倒计数值
        }
        while((temp&0x01)&&(!(temp&(1<<16))));    //等待时间到达
        SysTick->CTRL=0;    //关闭计数器
        SysTick->VAL=0;        //清空计数器
}

void SDA_OUT()
{
        GPIO_InitTypeDef GPIO_InitStructure;
        RCC_AHBPeriphClockCmd(EEPROM_RCC_I2C_PORT, ENABLE);        /* 打开GPIO时钟 */

  GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SDA_PIN;                             //LED引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                      //输出模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                  //高速输出
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                     //开漏输出
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;                       //上拉
        GPIO_Init(EEPROM_GPIO_PORT_I2C, &GPIO_InitStructure);

}

void SDA_IN()
{
        GPIO_InitTypeDef GPIO_InitStructure;
        RCC_AHBPeriphClockCmd(EEPROM_RCC_I2C_PORT, ENABLE);        /* 打开GPIO时钟 */

  GPIO_InitStructure.GPIO_Pin =EEPROM_I2C_SDA_PIN;                             //LED引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;                      //输出模式
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                  //高速输出
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                     //开漏输出
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;                       //上拉
        GPIO_Init(EEPROM_GPIO_PORT_I2C, &GPIO_InitStructure);
}

void IIC_Init(void)
{                                             
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_AHBPeriphClockCmd(EEPROM_RCC_I2C_PORT, ENABLE);        /* 打开GPIO时钟 */

  GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_PIN |EEPROM_I2C_SDA_PIN;                           
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                     
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                  
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                  
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;                    
        GPIO_Init(EEPROM_GPIO_PORT_I2C, &GPIO_InitStructure);
       
        GPIO_SetBits(EEPROM_GPIO_PORT_I2C,EEPROM_I2C_SCL_PIN|EEPROM_I2C_SDA_PIN);
}


//产生IIC起始信号
void IIC_Start(void)
{
        SDA_OUT();     //sda线输出
        EEPROM_I2C_SDA_1();                    
        EEPROM_I2C_SCL_1();
        delay_us(4);
        //i2c_Delay();
        EEPROM_I2C_SDA_0();//START:when CLK is high,DATA change form high to low
        //i2c_Delay();
        delay_us(4);
        EEPROM_I2C_SCL_0();//钳住I2C总线,准备发送或接收数据
}          
//产生IIC停止信号
void IIC_Stop(void)
{
        SDA_OUT();//sda线输出
        EEPROM_I2C_SCL_0();
        EEPROM_I2C_SDA_0();//STOP:when CLK is high DATA change form low to high
//         i2c_Delay();
        delay_us(4);
        EEPROM_I2C_SCL_1();
        EEPROM_I2C_SDA_1();//发送I2C总线结束信号
//        i2c_Delay();
        delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
uint8_t IIC_Wait_Ack(void)
{
        uint8_t ucErrTime=0;
        SDA_OUT();  
        EEPROM_I2C_SDA_1();
        //i2c_Delay();
        delay_us(1);
  SDA_IN();      //SDA设置为输入       
        EEPROM_I2C_SCL_1();
        delay_us(1);
        //i2c_Delay();       
        while(EEPROM_I2C_SDA_READ())
        {
                ucErrTime++;
                if(ucErrTime>250)
                {
                        IIC_Stop();
                        return 1;
                }
        }
        EEPROM_I2C_SCL_0();//时钟输出0           
        return 0;  
}
//产生ACK应答
void IIC_Ack(void)
{
        EEPROM_I2C_SCL_0();
        SDA_OUT();
        EEPROM_I2C_SDA_0();
        //i2c_Delay();
        delay_us(2);
        EEPROM_I2C_SCL_1();
        //i2c_Delay();
        delay_us(2);
        EEPROM_I2C_SCL_0();
}
//不产生ACK应答                    
void IIC_NAck(void)
{
        EEPROM_I2C_SCL_0();
        SDA_OUT();
        EEPROM_I2C_SDA_1();
        //i2c_Delay();
        delay_us(2);
        EEPROM_I2C_SCL_1();
        //i2c_Delay();
        delay_us(2);
        EEPROM_I2C_SCL_0();
}                                                                              
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答                          
void IIC_Send_Byte(uint8_t txd)
{                        
    uint8_t t;   
                SDA_OUT();             
    EEPROM_I2C_SCL_0();//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
                if((txd&0x80)>>7)
                        EEPROM_I2C_SDA_1();
                else
                        EEPROM_I2C_SDA_0();
                txd<<=1;           
                //i2c_Delay();   //对TEA5767这三个延时都是必须的
                delay_us(2);
                EEPROM_I2C_SCL_1();
                delay_us(2);
                //i2c_Delay();
                EEPROM_I2C_SCL_0();       
                i2c_Delay();
    }         
}             
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
uint8_t IIC_Read_Byte(unsigned char ack)
{
        unsigned char i,receive=0;
        SDA_IN();//SDA设置为输入
  for(i=0;i<8;i++ )
        {
                EEPROM_I2C_SCL_0();
                //i2c_Delay();
                delay_us(2);
                EEPROM_I2C_SCL_1();
                receive<<=1;
                if(EEPROM_I2C_SDA_READ())
                        receive++;   
                delay_us(1);
                //i2c_Delay();
  }                                         
        if (!ack)
                        IIC_NAck();//发送nACK
        else
                        IIC_Ack(); //发送ACK   
        return receive;
}
这是小弟从原子哥IIC实验拷过来的程序,用在我的F030上,一直读出来的数据都是0xFF,请求各位大佬指出错在什么地方

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

使用道具 举报

25

主题

82

帖子

0

精华

高级会员

Rank: 4

积分
520
金钱
520
注册时间
2018-8-15
在线时间
85 小时
 楼主| 发表于 2018-8-31 16:41:42 | 显示全部楼层
已解决,硬件上没有上拉电阻
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-19 14:51

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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