1. 接收电量探测设备发送的电量信息
2. 将接收到的电量信息通过图标进行显示
3. 能够查看历史电量
1. 电量探测设备通过Lora模块将电量数据发送到EVB-AIoT连接的Lora模块
2. 本程序通过TencentOS的AT和UART模块接收电量数据,并且进行保存
3. 本程序的另一个线程根据当前时间从保存的数据中读取并进行图标的绘制
4. 通过板子的F1、F2 2个按钮对本程序进行控制,单个按钮短按或者长按来显示不同时间的数据,2个按钮同时按来切换显示的模式
// Send
int atk_lora_send(const char *buf, size_t len, char * expected, char * recv_buf, size_t recv_buf_size)
{
int try = 0;
at_echo_t echo;
char cmd[128] = {0};
if (len > sizeof(cmd) - 2) {
return -1;
}
memcpy(cmd, buf, sizeof(cmd) > len ? len : sizeof(cmd));
memcpy(cmd + len, "\r\n", 2);
tos_at_echo_create(&echo, NULL, 0, expected);
while (try++ < 10) {
tos_at_cmd_exec(&echo, 3000, cmd);
if (echo.status == AT_ECHO_STATUS_OK || echo.status == AT_ECHO_STATUS_EXPECT) {
PRINTF("%s %d\r\n", __FUNCTION__, __LINE__);
return 0;
}
}
return -1;
}
// Recv
static void atk_lora_at_event_callback(atk_lora_recv_event_t * event_handler,
char * incoming_data_buffer, uint32_t size)
{
int offset = 0;
int err = 0;
int is_recv_finish = 0;
uint8_t data;
memset(incoming_data_buffer, 0x00, size);
k_tick_t begin = tos_systick_get();
while ((tos_systick_get() - begin) < event_handler->timeout
&& 0 == is_recv_finish
&& 0 == err)
{
tos_at_uart_read(&data, 1);
switch (data)
{
case '\r':
continue;
case '\n':
is_recv_finish = 1;
break;
default:
if (offset < size)
{
incoming_data_buffer[offset++] = data;
continue;
}
printf(" ERR:incomming data is big ,please give more space for incoming_data_buffer\n");
err = -1;
break;
}
}
// printf("[%p] Received err: %d finished: %d prefix: %s data: %s\n",
// event_handler, err, is_recv_finish, event_handler->event, incoming_data_buffer);
if (0 != is_recv_finish && event_handler->handler)
{
event_handler->handler(event_handler->event, incoming_data_buffer, offset);
}
}
void draw_axis(uint32_t frameBuffer[APP_IMG_HEIGHT][APP_IMG_WIDTH], uint32_t fg_color, uint32_t bg_color)
{
int y_max = g_y_max;
int y_min = g_y_min;
// Draw axises
{
draw_line(CONF_Y_AXIS_LABEL_WIDTH, CONF_X_AXIS_LABEL_HEIGHT,
CONF_Y_AXIS_LABEL_WIDTH, APP_IMG_HEIGHT - CONF_Y_AXIS_NAME_HEIGHT,
frameBuffer, fg_color);
draw_line(CONF_Y_AXIS_LABEL_WIDTH, APP_IMG_HEIGHT - CONF_Y_AXIS_NAME_HEIGHT,
CONF_Y_AXIS_LABEL_WIDTH - CONF_AXIS_ARROW_HALF_WIDTH,
APP_IMG_HEIGHT - CONF_Y_AXIS_NAME_HEIGHT - CONF_AXIS_ARROW_HEIGHT,
frameBuffer, fg_color);
draw_line(CONF_Y_AXIS_LABEL_WIDTH, APP_IMG_HEIGHT - CONF_Y_AXIS_NAME_HEIGHT,
CONF_Y_AXIS_LABEL_WIDTH + CONF_AXIS_ARROW_HALF_WIDTH,
APP_IMG_HEIGHT - CONF_Y_AXIS_NAME_HEIGHT - CONF_AXIS_ARROW_HEIGHT,
frameBuffer, fg_color);
draw_string(CONF_Y_AXIS_LABEL_WIDTH,
APP_IMG_HEIGHT - CONF_Y_AXIS_NAME_HEIGHT, g_y_label, 24,
frameBuffer, fg_color, bg_color);
draw_line(CONF_Y_AXIS_LABEL_WIDTH, CONF_X_AXIS_LABEL_HEIGHT,
APP_IMG_WIDTH - CONF_X_AXIS_NAME_WIDTH, CONF_X_AXIS_LABEL_HEIGHT,
frameBuffer, fg_color);
draw_line(APP_IMG_WIDTH - CONF_X_AXIS_NAME_WIDTH, CONF_X_AXIS_LABEL_HEIGHT,
APP_IMG_WIDTH - CONF_X_AXIS_NAME_WIDTH - CONF_AXIS_ARROW_HEIGHT,
CONF_X_AXIS_LABEL_HEIGHT + CONF_AXIS_ARROW_HALF_WIDTH,
frameBuffer, fg_color);
draw_line(APP_IMG_WIDTH - CONF_X_AXIS_NAME_WIDTH, CONF_X_AXIS_LABEL_HEIGHT,
APP_IMG_WIDTH - CONF_X_AXIS_NAME_WIDTH - CONF_AXIS_ARROW_HEIGHT,
CONF_X_AXIS_LABEL_HEIGHT - CONF_AXIS_ARROW_HALF_WIDTH,
frameBuffer, fg_color);
draw_string_v_center_align(APP_IMG_WIDTH - CONF_X_AXIS_NAME_WIDTH,
CONF_X_AXIS_LABEL_HEIGHT, CONF_X_AXIS_NAME, 24,
frameBuffer, fg_color, bg_color);
}
// Draw scales
{
// Draw Y scales
int y_scale_step = (y_max - y_min) / CONF_Y_AXIS_N_SCALES;
int y_step = (APP_IMG_HEIGHT - CONF_X_AXIS_LABEL_HEIGHT -
CONF_Y_AXIS_NAME_HEIGHT - CONF_AXIS_ARROW_HEIGHT -
CONF_X_AXIS_0_POINT_OFFSET) /
CONF_Y_AXIS_N_SCALES;
int y_offset = 0;
int y_scale = y_min;
for (int i = 0; i < CONF_Y_AXIS_N_SCALES + 1; ++i)
{
draw_line(CONF_Y_AXIS_LABEL_WIDTH,
CONF_X_AXIS_LABEL_HEIGHT + y_offset + CONF_Y_AXIS_0_POINT_OFFSET,
CONF_Y_AXIS_LABEL_WIDTH - 10,
CONF_X_AXIS_LABEL_HEIGHT + y_offset + CONF_Y_AXIS_0_POINT_OFFSET,
frameBuffer, fg_color);
char scale[16] = {0};
snprintf(scale, sizeof(scale), "%d", y_scale);
draw_string_v_center_right_align(CONF_Y_AXIS_LABEL_WIDTH - 10,
CONF_X_AXIS_LABEL_HEIGHT + y_offset + CONF_Y_AXIS_0_POINT_OFFSET,
scale, 24, frameBuffer, fg_color, bg_color);
y_offset += y_step;
y_scale += y_scale_step;
}
// Draw X scales
int x_step = CONF_X_AXIS_STEP;
int x_scale_step = CONF_X_AXIS_SCALE_STEP;
int x_offset = 0;
for (int i = 0; i < CONF_X_AXIS_N_SCALES + 1; ++i)
{
draw_line(
CONF_Y_AXIS_LABEL_WIDTH + x_offset + CONF_X_AXIS_0_POINT_OFFSET,
CONF_X_AXIS_LABEL_HEIGHT,
CONF_Y_AXIS_LABEL_WIDTH + x_offset + CONF_X_AXIS_0_POINT_OFFSET,
CONF_X_AXIS_LABEL_HEIGHT - 10,
frameBuffer, fg_color);
char scale[32] = {0};
if (K_NULL != g_k_tick_t_2_x_scale_label)
{
g_k_tick_t_2_x_scale_label(i, scale, sizeof(scale));
} else
{
k_tick_t_2_format_time_of_day(i, scale, sizeof(scale));
}
draw_string_h_center_align(
CONF_Y_AXIS_LABEL_WIDTH + x_offset + CONF_X_AXIS_0_POINT_OFFSET,
10, scale, 16, frameBuffer, fg_color, bg_color);
x_offset += x_step;
}
}
g_fg_color = fg_color;
g_bg_color = bg_color;
}
void axis_redraw(uint32_t frameBuffer[APP_IMG_HEIGHT][APP_IMG_WIDTH])
{
int x_begin = CONF_Y_AXIS_LABEL_WIDTH + CONF_X_AXIS_0_POINT_OFFSET;
int x_offset_point = CONF_X_AXIS_STEP / CONF_X_AXIS_SCALE_SECTION_N_POINTS;
int y_max = g_y_max;
int y_min = g_y_min;
axis_clear_data(frameBuffer);
draw_axis(frameBuffer, g_fg_color, g_bg_color);
for (int i = 0; i < g_index - 1; ++i)
{
draw_line(x_begin + i * x_offset_point, get_y_value(y_max, y_min, g_values[i]),
x_begin + (i + 1) * x_offset_point, get_y_value(y_max, y_min, g_values[i + 1]),
frameBuffer, g_data_color);
}
if (g_index_loop)
{
int index_begin = g_index + 1;
if (index_begin >= N_G_VALUES)
{
for (int i = 0; i < N_G_VALUES - 1; ++i)
{
draw_line(x_begin + i * x_offset_point, get_y_value(y_max, y_min, g_values[i]),
x_begin + (i + 1) * x_offset_point, get_y_value(y_max, y_min, g_values[i + 1]),
frameBuffer, g_data_color);
}
} else
{
int offset = 0;
for (int i = index_begin; i < N_G_VALUES - 1; ++i, ++offset)
{
draw_line(x_begin + offset * x_offset_point, get_y_value(y_max, y_min, g_values[i]),
x_begin + (offset + 1) * x_offset_point, get_y_value(y_max, y_min, g_values[i + 1]),
frameBuffer, g_data_color);
}
draw_line(x_begin + offset * x_offset_point, get_y_value(y_max, y_min, g_values[N_G_VALUES - 1]),
x_begin + (offset + 1) * x_offset_point, get_y_value(y_max, y_min, g_values[0]),
frameBuffer, g_data_color);
++offset;
for (int i = 0; i < index_begin - 1; ++i, ++offset)
{
draw_line(x_begin + offset * x_offset_point, get_y_value(y_max, y_min, g_values[i]),
x_begin + (offset + 1) * x_offset_point, get_y_value(y_max, y_min, g_values[i + 1]),
frameBuffer, g_data_color);
}
}
} else
{
for (int i = 0; i < g_index - 1; ++i)
{
draw_line(x_begin + i * x_offset_point, get_y_value(y_max, y_min, g_values[i]),
x_begin + (i + 1) * x_offset_point, get_y_value(y_max, y_min, g_values[i + 1]),
frameBuffer, g_data_color);
}
}
}
static void buttons_main(void * arg)
{
while (g_run)
{
k_tick_t cur = get_sys_time();
for (buttons_id_t id = BTN_ID_1; id < BTN_ID_COUNT; ++id)
{
int event = 0;
tos_mutex_pend(&g_button_mutex);
if (has_status(g_btn_contexts[id].comming_pressed_status))
{
if (g_btn_contexts[id].comming_pressed_status != g_btn_contexts[id].pressed_status)
{
if (BTN_STATUS_PRESSED == g_btn_contexts[id].comming_pressed_status)
{
g_btn_contexts[id].pressed_time = get_sys_time();
event |= BTN_EVENT_PRESSED;
} else
{
if ((cur - g_btn_contexts[id].pressed_time) < BTN_LONG_PRESSED_TIME)
{
event |= BTN_EVENT_CLICK;
}
event |= BTN_EVENT_RELEASED;
g_btn_contexts[id].in_long_pressed = 0;
}
g_btn_contexts[id].pressed_status = g_btn_contexts[id].comming_pressed_status;
} else
{
if (BTN_STATUS_PRESSED == g_btn_contexts[id].pressed_status)
{
if ((cur - g_btn_contexts[id].pressed_time) >= BTN_LONG_PRESSED_TIME
&& !g_btn_contexts[id].in_long_pressed)
{
event |= BTN_EVENT_LONG_PRESS;
g_btn_contexts[id].in_long_pressed = 1;
}
}
}
g_btn_contexts[id].comming_pressed_status = BTN_STATUS_NON_INIT;
} else // No comming status
{
if (BTN_STATUS_PRESSED == g_btn_contexts[id].pressed_status)
{
if ((cur - g_btn_contexts[id].pressed_time) >= BTN_LONG_PRESSED_TIME
&& !g_btn_contexts[id].in_long_pressed)
{
event |= BTN_EVENT_LONG_PRESS;
g_btn_contexts[id].in_long_pressed = 1;
}
}
}
tos_mutex_post(&g_button_mutex);
if (event > 0)
{
g_btn_contexts[id].callback(event);
}
}
tos_task_delay(10);
}
}
static void btn_ctrl_main(void * arg)
{
while (g_run)
{
btn_ctrl_do_what_t do_what = BTN_CTRL_NOTHING;
tos_mutex_pend(&g_btn_ctrl_mutex);
if (BTN_CTRL_F1_F2_PRESSED != g_btn_ctrl_status.do_what)
{
if ((g_btn_ctrl_status.btn_status[BTN_ID_1] & BTN_EVENT_PRESSED)
&& (g_btn_ctrl_status.btn_status[BTN_ID_2] & BTN_EVENT_PRESSED))
{
g_btn_ctrl_status.do_what = do_what = BTN_CTRL_F1_F2_PRESSED;
g_btn_ctrl_status.btn_status[BTN_ID_1] = BTN_EVENT_PRESSED;
g_btn_ctrl_status.btn_status[BTN_ID_2] = BTN_EVENT_PRESSED;
} else if (BTN_EVENT_LONG_PRESS & g_btn_ctrl_status.btn_status[BTN_ID_1])
{
g_btn_ctrl_status.do_what = BTN_CTRL_NOTHING;
do_what = BTN_CTRL_F1_LONG_PRESSED;
g_btn_ctrl_status.btn_status[BTN_ID_1] = BTN_EVENT_LONG_PRESS;
} else if (BTN_EVENT_LONG_PRESS & g_btn_ctrl_status.btn_status[BTN_ID_2])
{
g_btn_ctrl_status.do_what = BTN_CTRL_NOTHING;
do_what = BTN_CTRL_F2_LONG_PRESSED;
g_btn_ctrl_status.btn_status[BTN_ID_2] = BTN_EVENT_LONG_PRESS;
} else if (BTN_EVENT_CLICK & g_btn_ctrl_status.btn_status[BTN_ID_1])
{
g_btn_ctrl_status.do_what = BTN_CTRL_NOTHING;
do_what = BTN_CTRL_F1_CLICK;
g_btn_ctrl_status.btn_status[BTN_ID_1] = BTN_EVENT_RELEASED;
} else if (BTN_EVENT_CLICK & g_btn_ctrl_status.btn_status[BTN_ID_2])
{
g_btn_ctrl_status.do_what = BTN_CTRL_NOTHING;
do_what = BTN_CTRL_F2_CLICK;
g_btn_ctrl_status.btn_status[BTN_ID_2] = BTN_EVENT_RELEASED;
}
} else
{
if ((g_btn_ctrl_status.btn_status[BTN_ID_1] & BTN_EVENT_RELEASED)
&& (g_btn_ctrl_status.btn_status[BTN_ID_2] & BTN_EVENT_RELEASED))
{
g_btn_ctrl_status.do_what = BTN_CTRL_NOTHING;
do_what = BTN_CTRL_F1_F2_RELEASED;
g_btn_ctrl_status.btn_status[BTN_ID_1] = BTN_EVENT_RELEASED;
g_btn_ctrl_status.btn_status[BTN_ID_2] = BTN_EVENT_RELEASED;
}
}
tos_mutex_post(&g_btn_ctrl_mutex);
btn_ctrl_do_what(do_what);
tos_task_delay(10);
}
}
https://gitee.com/delightedok/tos-electricity-consumption.git
https://gitee.com/delightedok/electricity-consumption-terminal.git
1. 报名的时候打算用KV来对数据进行保存和读取,但是在实践中的时候发现GPIO_AD_B0_02被ELCDIF使用了;而如果使用NOR Flash驱动的时候,如果把framebuffer定义在NCACHE_REGION的时候,初始化BSS会出现Hard fault错误;最后尝试了SD卡,但是在发送CMD8数据的时候收不到SD卡的应答,所以最后选择了仅把数据放在内存中
2. 使用AT框架进行数据的收发的时候发现如果想使用同步的方式对数据进行读写,会出现读到的数据不完整的问题,看AT的代码认为是框架读到了跟expected相同的数据后就做出了返回,没有等待\r\n的到来,最后选择了使用异步的方式来处理返回的数据
3. 由于Lora模块占用了Wifi模块ESP8266的座子,因此时间同步选择了通过Lora模块来进行
1. 移植到开源UI库中,例如LVGL
2. 数据保存到SD卡中
感谢这次的比赛让我熟悉单片机层面的知识,对于嵌入式的初学者,这块板子个人感觉确实不错,有很多SDK的demo帮助我们调试和理解。感谢大佬们的分享和帮助。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。