shuichan_new/STM32F103_App1/HardWare/24C02/24c02.c

227 lines
7.5 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 "app_loop.h" /* storage_lock/unlock跨任务访问互斥 */
#include <string.h>
#include <stdio.h>
/* MQTT 配置参数 — 设备身份只存 EEPROM由蓝牙 SETMQTT 灌入),固件不含身份。
* 服务器地址/端口/主题默认取自 main.h 宏,也可用蓝牙 SETIP 修改 */
uint8_t g_mqtt_configured = 0; /* 1=EEPROM 中已有有效设备身份 */
MqttInfo_Str MqttInfoStr = {
.ClientID = "",
.Username = "",
.Passward = "",
.ServerIP = MQTT_SERVER_IP,
.Topic = MQTT_TOPIC,
.ServerPort = MQTT_SERVER_PORT,
.Relay_State = {0},
.Magic = 0, /* 身份写入SETMQTT时置 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 读初始化错误 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 写入错误 @%u, 重试=%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;
uint8_t ret;
ptr = data;
storage_lock();
ret = m24c02ReadSequential(addr,ptr,len);
storage_unlock();
return ret;
}
/*-------------------------------------------------*/
/*函数名:向 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 页写入错误 @%u, 重试=%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;
storage_lock();
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 写入失败 @%u, err=0x%02X", addr, e);
}
err |= e;
addr += chunk;
ptr += chunk;
len -= chunk;
}
storage_unlock();
if (err) {
log_warn("> EEPROM 写入总 ACK 错误=0x%02X", err);
} else {
log_info("> EEPROM 写入成功");
}
return err;
}
/*函数名从EEprom读取或验证MQTT配置信息 */
/*输入参数:无 */
/*返回值:无 */
/*-------------------------------------------------*/
void eepromReadInfo(void) {
uint8_t read_err;
/* 先做一次单字节读写探测确认IIC基本通信正常不打印异常时才报 */
uint8_t probe_wr = 0xA5;
m24c02WriteOneByte(250, probe_wr);
uint8_t probe_rd = m24c02ReadOneByte(250);
if (probe_rd != probe_wr) {
log_warn("> EEPROM 探测异常: 写=0x%02X, 读=0x%02X", probe_wr, probe_rd);
}
/* 从EEPROM读取配置不打印err 异常时才报) */
memset(&MqttInfoStr, 0, MQTT_STRUCT_LEN);
read_err = eepromReadData(0, &MqttInfoStr, MQTT_STRUCT_LEN);
if (read_err != 0) {
log_warn("> EEPROM 读取异常 err=%d", read_err);
}
/* 配置有效 = 魔数匹配 且 客户端ID非空身份只认 EEPROM不再与编译宏比对 */
if (MqttInfoStr.Magic == EEPROM_MAGIC && MqttInfoStr.ClientID[0] != 0) {
g_mqtt_configured = 1;
log_info("EEPROM 配置有效, Ver=%u", MqttInfoStr.Ver);
return;
}
/* 未配置:等待蓝牙 SETMQTT 灌入(不写 EEPROM */
g_mqtt_configured = 0;
if (MqttInfoStr.Magic != EEPROM_MAGIC) {
/* 全新板/整片擦除(全0xFF):全部回编译默认值,版本号/继电器状态归 0 */
memset(&MqttInfoStr, 0, MQTT_STRUCT_LEN);
strcpy(MqttInfoStr.ServerIP, MQTT_SERVER_IP);
strcpy(MqttInfoStr.Topic, MQTT_TOPIC);
MqttInfoStr.ServerPort = MQTT_SERVER_PORT;
} else {
/* 有 Magic 但无身份(如只 SETIP 过):保留 EEPROM 服务器配置,身份留空;
* 服务器字段防御:首字符非数字视为脏数据,回默认值 */
MqttInfoStr.ClientID[0] = 0;
MqttInfoStr.Username[0] = 0;
MqttInfoStr.Passward[0] = 0;
if (MqttInfoStr.ServerIP[0] < '0' || MqttInfoStr.ServerIP[0] > '9') {
strcpy(MqttInfoStr.ServerIP, MQTT_SERVER_IP);
strcpy(MqttInfoStr.Topic, MQTT_TOPIC);
MqttInfoStr.ServerPort = MQTT_SERVER_PORT;
}
}
log_warn("> EEPROM 无设备身份,进入待配置模式(蓝牙 SETMQTT 灌入)");
}