找回密码
 立即注册

QQ登录

只需一步,快速开始

帖子
查看: 10147|回复: 1
收起左侧

STM32F103 硬件I2C成功。已验证。

[复制链接]
ID:99624 发表于 2015-12-27 04:00 | 显示全部楼层 |阅读模式
首先声明这里没有打开STM32的事件中断。本人菜鸟玩了两天I2C。
#include"stm32f10x_lib.h"
#include"stm32f10x_it.h"
#include"sys.h"


#define AT24C02_Addr_Write 0XA0;
#define AT24C02_Addr_Read(0XA0+1);


void IIC1_Init(u8 Addr);
void AT24C02_WriteByte(u8 ByteAddr,u8 Data);
int AT24C02_ReadByte(u8 ByteAddr);
int N;


int main(void)
{
Stm32_Clock_Init(9); //中断向量表映射到flash区,(SYSTEM=72MHZ AHB=72MHZAPB1=36MHZ APB2=72MHZ PLL=72MHZ PLL2=40MHZ)
delay_init(72);//延时初始化

RCC->APB2ENR |= 1<<3; //使能PORTB时钟;
GPIOB->CRL &= 0x00FFFFFF; //PB6 I2C1_SCL ,PB7I2C1_SDL
GPIOB->CRL |= 0xFF000000; //复用开漏输出
IIC1_Init(0X30);//初始化IIC1接口地址为0X30
AT24C02_WriteByte(0X02,0XAA);//向AT24C02的0X02单元写入0XAA
delay_ms(3);//延时不可小于2ms
N=AT24C02_ReadByte(0X02); //从AT24C02的0X02单元读出数据
while(1)
{


}
}




//IIC1初始化,Addr为IIC1的自身地址
void IIC1_Init(u8 Addr)
{
RCC->APB1ENR |= 1<<21; //打开I2C1时钟
RCC->APB1RSTR |= 1<<21; //复位I2C1
RCC->APB1RSTR &= ~(1<<21); //复位结束I2C1

I2C1->CR1 |= 1<<15; //复位寄存器
I2C1->CR1 &= ~(1<<15); //复位结束
//I2C模块时钟频率,2~36MHz之间
I2C1->CR2 |= 36 ; //000000:禁用 000001:禁用

I2C1->CCR &= ~(1<<15); //I2C主模式 0:标准模式的I2C1:快速模式的I2C
//I2C1->CCR &= ~(1<<14); //快速模式时的占空比 0:Tlow/Thigh=21:Tlow/Thigh=16/9 (标准模式时Tlow/Thigh=1/1)
//得到200KHZ频率
I2C1->CCR |= 90<<0;//标准模式时钟控制分频系数=PCLK1/2/f,f为想得到的频率

I2C1->TRISE |= 37;//最大允许SCL上升时间为1000ns,故TRISE[5:0]中必须写入(1us/(1/36)us =36+1)。

//I2C1->CR1 |= 1<<10;//打开ACK应答,在接收到一个字节后返回一个应答
I2C1->CR1 |= 1<<6; //广播呼叫使能
I2C1->CR1 &= ~(1<<1); //0:I2C模式1:SMBus模式


I2C1->OAR1 &= ~(1<<15);//寻址模式 1:响应10位地址0:响应7位地址
I2C1->OAR1 |= 1<<14; //必须始终由软件保持为1
I2C1->OAR1 |= Addr<<1; //设置接口地址的7~1位

//I2C1->CR2 |= 1<<10; //缓冲器中断使能
//I2C1->CR2 |= 1<<9; //事件中断使能
I2C1->CR2 |= 1<<8; //出错中断使能


I2C1->CR1 |= 1<<0; //开启I2C1
}


//向AT24C02写一个字节,ByteAddr字节地址(0~255),Data所要写入的数据
void AT24C02_WriteByte(u8 ByteAddr,u8 Data)
{
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 = ByteAddr;//写入字节地址


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产生停止条件
}


//从AT24C02读出一个字节,ByteAddr字节地址(0~255)
int AT24C02_ReadByte(u8 ByteAddr)
{
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 = ByteAddr;//写入字节地址


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;
}



void I2C1_ER_IRQHandler(void)
{
if(I2C1->SR1 & 1<<10) //应答失败
{
I2C1->SR1 &=~(1<<10); //清除中断
}

if(I2C1->SR1 & 1<<14) //超时
{
I2C1->SR1 &=~(1<<14); //清除中断
}

if(I2C1->SR1 & 1<<11) //过载/欠载
{
I2C1->SR1 &=~(1<<11); //清除中断
}

if(I2C1->SR1 & 1<<9) //仲裁丢失
{
I2C1->SR1 &=~(1<<9); //清除中断
}

if(I2C1->SR1 & 1<<8) //总线出错
{
I2C1->SR1 &=~(1<<8); //清除中断
}
}

回复

举报

ID:480096 发表于 2019-3-29 20:10 | 显示全部楼层
哥就是等的你这个代码,救了我了。我很喜欢这个代码
回复

举报

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

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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