模拟IIC通信
来源:互联网 发布:淘宝情侣装店铺排名 编辑:程序博客网 时间:2024/06/07 20:54
1.初始化I2C_MoniConfig()函数前,请先初始化SysTick_init(),以便可以使用延迟函数
************************************************************************/
#include "i2c_moni.h"
#include "systick.h"
#define I2C_PORT GPIOB
#define I2C_SCL GPIO_Pin_6
#define I2C_SDA GPIO_Pin_7
#define RCC_I2C_PORT RCC_APB2Periph_GPIOB
//控制管脚输出高低电平
#define I2C_SCL_LOW (I2C_PORT->BRR |= I2C_SCL)
#define I2C_SCL_HIGH (I2C_PORT->BSRR |= I2C_SCL)
#define I2C_SDA_LOW (I2C_PORT->BRR |= I2C_SDA)
#define I2C_SDA_HIGH (I2C_PORT->BSRR |= I2C_SDA)
//读取管脚的电平状态
#define I2C_SDA_READ (I2C_PORT->IDR & I2C_SDA)
//I2C初始化配置
void I2C_MoniConfig(void){
GPIO_InitTypeDef GPIO_initStruct;
RCC_APB2PeriphClockCmd(RCC_I2C_PORT,ENABLE);
GPIO_initStruct.GPIO_Pin = I2C_SCL|I2C_SDA;
GPIO_initStruct.GPIO_Mode = GPIO_Mode_Out_OD;//必须为通用开漏输出
GPIO_initStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(I2C_PORT,&GPIO_initStruct);
I2C_SCL_LOW;
delay_us(1);
I2C_SDA_HIGH;
delay_us(1);
}
//内部函数,判断总线是否处于空闲状态,若不是,则循环的提供SCL时钟驱动,直到从机释放SDA线
void _I2C_IsBusy(void)
{
//读取SDA线上的电平状态,若为低电平则说明总线被从机控制,若为高电平则说明总线空闲,可以准备发送开始条件
while(!I2C_SDA_READ){
I2C_SCL_LOW;
delay_us(3);
I2C_SCL_HIGH;
delay_us(3);
}
}
//产生开始信号
void I2C_Start(void){
//判断下总线是否处于空闲状态
_I2C_IsBusy();
//先让SCL中的电平为低,防止因为SCL处于高电平而使后面将SDA拉高时,可能会触发一个stop信号
I2C_SCL_LOW;
delay_us(1);
I2C_SDA_HIGH;
delay_us(1);
I2C_SCL_HIGH;
delay_us(1);
I2C_SDA_LOW;
delay_us(1);
I2C_SCL_LOW;
delay_us(1);
}
//产生结束信号
void I2C_Stop(void){
I2C_SCL_LOW;
delay_us(1);
I2C_SDA_LOW;
delay_us(1);
I2C_SCL_HIGH;
delay_us(1);
I2C_SDA_HIGH;
delay_us(1);
}
//产生应答信号或者非应答信号,ackState->为ENABLE时,则产生应答信号
void I2C_SetAck(FunctionalState ackState){
I2C_SCL_LOW;
delay_us(1);
if(ackState == ENABLE){
I2C_SDA_LOW;
delay_us(1);
}else{
I2C_SDA_HIGH;
delay_us(1);
}
I2C_SCL_HIGH;
delay_us(2);
I2C_SCL_LOW;
delay_us(1);
I2C_SDA_HIGH;
delay_us(1);
}
//获得应答信号(ENABLE)或者非应答信号(DISABLE)
FunctionalState I2C_GetAck(void){
FunctionalState ask;
I2C_SCL_HIGH;
delay_us(1);
//读取SDA线上的电平状态
if(I2C_SDA_READ){
ask = DISABLE;
}else{
ask = ENABLE;
}
I2C_SCL_LOW;
delay_us(1);
return ask;
}
//写出数据给从机,并返回应答或者非应答信号
FunctionalState MoniI2C_WriteByte(u8 data){
u8 i;
//类似移位寄存器的功能,将数据通过I/O口发送出去
for(i=0;i<8;i++){
I2C_SCL_LOW;
delay_us(1);
if(data & 0x80){
I2C_SDA_HIGH;
}else{
I2C_SDA_LOW;
}
data <<=1;
delay_us(1);
I2C_SCL_HIGH;
delay_us(2);
}
I2C_SCL_LOW;
delay_us(1);
I2C_SDA_HIGH;
delay_us(1);
return I2C_GetAck();
}
//读取从机发送的数据,并决定是应答还是非应答
u8 MoniI2C_ReadByte(FunctionalState ackState){
u8 i;
u8 data = 0x00;
//类似移位寄存器的功能,将数据从I/O口中读取进来
for(i=0;i<8;i++){
I2C_SCL_HIGH;
delay_us(1);
//先移位,后赋值
data <<=1;
if(I2C_SDA_READ){
data |= 0x01;
}
I2C_SCL_LOW;
delay_us(2);
}
//发送响应(或非响应)给MPU6050
I2C_SetAck(ackState);
return data;
}
/********************************************************
往从机中的寄存器写入一个字节的数据
*addr:设备地址
*reg:寄存器地址
*data:要写入的数据
*返回值:0为正常写入,1为写入异常
**********************************************************/
u8 MoniI2c_WriteByteToSlave(u8 addr,u8 reg,u8 data)
{
FunctionalState state;//用来记录ACK还是NACK
I2C_Start(); //产生起始信号
state = MoniI2C_WriteByte(addr<<1|0); //将从机地址和写方向写入总线
if(state == ENABLE){ //判断从机是否响应了地址
state = MoniI2C_WriteByte(reg); //将要写入数据的寄存器地址
if(state == ENABLE){
MoniI2C_WriteByte(data); //将数据发送给从机
//正常写入,产生停止信号,并返回0
I2C_Stop();
return 0;
}
}
//写入异常,产生停止信号,并返回1
I2C_Stop();
return 1;
}
/************************************************************
往从机中的寄存器写入多个数据
*addr:器件的地址
*reg:首个写入数据的寄存器地址
*len:要写入的数据的个数
*buf:要写入的数据区的首地址
*返回值:成功写入则返回0,失败则返回1
**************************************************************/
u8 MoniI2c_WriteSomeDataToSlave(u8 addr,u8 reg,u8 len,u8 *buf)
{
FunctionalState state;//用来记录ACK还是NACK
u8 i;
I2C_Start(); //产生起始信号
state = MoniI2C_WriteByte(addr<<1|0); //将从机地址和写方向写入总线
if(state == ENABLE){ //判断从机是否响应了地址,
state = MoniI2C_WriteByte(reg); //将要写入数据的首个寄存器地址发送给从机
if(state == ENABLE){
for(i=0;i<len;i++){//开始将数据区的数据都发送给从机
state = MoniI2C_WriteByte(*(buf+i)); //将数据发送给从机
if(state == DISABLE){
I2C_Stop(); //从机未应答,产生停止信号结束数据传输,并返回1
return 1;
}
}
//正常产生停止信号,返回0
I2C_Stop();
return 0;
}
}
//写入异常,产生结束信号,返回1
I2C_Stop();
return 1;
}
/********************************************************
往从机中的寄存器读取一个字节的数据
*addr:设备地址
*reg:寄存器地址
*buf:读取到的数据存储的内存区
*返回值:0为正常读取,1为读取异常
**********************************************************/
u8 MoniI2c_ReadFromSlave(u8 addr,u8 reg,u8 *buf)
{
FunctionalState state;
I2C_Start();
state = MoniI2C_WriteByte(addr<<1|0);//发送从机地址和写方向
if(state == ENABLE){
state = MoniI2C_WriteByte(reg);//发送要读取数据的寄存器的地址
if(state == ENABLE){
I2C_Start(); //发送Sr信号,
state = MoniI2C_WriteByte(addr<<1|1);//发送从机地址和读方向
if(state == ENABLE){
*buf = MoniI2C_ReadByte(DISABLE);//读取完一个数据后,向从机发送一个NACK信号,结束从机发送数据
//正常数据读取,产生停止信号,并返回0
I2C_Stop();
return 0;
}
}
}
//数据读取异常,产生stop信号,并返回1
I2C_Stop();
return 1; //数据读取失败,返回0
}
/************************************************************************
从从机中读取采样到的高8位和低8位的数据
*addr:器件的地址
*reg:要读取数据的首个数据的寄存器地址
*len:读取的数据个数
*buf:读取到的8位数据存放区的地址,即通过指针的方式将读取到的数据返回给调用者。
*返回值:成功读取则返回0,失败则返回1
*************************************************************************/
u8 MoniI2c_ReadSomeDataFromSlave(u8 addr,u8 reg,u8 len,u8 *buf)
{
FunctionalState state;
I2C_Start();
state = MoniI2C_WriteByte(addr<<1|0);//写入从机地址和写方向
if(state == ENABLE){
state = MoniI2C_WriteByte(reg);//写入要读取数据的首个寄存器的地址
if(state == ENABLE){
I2C_Start();
state = MoniI2C_WriteByte(addr<<1|1);//重新发送起始信号,转为读方向,开始读取数据
if(state == ENABLE){
while(len){
if(len==1){
*buf = MoniI2C_ReadByte(DISABLE);//当最后一个数据接收时,给从机发送一个NACK信号
}else{
*buf = MoniI2C_ReadByte(ENABLE);//当一个数据接收时,给从机发送一个ACK信号
}
len--;
buf++;
}
//数据正常读取,产生停止信号,结束此次数据的传输,并返回0
I2C_Stop();
return 0;
}
}
}
//数据读取异常,产生stop信号,结束此次数据读取
I2C_Stop();
return 1; //数据读取失败,返回1
************************************************************************/
#include "i2c_moni.h"
#include "systick.h"
#define I2C_PORT GPIOB
#define I2C_SCL GPIO_Pin_6
#define I2C_SDA GPIO_Pin_7
#define RCC_I2C_PORT RCC_APB2Periph_GPIOB
//控制管脚输出高低电平
#define I2C_SCL_LOW (I2C_PORT->BRR |= I2C_SCL)
#define I2C_SCL_HIGH (I2C_PORT->BSRR |= I2C_SCL)
#define I2C_SDA_LOW (I2C_PORT->BRR |= I2C_SDA)
#define I2C_SDA_HIGH (I2C_PORT->BSRR |= I2C_SDA)
//读取管脚的电平状态
#define I2C_SDA_READ (I2C_PORT->IDR & I2C_SDA)
//I2C初始化配置
void I2C_MoniConfig(void){
GPIO_InitTypeDef GPIO_initStruct;
RCC_APB2PeriphClockCmd(RCC_I2C_PORT,ENABLE);
GPIO_initStruct.GPIO_Pin = I2C_SCL|I2C_SDA;
GPIO_initStruct.GPIO_Mode = GPIO_Mode_Out_OD;//必须为通用开漏输出
GPIO_initStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(I2C_PORT,&GPIO_initStruct);
I2C_SCL_LOW;
delay_us(1);
I2C_SDA_HIGH;
delay_us(1);
}
//内部函数,判断总线是否处于空闲状态,若不是,则循环的提供SCL时钟驱动,直到从机释放SDA线
void _I2C_IsBusy(void)
{
//读取SDA线上的电平状态,若为低电平则说明总线被从机控制,若为高电平则说明总线空闲,可以准备发送开始条件
while(!I2C_SDA_READ){
I2C_SCL_LOW;
delay_us(3);
I2C_SCL_HIGH;
delay_us(3);
}
}
//产生开始信号
void I2C_Start(void){
//判断下总线是否处于空闲状态
_I2C_IsBusy();
//先让SCL中的电平为低,防止因为SCL处于高电平而使后面将SDA拉高时,可能会触发一个stop信号
I2C_SCL_LOW;
delay_us(1);
I2C_SDA_HIGH;
delay_us(1);
I2C_SCL_HIGH;
delay_us(1);
I2C_SDA_LOW;
delay_us(1);
I2C_SCL_LOW;
delay_us(1);
}
//产生结束信号
void I2C_Stop(void){
I2C_SCL_LOW;
delay_us(1);
I2C_SDA_LOW;
delay_us(1);
I2C_SCL_HIGH;
delay_us(1);
I2C_SDA_HIGH;
delay_us(1);
}
//产生应答信号或者非应答信号,ackState->为ENABLE时,则产生应答信号
void I2C_SetAck(FunctionalState ackState){
I2C_SCL_LOW;
delay_us(1);
if(ackState == ENABLE){
I2C_SDA_LOW;
delay_us(1);
}else{
I2C_SDA_HIGH;
delay_us(1);
}
I2C_SCL_HIGH;
delay_us(2);
I2C_SCL_LOW;
delay_us(1);
I2C_SDA_HIGH;
delay_us(1);
}
//获得应答信号(ENABLE)或者非应答信号(DISABLE)
FunctionalState I2C_GetAck(void){
FunctionalState ask;
I2C_SCL_HIGH;
delay_us(1);
//读取SDA线上的电平状态
if(I2C_SDA_READ){
ask = DISABLE;
}else{
ask = ENABLE;
}
I2C_SCL_LOW;
delay_us(1);
return ask;
}
//写出数据给从机,并返回应答或者非应答信号
FunctionalState MoniI2C_WriteByte(u8 data){
u8 i;
//类似移位寄存器的功能,将数据通过I/O口发送出去
for(i=0;i<8;i++){
I2C_SCL_LOW;
delay_us(1);
if(data & 0x80){
I2C_SDA_HIGH;
}else{
I2C_SDA_LOW;
}
data <<=1;
delay_us(1);
I2C_SCL_HIGH;
delay_us(2);
}
I2C_SCL_LOW;
delay_us(1);
I2C_SDA_HIGH;
delay_us(1);
return I2C_GetAck();
}
//读取从机发送的数据,并决定是应答还是非应答
u8 MoniI2C_ReadByte(FunctionalState ackState){
u8 i;
u8 data = 0x00;
//类似移位寄存器的功能,将数据从I/O口中读取进来
for(i=0;i<8;i++){
I2C_SCL_HIGH;
delay_us(1);
//先移位,后赋值
data <<=1;
if(I2C_SDA_READ){
data |= 0x01;
}
I2C_SCL_LOW;
delay_us(2);
}
//发送响应(或非响应)给MPU6050
I2C_SetAck(ackState);
return data;
}
/********************************************************
往从机中的寄存器写入一个字节的数据
*addr:设备地址
*reg:寄存器地址
*data:要写入的数据
*返回值:0为正常写入,1为写入异常
**********************************************************/
u8 MoniI2c_WriteByteToSlave(u8 addr,u8 reg,u8 data)
{
FunctionalState state;//用来记录ACK还是NACK
I2C_Start(); //产生起始信号
state = MoniI2C_WriteByte(addr<<1|0); //将从机地址和写方向写入总线
if(state == ENABLE){ //判断从机是否响应了地址
state = MoniI2C_WriteByte(reg); //将要写入数据的寄存器地址
if(state == ENABLE){
MoniI2C_WriteByte(data); //将数据发送给从机
//正常写入,产生停止信号,并返回0
I2C_Stop();
return 0;
}
}
//写入异常,产生停止信号,并返回1
I2C_Stop();
return 1;
}
/************************************************************
往从机中的寄存器写入多个数据
*addr:器件的地址
*reg:首个写入数据的寄存器地址
*len:要写入的数据的个数
*buf:要写入的数据区的首地址
*返回值:成功写入则返回0,失败则返回1
**************************************************************/
u8 MoniI2c_WriteSomeDataToSlave(u8 addr,u8 reg,u8 len,u8 *buf)
{
FunctionalState state;//用来记录ACK还是NACK
u8 i;
I2C_Start(); //产生起始信号
state = MoniI2C_WriteByte(addr<<1|0); //将从机地址和写方向写入总线
if(state == ENABLE){ //判断从机是否响应了地址,
state = MoniI2C_WriteByte(reg); //将要写入数据的首个寄存器地址发送给从机
if(state == ENABLE){
for(i=0;i<len;i++){//开始将数据区的数据都发送给从机
state = MoniI2C_WriteByte(*(buf+i)); //将数据发送给从机
if(state == DISABLE){
I2C_Stop(); //从机未应答,产生停止信号结束数据传输,并返回1
return 1;
}
}
//正常产生停止信号,返回0
I2C_Stop();
return 0;
}
}
//写入异常,产生结束信号,返回1
I2C_Stop();
return 1;
}
/********************************************************
往从机中的寄存器读取一个字节的数据
*addr:设备地址
*reg:寄存器地址
*buf:读取到的数据存储的内存区
*返回值:0为正常读取,1为读取异常
**********************************************************/
u8 MoniI2c_ReadFromSlave(u8 addr,u8 reg,u8 *buf)
{
FunctionalState state;
I2C_Start();
state = MoniI2C_WriteByte(addr<<1|0);//发送从机地址和写方向
if(state == ENABLE){
state = MoniI2C_WriteByte(reg);//发送要读取数据的寄存器的地址
if(state == ENABLE){
I2C_Start(); //发送Sr信号,
state = MoniI2C_WriteByte(addr<<1|1);//发送从机地址和读方向
if(state == ENABLE){
*buf = MoniI2C_ReadByte(DISABLE);//读取完一个数据后,向从机发送一个NACK信号,结束从机发送数据
//正常数据读取,产生停止信号,并返回0
I2C_Stop();
return 0;
}
}
}
//数据读取异常,产生stop信号,并返回1
I2C_Stop();
return 1; //数据读取失败,返回0
}
/************************************************************************
从从机中读取采样到的高8位和低8位的数据
*addr:器件的地址
*reg:要读取数据的首个数据的寄存器地址
*len:读取的数据个数
*buf:读取到的8位数据存放区的地址,即通过指针的方式将读取到的数据返回给调用者。
*返回值:成功读取则返回0,失败则返回1
*************************************************************************/
u8 MoniI2c_ReadSomeDataFromSlave(u8 addr,u8 reg,u8 len,u8 *buf)
{
FunctionalState state;
I2C_Start();
state = MoniI2C_WriteByte(addr<<1|0);//写入从机地址和写方向
if(state == ENABLE){
state = MoniI2C_WriteByte(reg);//写入要读取数据的首个寄存器的地址
if(state == ENABLE){
I2C_Start();
state = MoniI2C_WriteByte(addr<<1|1);//重新发送起始信号,转为读方向,开始读取数据
if(state == ENABLE){
while(len){
if(len==1){
*buf = MoniI2C_ReadByte(DISABLE);//当最后一个数据接收时,给从机发送一个NACK信号
}else{
*buf = MoniI2C_ReadByte(ENABLE);//当一个数据接收时,给从机发送一个ACK信号
}
len--;
buf++;
}
//数据正常读取,产生停止信号,结束此次数据的传输,并返回0
I2C_Stop();
return 0;
}
}
}
//数据读取异常,产生stop信号,结束此次数据读取
I2C_Stop();
return 1; //数据读取失败,返回1
}
//i2c_moni.h文件
#ifndef __I2C_MONI_H
#define __I2C_MONI_H
#include "stm32f10x.h"
void I2C_MoniConfig(void);
void I2C_Start(void);
void I2C_Stop(void);
FunctionalState MoniI2C_WriteByte(u8 data);
u8 MoniI2C_ReadByte(FunctionalState ackState);
u8 MoniI2c_WriteByteToSlave(u8 addr,u8 reg,u8 data);
u8 MoniI2c_WriteSomeDataToSlave(u8 addr,u8 reg,u8 len,u8 *buf);
u8 MoniI2c_ReadFromSlave(u8 addr,u8 reg,u8 *buf);
u8 MoniI2c_ReadSomeDataFromSlave(u8 addr,u8 reg,u8 len,u8 *buf);
#endif
阅读全文
0 0
- 模拟IIC通信
- GPIO口模拟IIC通信
- STM32硬件IIC与51模拟IIC通信
- 模拟IIC通信(没有用应答)
- 模拟IIC
- IIC通信
- IIC通信
- IIC通信
- 单片机模拟 IIC 总线与 EEPROM(AT24C02)通信
- 蓝牙BLE基础:CC2541通信系列之模拟IIC协议
- 标准IIC和IO口模拟IIC之间的主从机通信区别
- i/o 模拟IIC
- 模拟IIC协议
- C语言模拟IIC
- 模拟IIC移植
- STM32模拟 IIC
- linux模拟iic代码
- STM32软件模拟IIC
- 第八周项目4-稀疏矩阵的三元组表示的实现及应用
- Dgital Image Processing hm2
- 树链剖分 树
- 【机器学习】强化学习总结
- Dubbo扩展:Dubbox
- 模拟IIC通信
- Vue-router 切换组件页面时进入进出动画
- 九度oj 1005 Graduate Admission
- LaTex(PART XV)figure
- 古文觀止卷九_賀進士王參元失火書_柳宗元
- 如何整理知识体系
- windows10+GeForce940M+cuda8.0+Anaconda3.4.2.0 + tensorflow-gpu(0.12.0rcl)安装教程
- spring-tools:在STS中安装部署Spring Roo2.0.RELEASE
- 底部快速butto