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

[复制链接]
2739|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)
{


}
}

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
}

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


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); //清除中断
}
}

zhuotuzi 发表于 2016-11-21 18:50 | 显示全部楼层
在网上搜集了一些源码,经过整理,调试没有问题。
硬件平台:STM32F103ZET6
开发平台:keil 4



  1. #define I2C_EE                      I2C1

  2. void I2C_Configuration(void)
  3. {
  4.     I2C_InitTypeDef  I2C_InitStructure;
  5.     GPIO_InitTypeDef  GPIO_InitStructure;

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

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

  34. void I2C_EE_Standby(void)     
  35. {
  36.     vu16 SR1_Tmp;
  37.     do{
  38.         /*起始位*/
  39.         I2C_GenerateSTART(I2C1, ENABLE);
  40.         /*读SR1*/
  41.         SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);
  42.         /*器件地址(写)*/
  43.         I2C_Send7bitAddress(I2C1, I2C_EE_HW_ADDR, I2C_Direction_Transmitter);
  44.     }while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));
  45.     /**/
  46.     I2C_ClearFlag(I2C1, I2C_FLAG_AF);
  47.     /*停止位*/   
  48.     I2C_GenerateSTOP(I2C1, ENABLE);
  49. }

  50. void I2C_EE_ByteWrite(uint16 mem_addr, uint8 dat)
  51. {
  52.     I2C_EE_ReadArray(&dat, mem_addr, 1);
  53. }
  54. /*************************************************
  55. **函数名:I2C_EE_WriteArray
  56. **功能:写多个字节
  57. **注意事项:字写入同样需要调用忙判断
  58. *************************************************/
  59. void I2C_EE_WriteArray(uint16 mem_addr ,u8* pBuffer,u16 len)
  60. {
  61.     uint8 hw_addr,byte_addr;
  62.    
  63.     if( len == 0 )
  64.         return;
  65.    
  66.     if( mem_addr >= I2C_EE_MAX_BYTE_ADDR )  return;

  67. #ifdef _24C04_C08_C16   // 超过256字节,有分页地址
  68.    
  69.     if( mem_addr > 255 )    // eeprom address calc
  70.     {
  71.         hw_addr = I2C_EE_HW_ADDR | (uint8)(mem_addr>>7); // Set target slave address-
  72.     }
  73.     else
  74.     {
  75.         hw_addr = I2C_EE_HW_ADDR;               // Set target slave address
  76.     }
  77. #else

  78.     hw_addr = I2C_EE_HW_ADDR;               // Set target slave address

  79. #endif

  80.     byte_addr = (uint8)mem_addr;


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

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

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

  90.     while(len)
  91.     {
  92.         /* 写一个字节*/
  93.         I2C_SendData(I2C_EE, *pBuffer);
  94.         while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
  95.       
  96.         pBuffer++; // 指向下一个存储空间
  97.         len--;       // 数目调整
  98.     }
  99.    
  100.     /* 停止位*/
  101.     I2C_GenerateSTOP(I2C_EE, ENABLE);

  102.     I2C_EE_Standby();
  103. }

  104. uint8 I2C_EE_ByteRead(uint16 mem_addr)
  105. {
  106.     uint8 recd;
  107.     I2C_EE_ReadArray(&recd, mem_addr, 1);
  108.     return recd;
  109. }
  110. /***************************************************
  111. **函数名:I2C_ReadS
  112. **功能:读取24C02多个字节
  113. **注意事项:24C02是256字节,8位地址,A0-A2固定为0,从器件地址为EEPROM_ADDR
  114. ***************************************************/
  115. void I2C_EE_ReadArray(uint8* pBuffer, uint16 mem_addr , u16 len)
  116. {
  117.     uint8 hw_addr,byte_addr;
  118.    
  119.     if( len == 0 )
  120.         return;
  121.    
  122.     if( mem_addr >= I2C_EE_MAX_BYTE_ADDR )  return;

  123. #ifdef _24C04_C08_C16   // 超过256字节,有分页地址
  124.    
  125.     if( mem_addr > 255 )    // eeprom address calc
  126.     {
  127.         hw_addr = I2C_EE_HW_ADDR | (uint8)(mem_addr>>7); // Set target slave address-
  128.     }
  129.     else
  130.     {
  131.         hw_addr = I2C_EE_HW_ADDR;               // Set target slave address
  132.     }
  133. #else

  134.     hw_addr = I2C_EE_HW_ADDR;               // Set target slave address

  135. #endif

  136.     byte_addr = (uint8)mem_addr;

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

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

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

  147.     /*发送储存地址*/
  148.     I2C_SendData(I2C_EE, byte_addr);
  149.     while (!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_TRANSMITTED));/*数据已发送*/
  150.       
  151.     /*起始位*/
  152.     I2C_GenerateSTART(I2C_EE, ENABLE);
  153.     while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_MODE_SELECT));
  154.    
  155.     /*器件读*/
  156.     I2C_Send7bitAddress(I2C_EE, hw_addr, I2C_Direction_Receiver);
  157.     while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
  158.    
  159.     while(len)
  160.     {
  161.         if(len==1)
  162.         {
  163.              I2C_AcknowledgeConfig(I2C_EE, DISABLE); //最后一位后要关闭应答的
  164.          I2C_GenerateSTOP(I2C_EE, ENABLE);           //发送停止位
  165.         }
  166.         while(!I2C_CheckEvent(I2C_EE, I2C_EVENT_MASTER_BYTE_RECEIVED)); /* EV7 */
  167.         *pBuffer = I2C_ReceiveData(I2C_EE);
  168.         pBuffer++; // 指向下一个存储空间
  169.         len--;       // 数目调整
  170.     }
  171.     //再次允许应答模式
  172.     I2C_AcknowledgeConfig(I2C_EE, ENABLE);
  173. }
  174. //  应用代码示例
  175. void I2C_EE_Init(void)
  176. {
  177.     Uint8 buf[4] = {1,2,3,4};
  178.     I2C_Configuration();
  179. I2C_EE_WriteArray(0x0200,       buf,    4);
  180.     I2C_EE_ReadArray(buf,           0x0200, 4);
  181. }


zhuotuzi 发表于 2016-11-21 19:01 | 显示全部楼层
zhuotuzi 发表于 2016-11-21 19:03 | 显示全部楼层
纯寄存器的就很少用的了。真滴。
shuizhongyu521 发表于 2016-11-22 14:49 | 显示全部楼层
硬i2c别用了 稳定性不行
songchenping 发表于 2016-11-22 16:24 | 显示全部楼层
这种程序都烂大街了
 楼主| 刷新知识 发表于 2016-11-22 17:57 | 显示全部楼层
zhuotuzi 发表于 2016-11-21 18:44
/*******************************************************************************
* Function Name : ...

谢谢!!!!!!!!!!!!!!!!!!!!!!
 楼主| 刷新知识 发表于 2016-11-22 18:24 | 显示全部楼层
songchenping 发表于 2016-11-22 16:24
这种程序都烂大街了

看了很多,但是总出问题。。。。
songchenping 发表于 2016-11-23 08:16 | 显示全部楼层
刷新知识 发表于 2016-11-22 18:24
看了很多,但是总出问题。。。。

适当的时候用示波器看一下波形
 楼主| 刷新知识 发表于 2016-11-23 10:15 | 显示全部楼层
songchenping 发表于 2016-11-23 08:16
适当的时候用示波器看一下波形

我竟然莫名其妙的配制出来了。。。。。。但是还是有bug。。。。
zhuotuzi 发表于 2016-12-4 14:22 | 显示全部楼层
寄存器的很少用的,不清楚,都玩库函数。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

8

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部