OpenEdv-开源电子网

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

精英版 寄存器硬件IIC

[复制链接]

0

主题

25

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
280
金钱
280
注册时间
2019-12-26
在线时间
134 小时
发表于 2020-3-27 21:20:50 | 显示全部楼层 |阅读模式
本帖最后由 无敌是多么寂寞1 于 2020-3-27 21:28 编辑

F103的硬件IIC读写AT24C02,已经可以实现读取了,但是会时不时出现小bug,也想请大家指教
void I2C_Init(u8 ADDR)
{
        RCC->APB2ENR |=1<<3;//开启PORTB时钟
        RCC->APB1ENR |=1<<21;//开启I2C1时钟
        RCC->APB1RSTR |= 1<<21; //复位I2C1
        RCC->APB1RSTR &= ~(1<<21); //复位结束I2C1
        I2C1->CR1 |= 1<<15; //复位寄存器
        I2C1->CR1 &= ~(1<<15); //复位结束

        GPIOB->CRL &=0X00FFFFFF;//初始化PB6、PB7
        GPIOB->CRL |=0XFF000000;//复用开漏50MHZ
        
        I2C1->CR2|=36<<0;//I2C时钟频率8M
        
        I2C1->CCR |= 180<<0; //标准模式时钟控制 分频系数=PCLK1/2/f,f为想得到的频率  100KHz
        I2C1->TRISE |= 37; //最大允许SCL上升时间为1000ns,故TRISE[5:0]中必须写入(1us/(1/36)us = 36+1)
        I2C1->CCR &= ~(1<<15);//I2C主模式 0:标准模式的I2C 1:快速模式的I2C
        
        I2C1->OAR1 |= 1<<14; //必须始终由软件保持为1
        I2C1->OAR1 |=ADDR<<1;//设置地址
               
        I2C1->CR1 |=1<<0;//启用I2C
}

void I2C1_GPIO_Set(u8 mode)
{
        if(mode)
        {
                GPIOB->CRL &=0X00FFFFFF;//初始化PB6、PB7
                GPIOB->CRL |=0X33000000;//复用开漏50MHZ
                GPIOB->ODR &=~(3<<6);//强制拉低总线
                delay_us(1);
                GPIOB->ODR |=3<<6;//强制拉高总线
                delay_us(4);
        }
        else
        {
                GPIOB->CRL &=0X00FFFFFF;//初始化PB6、PB7
                GPIOB->CRL |=0XFF000000;//复用开漏50MHZ
        }
}

void I2C_WriteDate(u8 Data_Addr,u8 data)
{
        int clear;
        clear=clear;
        I2C1_GPIO_Set(I2C_GPIOPP);
        while(I2C1->SR2&(1<<1));//等待SR2.Busy=0(总线空闲)               
        I2C1->CR1 |= 1<<8; //I2C1产生起始条件
        
        I2C1_GPIO_Set(I2C_GPIOAF);
        
        while(!(I2C1->SR1&=1<<0));//等待SR1.SB=1开始位已经发送
        I2C1->SR1 &= ~(1<<10);//SR1.AF清零
        I2C1->DR = AT24C02_Addr_Write;//写入AT24C02的地址Addr,写指令,SR1.SB清零

        while(!(I2C1->SR1&=1<<1));//等待SR1.ADDR=1,从设备应答
        clear=I2C1->SR1;
        clear=I2C1->SR2;//SR1.ADDR清零
        I2C1->DR = Data_Addr;//写入字节地址

        while(!(I2C1->SR1&(1<<2)));//等待SR1.BTF=1,字节地址发送完毕
        clear=I2C1->SR1;//SR1.BTF清零
        I2C1->DR = data;//发送要写入的数据

        while(!(I2C1->SR1&(1<<2)));//数据发送完成

        I2C1->CR1 |= 1<<9; //I2C1产生停止条件
}

u8 I2C_Read_Data(u8 Data_Addr)
{
        int clear;
        clear=clear;
        while(I2C1->SR2&(1<<1)); //等待SR2.Busy=0(总线空闲)
        I2C1->CR1 |= 1<<8; //I2C1产生起始条件

        while(!(I2C1->SR1&(1<<0)));//等待SR1.SB=1开始位已经发送
        I2C1->SR1 &= ~(1<<10);//SR1.AF清零
        I2C1->DR = AT24C02_Addr_Write;//写入AT24C02的地址Addr,写指令,SR1.SB清零

        while(!(I2C1->SR1&(1<<1)));//等待SR1.ADDR=1,从设备应答
        clear=I2C1->SR1;
        clear=I2C1->SR2;//SR1.ADDR清零
        I2C1->DR = Data_Addr;//读取字节地址

        I2C1->CR1 |= 1<<8; //I2C1产生起始条件

        while(!(I2C1->SR1&(1<<0)));//等待SR1.SB=1开始位已经发送
        I2C1->SR1 &= ~(1<<10);//SR1.AF清零
        I2C1->DR = AT24C02_Addr_Read;//写入AT24C02的地址Addr,读指令,SR1.SB清零

        while(!(I2C1->SR1&(1<<1)));//等待SR1.ADDR=1,从设备应答
        clear=I2C1->SR1;
        clear=I2C1->SR2;//SR1.ADDR清零

        while(!(I2C1->SR1&(1<<6)));//等待SR1.RxNE=1,接收到数据
        I2C1->CR1 |= 1<<9; //I2C1产生停止条件
        return I2C1->DR;
}

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

使用道具 举报

15

主题

1061

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
3627
金钱
3627
注册时间
2019-8-14
在线时间
1054 小时
发表于 2020-3-27 23:02:06 | 显示全部楼层
回复 支持 反对

使用道具 举报

4

主题

12

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2019-12-26
在线时间
9 小时
发表于 2020-4-13 17:30:34 | 显示全部楼层
楼主有完整的硬件IIC寄存器代码么?比方说还有start,stop等方法
回复 支持 反对

使用道具 举报

0

主题

28

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
432
金钱
432
注册时间
2016-6-23
在线时间
66 小时
发表于 2020-12-1 08:14:52 | 显示全部楼层
硬件IIC确实有问题,我调的时候起始条件发不出来,再读EEROM的时候数据寄存器里的值都变化。硬件有问题,不稳定。
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-23 01:56

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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