打印
[STM32F1]

能否分享一下STM32F103简单的I2C寄存器操作程序???

[复制链接]
2317|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
刷新知识|  楼主 | 2016-11-21 16:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
都说I2C硬件有问题,不知道怎么配置-_-
沙发
mmuuss586| | 2016-11-21 16:51 | 只看该作者
看看本版的精华帖子,很多提供开发板厂家都分享了程序的,比如:正点原子、野火等;

使用特权

评论回复
板凳
zhuotuzi| | 2016-11-21 18:39 | 只看该作者
楼主你下载这个系列的CUBE开发包就行了,里面有的,还问,官方提供了。啊啊

使用特权

评论回复
地板
zhuotuzi| | 2016-11-21 18:39 | 只看该作者
#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=72MHZ APB1=36MHZ APB2=72MHZ PLL=72MHZ PLL2=40MHZ)
delay_init(72);//延时初始化

RCC->APB2ENR |= 1<<3; //使能PORTB时钟;
GPIOB->CRL &= 0x00FFFFFF; //PB6 I2C1_SCL ,PB7 I2C1_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)
{


}
}

使用特权

评论回复
5
zhuotuzi| | 2016-11-21 18:40 | 只看该作者
//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:标准模式的I2C 1:快速模式的I2C
//I2C1->CCR &= ~(1<<14); //快速模式时的占空比 0:Tlow/Thigh=2 1: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
}

使用特权

评论回复
6
zhuotuzi| | 2016-11-21 18:42 | 只看该作者
//向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产生停止条件
}

使用特权

评论回复
7
zhuotuzi| | 2016-11-21 18:42 | 只看该作者
//从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;
}


使用特权

评论回复
8
zhuotuzi| | 2016-11-21 18:44 | 只看该作者


/*******************************************************************************
* Function Name : I2C1_ER_IRQHandler
* Description : This function handles I2C1 Error interrupt request.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
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); //清除中断
}
}

使用特权

评论回复
9
zhuotuzi| | 2016-11-21 18:50 | 只看该作者
在网上搜集了一些源码,经过整理,调试没有问题。
硬件平台:STM32F103ZET6
开发平台:keil 4



#define I2C_EE                      I2C1

void I2C_Configuration(void)
{
    I2C_InitTypeDef  I2C_InitStructure;
    GPIO_InitTypeDef  GPIO_InitStructure;

    /* GPIOB Periph clock enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,    ENABLE); // 开启时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,     ENABLE);
   
    /* eeprom wp Control Pin set */
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_WriteBit(GPIOB, GPIO_Pin_8, Bit_RESET);        // 设置初始化态,取消保护
   
    /* PB6,7 SCL and SDA */
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;  // 复用开漏输出
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    I2C_DeInit(I2C_EE);
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;         
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 100000;       //100K速度
    I2C_Cmd(I2C_EE, ENABLE);  // 开启I2C模块
    I2C_Init(I2C_EE, &I2C_InitStructure); // 写入I2C配置
    /*允许1字节1应答模式*/
    I2C_AcknowledgeConfig(I2C_EE, ENABLE);
}

void I2C_EE_Standby(void)     
{
    vu16 SR1_Tmp;
    do{
        /*起始位*/
        I2C_GenerateSTART(I2C1, ENABLE);
        /*读SR1*/
        SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);
        /*器件地址(写)*/
        I2C_Send7bitAddress(I2C1, I2C_EE_HW_ADDR, I2C_Direction_Transmitter);
    }while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));
    /**/
    I2C_ClearFlag(I2C1, I2C_FLAG_AF);
    /*停止位*/   
    I2C_GenerateSTOP(I2C1, ENABLE);
}

void I2C_EE_ByteWrite(uint16 mem_addr, uint8 dat)
{
    I2C_EE_ReadArray(&dat, mem_addr, 1);
}
/*************************************************
**函数名:I2C_EE_WriteArray
**功能:写多个字节
**注意事项:字写入同样需要调用忙判断
*************************************************/
void I2C_EE_WriteArray(uint16 mem_addr ,u8* pBuffer,u16 len)
{
    uint8 hw_addr,byte_addr;
   
    if( len == 0 )
        return;
   
    if( mem_addr >= I2C_EE_MAX_BYTE_ADDR )  return;

#ifdef _24C04_C08_C16   // 超过256字节,有分页地址
   
    if( mem_addr > 255 )    // eeprom address calc
    {
        hw_addr = I2C_EE_HW_ADDR | (uint8)(mem_addr>>7); // Set target slave address-
    }
    else
    {
        hw_addr = I2C_EE_HW_ADDR;               // Set target slave address
    }
#else

    hw_addr = I2C_EE_HW_ADDR;               // Set target slave address

#endif

    byte_addr = (uint8)mem_addr;


    /* 起始位 */
    I2C_GenerateSTART(I2C_EE, ENABLE);
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));

    /* 发送器件地址(写)*/
    I2C_Send7bitAddress(I2C_EE, hw_addr, I2C_Direction_Transmitter);
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    /*发送数据起始地址*/
    I2C_SendData(I2C_EE, byte_addr);
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    while(len)
    {
        /* 写一个字节*/
        I2C_SendData(I2C_EE, *pBuffer);
        while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
      
        pBuffer++; // 指向下一个存储空间
        len--;       // 数目调整
    }
   
    /* 停止位*/
    I2C_GenerateSTOP(I2C_EE, ENABLE);

    I2C_EE_Standby();
}

uint8 I2C_EE_ByteRead(uint16 mem_addr)
{
    uint8 recd;
    I2C_EE_ReadArray(&recd, mem_addr, 1);
    return recd;
}
/***************************************************
**函数名:I2C_ReadS
**功能:读取24C02多个字节
**注意事项:24C02是256字节,8位地址,A0-A2固定为0,从器件地址为EEPROM_ADDR
***************************************************/
void I2C_EE_ReadArray(uint8* pBuffer, uint16 mem_addr , u16 len)
{
    uint8 hw_addr,byte_addr;
   
    if( len == 0 )
        return;
   
    if( mem_addr >= I2C_EE_MAX_BYTE_ADDR )  return;

#ifdef _24C04_C08_C16   // 超过256字节,有分页地址
   
    if( mem_addr > 255 )    // eeprom address calc
    {
        hw_addr = I2C_EE_HW_ADDR | (uint8)(mem_addr>>7); // Set target slave address-
    }
    else
    {
        hw_addr = I2C_EE_HW_ADDR;               // Set target slave address
    }
#else

    hw_addr = I2C_EE_HW_ADDR;               // Set target slave address

#endif

    byte_addr = (uint8)mem_addr;

    while(I2C_GetFlagStatus(I2C_EE, I2C_FLAG_BUSY));
      
    /*允许1字节1应答模式*/
    I2C_AcknowledgeConfig(I2C_EE, ENABLE);

    /* 发送起始位 */
    I2C_GenerateSTART(I2C_EE, ENABLE);
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/

    /*发送器件地址(写)*/
    I2C_Send7bitAddress(I2C_EE,  hw_addr , I2C_Direction_Transmitter);
    while (!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    /*发送储存地址*/
    I2C_SendData(I2C_EE, byte_addr);
    while (!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_TRANSMITTED));/*数据已发送*/
      
    /*起始位*/
    I2C_GenerateSTART(I2C_EE, ENABLE);
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));
   
    /*器件读*/
    I2C_Send7bitAddress(I2C_EE, hw_addr, I2C_Direction_Receiver);
    while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
   
    while(len)
    {
        if(len==1)
        {
             I2C_AcknowledgeConfig(I2C_EE, DISABLE); //最后一位后要关闭应答的
         I2C_GenerateSTOP(I2C_EE, ENABLE);           //发送停止位
        }
        while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_RECEIVED)); /* EV7 */
        *pBuffer = I2C_ReceiveData(I2C_EE);
        pBuffer++; // 指向下一个存储空间
        len--;       // 数目调整
    }
    //再次允许应答模式
    I2C_AcknowledgeConfig(I2C_EE, ENABLE);
}
//  应用代码示例
void I2C_EE_Init(void)
{
    Uint8 buf[4] = {1,2,3,4};
    I2C_Configuration();
I2C_EE_WriteArray(0x0200,       buf,    4);
    I2C_EE_ReadArray(buf,           0x0200, 4);
}


使用特权

评论回复
10
zhuotuzi| | 2016-11-21 19:01 | 只看该作者
11
zhuotuzi| | 2016-11-21 19:03 | 只看该作者
纯寄存器的就很少用的了。真滴。

使用特权

评论回复
12
shuizhongyu521| | 2016-11-22 14:49 | 只看该作者
硬i2c别用了 稳定性不行

使用特权

评论回复
13
songchenping| | 2016-11-22 16:24 | 只看该作者
这种程序都烂大街了

使用特权

评论回复
14
刷新知识|  楼主 | 2016-11-22 17:57 | 只看该作者
zhuotuzi 发表于 2016-11-21 18:44
/*******************************************************************************
* Function Name : ...

谢谢!!!!!!!!!!!!!!!!!!!!!!

使用特权

评论回复
15
刷新知识|  楼主 | 2016-11-22 18:24 | 只看该作者
songchenping 发表于 2016-11-22 16:24
这种程序都烂大街了

看了很多,但是总出问题。。。。

使用特权

评论回复
16
songchenping| | 2016-11-23 08:16 | 只看该作者
刷新知识 发表于 2016-11-22 18:24
看了很多,但是总出问题。。。。

适当的时候用示波器看一下波形

使用特权

评论回复
17
刷新知识|  楼主 | 2016-11-23 10:15 | 只看该作者
songchenping 发表于 2016-11-23 08:16
适当的时候用示波器看一下波形

我竟然莫名其妙的配制出来了。。。。。。但是还是有bug。。。。

使用特权

评论回复
18
zhuotuzi| | 2016-12-4 14:22 | 只看该作者
寄存器的很少用的,不清楚,都玩库函数。

使用特权

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

本版积分规则

3

主题

8

帖子

0

粉丝