shuichan_old/V1.1/STM32F103_App1/HardWare/24C02/24c02.c

225 lines
8.3 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 "24c02.h"
#include "iic.h"
#include <string.h>
#include <stdio.h>
/* MQTT 配置参数 — 首次上电自动写入 EEPROM
* 所有默认值来自 main.h 的 MQTT_xxx 宏,保证全局唯一配置源
*/
MqttInfo_Str MqttInfoStr = {
.ClientID = MQTT_CLIENT_ID,
.Username = MQTT_USERNAME,
.Passward = MQTT_PASSWORD,
.ServerIP = MQTT_SERVER_IP,
.Topic = MQTT_TOPIC,
.ServerPort = MQTT_SERVER_PORT,
.Relay_State = {0},
.Magic = 0, /* 首次上电由 eepromReadInfo() 写入 EEPROM_MAGIC */
};
/*-------------------------------------------------*/
/*读取AT24C02指定地址的一个字节数据 */
/*输入参数:ReadAddr:需要读取数据的地址 */
/*返回值:读取到的数据 */
/*-------------------------------------------------*/
uint8_t m24c02ReadOneByte(uint8_t ReadAddr) {
uint8_t receive;
uint8_t err = 0;
iicStart();
err |= iicSendByteAck(M24C02_WADDR);
err |= iicSendByteAck(ReadAddr);
iicStart();
err |= iicSendByteAck(M24C02_RADDR);
if (err) {
iicStop();
log_warn("> EE read init err=0x%02X", err);
return 0xFF;
}
receive=iicReadByte(0);
iicStop();
HAL_Delay(5);
return receive;
}
/*-------------------------------------------------*/
/*函数名:向指定地址写入一个数据 */
/*输入参数:WriteAddr :写入数据的目的地址 */
/*输入参数:DataToWrite:要写入的数据 */
/*返回值0=成功, 1=无ACK(设备未响应) */
/*-------------------------------------------------*/
uint8_t m24c02WriteOneByte(uint8_t WriteAddr,uint8_t DataToWrite) {
uint8_t ack_err = 0;
uint8_t retry = 3;
while (retry--) {
ack_err = 0;
iicStart();
ack_err |= iicSendByteAck(M24C02_WADDR);
ack_err |= iicSendByteAck(WriteAddr);
ack_err |= iicSendByteAck(DataToWrite);
iicStop();
HAL_Delay(10);
if (ack_err == 0) break;
log_warn("> EE write err @%u, retry=%u", WriteAddr, retry);
HAL_Delay(5);
}
return ack_err;
}
/*-------------------------------------------------*/
/*函数名:从指定的地址读取指定长度的数据 */
/*输入参数:ReadAddr:需要读取数据的地址 */
/*输入参数:Redata:保存数据的缓冲区 */
/*输入参数:Redatalen:读取数据的长度 */
/*返回值0=成功, 1=设备无ACK */
/*-------------------------------------------------*/
uint8_t m24c02ReadSequential(uint8_t ReadAddr,uint8_t *Redata,uint16_t Redatalen) {
uint16_t i;
uint8_t ack_err = 0;
iicStart();
ack_err |= iicSendByteAck(M24C02_WADDR);
ack_err |= iicSendByteAck(ReadAddr);
iicStart();
ack_err |= iicSendByteAck(M24C02_RADDR);
for(i=0; i<(Redatalen-1); i++) {
Redata[i]=iicReadByte(1);
}
Redata[Redatalen-1]=iicReadByte(0);
iicStop();
HAL_Delay(5);
return ack_err;
}
/*-------------------------------------------------*/
/*函数名从EEprom指定的地址读取数据 */
/*输入参数:addr:需要读取数据的地址 */
/*输入参数:data:读取数据缓冲区 */
/*输入参数:len:要读取的数据长度 */
/*返回值0=成功, 1=设备无ACK */
/*-------------------------------------------------*/
uint8_t eepromReadData(uint8_t addr,void *data, uint16_t len) {
uint8_t *ptr;
ptr = data;
return m24c02ReadSequential(addr,ptr,len);
}
/*-------------------------------------------------*/
/*函数名:向 24C02 写入同一页内的若干字节 */
/*输入参数:WriteAddr:起始地址 */
/* data :数据缓冲区 */
/* len :长度(不得跨页, 页大小 8 字节) */
/*返回值0=成功, 1=无ACK(设备未响应) */
/*-------------------------------------------------*/
#define M24C02_PAGE_SIZE 8u
static uint8_t m24c02WritePage(uint8_t WriteAddr, const uint8_t *data, uint8_t len) {
uint8_t ack_err = 0;
uint8_t retry = 3;
uint8_t i;
while (retry--) {
ack_err = 0;
iicStart();
ack_err |= iicSendByteAck(M24C02_WADDR);
ack_err |= iicSendByteAck(WriteAddr);
for (i = 0; i < len && ack_err == 0; i++) {
ack_err |= iicSendByteAck(data[i]);
}
iicStop();
HAL_Delay(10);
if (ack_err == 0) break;
log_warn("> EE page write err @%u, retry=%u", WriteAddr, retry);
HAL_Delay(5);
}
return ack_err;
}
/*-------------------------------------------------*/
/*函数名EEprom指定地址写入指定字节的数据 */
/* 按页边界切分, 页写入, 每页一个写周期 */
/*输入参数:addr地址 */
/*输入参数:data写入的数据 */
/*输入参数:len写入数据的长度 */
/*返回值0=成功, 1=有页写入失败 */
/*-------------------------------------------------*/
uint8_t eepromWriteData(uint8_t addr, void *data, uint16_t len) {
uint8_t *ptr = data;
uint8_t err = 0;
while (len > 0) {
/* 当前地址到页边界的距离, 避免跨页回卷 */
uint8_t chunk = M24C02_PAGE_SIZE - (addr % M24C02_PAGE_SIZE);
if (chunk > len) chunk = (uint8_t)len;
uint8_t e = m24c02WritePage(addr, ptr, chunk);
if (e) {
log_warn("> EE write fail @%u, err=0x%02X", addr, e);
}
err |= e;
addr += chunk;
ptr += chunk;
len -= chunk;
}
if (err) {
log_warn("> EEPROM write total ACK err=0x%02X", err);
} else {
log_info("> EEPROM write OK");
}
return err;
}
/*函数名从EEprom读取或验证MQTT配置信息 */
/*输入参数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void eepromReadInfo(void) {
MqttInfo_Str tmp_read;
uint8_t read_err;
/* 先做一次单字节读写探测确认IIC基本通信正常 */
uint8_t probe_wr = 0xA5;
m24c02WriteOneByte(250, probe_wr);
uint8_t probe_rd = m24c02ReadOneByte(250);
log_info("> EEPROM probe: wr=0x%02X, rd=0x%02X", probe_wr, probe_rd);
/* 从EEPROM读取配置 */
memset(&MqttInfoStr, 0, MQTT_STRUCT_LEN);
read_err = eepromReadData(0, &MqttInfoStr, MQTT_STRUCT_LEN);
log_info("> EEPROM read err=%d, Magic=0x%08X, Ver=%u",
read_err, MqttInfoStr.Magic, MqttInfoStr.Ver);
/* MQTT字段与编译时常量比对 (Ver由OTA管理, 不参与校验) */
if (MqttInfoStr.Magic == EEPROM_MAGIC &&
strcmp(MqttInfoStr.ClientID, MQTT_CLIENT_ID) == 0 &&
strcmp(MqttInfoStr.Username, MQTT_USERNAME) == 0 &&
strcmp(MqttInfoStr.Passward, MQTT_PASSWORD) == 0 &&
strcmp(MqttInfoStr.ServerIP, MQTT_SERVER_IP) == 0 &&
strcmp(MqttInfoStr.Topic, MQTT_TOPIC) == 0 &&
MqttInfoStr.ServerPort == MQTT_SERVER_PORT) {
log_info("EEPROM config valid, Ver=%u", MqttInfoStr.Ver);
} else {
/* 配置损坏/变更/未初始化 */
uint16_t savedVer = MqttInfoStr.Ver;
int magic_ok = (MqttInfoStr.Magic == EEPROM_MAGIC);
memset(&MqttInfoStr, 0, MQTT_STRUCT_LEN);
strcpy(MqttInfoStr.ClientID, MQTT_CLIENT_ID);
strcpy(MqttInfoStr.Username, MQTT_USERNAME);
strcpy(MqttInfoStr.Passward, MQTT_PASSWORD);
strcpy(MqttInfoStr.ServerIP, MQTT_SERVER_IP);
strcpy(MqttInfoStr.Topic, MQTT_TOPIC);
MqttInfoStr.ServerPort = MQTT_SERVER_PORT;
/* 魔数匹配→保留EEPROM版本号; 魔数不匹配→归0(新板/重置) */
MqttInfoStr.Ver = magic_ok ? savedVer : 0;
/* 新板/配置重置时,继电器默认全关(0)不保留空白EEPROM的0xFF */
memset(MqttInfoStr.Relay_State, 0, sizeof(MqttInfoStr.Relay_State));
MqttInfoStr.Magic = EEPROM_MAGIC;
eepromWriteData(0, &MqttInfoStr, MQTT_STRUCT_LEN);
log_info("> EEPROM write done, Magic=0x%08X", MqttInfoStr.Magic);
/* 立即回读验证 */
memset(&tmp_read, 0, MQTT_STRUCT_LEN);
read_err = eepromReadData(0, &tmp_read, MQTT_STRUCT_LEN);
log_info("> EEPROM verify err=%d, Magic=0x%08X, Ver=%u",
read_err, tmp_read.Magic, tmp_read.Ver);
log_info("EEPROM repaired, Ver=%u", MqttInfoStr.Ver);
}
}