我有这个:
typedef struct menu_item_def {
byte x; byte y; // Coordinates of the start for the line of test
byte selected; // set to 1 if the menu buttons have this option selected
char *mtext; // What to say, including sprintf placeholders: eg: "STOP TIMER...% 4.2i MIN"
byte mdatatype1; // 0 means this is actual data to print. 1 means go call the supplied function to get the data when needed.
void *mdata1; // Where to get any data from for the menu (upto 2 different bits allowed per line)
} menu_item_type;
然后这个: -
struct menu_item_def sub_menu_items[MAX_MENU_LINES] = {
{1,2,0, "MOTOR RPM.....% 5.1i RPM" ,0,(void *)8500,0,0},
{1,2,1, "ALARM MAX....% 5.2f Lt/Hr" ,0,(void *)85,0,0},
{1,2,0, "ALARM MIN.... %s" ,2,(void *)"ON/OFF",0,0},
};
所以我稍后可以将菜单传递给这样的函数:
Menu(sub_menu_items);
如何将所有内容移动到FLASH中?
我已经尝试过一堆东西的组合,但没有什么能减少"全局变量使用688字节(33%)"消息,除了这个凌乱的kludge:
const char string_0[] PROGMEM = "STOP TIMER....% 5.1i MIN";
struct menu_item_def main_menu_items[MAX_MENU_LINES] = {
{ 1,2,0, (char *)string_0 ,0, (void *)83,0,0 },
{ 1,2,1, "CHEM RATE...% 5.2i Lt/Hr" ,1, (void *)DemoData,0,0 },
{ 1,2,0, "CHEM PUMP....... %s" ,2, (void *)"ON/OFF",0,0 },
};
这会破坏我将可读菜单编码到我的源代码中的能力,并且沿途所有菜单工作都会增加三倍......
我怎样才能以某种方式完成这项工作,同时保持"定义"我的菜单行在我的源代码中是一行的吗?
答案 0 :(得分:1)
假设字符串长度相似,您需要做的就是使字符串成为固定长度的数组,例如。
typedef struct menu_item_def {
byte x; byte y; // Coordinates of the start for the line of test
byte selected; // set to 1 if the menu buttons have this option selected
char mtext [30]; // What to say, including sprintf placeholders: eg: "STOP TIMER...% 4.2i MIN"
byte mdatatype1; // 0 means this is actual data to print. 1 means go call the supplied function to get the data when needed.
void *mdata1; // Where to get any data from for the menu (upto 2 different bits allowed per line)
} menu_item_type;
现在整个结构可以在PROGMEM中,例如
const struct menu_item_def sub_menu_items[MAX_MENU_LINES] PROGMEM = {
{1,2,0, "MOTOR RPM.....% 5.1i RPM" ,0,(void *)8500,0,0},
{1,2,1, "ALARM MAX....% 5.2f Lt/Hr" ,0,(void *)85,0,0},
{1,2,0, "ALARM MIN.... %s" ,2,(void *)"ON/OFF",0,0},
};
要访问字符串数据,您需要一个合适的中间函数,例如
// Print a string from Program Memory directly to save RAM
void printProgStr (const char * str)
{
char c;
if (!str)
return;
while ((c = pgm_read_byte(str++)))
Serial.print (c);
} // end of printProgStr
对于其他值,请视情况使用pgm_read_byte
或pgm_read_word
。
答案 1 :(得分:0)
我能说的最好 - 必须使用宏 - 由于芯片的架构和PROGMEM的工作方式,任何其他方式都是不可能的。
以下说明了我实施的内容,并且或多或少是“答案”。
此代码的结尾是“Readably init structure”部分 - MAKE_MENU宏。
代码的开头是支持宏的所有支持。
警告:arduino中存在各种大小和行端限制和错误:如果你正在使用它,经常和经常编译 - 调试宏错误是不可能的,所以你不能让错误蔓延到
对于任何一个人挠头:PROGMEM允许你把一些东西放在FLASH中(你已经有很多)而不是将它存储在SRAM中(这是非常有限的)。当你使用arduino变量耗尽空间时,你需要做这些事情。
#include <avr/pgmspace.h> // This lets us store static variables in FLASH instead of SRAM
#define MAX_MENU_WIDTH 64 // Max number of characters on a single menu line, PLUS 1
#define SERIAL_RATE 115200 // The BAUD rate of the serial port
// This is the definition of each line in a menu. Each line uses 14 bytes of SRAM
typedef struct menu_item_def {
byte x; byte y; // Coordinates of the start for the line of test
byte selected; // set to 1 if the menu buttons have this option selected
byte mdatatype1; // This number explains how to use the following 2 mdata* as output when needed:
char *mtext; // What to say, including sprintf placeholders: eg: "STOP TIMER...% 4.2i MIN"
void *mdata1; // Refer to the "int Menu()" function for details.
void *mdata2;
void *mdata3;
void *mdata4;
} menu_item_type;
#define Pv(a,b) a ## _ ## b
#define Ev(a,b) Pv(a,b)
// The following macro makes menu definitions easy-to-type, and stores menu text in (unchangeable) FLASH and menu data in (precious but small) SRAM
// These numbers should range from 1 to MAX_MENU_LINES. Best not to edit these, or add more than 12: they're already at the absolute max size that an arduino macro can be.
#define FLASH_PART(n, m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11) \
const char Ev(n,0)[] PROGMEM=m0; \
const char Ev(n,1)[] PROGMEM=m1; \
const char Ev(n,2)[] PROGMEM=m2; \
const char Ev(n,3)[] PROGMEM=m3; \
const char Ev(n,4)[] PROGMEM=m4; \
const char Ev(n,5)[] PROGMEM=m5; \
const char Ev(n,6)[] PROGMEM=m6; \
const char Ev(n,7)[] PROGMEM=m7; \
const char Ev(n,8)[] PROGMEM=m8; \
const char Ev(n,9)[] PROGMEM=m9; \
const char Ev(n,10)[] PROGMEM=m10; \
const char Ev(n,11)[] PROGMEM=m11;
#define MAX_MENU_LINES 12 // How many lines are on each of your menu screens
#define MAKE_MENU(n, x0,y0,s0,m0,t0,f0,d0,z0,q0, x1,y1,s1,m1,t1,f1,d1,z1,q1, x2,y2,s2,m2,t2,f2,d2,z2,q2, x3,y3,s3,m3,t3,f3,d3,z3,q3, x4,y4,s4,m4,t4,f4,d4,z4,q4, x5,y5,s5,m5,t5,f5,d5,z5,q5, x6,y6,s6,m6,t6,f6,d6,z6,q6, x7,y7,s7,m7,t7,f7,d7,z7,q7, x8,y8,s8,m8,t8,f8,d8,z8,q8, x9,y9,s9,m9,t9,f9,d9,z9,q9, x10,y10,s10,m10,t10,f10,d10,z10,q10, x11,y11,s11,m11,t11,f11,d11,z11,q11) \
FLASH_PART(n, m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11) \
struct menu_item_def n[MAX_MENU_LINES] = { {x0,y0,s0,t0,(char *)Ev(n,0),f0,d0,z0,q0},{x1,y1,s1,t1,(char *)Ev(n,1),f1,d1,z1,q1},{x2,y2,s2,t2,(char *)Ev(n,2),f2,d2,z2,q2},{x3,y3,s3,t3,(char *)Ev(n,3),f3,d3,z3,q3},{x4,y4,s4,t4,(char *)Ev(n,4),f4,d4,z4,q4},{x5,y5,s5,t5,(char *)Ev(n,5),f5,d5,z5,q5},{x6,y6,s6,t6,(char *)Ev(n,6),f6,d6,z6,q6},{x7,y7,s7,t7,(char *)Ev(n,7),f7,d7,z7,q7},{x8,y8,s8,t8,(char *)Ev(n,8),f8,d8,z8,q8},{x9,y9,s9,t9,(char *)Ev(n,9),f9,d9,z9,q9},{x10,y10,s10,t10,(char *)Ev(n,10),f10,d10,z10,q10},{x11,y11,s11,t11,(char *)Ev(n,11),f11,d11,z11,q11}, };
//FINALLY - Here is the "readable" way to initialize the structures (all the 7,8,9 stuff are placeholders for future expansion):
MAKE_MENU (main_menu_items,
1,1,1, "STOP TIMER.....% 5.1i MIN" ,0, (void *)83, (void *)7, (void *)8, (void *)9,
1,2,1, "CHEM ON/OFF....%s" ,2, (void *)"ON/OFF", (void *)7, (void *)8, (void *)9,
1,3,0, "MOTOR RPM......% s RPM" ,1, (void *)ReadRPM, (void *)7, (void *)8, (void *)9,
1,4,1, "TOT CHEM RATE..% 5.2i L/Hr" ,1, (void *)DemoData, (void *)7, (void *)8, (void *)9,
1,5,0, "TOT CHEM USED..% 5.2i L/Hr" ,1, (void *)DemoData, (void *)7, (void *)8, (void *)9,
1,6,1, "CHEM 1 RATE....% 23.6i L/Hr" ,0, (void *)83, (void *)7, (void *)8, (void *)9,
1,7,1, "CHEM 2 RATE....% 16.3i L/Hr" ,0, (void *)84, (void *)7, (void *)8, (void *)9,
1,8,1, "CHEM 3 RATE....% 34.9i L/Hr" ,0, (void *)85, (void *)7, (void *)8, (void *)9,
1,9,0, "PH READ........% s PH" ,1, (void *)ReadpHVolts, (void *)7, (void *)8, (void *)9,
1,10,1, "PH: Min: %f Max: %f" ,1, (void *)ReadpHMin, (void *)7, (void *)ReadpHMax, (void *)9,
1,11,0, "BATT VOLTS.....% s V" ,1, (void *)ReadBatt, (void *)7, (void *)8, (void *)9,
1,12,0, "Msg:%s" ,1, (void *)DemoData, (void *)7, (void *)8, (void *)9
);