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);
}