单片机实现分页显示环形更新的历史数据
就是在EEPROM 或者FLASH 里采用类似环形缓冲区的结构来存储历史数据,如果数据总数超过了总容量,就用最新数据覆盖最旧的数据。然后把历史数据按从新到旧的顺序分页显示在屏幕上。
环形缓冲
需要记录当前写入的数据总数和写入位置:
- 如果写入量超过了总的存储容量,则数据总数不再增加,所以数据总数最大等于存储容量;
- 新的数据总是写入到当前写入位置,然后让写入位置自增;
- 当写入量超过总容量时,写入位置归零,重新从开头写,从而覆盖旧数据,形成回环;
- 最新的数据位于当前写入位置前一个;
下面不讨论用环形缓冲记录历史数据具体怎么实现,只考虑显示数据。
分页显示
第一页的第一个数据是当前写入位置的前一个,后面的数据读取位置依次递减,和写入位置的递增刚好相反,如果减到了0,就回到缓冲区末尾。
比方说,如果缓冲区总量是10,里面的当前数据是:
u16 data_buffer[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
写入位置是2,那么就从1 开始向前读。如果一页显示4 个数据,那么第一页输出的内容就是[ 1, 0, 9, 8 ]
,后面的页依此类推。如果缓冲区总容量是10,但是当前只记录了2 个数据,那么读取时就不能自动回环,第一页内容是[ 1, 0 ]
,没有后续。
验证实现
下面是用来验证分页显示算法的实现,可以直接运行:
#include <iostream>
#include <stdint.h>using namespace std;using u16 = uint16_t;// 环形缓冲区 - 存储历史数据
u16 data_buf[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19};// 分页配置
u16 ITEMS_PER_PAGE = 4; // 每页显示4条数据
u16 BUFFER_SIZE = 10; // 缓冲区总容量// 这些用来跟踪数据记录状态的变量要和数据一样存储在Flash 或EEPROM 里,
// 每次写入新数据时更新
u16 current_index = 9; // 当前读取位置,根据当前写入位置计算,这里省略
u16 total_items = 10; // 当前记录的数据量// 分页显示函数
// 从第一页开始,page_num 最小等于1
void show_page(u16 page_num) {// 页码检查 (从1开始)if(page_num < 1) {return;}// 计算当前页之前有多少条数据u16 items_before = ITEMS_PER_PAGE * (page_num - 1);// 检查请求的页码是否超出范围if(items_before >= total_items) {return;}// 计算要显示的页的起始位置u16 start_index;if(items_before > current_index) {// 处理环形缓冲区回绕u16 wrap_around = items_before - current_index;start_index = BUFFER_SIZE - wrap_around;} else {start_index = current_index - items_before;}// 计算当前页实际显示的数据量,如果是最后一页,可能剩余数据不足一整页u16 total_requested = items_before + ITEMS_PER_PAGE;u16 items_to_show = ITEMS_PER_PAGE;if(total_requested > total_items) {items_to_show = total_items - items_before;}// 显示数据for(; items_to_show > 0; --items_to_show) {// 从后往前遍历一页数据cout << data_buf[start_index] << endl;if(start_index < 1) {start_index = BUFFER_SIZE - 1;}else {--start_index;}}
}// 主函数 - 测试代码
int main() {show_page(1);cout << "=============" << endl;show_page(2);cout << "=============" << endl;show_page(3);return 0;
}