完整代码:Pastebin
启用评论的完整代码(谷歌云端硬盘(:SerialGrapherV0.9
正在进行的代码接近底部。
youTube 图形代码运行示例:Grapher
背景:我的目标是编写一个库,允许调用方Arduino通过串行驱动被调用方Arduino,并在SSD1306 I2C显示器上打印到主定义的图形或图形(没有SPI版本可供测试(。图形代码已完成。目前我可以有 4 个可以同步或异步更新的图形,没有空白,只写入需要更新的部分。
两个 arduinos 目前运行相同的草图,并通过与地面绑定的pullup_input确定它们的角色,但是在更高版本中,草图将使用带有 #defined 布尔值的 if 语句进行编译,以大大节省调用方 arduino 的程序空间。
迄今: 实际的图形正在工作,并且每当图形添加(graphNumber,newVal(时图形都会更新;被称为。 每个图的 xpos、ypos、xlength 和 ylength 可以在调用方定义如下:
#define masterGraphNum 4 //Set this to the number of Graphs you want.
graphStruct graph[masterGraphNum] = { //Each set of brackets is an instance of a graph, one for each specified in graphNum, set the array number on the receiver to the max number of graphs you can use.
//Graph 1 //Usage: {LeftX, TopY, width, height}
{0, 0, 31, 32},
//Graph 2
{32, 0, 31, 32},
//Graph 3
{64, 0, 31, 32},
//Graph 4
{96, 0, 31, 32},
};
目前我正在尝试使用delete[] (graph);
后跟graphStruct *graph = new graphStruct[incomingGraphNum];
其中 incomingGraphNum 是由调用方发送并由被调用方接收的 int,这似乎一开始有效,但是在短时间绘制 ~15 秒后,arduino 崩溃并重新启动。
流:
- 被叫方无限期等待连接
- 调用方发送就绪字节
- 被叫方确认
- 调用方发送所需的图形数
- 不起作用:重新初始化图形
- 图形通过调用函数添加数据
- NYI:通过串行发送图形编号和新值
我的问题是现在从函数中实例化全局可访问的结构数组,因为我不想将图形的数量预先编码到被调用者中,以及在结构中分配缓冲区数组的大小。
要使函数工作 图[] 需要全局声明。我想在被调用方设置期间在函数中全局声明 graph[图数],因为我想将其变成我未来项目的即插即用诊断工具。
后续步骤: 设置数据包以发送图形数据。不太难,基本上发送两个整数,如(graph#,graphData( 添加图表"标题"(如"ACC"或"光强度"(
实现:
- 绘图系统
- 简单的串行"呼叫 - 响应"系统和确认系统。(刚刚发现了Arduino IDE中包含的流函数,目前正在重写一些部分以使用Serial.parseInt((而不是修改后的serialEvent((。
- 基本错误处理
- 循环/秒计数器
一些可能会有所帮助的想法。
显示为 128 像素,因此您需要一个不超过该值的缓冲区。我建议你把它做成一个单一的全局缓冲区(而不是每个结构都有自己的缓冲区(。这永远不需要用new/delete
重新调整大小,无论你有多少图表。
uint8_t global_graph_buffer[128];
请注意,我已将其从int
更改为byte
。显示器的高度只有 30 或 40 像素 (?(,因此无需存储任何大于此的数字。只需在端口上输入时缩小值即可。
graph_buffer[x] = map(incoming_data, 0, max_input, 0, height_of_graph);
请参阅 Arduinomap()
函数。
接下来,你真的需要图表的y_pos和高度吗?您是否打算使用超过 1 行图表?如果没有,请删除这些结构成员。此外,您还可以摆脱x_pos和宽度字段。这些可以根据指数计算。
struct graphStruct {
uint8_t gx; // Removed
uint8_t gy; // Removed
uint8_t gw; // Removed
uint8_t gh; // Removed
int gVal; // What is this for?
//int graphBuffer[graphBufferSize]; This is gone
uint8_t start_index; // First index in the global array
uint8_t end_index; // Last index
bool isReady; // What is this for?
};
要计算x_pos和宽度:
x_pos = start_index
width = end_index - start_index
要处理传入的数据,请仅移动给定图形的缓冲区部分并添加值:
int incoming_data = some_value_from_serial;
// Shift
for (byte i = graph[graphNumber].start_index+1; i < graph[graphNumber].end_index; i++) {
global_graph_buffer[i] = global_graph_buffer[i-1]
}
// Store
global_graph_buffer[i] = map(incoming_data, 0, graphMax, 0, 128);
最后,您需要考虑:一次可以实际显示多少个图形?设置一个最大值,并在开始时只创建那么多结构。如果您使用全局缓冲区,正如我建议的那样,您可以多次重用结构(不必使用new/delete
(。只需更改start_index
和end_index
字段即可。
不确定这些是否有帮助,但也许您可以从中获得一些想法。