1.5wuling_zhuanjietou/SYSTEM/24cxx.c
2024-10-17 09:06:51 +08:00

464 lines
9.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "24cxx.h"
#include "bsp_i2c_gpio.h"
#include "led.h"
//初始化IIC
void ee_Init(void)
{
bsp_InitI2C();
}
//在AT24CXX指定地址读取一个数据
//ReadAddr :开始读数的地址
//返回值 :读取到的数据
u8 ee_ReadOneByte(u16 ReadAddr)
{
u8 temp = 0;
IIC_Start();
if (EE_TYPE > AT24C16) {
IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_WR);//发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr / 256); //发送高地址
} else IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_WR + ((ReadAddr / 256) << 1)); //发送器件地址0xA0,写数据
IIC_Wait_Ack();
IIC_Send_Byte(ReadAddr % 256); //发送低地址
IIC_Wait_Ack();
IIC_Start();
if (1)IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_RD); //进入接收模式
else IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_RD + ((ReadAddr / 256) << 1)); //进入接收模式
IIC_Wait_Ack();
temp = IIC_Read_Byte(1);
IIC_Stop();//产生一个停止条件
return temp;
}
//在AT24CXX指定地址写一个数据
//WriteAddr:写入数据的目的地址
//data :要写入的数据
void ee_WriteOneByte(u16 WriteAddr, u8 data)
{
IIC_Start();
if (EE_TYPE > AT24C16) {
IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_WR);
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr / 256); //发送高地址
} else IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_WR + ((WriteAddr / 256) << 1));
IIC_Wait_Ack();
IIC_Send_Byte(WriteAddr % 256); //发送低地址
IIC_Wait_Ack();
IIC_Send_Byte(data);
IIC_Wait_Ack();
IIC_Stop();//产生一个停止条件
Delay_MS(6);
}
#if 1
//向EEPROM写入多个字节
uint8_t ee_WriteBytes(uint8_t *_pWriteBuf, uint16_t _usAddress, uint16_t _usSize)
{
uint16_t i, m;
uint16_t addr;
addr = _usAddress;
for (i = 0; i < _usSize; i++) {
//当第一次或者地址对齐到8就要重新发起起始信号和EEPROM地址
//为了解决8地址对齐问题
if (i == 0 || (addr % EE_PAGE_SIZE) == 0) {
if (i != 0) {
IIC_Stop();
Delay_MS(6);
}
//发送起始地址
IIC_Start();
//发送设备写地址
if (EE_TYPE > AT24C16) {
IIC_Send_Byte(EE_DEV_ADDR|EEPROM_I2C_WR);
if (IIC_Wait_Ack() != 0) {
goto cmd_fail;
}
IIC_Send_Byte(addr / 256); //发送高地址
} else IIC_Send_Byte((EE_DEV_ADDR + ((addr / 256) << 1)) | EEPROM_I2C_WR);
//等待从机应答
if (IIC_Wait_Ack() != 0) {
goto cmd_fail;
}
//EEPROM应答后发送EEPROM的内部存储器地址
IIC_Send_Byte((uint8_t)addr);
//等待从机应答
if (IIC_Wait_Ack() != 0) {
goto cmd_fail;
}
}
//发送数据
IIC_Send_Byte(_pWriteBuf[i]);
//等待应答
if (IIC_Wait_Ack() != 0) {
goto cmd_fail;
}
//写入地址加1
addr++;
}
IIC_Stop();
return 1;
cmd_fail:
IIC_Stop();
return 0;
}
uint8_t ee_ReadBytes(uint8_t *_pReadBuf, uint16_t _usAddress, uint16_t _usSize)
{
uint16_t i;
//发送起始地址
IIC_Start();
//发送设备写地址
if (EE_TYPE > AT24C16) {
IIC_Send_Byte(EE_DEV_ADDR);
if (IIC_Wait_Ack() != 0) {
goto cmd_fail;
}
IIC_Send_Byte(_usAddress / 256); //发送高地址
} else IIC_Send_Byte((EE_DEV_ADDR + ((_usAddress / 256) << 1)) | EEPROM_I2C_WR);
if (IIC_Wait_Ack() != 0) {
goto cmd_fail;
}
IIC_Send_Byte((uint8_t)_usAddress);
if (IIC_Wait_Ack() != 0) {
goto cmd_fail;
}
IIC_Start();
if (EE_TYPE > AT24C16) IIC_Send_Byte(EE_DEV_ADDR | EEPROM_I2C_RD);
else IIC_Send_Byte((EE_DEV_ADDR + ((_usAddress / 256) << 1)) | EEPROM_I2C_RD);
if (IIC_Wait_Ack() != 0) {
goto cmd_fail;
}
for (i = 0; i < _usSize; i++) {
/* 每读完1个字节后需要发送Ack 最后一个字节不需要Ack发Nack */
_pReadBuf[i] = IIC_Read_Byte(i != _usSize - 1?1:0);
}
IIC_Stop();
return 1;
cmd_fail:
IIC_Stop();
return 0;
}
#endif
#if 0
static void IIC1_Start(void); //发送起始信号
static void IIC1_Stop(void); //发送停止信号
static void IIC1_Write_Byte(u8 dat);//发送一个字节
static u8 IIC1_Read_Byte(unsigned char ack);//接收一个字节
static u8 IIC1_Wait_Ack(void);//等待ACK信号
static void IIC1_Ack(void);//发送ACK信号
static void IIC1_NAck(void);//不发送ACK信号
void I2C_delay(uint16_t n)
{
u8 i = 100 * n; //这里可以优化速度 经测试最低到5还能写入
while (i) {
i--;
}
}
//初始化IIC
void AT24cxx_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /* 打开GPIO时钟 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; //SDA,SCL
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
IIC_SDA1;
IIC_SCL1;
}
//在AT24CXX指定地址读取一个数据
//ReadAddr :开始读数的地址
//返回值 :读取到的数据
u8 AT24cxx_ReadOneByte(u16 ReadAddr)
{
u8 temp = 0;
IIC1_Start();
if (EE_TYPE > AT24C16) {
IIC1_Write_Byte(0xa0);//发送写命令
IIC1_Wait_Ack();
IIC1_Write_Byte(ReadAddr / 256); //发送高地址
} else IIC1_Write_Byte(0xa0 + ((ReadAddr / 256) << 1)); //发送器件地址0xA0,写数据
IIC1_Wait_Ack();
IIC1_Write_Byte(ReadAddr % 256); //发送低地址
IIC1_Wait_Ack();
IIC1_Start();
if (EE_TYPE > AT24C16)IIC1_Write_Byte(0xa1); //进入接收模式
else IIC1_Write_Byte(0xa1 + ((ReadAddr / 256) << 1)); //进入接收模式
IIC1_Wait_Ack();
temp = IIC1_Read_Byte(1);
IIC1_Stop();//产生一个停止条件
return temp;
}
//在AT24CXX指定地址写一个数据
//WriteAddr:写入数据的目的地址
//data :要写入的数据
void AT24cxx_WriteOneByte(u16 WriteAddr, u8 data)
{
IIC1_Start();
if (EE_TYPE > AT24C16) {
IIC1_Write_Byte(0xa0);
IIC1_Wait_Ack();
IIC1_Write_Byte(WriteAddr / 256); //发送高地址
} else IIC1_Write_Byte(0xa0 + ((WriteAddr / 256) << 1));
IIC1_Wait_Ack();
IIC1_Write_Byte(WriteAddr % 256); //发送低地址
IIC1_Wait_Ack();
IIC1_Write_Byte(data);
IIC1_Wait_Ack();
IIC1_Stop();//产生一个停止条件
I2C_delay(2);
}
//在AT24CXX指定地址开始写入指定长度的数据
//该函数用于写入16位或32位的数据
//WriteAddr:开始写入的地址
//data :要写入的数据
//len :要写入数据的长度24
void AT24cxx_WriteLenByte(u16 WriteAddr, u32 data, u8 len)
{
u8 i;
for (i = 0; i < len; i++) {
AT24cxx_WriteOneByte(WriteAddr + i, (data >> (8 * i)) & 0xff);
}
}
//在AT24CXX指定地址开始读出指定长度的数据
//该函数用于读出16bit或者32bit的数据.
//ReadAddr :开始读出的地址
//返回值 :数据
//len :要读出数据的长度2,4
u32 AT24cxx_ReadLenByte(u16 ReadAddr, u8 len)
{
u8 i;
u32 temp = 0;
for (i = 0; i < len; i++) {
temp <<= 8;
temp += AT24cxx_ReadOneByte(ReadAddr + len - i - 1);
}
return temp;
}
//在AT24CXX指定地址开始写入指定长度的数据
//该函数用于写入指定的字节数
//WriteAddr:开始写入的地址
//buf :数据数组首地址
//len :要写入数据的个数
void AT24cxx_Write(u16 WriteAddr, u8 *buf, u16 len)
{
u16 i;
for (i = 0; i < len; i++) {
IWDG_Feed();
AT24cxx_WriteOneByte(WriteAddr, *buf);
WriteAddr++;
buf++;
}
}
//在AT24CXX指定地址开始读出指定长度的数据
//该函数用于读出指定的字节数
//ReadAddr:开始读出数据的地址
//len :要写入数据的个数
//buf :数据数组首地址
void AT24cxx_Read(u16 ReadAddr, u8 *buf, u16 len)
{
while (len--) {
IWDG_Feed();
*buf++ = AT24cxx_ReadOneByte(ReadAddr++);
}
}
//检查AT24CXX是否正常
//这里用了24XX的第一个地址(0)来存储标志字.
//返回1检测失败
//返回0检查成功
u8 AT24cxx_Check(void)
{
u8 temp1, temp2;
AT24cxx_WriteOneByte(0x010, 0x55);
temp1 = AT24cxx_ReadOneByte(0x010); //避免每次开机都写AT24CXX
temp2 = temp1;
if (temp2 == 0x55)return 0;
else {
AT24cxx_WriteOneByte(0x010, 0x55);
temp1 = AT24cxx_ReadOneByte(0x010);
temp2 = temp1;
if (temp2 == 0x55)return 0;
}
return 1;
}
//产生IIC起始信号
static void IIC1_Start(void)
{
IIC_SDA1;
IIC_SCL1;
I2C_delay(4);
IIC_SDA0;
I2C_delay(4);
IIC_SCL0;
I2C_delay(4);
}
//产生IIC停止信号
static void IIC1_Stop(void)
{
IIC_SDA0;
IIC_SCL1;
I2C_delay(2);
IIC_SDA1;
I2C_delay(4);
// IIC_SCL0;
}
//返回1接收应答失败返回0接收应答成功
static u8 IIC1_Wait_Ack(void)
{
u8 i;
SDA_IN();
IIC_SCL0;
I2C_delay(2);
IIC_SCL1;
I2C_delay(2);
while (Read_IIC_SDA()) {
i++;
if (i > 250) {
IIC1_Stop();
return 1;
}
}
IIC_SCL0;
I2C_delay(2);
return 0;
}
//产生ACK应答
static void IIC1_Ack(void)
{
IIC_SCL0;
SDA_OUT();
IIC_SDA0;
I2C_delay(2);
IIC_SCL1;
I2C_delay(2);
IIC_SCL0;
}
//不产生ACK应答
static void IIC1_NAck(void)
{
IIC_SCL0;
SDA_OUT();
IIC_SDA1;
I2C_delay(2);
IIC_SCL1;
I2C_delay(2);
IIC_SCL0;
}
//IIC发送一个字节
//返回从机有无应答
//0有应答
//1无应答
void IIC1_Write_Byte(u8 dat)
{
u8 t;
SDA_OUT();
I2C_delay(2);
for (t = 0; t < 8; t++) {
IIC_SCL0;
if (dat & 0x80) {
IIC_SDA1;
} else {
IIC_SDA0;
}
I2C_delay(2);
IIC_SCL1;
dat <<= 1;
I2C_delay(2);
}
IIC_SCL0;
I2C_delay(2);
}
//读1个字节ack=0时发送ACK,ack=1发送NACK
u8 IIC1_Read_Byte(unsigned char ack)
{
u8 i, receive;
SDA_IN();//SDA设为输入
IIC_SDA0;
I2C_delay(2);
for (i = 0; i < 8; i++) {
IIC_SCL0;
I2C_delay(2);
IIC_SCL1;
receive <<= 1;
I2C_delay(2);
if (Read_IIC_SDA())receive++;
I2C_delay(2);
}
IIC_SDA1;
I2C_delay(2);
IIC_SCL0;
I2C_delay(2);
if (!ack)
IIC1_Ack();
else
IIC1_NAck();
return receive;
}
#endif