搜索
查看: 1588|回复: 0

[分享] STM32学习笔记16—EEPROM存储实验

[复制链接]

该用户从未签到

193

主题

194

帖子

0

蝴蝶豆

金牌会员

最后登录
2021-3-12
发表于 2021-3-10 13:23:34 | 显示全部楼层 |阅读模式
STM32学习笔记16—EEPROM存储实验

16.1 EEPROM概述

EEPROM(ElectricallyErasable Programmable read only memory),称为带电可擦除可编程只读存储器,是一种可以断电保存数据的存储芯片,EEPROM可以在电脑上或专用设备上擦除已有信息,重新编程,一般用在即插即用设备中,这种存储芯片可以通过高于普通电压的作用来擦除或重写,EEPROM芯片一般用在需要频繁存储数据,但是数据量不大的场合,本实验以Atmel公司设计的AT24C02为例,来详细描述EEPROM的基本操作。

AT24C02是一片存储容量在2Kbit的的存储芯片,即存储容量512Byte,通过IIC总线协议进行数据通信,STM32F1内置的IIC模块,但是由于当时设计的时候为了规避飞利浦关于IIC通信协议的专利技术,将IIC设计的比较复杂,并且当操作不当的时候容易锁住总线,但是ST公司关于硬件IIC方面也提出了对应的软件解决方案,我们在这个存储实验中采用IO口模拟IIC协议与硬件IIC模块两种方式来实现EEPROM存储。

IIC是一种只利用两根线来进行数据交换的串行通信协议,IIC的电气线路包括两根线,即时钟线SCL和数据线SDA,高速IIC总线一般可达400kbps以上,在传送过程中一共有三种类型的信号,分别是开始信号,结束信号和应答信号,我们在51单片机开发中曾将IIC协议通过端口模拟成功的控制了EEPROM的读写,现在只需要将之前的代码移植过来修改一下底层寄存器即可使用。STM32F1系列的硬件IIC结构框图如下图所示。

3.1.png

从结构可以发现,STM32的硬件IIC模块我们只需要配置好寄存器,然后既可以不考虑具体的IIC协议,直接读数据寄存器就可以获取到总线上的数据,这也是硬件IIC的优势所在。

16.2 AT24C02通信时序

16.2.1 写时序

(1)写1个字节
3.2.png

第1步:发送开始信号
第2步:发送器件7位地址+1位读写控制后等待芯片应答
第3步:发送写入的地址后等待芯片应答
第4步:写入需要存储的数据后等待芯片应答
第5步:发送结束信号
第6步:等待20ms左右

(2)写n个字节
3.3.png

写n个字节适用于在连续的n个地址上写入n个数据,当需要写入n个数据的时候,这种连续写的方式比单个写的速度有显著性优势,具体步骤如下。
第1步:发送开始信号
第2步:发送器件7位地址+1位读写控制后等待芯片应答
第3步:发送写入的地址后等待芯片应答
第4步:写入需要存储的数据1后等待芯片应答
……
第n+4步:写入需要存储的数据n后等待芯片应答
第n+5步:发送结束信号
第n+6步:等待20ms左右

注:AT24C系列芯片进行1次完整的写时序,必须等待5ms以上,手册给出的典型值是5ms,一般默认20ms。

16.2.2 读时序

(1)读1个字节
3.4.png

第1步:发送开始信号
第2步:发送器件7位地址+1位读写控制后等待芯片应答
第3步:发送写入的地址后等待芯片应答
第4步:重新发送开始信号
第5步:发送器件7位地址+1位读写控制(读)后等待芯片应答
第6步:开始接收返回的的数据
第7步:发送结束信号

(2)读n个字节
3.5.png

写n个字节适用于读取存储在连续的n个地址上写入n个数据,当需要写入n个数据的时候,这种连续写的方式比单个写的速度有显著性优势,具体步骤如下。
第1步:发送开始信号
第2步:发送器件7位地址+1位读写控制后等待芯片应答
第3步:发送写入的地址后等待芯片应答
第4步:重新发送开始信号
第5步:发送器件7位地址+1位读写控制(读)后等待芯片应答
第6步:接收返回的的数据1后发送应答信号
第7步:接收返回的的数据2后发送应答信号
……
第n+6步:接收返回的的数据n
第n+7步:发送结束信号

16.3 STM32内部IIC协议相关寄存器

16.3.1 控制寄存器1:I2Cx_CR1

3.6.png

Bit 15:软件复位
0:I2C模块不处于复位
1:I2C模块处于复位
Bit 13:SMBus提醒:软件可以设置或清除该位,当PE=0时,由硬件清除
0:释放SMBAlert引脚使其变高,提醒响应地址头紧跟在NACK信号后面
1:驱动SMBAlert引脚使其变低,提醒响应地址头紧跟在ACK信号后面
Bit 12:数据包出错检测
0:无PEC传输
1:PEC传输
Bit 11:应答/PEC位置
0:ACK位控制当前移位寄存器内正在接收的字节的ACK。PEC位表明当前移位寄存器内的字节是PEC
1:ACK位控制在移位寄存器里接收的下一个字节的ACK。PEC位表明在移位寄存器里接收的下一个字节是PEC
注1:POS位只能用在2字节的接收配置中,必须在接收数据之前配置
注2:为了NACK第2个字节,必须在清除ADDR为之后清除ACK位
注3:为了检测第2个字节的PEC,必须在配置了POS位之后,拉伸ADDR事件时设置PEC位
Bit 10:应答使能
0:无应答返回
1:在接收到一个字节后返回一个应答
Bit 9:停止条件产生
在主模式下:
0:无停止条件产生
1:在当前字节传输或在当前起始条件发出后产生停止条件
在从模式下:
0:无停止条件产生
1:在当前字节传输或释放SCL和SDA线
Bit 8:起始条件产生
在主模式下:
0:无起始条件产生
1:重复产生起始条件
在从模式下:
0:无起始条件产生
1:当总线空闲时,产生起始条件
Bit 7:禁止时钟延长
0:允许时钟延长
1:禁止时钟延长
Bit 6:广播呼叫使能
0:禁止广播呼叫,以非应答响应地址00h
1:允许广播呼叫,以应答响应地址00h
Bit 5:PEC使能
0:禁止PEC计算
1:开启PEC计算
Bit 4:ARP使能
0:禁止ARP
1:使能ARP
注1:如果SMBTYPE=0,使用SMBus设备的默认地址
注2:如果SMBTYPE=1,使用SMBus的主地址
Bit 3:SMBus类型
0:SMBus设备
1:SMBus主机
Bit 1:SMBus模式
0:I2C模式
1:SMBus模式
Bit 0:I2C模块使能
0:禁用I2C模块
1:启用I2C模块,根据SMBus位的设置,相应的I/O口需配置为复用功能
:在主模式下,通讯结束之前,绝不能清除该位

16.3.2 控制寄存器2:I2Cx_CR2
3.7.png

Bit 12:DMA最后一次传输
0:下一次DMA的EOT不是最后的传输
1:下一次DMA的EOT是最后的传输
Bit 11:DMA请求使能
0:禁止DMA请求
1:当TxE=1或RxNE=1时,允许DMA请求
Bit 10:缓冲器中断使能
0:当TxE=1或RxNE=1时,不产生任何中断
1:当TxE=1或RxNE=1时,产生事件中断
Bit 9:事件中断使能
0:禁止事件中断
1:允许事件中断
在下列条件下,将产生该中断:
SB=1(主模式)
ADDR=1(主/从模式)
ADD10=1(主模式)
STOPF=1(从模式)
BTF=1,但是没有TxE或RxNE事件
如果ITBUFEN=1,TxE事件为1
如果ITBUFEN=1,RxNE事件为1
Bit 8:出错中断使能
0:禁止出错中断
1:允许出错中断
在下列条件下,将产生该中断:
BERR=1
ARLO=1
AF=1
OVR=1
PECERR=1
TIMEOUT=1
SMBAlert=1
Bit 5~Bit 0:I2C模块时钟频率,允许的范围在2~36MHz之间
000000:禁用
000001:禁用
000010:2MHz
...
100100:36MHz
大于100100:禁用

16.3.3 上升时间寄存器:I2Cx_TRISE

3.8.png
Bit 5~Bit 0:在快速/标准模式下的SCL最大上升时间(主模式)
例如:标准模式中最大允许SCL上升时间为1000ns。如果在I2C_CR2寄存器中FREQ中的值等于0x08且TPCLK1=125ns,故TRISE中必须写入09h(1000ns/125ns=8+1)
:只有当PE=0时,才能设置TRISE

16.3.4 时钟控制寄存器:I2Cx_CCR

3.9.png
Bit 15:I2C主模式选项
0:标准模式的I2C
1:快速模式的I2C
Bit 14:快速模式时的占空比
0:快速模式下Tlow/Thigh=2
1:快速模式下Tlow/Thigh=16/9
Bit 11~Bit 0:快速/标准模式下的时钟控制分频系数(主模式)
在I2C标准模式或SMBus模式下:
Thigh=CCR×TPCLK1
Tlow=CCR×TPCLK1
在I2C快速模式下:
如果DUTY=0:
Thigh=CCR×TPCLK1
Tlow=2×CCR×TPCLK1
如果DUTY=1:
Thigh=9×CCR×TPCLK1
Tlow=16×CCR×TPCLK1
例如:在标准模式下,产生100kHz的SCL的频率,如果FREQR=08,TPCLK1=125ns,则CCR必须写入0x28(40×125ns=5000ns)
注1:允许设定的最小值为0x04,在快速DUTY模式下允许的最小值为0x01
注2:fCK应当是10MHz的整数倍,这样可以正确产生400kHz的快速时钟

16.3.5 自身地址寄存器1:I2Cx_OAR1

3.10.png
Bit 15:寻址模式(从模式)
0:7位从地址(不响应10位地址)
1:10位从地址(不响应7位地址)
Bit 9~Bit 8:接口地址
7位地址模式时不用关心
10位地址模式时为地址的9~8位
Bit 7~Bit 1:接口地址,地址的7~1位
Bit 0:接口地址
7位地址模式时不用关心
10位地址模式时为地址第0位

16.3.6 自身地址寄存器2:I2Cx_OAR2

3.11.png
Bit 7~Bit 1:接口地址,在双地址模式下地址的7~1位
Bit 0:双地址模式使能位
0:在7位地址模式下,只有OAR1被识别
1:在7位地址模式下,OAR1和OAR2都被识别

16.3.7 状态寄存器1:I2Cx_SR1

3.12.png
Bit 15: SMBus提醒
在SMBus主机模式下:
0:无SMBus提醒
1:在引脚上产生SMBAlert提醒事件
在SMBus从机模式下:
0:没有SMBAlert响应地址头序列
1:收到SMBAlert响应地址头序列至SMBAlert变低
Bit 14:超时或Tlow错误
0:无超时错误
1:SCL低电平达到25ms;或主机低电平累积时间超过10ms;或从设备低电平累积时间超过25ms
Bit 12:在接收时发生PEC错误
0:无PEC错误:接收到PEC后接收器返回ACK(如果ACK=1)
1:有PEC错误:接收到PEC后接收器返回NACK(不管ACK是什么值)
Bit 11:过载/欠载
0:无过载/欠载
1:出现过载/欠载
Bit 10:应答失败
0:没有应答失败
1:应答失败
Bit 9:仲裁丢失(主模式)
0:没有检测到仲裁丢失
1:检测到仲裁丢失
Bit 8:总线出错
0:无起始或停止条件出错
1:起始或停止条件出错
Bit 7:数据寄存器为空(发送时)
0:数据寄存器非空
1:数据寄存器空
Bit 6:数据寄存器非空(接收时)
0:数据寄存器为空
1:数据寄存器非空
Bit 4:停止条件检测位(从模式)
0:没有检测到停止条件
1:检测到停止条件
Bit 3:10位头序列已发送(主模式)
0:没有ADD10事件发生
1:主设备已经将第一个地址字节发送出去
Bit 2:字节发送结束
0:字节发送未完成
1:字节发送结束
Bit 1:地址已被发送(主模式)/地址匹配(从模式)
地址匹配(从模式)
0:地址不匹配或没有收到地址
1:收到的地址匹配Bit 1:
地址发送标志(主模式)
0:地址发送没有结束
1:地址发送结束
10位地址模式时,当收到地址的第二个字节的ACK后该位被置1
7位地址模式时,当收到地址的ACK后该位被置1
Bit 0:起始位(主模式)
0:未发送起始条件
1:起始条件已发送
16.3.8 状态寄存器2:I2Cx_SR2

3.13.png
Bit 15~Bit 8:数据包出错检测,当ENPEC=1时,PEC[7:0]存放内部的PEC的值
Bit 7:双标志(从模式)
0:接收到的地址与OAR1内的内容相匹配
1:接收到的地址与OAR2内的内容相匹配
Bit 6:SMBus主机头系列(从模式)
0:未收到SMBus主机的地址
1:当SMBTYPE=1且ENARP=1时,收到SMBus主机地址
Bit 5:SMBus设备默认地址(从模式)
0:未收到SMBus设备的默认地址
1:当ENARP=1时,收到SMBus设备的默认地址
Bit 4:广播呼叫地址(从模式)
0:未收到广播呼叫地址
1:当ENGC=1时,收到广播呼叫的地址
Bit 2:发送/接收
0:接收到数据
1:数据已发送
Bit 1:总线忙,在检测到SDA或SCl为低电平时,硬件将该位1
0:在总线上无数据通讯
1:在总线上正在进行数据通讯
Bit 0:主从模式
0:从模式
1:主模式

16.3.9 数据寄存器:I2Cx_DR

3.14.png
Bit 7~Bit 0:8位数据寄存器,用于存放接收到的数据或放置用于发送到总线的数据
发送器模式:当写一个字节至DR寄存器时,自动启动数据传输。一旦传输开始,如果能及时把下一个需传输的数据写入DR寄存器,I2C模块将保持连续的数据流
接收器模式:接收到的字节被拷贝到DR寄存器。在接收到下一个字节之前读出数据寄存器,即可实现连续的数据传送
注1:在从模式下,地址不会被拷贝进数据寄存器DR
注2:硬件不管理写冲突(如果TxE=0,仍能写入数据寄存器)
注3:如果在处理ACK脉冲时发生ARLO事件,接收到的字节不会被拷贝到数据寄存器里,因此不能读到它

16.4 实验例程

16.4.1 软件模拟IIC控制

(1)创建at24cxx.h文件,并输入以下代码。
  1. /*********************************************************************************************************
  2.                 EEPROM    驱    动    文    件
  3. *********************************************************************************************************/
  4. #ifndef _AT24Cxx_H_
  5. #define _AT24Cxx_H_

  6. #include "sys.h"
  7. /*********************************************************************************************************
  8.                 硬    件    端    口    定    义
  9. *********************************************************************************************************/
  10. #define IIC_SCL      PBout( 6 )
  11. #define IIC_SDA      PBout( 7 )
  12. #define IIC_SDA_READ  PBin( 7 )
  13. /*********************************************************************************************************
  14.                     函    数    列    表
  15. *********************************************************************************************************/
  16. void AT24Cxx_Init( void ) ;                                        //AT24C初始化
  17. void AT24Cxx_Write_Data( u16 Address, u8 Data ) ;                            //写入1个数据
  18. void AT24Cxx_Write_nData( u16 Address, u8 *Buffer, u16 Len ) ;                      //写入n个数据
  19. void AT24Cxx_Read_Data( u16 Address, u8 *Data ) ;                            //读取1个数据
  20. void AT24Cxx_Read_nData( u16 Address, u8 *Buffer, u16 Len ) ;                      //读取n个数据

  21. #endif
复制代码

(2)创建at24cxx.c文件,并输入以下代码。
  1. /*********************************************************************************************************
  2.                 EEPROM    驱    动    程    序
  3. *********************************************************************************************************/
  4. #include "at24cxx.h"
  5. #include "delay.h"
  6. /***************************************************
  7. Name    :IIC_Start
  8. Function  :IIC起始信号
  9. Paramater  :None
  10. Return    :None
  11. ***************************************************/
  12. void IIC_Start()
  13. {
  14.   GPIOB->CRL &= 0x0FFFFFFF ;                                      //PB7推挽输出
  15.   GPIOB->CRL |= 0x30000000 ;
  16.   IIC_SDA = 1 ;
  17.   IIC_SCL = 1 ;
  18.   delay_us( 4 ) ;
  19.   IIC_SDA = 0 ;
  20.   delay_us( 4 ) ;
  21.   IIC_SCL = 0 ;
  22. }
  23. /***************************************************
  24. Name    :IIC_Stop
  25. Function  :IIC停止信号
  26. Paramater  :None
  27. Return    :None
  28. ***************************************************/
  29. void IIC_Stop()
  30. {
  31.   GPIOB->CRL &= 0x0FFFFFFF ;                                      //PB7推挽输出
  32.   GPIOB->CRL |= 0x30000000 ;
  33.   IIC_SCL = 0 ;
  34.   IIC_SDA = 0 ;
  35.    delay_us( 4 ) ;
  36.   IIC_SCL = 1 ;
  37.   IIC_SDA = 1 ;
  38.   delay_us( 4 ) ;
  39. }
  40. /***************************************************
  41. Name    :IIC_Wait_Ack
  42. Function  :IIC等待应答
  43. Paramater  :None
  44. Return    :
  45.       0:成功
  46.       1:失败
  47. ***************************************************/
  48. void IIC_Wait_Ack()
  49. {
  50.   u8 Time = 0 ;
  51.   GPIOB->CRL &= 0x0FFFFFFF ;
  52.   GPIOB->CRL |= 0x80000000 ;
  53.   IIC_SDA = 1 ;
  54.   delay_us( 1 ) ;
  55.   IIC_SCL = 1 ;
  56.   delay_us( 1 ) ;
  57.   while( IIC_SDA_READ )
  58.   {
  59.     Time ++ ;
  60.     if( Time>250 )
  61.     {
  62.       IIC_Stop() ;
  63.       break ;
  64.     }
  65.   }
  66.   IIC_SCL = 0 ;
  67. }
  68. /***************************************************
  69. Name    :IIC_Send_Byte
  70. Function  :IIC发送一个字节
  71. Paramater  :
  72.       ack:应答使能
  73.         0:不应答
  74.         1:应答
  75. Return    :None
  76. ***************************************************/
  77. void IIC_Send_Byte( u8 Byte )
  78. {
  79.   u8 i;
  80.   GPIOB->CRL &= 0x0FFFFFFF ;                                      //PB7推挽输出
  81.   GPIOB->CRL |= 0x30000000 ;
  82.   IIC_SCL = 0 ;
  83.   for( i=0; i<8; i++ )
  84.   {
  85.     if( ( Byte&0x80 )==0x80 )
  86.       IIC_SDA = 1 ;
  87.     else
  88.       IIC_SDA = 0 ;
  89.     Byte <<= 1 ;
  90.     delay_us( 2 ) ;
  91.     IIC_SCL = 1 ;
  92.     delay_us( 2 ) ;
  93.     IIC_SCL = 0 ;
  94.     delay_us( 2 ) ;
  95.   }
  96. }
  97. /***************************************************
  98. Name    :IIC_Read_Byte
  99. Function  :IIC读取一个字节
  100. Paramater  :
  101.       ack:应答使能
  102.         0:不应答
  103.         1:应答
  104. Return    :None
  105. ***************************************************/
  106. u8 IIC_Read_Byte( u8 Ack )
  107. {
  108.   u8 i,Byte=0;
  109.   GPIOB->CRL &= 0x0FFFFFFF ;
  110.   GPIOB->CRL |= 0x80000000 ;
  111.   for( i=0; i<8; i++ )
  112.   {
  113.     IIC_SCL = 0 ;
  114.     delay_us( 2 ) ;
  115.     IIC_SCL = 1 ;
  116.     Byte <<= 1 ;
  117.     if( IIC_SDA_READ )
  118.       Byte |= 0x01 ;
  119.     delay_us( 1 ) ;
  120.   }
  121.   IIC_SCL = 0 ;
  122.   GPIOB->CRL &= 0x0FFFFFFF ;                                      //PB7推挽输出
  123.   GPIOB->CRL |= 0x30000000 ;
  124.   IIC_SDA = 1 - Ack ;
  125.   delay_us( 2 ) ;
  126.   IIC_SCL = 1 ;
  127.   delay_us( 2 ) ;
  128.   IIC_SCL = 0 ;
  129.   return Byte ;
  130. }
  131. /***************************************************
  132. Name    :AT24Cxx_Write_Data
  133. Function  :写入1个数据
  134. Paramater  :
  135.       Address:地址
  136.       Data:数据
  137. Return    :读到的数据
  138. ***************************************************/
  139. void AT24Cxx_Write_Data( u16 Address, u8 Data )
  140. {                                                      
  141.   IIC_Start() ;
  142.   IIC_Send_Byte( 0xA0|( Address/256 )<<1 ) ;                              //发送器件地址,写数据
  143.   IIC_Wait_Ack() ;
  144.   IIC_Send_Byte( Address%256 ) ;                                    //发送低地址
  145.   IIC_Wait_Ack() ;
  146.   IIC_Send_Byte( Data ) ;                                        //发送字节
  147.   IIC_Wait_Ack() ;
  148.   IIC_Stop() ;                                            //产生一个停止条件
  149.   delay_ms( 10 ) ;                                          //EEPROM的写入速度比较慢
  150. }
  151. /***************************************************
  152. Name    :AT24Cxx_Write_nData
  153. Function  :写入n个数据
  154. Paramater  :
  155.       Address:地址
  156.       *Buffer:数据缓存
  157.       Len:数据长度
  158. Return    :None
  159. ***************************************************/
  160. void AT24Cxx_Write_nData( u16 Address, u8 *Buffer, u16 Len )
  161. {
  162.   u16 i ;
  163.   for( i=0; i<Len; i++ )
  164.     AT24Cxx_Write_Data( Address+i, Buffer[ i ] ) ;
  165.   IIC_Stop() ;                                            //产生一个停止条件
  166.   delay_ms( 10 ) ;                                          //EEPROM的写入速度比较慢
  167. }
  168. /***************************************************
  169. Name    :AT24Cxx_Read_Data
  170. Function  :读取1个数据
  171. Paramater  :
  172.       Address:开始读数的地址
  173.       *Data:数据指针
  174. Return    :None
  175. ***************************************************/
  176. void AT24Cxx_Read_Data( u16 Address, u8 *Data )
  177. {
  178.   IIC_Start() ;
  179.   IIC_Send_Byte( 0xA0|( Address/256 )<<1 ) ;                              //发送器件地址,写数据
  180.   IIC_Wait_Ack() ;
  181.   IIC_Send_Byte( Address%256 ) ;                                    //发送低地址
  182.   IIC_Wait_Ack() ;
  183.   IIC_Start() ;
  184.   IIC_Send_Byte( 0xA1 ) ;                                        //进入接收模式
  185.   IIC_Wait_Ack() ;
  186.   *Data = IIC_Read_Byte( 0 );
  187.   IIC_Stop() ;                                            //产生一个停止条件
  188. }
  189. /***************************************************
  190. Name    :AT24Cxx_Read_nData
  191. Function  :读取n个数据
  192. Paramater  :
  193.       Address:地址
  194.       *Buffer:数据缓存
  195.       Len:数据长度
  196. Return    :None
  197. ***************************************************/
  198. void AT24Cxx_Read_nData( u16 Address, u8 *Buffer, u16 Len )
  199. {
  200.   u16 i ;
  201.   IIC_Start() ;
  202.   IIC_Send_Byte( 0xA0|( Address/256 )<<1 ) ;                              //发送器件地址,写数据
  203.   IIC_Wait_Ack() ;
  204.   IIC_Send_Byte( Address%256 ) ;                                    //发送低地址
  205.   IIC_Wait_Ack() ;
  206.   IIC_Start() ;
  207.   IIC_Send_Byte( 0xA1 ) ;                                        //进入接收模式
  208.   IIC_Wait_Ack() ;
  209.   for( i=0; i<Len-1; i++ )
  210.     Buffer[ i ] = IIC_Read_Byte( 1 ) ;
  211.   Buffer[ Len-1 ] = IIC_Read_Byte( 0 );
  212.   IIC_Stop() ;                                            //产生一个停止条件
  213. }
  214. /***************************************************
  215. Name    :AT24Cxx_Check
  216. Function  :检查AT24C是否正常
  217. Paramater  :None
  218. Return    :
  219.       0:成功
  220.       1:失败
  221. ***************************************************/
  222. u8 AT24Cxx_Check()
  223. {
  224.   u8 Data ;
  225.   AT24Cxx_Read_Data( 255, &Data ) ;
  226.   if( Data!=0x55 )
  227.   {
  228.     AT24Cxx_Write_Data( 255, 0x55 ) ;
  229.     AT24Cxx_Read_Data( 255, &Data ) ;
  230.     if( Data!=0x55 )
  231.       return 0 ;
  232.   }
  233.   return 1 ;
  234. }
  235. /***************************************************
  236. Name    :AT24Cxx_Init
  237. Function  :AT24C初始化
  238. Paramater  :None
  239. Return    :None
  240. ***************************************************/
  241. void AT24Cxx_Init()
  242. {
  243.   RCC->APB2ENR |= 1<<3 ;                                        //先使能外设GPIOB时钟
  244.   GPIOB->CRL &= 0x00FFFFFF ;                                      //PB6和PB7推挽输出
  245.   GPIOB->CRL |= 0x33000000 ;
  246.   GPIOB->ODR |= 3<<6 ;                                        //PB6和PB7输出高
  247.   while( AT24Cxx_Check()==0 ) ;
  248. }
复制代码

(3)创建1.c文件并输入以下代码。
  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart1.h"
  4. #include "lcd.h"
  5. #include "at24cxx.h"

  6. u8 TEXT_Buffer[] = "STM32F103 IIC Test" ;
  7. int main()
  8. {
  9.   u8 datatemp[ 17 ] ;
  10.   STM32_Clock_Init( 9 ) ;                                        //STM32时钟初始化
  11.   SysTick_Init( 72 ) ;                                        //SysTick初始化
  12.   USART1_Init( 72, 115200 ) ;                                      //初始化串口1波特率115200
  13.   LCD_Init() ;                                            //LCD初始化
  14.   AT24Cxx_Init() ;                                          //AT24C初始化
  15.    POINT_COLOR = RED ;                                          //设置字体为红色
  16.   AT24Cxx_Write_nData( 0, TEXT_Buffer, 18 ) ;                              //从第0个地址处开始写入
  17.   AT24Cxx_Read_nData( 0, datatemp, 18 ) ;                                //从第0个地址处开始读出
  18.   LCD_ShowString( 0, 0, datatemp ) ;                                  //显示读到的字符串
  19.   while( 1 )
  20.   {
  21.    
  22.   }
  23. }
复制代码

16.4.2 硬件IIC控制

注:由于STM32的硬件IIC总是容易卡死(这也是为什么网络上几乎没有硬件IIC通讯的例子的原因),所以这里采用了ST内部提供的通讯机制来保证IIC的正常使用。

(1)创建at24cxx.h文件并输入以下代码。
  1. /*********************************************************************************************************
  2.                 EEPROM    驱    动    文    件
  3. *********************************************************************************************************/
  4. #ifndef _AT24Cxx_H_
  5. #define _AT24Cxx_H_

  6. #include "sys.h"
  7. /*********************************************************************************************************
  8.                     函    数    列    表
  9. *********************************************************************************************************/
  10. void AT24Cxx_Init( void ) ;                                        //AT24C初始化
  11. void IIC_Write_Data( u8 Address, u8 Data ) ;                              //写入1个数据
  12. void AT24Cxx_Write_nData( u16 Address, u8 *Buffer, u16 Len ) ;                      //写入n个数据
  13. void AT24Cxx_Read_Data( u16 Address, u8 *Data ) ;                            //读取1个数据
  14. void AT24Cxx_Read_nData( u16 Address, u8 *Buffer, u16 Len ) ;                      //读取n个数据

  15. #endif
复制代码

(2)创建at24cxx.c文件并输入以下代码。
  1. /*********************************************************************************************************
  2.                 EEPROM    驱    动    程    序
  3. *********************************************************************************************************/
  4. #include "at24cxx.h"
  5. #include "delay.h"
  6. /***************************************************
  7. Name    :IIC_Write_Data
  8. Function  :写入1个数据
  9. Paramater  :
  10.       Address:地址
  11.       Byte:读取的字节
  12. Return    :None
  13. ***************************************************/
  14. void IIC_Write_Data( u8 Address, u8 Byte )
  15. {
  16.   u16 Time, tmpreg ;
  17.   tmpreg = tmpreg ;
  18.   //等待BUSY标志置0
  19.   Time = 0 ;
  20.   while( ( ( I2C1->SR2&0x02 )==0x02 )&&( Time<65535 ) )
  21.     Time ++ ;
  22.   I2C1->CR1 &= ~( 1<<11 ) ;                                      //禁用Pos
  23.   I2C1->CR1 |= 1<<8 ;                                          //开始信号
  24.   //等待SB标志置1
  25.   Time = 0 ;
  26.   while( ( ( I2C1->SR1&0x01 )==0 )&&( Time<65535 ) )
  27.     Time ++ ;
  28.   I2C1->DR = 0xA0 ;                                          //发送从机地址
  29.   //等待地址发送结束
  30.   Time = 0 ;
  31.   while( ( ( I2C1->SR1&0x02 )==0 )&&( Time<65535 ) )
  32.   {
  33.     Time ++ ;
  34.     if( ( I2C1->SR1&0x400 )==0x400 )
  35.     {
  36.       I2C1->SR1 &= ~( 1<<10 ) ;                                  //清除AF标志
  37.       I2C1->CR1 |= 1<<9 ;                                      //结束信号
  38.       break ;
  39.     }
  40.   }
  41.   tmpreg = I2C1->SR1 ;                                        //清除地址标志
  42.   tmpreg = I2C1->SR2 ;
  43.   //等待TXE标志置0
  44.   Time = 0 ;
  45.   while( ( ( I2C1->SR2&0x04)==0 )&&( Time<65535 ) )
  46.   {
  47.     Time ++ ;
  48.     //检查是否检测到NACK
  49.     if( ( I2C1->SR1&0x400 )==0x400 )
  50.     {
  51.       I2C1->SR1 &= ~( 1<<10 ) ;
  52.       I2C1->CR1 |= 1<<9 ;                                      //结束信号
  53.       break ;
  54.     }
  55.   }
  56.   I2C1->DR = Address ;                                        //发送寄存器地址
  57.   //等待TXE标志置1
  58.   Time = 0 ;
  59.   while( ( ( I2C1->SR1&0x80 )==0 )&&( Time<65535 ) )
  60.   {
  61.     Time ++ ;
  62.     //检查是否检测到NACK
  63.     if( ( I2C1->SR1&0x400 )==0x400 )
  64.     {
  65.       I2C1->SR1 &= ~( 1<<18 ) ;                                  //清除NACKF标志
  66.       I2C1->CR1 |= 1<<9 ;                                      //结束信号
  67.       break ;
  68.     }
  69.   }
  70.   I2C1->DR = Byte ;                                          //发送数据
  71.   //等待BTF标志被置1
  72.   Time = 0 ;
  73.   while( ( ( I2C1->SR1&0x04 )==0 )&&( Time<65535 ) )
  74.   {
  75.     Time ++ ;
  76.     //检查是否检测到NACK
  77.     if( ( I2C1->SR1&0x400 )==0x400 )
  78.     {
  79.       I2C1->SR1 &= ~( 1<<10 ) ;                                  //清除NACKF标志
  80.       I2C1->CR1 |= 1<<9 ;                                      //结束信号
  81.       break ;
  82.     }
  83.   }
  84.   I2C1->CR1 |= 1<<9 ;                                          //结束信号
  85.   delay_ms( 10 ) ;
  86. }
  87. /***************************************************
  88. Name    :IIC_Read_Data
  89. Function  :读取1个数据
  90. Paramater  :
  91.       Address:地址
  92. Return    :读取的数据
  93. ***************************************************/
  94. void IIC_Read_Data( u8 Address, u8 *Data )
  95. {
  96.   u16 tmpreg, Time;
  97.   tmpreg = tmpreg ;
  98.     //等待BUSY标志置0
  99.   Time = 0 ;
  100.   while( ( ( I2C1->SR1&0x02 )==0x02 )&&( Time<65535 ) )
  101.     Time ++ ;
  102.   I2C1->CR1 &= ~( 1<<11 ) ;                                      //禁用Pos
  103.     //发送从机地址
  104.   I2C1->CR1 |= 1<<8 ;                                          //开始信号
  105.   Time = 0 ;
  106.   //等待SB标志置1
  107.   while( ( ( I2C1->SR1&0x01 )==0 )&&( Time<65535 ) )
  108.     Time ++ ;
  109.   I2C1->DR = 0xA0 ;                                          //发送从机地址
  110.   //等待地址发送结束
  111.   while( ( ( I2C1->SR1&0x02 )==0 )&&( Time<65535 ) )
  112.   {
  113.     if( ( I2C1->SR1&0x400 )==0x400 )
  114.     {
  115.       I2C1->SR1 &= ~( 1<<10 ) ;                                  //清除AF标志
  116.       I2C1->CR1 |= 1<<9 ;                                      //停止信号
  117.       break ;
  118.     }
  119.   }
  120.   tmpreg = I2C1->SR1;                                          //清除ADDR标志
  121.   tmpreg = I2C1->SR2;
  122.   //等待TXE标志置1
  123.   while( ( ( I2C1->SR1&0x80 )==0 )&&( Time<65535 ) )
  124.   {
  125.     //检查是否检测到NACK
  126.     if( ( I2C1->SR1&0x400)==0x400 )
  127.     {
  128.       I2C1->SR1 &= ~( 1<<10 ) ;                                  //清除NACKF标志
  129.       I2C1->CR1 |= 1<<9 ;                                      //通用结束
  130.       break ;
  131.     }
  132.   }
  133.   I2C1->DR = Address ;                                        //写入数据
  134.   //等待BTF标志置1
  135.   while( ( ( I2C1->SR1&0x04 )==0 )&&( Time<65535 ) )
  136.   {
  137.     //检查是否检测到NACK
  138.     if( ( I2C1->SR1&0x400)==0x400 )
  139.     {
  140.       I2C1->SR1 &= ~( 1<<10 ) ;                                  //清除NACKF标志
  141.       I2C1->CR1 |= 1<<9 ;                                      //通用结束
  142.       break ;
  143.     }
  144.   }
  145.   I2C1->CR1 |= 1<<9 ;                                          //通用结束
  146.   //等待忙标志退出
  147.   Time = 0 ;
  148.   while( ( ( I2C1->SR1&0x02 )==0x02 )&&( Time<65535 ) )
  149.     Time ++ ;
  150.   I2C1->CR1 &= ~( 1<<11 ) ;                                      //禁用Pos
  151.     //发送从机地址
  152.   I2C1->CR1 |= 1<<10 ;                                        //开启应答信号
  153.   I2C1->CR1 |= 1<<8 ;                                          //开始信号
  154.   //等待SB标志置1
  155.   Time = 0 ;
  156.   while( ( ( I2C1->SR1&0x01 )==0 )&&( Time<65535 ) )
  157.     Time ++ ;
  158.   I2C1->DR = 0xA1 ;                                          //发送从机地址
  159.   //等待地址标志置1
  160.   while( ( ( I2C1->SR1&0x02 )==0 )&&( Time<65535 ) )
  161.   {
  162.     Time ++ ;
  163.     //检查是否检测到STOPF
  164.     if( ( I2C1->SR1&0x10 )==0x10 )
  165.     {
  166.       I2C1->SR1 &= ~( 1<<4 ) ;                                  //清除停止标志
  167.       break ;
  168.     }
  169.   }
  170.   I2C1->CR1 &= ~( 1<<10 ) ;                                      //禁止应答
  171.   tmpreg = I2C1->SR1;                                          //清除ADDR标志
  172.   tmpreg = I2C1->SR2;
  173.   I2C1->CR1 |= 1<<9 ;                                          //通用应答
  174.   //等待直到RXNE标志置1
  175.   Time = 0 ;
  176.   while( ( ( I2C1->SR1&0x40 )==0 )&&( Time<65535 ) )
  177.   {
  178.     Time ++ ;
  179.     //检查是否检测到STOPF
  180.     if( ( I2C1->SR1&0x10 )==0x10 )
  181.     {
  182.       I2C1->SR1 &= ~( 1<<4 ) ;                                  //清除停止标志
  183.       break ;
  184.     }
  185.   }
  186.   *Data = I2C1->DR ;                                          //从DR读取数据
  187. }
  188. /***************************************************
  189. Name    :AT24Cxx_Write_nData
  190. Function  :写入n个数据
  191. Paramater  :
  192.       Address:地址
  193.       *Buffer:数据缓存
  194.       Len:数据长度
  195. Return    :None
  196. ***************************************************/
  197. void AT24Cxx_Write_nData( u16 Address, u8 *Buffer, u16 Len )
  198. {
  199.   u16 i ;
  200.   for( i=0; i<Len; i++ )
  201.     IIC_Write_Data( Address+i, Buffer[ i ] ) ;
  202. }
  203. /***************************************************
  204. Name    :AT24Cxx_Read_nData
  205. Function  :读取n个数据
  206. Paramater  :
  207.       Address:地址
  208.       *Buffer:数据缓存
  209.       Len:数据长度
  210. Return    :None
  211. ***************************************************/
  212. void AT24Cxx_Read_nData( u16 Address, u8 *Buffer, u16 Len )
  213. {
  214.   u16 i ;
  215.   for( i=0; i<Len; i++ )
  216.     IIC_Read_Data( Address+i, &Buffer[ i ] ) ;
  217. }
  218. /***************************************************
  219. Name    :AT24Cxx_Check
  220. Function  :检查AT24C是否正常
  221. Paramater  :None
  222. Return    :
  223.       0:成功
  224.       1:失败
  225. ***************************************************/
  226. u8 AT24Cxx_Check()
  227. {
  228.   u8 Data ;
  229.   IIC_Read_Data( 255, &Data ) ;
  230.   if( Data!=0x55 )
  231.   {
  232.     IIC_Write_Data( 255, 0x55 ) ;
  233.     IIC_Read_Data( 255, &Data ) ;
  234.     if( Data!=0x55 )
  235.       return 0 ;
  236.   }
  237.   return 1 ;
  238. }
  239. /***************************************************
  240. Name    :AT24Cxx_Init
  241. Function  :AT24C初始化
  242. Paramater  :None
  243. Return    :None
  244. ***************************************************/
  245. void AT24Cxx_Init()
  246. {
  247.   RCC->APB2ENR |= 1<<3 ;                                        //先使能外设GPIOB时钟
  248.   GPIOB->CRL &= 0x00FFFFFF ;                                      //PB6和PB7推挽输出
  249.   GPIOB->CRL |= 0xFF000000 ;
  250.   RCC->APB1ENR |= 1<<21 ;
  251.   I2C1->CR1 |= 1<<15 ;
  252.   I2C1->CR1 &= ~( 1<<15 ) ;
  253.   I2C1->CR1 &= 1<<0 ;                                          //关闭I2C模块
  254.   I2C1->CR2 &= ~( 3<<0 ) ;
  255.   I2C1->CR2 |= 16<<0 ;                                        //I2C频率范围
  256.   I2C1->TRISE &= ~( 3<<0 ) ;
  257.   I2C1->TRISE |= 17<<0 ;                                        //I2C上升时间
  258.   I2C1->CCR &= ~( 1<<15 ) ;
  259.   I2C1->CCR &= ~( 1<<14 ) ;
  260.   I2C1->CCR &= ~( 0xFFF<<0 ) ;
  261.   I2C1->CCR |= 80<<0 ;                                        //I2C速度
  262.   I2C1->CR1 &= ~( 1<<6 ) ;
  263.   I2C1->CR1 &= ~( 1<<7 ) ;                                      //通用应答模式
  264.   //主机地址1+地址模式
  265.   I2C1->OAR1 &= ~( 1<<15 ) ;
  266.   I2C1->OAR1 &= ~( 3<<8 ) ;
  267.   I2C1->OAR1 &= ~( 0xFE<<1 ) ;
  268.   I2C1->OAR1 &= ~( 1<<0 ) ;
  269.   I2C1->OAR1 |= 1<<14 ;                                        //地址模式
  270.   //双模式+主机地址2
  271.   I2C1->OAR2 &= ~( 1<<0 ) ;
  272.   I2C1->OAR2 &= ~( 0x7F<<1 ) ;
  273.   I2C1->CR1 |= 1<<0 ;                                          //开启I2C模块
  274.   
  275.   while( AT24Cxx_Check()==0 ) ;
  276. }
复制代码

(3)创建1.c文件并输入以下代码。
  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart1.h"
  4. #include "at24cxx.h"

  5. u8 TEXT_Buffer[] = "STM32F103 IIC Test" ;
  6. int main()
  7. {
  8.   u8 datatemp[ 17 ] ;
  9.   STM32_Clock_Init( 9 ) ;                                        //STM32时钟初始化
  10.   SysTick_Init( 72 ) ;                                        //SysTick初始化
  11.   USART1_Init( 72, 115200 ) ;                                      //初始化串口1波特率115200
  12.   AT24Cxx_Init() ;                                          //AT24C初始化
  13.   AT24Cxx_Write_nData( 0, TEXT_Buffer, 18 ) ;                              //从第0个地址处开始写入
  14.   AT24Cxx_Read_nData( 0, datatemp, 18 ) ;                                //从第0个地址处开始读出
  15.   while( 1 )
  16.   {
  17.    
  18.   }
  19. }
复制代码

文章出处: 滑小稽笔记


回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条

Archiver|手机版|小黑屋|论坛-意法半导体STM32/STM8技术社区

GMT+8, 2024-4-24 23:40 , Processed in 0.171733 second(s), 32 queries .

Powered by Discuz! X3.4

Copyright © 2001-2024, Tencent Cloud.

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