![](https://i-blog.csdnimg.cn/blog_migrate/910de32315be808d4ef1757e8c5a62bb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3dd117d21c9987d122ed1b9b87b34b3d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/47bce9196adfc7c25c9aa8e55b45f5ec.png)
![](https://i-blog.csdnimg.cn/blog_migrate/592c80e210502ebbd7dfc54cddce3046.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1d739d6eea804563d3fda1356da3c13a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a1c7fb62f372111a36adf7019bfeaef5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a4b2543607fbb5f8c6a02f0b127bdc8a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a10b3dd58ce95ddd79899c1efd4dcfcb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c16e3aee2e2045f6fdf449de0a3d439e.png)
本章所要实现的功能是:首先检测 AT24C02 芯片是否存在,如果存在则输出 提示信息,然后通过按键 KEY_UP 和 KEY1 控制 AT24C02 数据读写,并输出写入和 读取的数据信息,最后让 DS0 指示灯闪烁提示系统正常运行。程序框架如下: (1)使能所用 GPIO 端口时钟,初始化 GPIO (2)使用软件模拟 I2C 通信时序,包含起始和停止信号、应答信号等 (3)编写 AT24C02 读写函数 (4)编写主函数
iic.h+iic.c
#ifndef _i2c_H
#define _i2c_H
#include "system.h"
#define IIC_SCL_PORT GPIOB
#define IIC_SCL_PIN GPIO_Pin_6
#define IIC_SCL_RCC RCC_APB2Periph_GPIOB
#define IIC_SDA_PORT GPIOB
#define IIC_SDA_PIN GPIO_Pin_7
#define IIC_SDA_RCC RCC_APB2Periph_GPIOB
#define IIC_SCL PBout(6)
#define IIC_SDA PBout(7)
#define READ_SDA PBin(7)
void IIC_Init();
void IIC_Send_Byte(u8 txd);//要发送的字节
u8 IIC_Read_Byte(u8 ack);
u8 IIC_Wait_Ack();
void IIC_Start();
void IIC_Stop();
void IIC_Ack();
void IIC_NAck();
#endif
#include "i2c.h"
#include "SysTick.h"
void IIC_Init()//用io口来模拟iic时序
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(IIC_SCL_RCC, ENABLE);
RCC_APB2PeriphClockCmd(IIC_SDA_RCC, ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=IIC_SCL_PIN ;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(IIC_SCL_PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN;
GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
IIC_SCL=1;
IIC_SDA=1;
}
void SDA_OUT()//SDA输出模式
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//输出模式
GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN ;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
}
void SDA_IN()//输入模式
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//输入模式
GPIO_InitStructure.GPIO_Pin=IIC_SDA_PIN ;
GPIO_Init(IIC_SDA_PORT,&GPIO_InitStructure);
}
void IIC_Start()//起始信号
{
SDA_OUT();
IIC_SCL=1;
IIC_SDA=1;
delay_us(5);//scl sda基本上时纳秒级的
IIC_SDA=0;
delay_us(5);
IIC_SCL=0;//使设备开始工作
}
void IIC_Stop()//停止信号
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;
IIC_SCL=1;
delay_us(5);//scl sda基本上时纳秒级的
IIC_SDA=1;//设备停止工作
delay_us(5);
}
void IIC_Ack()//应答信号
{
SDA_OUT();
IIC_SCL=0;
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
}
void IIC_NAck()//非应答信号
{
SDA_OUT();
IIC_SCL=0;
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
}
void IIC_Send_Byte(u8 txd)//要发送的字节
{
u8 i=0;
SDA_OUT();
IIC_SCL=0;//只有时钟低电平,数据线才能进行操作
for(i=0;i<8;i++)//串行通信,一位一位的穿
{
if((txd&0x80)>0)//从高位开始传输
IIC_SDA=1;//第八位为1,则发送高电平
else
IIC_SDA=0;//第八位为0,则发送低电平
txd<<=1;
delay_us(2);
IIC_SCL=1;//为了传输数据稳定
delay_us(2);
IIC_SCL=0;//只有时钟低电平,数据线才能进行操作
}
}
u8 IIC_Read_Byte(u8 ack)//读取字节函数,ack为应答信号
{
u8 i=0;
u8 rec_data=0;
SDA_IN();
for(i=0;i<8;i++)
{
IIC_SCL=0;//从机数据传输
delay_us(2);
IIC_SCL=1;//只有高电平的时候,数据才是稳定的,才可以读取
rec_data<<=1;//因为从传输的数据最高位读取,所以要从rec的最低位左移
if(READ_SDA)rec_data++;
delay_us(1);
}
if(!ack)//传输完一个字节之后在如果不应答就结束,否则继续传输
IIC_NAck();
else
IIC_Ack();
return rec_data;
}
u8 IIC_Wait_Ack()//等待从机的应答信号0成功,1失败
{
u8 temptime=0;
SDA_IN();
IIC_SCL=1;//只有高电平的时候,数据才是稳定的,才可以读取
delay_us(1);
while(READ_SDA)
{
temptime++;
if(temptime>250)
{
IIC_Stop();//停止信号
return 1;
}
}
IIC_SCL=0;//等待应答成功后,需要对从机进行数据间的传输
return 0;
}
at24cxx.h+at24cxx.c
#ifndef _at24cxx_H
#define _at24cxx_H
#include "system.h"
#include "i2c.h"
void AT24CXX_Init();
void AT24CXX_WriteOneByte(u8 WriteAddr,u8 dat);
u8 AT24CXX_ReadOneByte(u8 ReadAddr);
u8 AT24CXX_Check();
#endif
#include "at24cxx.h"
#include "SysTick.h"
void AT24CXX_Init()
{
IIC_Init();
}
void AT24CXX_WriteOneByte(u8 WriteAddr,u8 dat)//发送完一个字节就结束
//at24c02只能存256个字节,所以用u8
{
IIC_Start();
IIC_Send_Byte(0XA0);
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr);
IIC_Wait_Ack();
IIC_Send_Byte(dat);
IIC_Wait_Ack();
IIC_Stop();
delay_ms(10);
}
u8 AT24CXX_ReadOneByte(u8 ReadAddr)//读取一个字节
{
u8 temp=0;
IIC_Start();
IIC_Send_Byte(0XA0);
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr%256);//看开发原理图,随机读
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(0XA1);
IIC_Wait_Ack();
temp=IIC_Read_Byte(0);//读完一个字节就结束
IIC_Stop();
return temp;
}
u8 AT24CXX_Check()//检测AT124CXX是否读写正常 0正常,1不正常
{
u8 temp=0;
temp=AT24CXX_ReadOneByte(255);
if(temp==0x36)return 0;
else
{
AT24CXX_WriteOneByte(255,0x36);
temp=AT24CXX_ReadOneByte(255);
if(temp==0x36)return 0;
}
return 1;
}
main.c
#include "stm32f10x.h"
#include "led.h"
#include "system.h"
#include "SysTick.h"
#include "beep.h"
#include "key.h"
#include "exti.h"
#include "time.h"
#include "pwm.h"
#include "usart.h"
#include "stdio.h"
#include "iwdg.h"
#include "wwdg.h"
#include "input.h"
#include "touch_key.h"
#include "wkup.h"
#include "adc.h"
#include "adc_temp.h"
#include "lsens.h"
#include "dac.h"
#include "dma.h"
#include "rtc.h"
#include "at24cxx.h"
#include "i2c.h"
int main()
{
u8 i=0;
u8 key=0;
u8 k=0;
KEY_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置优先级分组
SysTick_Init(72);
LED_Init();
AT24CXX_Init();
USART1_Init(115200);//波特率115200
while(AT24CXX_Check())
{
printf("读写失败,AT24C02不正常\r\n");
delay_ms(500);
}
printf("AT24C02正常\r\n");
while(1)
{
key=KEY_Scan(0);
if(key==KEY_UP_PRESS)
{
k++;
if(k>255)k=255;
AT24CXX_WriteOneByte(0,k);
printf("写入的数据是:%d\r\n",k);
}
else if(key==KEY1_PRESS)
{
k=AT24CXX_ReadOneByte(0);
printf("读取的数据是:%d\r\n",k);
}
i++;
if(i%20==0)LED1=!LED1;
delay_ms(10);
}
}