Files
timemodle/src/main.cpp
2026-09-03 11:09:10 +08:00

289 lines
7.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 <Wire.h>
#include <TM1650.h>
#include <SPI.h>
#define SW_PIN 1 //重置TIMEER
#define FRAM_CS 10
#define FRAM_COUNT 10
#define FRAM_ADDR_OFFSET_TIME 4
#define FRAM_START_ADDR_TIME 0x0000 // 时间存储地址,0x0000 – 0x1FFF
#define FRAM_WREN 0x06 // 使能
#define FRAM_READ 0x03 // 读操作
#define FRAM_WRITE 0x02 // 写操作
#define FRAM_WRDI 0x04 //失能
#define FRAM_RDSR 0x05 //读状态
#define FRAM_WRSR 0x01 //写状态
uint32_t TimeTotle = 0;
uint32_t timebegin = 0;
TM1650 d;
//片选拉低,开始SPI
inline void framSelect()
{
SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
digitalWrite(FRAM_CS, LOW);
}
//片选拉高,结束SPI
inline void framDeselect()
{
digitalWrite(FRAM_CS, HIGH);
SPI.endTransaction();
}
//写使能,在执行写操作前必须调用
inline void framWriteEnable()
{
framSelect();
SPI.transfer(FRAM_WREN);
framDeselect();
}
uint8_t framReadStatus()
{
framSelect();
SPI.transfer(FRAM_RDSR);
uint8_t s = SPI.transfer(0x00);
framDeselect();
return s;
}
void framWriteStatus(uint8_t s)
{
framWriteEnable();
framSelect();
SPI.transfer(FRAM_WRSR);
SPI.transfer(s);
framDeselect();
}
void framWriteDisable()
{
framSelect();
SPI.transfer(FRAM_WRDI);
framDeselect();
}
// 确保可写(不需要保护时清零SR),放在 SPI.begin 与片选初始化之后调用一次 ensureFramWritable() ,即可确认未被保护。
void ensureFramWritable() {
uint8_t sr = framReadStatus();
// 若不需要任何块保护,统一清零
if (sr != 0x00) {
framWriteStatus(0x00);
}
framWriteDisable();
}
//读操作
//addr:读取地址(16位)
//返回:读取的32位数据(大端序)
uint32_t framRead32(uint16_t addr)
{
framSelect(); // 片选拉低,开始SPI
SPI.transfer(FRAM_READ); // 发送读操作指令
SPI.transfer((addr >> 8) & 0xFF); // 发送高8位地址
SPI.transfer(addr & 0xFF); // 发送低8位地址
uint32_t v = 0;
v |= ((uint32_t)SPI.transfer(0x00)) << 24; // 接收高8位数据
v |= ((uint32_t)SPI.transfer(0x00)) << 16; // 接收次高8位数据
v |= ((uint32_t)SPI.transfer(0x00)) << 8; // 接收次低8位数据
v |= ((uint32_t)SPI.transfer(0x00)); // 接收低8位数据
framDeselect(); // 片选拉高,结束SPI
return v; // 返回读取到的32位数据(大端序)
}
//写操作
//addr:写入地址(16位)
//val:写入的数据(32位)
void framWrite32(uint16_t addr, uint32_t val)
{
framWriteEnable();
framSelect(); // 片选拉低,开始SPI
SPI.transfer(FRAM_WRITE); // 发送写操作指令
SPI.transfer((addr >> 8) & 0xFF); // 发送高8位地址
SPI.transfer(addr & 0xFF); // 发送低8位地址
SPI.transfer((val >> 24) & 0xFF); // 发送高8位数据
SPI.transfer((val >> 16) & 0xFF); // 发送次高8位数据
SPI.transfer((val >> 8) & 0xFF); // 发送次低8位数据
SPI.transfer(val & 0xFF); // 发送低8位数据
framDeselect(); // 片选拉高,结束SPI
}
// TickType_t xLastWakeTime;
const TickType_t xFrequency = 1000 - 100;
bool flashdot=true;
//显示自定义4字符
//a:长度为4的字符数组,按从右到左显示
//dot:小数点位置索引
void showtime(char a[4],int dot=1)
{
char b[4];
for (size_t i = 0; i < 4; i++)
{
b[i]=a[3-i];
/* code */
}
d.displayString(b);
d.setDot(dot,flashdot);
flashdot=!flashdot;
}
//显示累计秒数
//second:累计秒数,内部按小时格式化为4位显示
void showtime(double second)
{
char bb[4];
int a=second;
int b=a%3600;
b=b*10/3600;
bb[0]=String(b).charAt(0);
int c=a/3600;
b=c%10;
bb[1]=String(b).charAt(0);
c=c/10;
b=c%10;
bb[2]=String(b).charAt(0);
c=c/10;
b=c%10;
bb[3]=String(b).charAt(0);
d.displayString(bb);
d.setDot(1,flashdot);
flashdot=!flashdot;
//Serial.println(bb);
}
int iiii=10;
void setup()
{
Serial.begin(115200); //Start serial communication at 9600 for debug statements
Serial.println("\n============system start===========\n");
Wire.setPins(5, 4); //SDA, SCL
Wire.begin(); //Join the bus as master
delay(500);
pinMode(SW_PIN, INPUT_PULLUP);
timebegin=millis();
pinMode(FRAM_CS, OUTPUT);
digitalWrite(FRAM_CS, HIGH);
SPI.begin(12, 13, 11, FRAM_CS); //SCK, MISO, MOSI, CS
ensureFramWritable();
uint32_t time_buffer[FRAM_COUNT];
for (uint32_t i = 0; i < FRAM_COUNT; i++)
{
time_buffer[i] = framRead32(FRAM_START_ADDR_TIME + i * FRAM_ADDR_OFFSET_TIME);
Serial.printf("time_buffer[%d] = %d \n", i, time_buffer[i]);
}
bool flag=true;
for (uint32_t i = 0; i < FRAM_COUNT; i++)
{
if(time_buffer[0] == time_buffer[i])
{
TimeTotle = time_buffer[0];
}
else
{
flag=false;
break;
}
}
uint32_t time_count_buffer[FRAM_COUNT] = {0,0,0,0,0,0,0,0,0,0};
uint32_t max_count = 0;
uint32_t max_count_index = 0;
if(!flag)
{
Serial.println("Time Counting...");
for (uint32_t i = 0; i < FRAM_COUNT; i++)
{
for(uint32_t j = 0; j < FRAM_COUNT; j++)
{
if(time_buffer[i] == time_buffer[j])
{
time_count_buffer[i]++;
}
}
Serial.printf("time_count_buffer[%d] = %d \n", i, time_count_buffer[i]);
if(time_count_buffer[i] > max_count)
{
max_count = time_count_buffer[i];
max_count_index = i;
}
}
Serial.printf("Max Count: %d \n", max_count);
TimeTotle = time_buffer[max_count_index];
}
Serial.printf("Initial TimeTotle: %d \n", TimeTotle);
Serial.println("TM1650 Example Code");
d.init();
d.setBrightness(0x01);
// xLastWakeTime = xTaskGetTickCount();
// unsigned long timenow=millis();
// if (TimeTotle<(unsigned long)(999.8*3600))
// {
// TimeTotle=TimeTotle+(timenow-timebegin)/1000;
// timebegin=timenow;
// }
// showtime(TimeTotle*1.0);
}
void loop()
{
unsigned long timenow=millis();
TimeTotle = TimeTotle+(timenow-timebegin)/1000;
timebegin = timenow;
Serial.printf("TimeTotle: %d \n", TimeTotle);
if (TimeTotle<(unsigned long)(999.8*3600))
{
showtime(TimeTotle*1.0);
}
else
{
uint32_t max_time = 999.9 * 3600;
Serial.printf("Time is over \n" );
showtime(max_time*1.0);
}
// Serial.println("show time");
if (digitalRead(SW_PIN)==0)
{
Serial.println("you have put the butten reset");
iiii--;
if (iiii==0)
{
TimeTotle=0;
for (uint32_t i = 0; i < FRAM_COUNT; i++)
{
framWrite32((FRAM_START_ADDR_TIME + i * FRAM_ADDR_OFFSET_TIME), (uint32_t)TimeTotle);
vTaskDelay(10);
}
Serial.println("you have reset the time");
}
}
else
{
iiii=10;
}
// Serial.println("save time");
for (uint32_t i = 0; i < FRAM_COUNT; i++)
{
framWrite32((FRAM_START_ADDR_TIME + i * FRAM_ADDR_OFFSET_TIME), (uint32_t)TimeTotle);
vTaskDelay(10);
}
vTaskDelay(xFrequency);
// delay(1000);
}