|  **银杏科技有限公司旗下技术文档发布平台**  ||||
|技术支持电话|**0379-69926675-801**|||
|技术支持邮件|Gingko@vip.163.com|||
^  版本  ^  日期  ^  作者  ^  修改内容  ^
|  V1.0  |  2021-01-05  |  yang  |  初次建立  | 
===== 实验三十三:lv_chart图表 =====
==== 一、图表 ====
图表是可视化数据点的基本对象,它有折线图(线上带点或不带点)和柱状图两种类型,还支持网格线、2个y轴、轴刻度和刻度文本。
图表的主体部分叫做 **LV_CHART_PART_BG** ,它使用所有典型的背景属性。其中**text**样式属性决定轴文本的样式,**line**属性决定刻度的样式,填充值在侧面增加了一些空间,因此会使数据序列区域更小,填充也可用于为轴文本和刻度线留出空间。
数据序列区域的背景称为 **LV_CHART_PART_SERIES_BG** ,并放置在主体背景上。在此部分上绘制了网格线和数据,除典型的背景样式属性外,网格线还使用线型属性。数据序列的样式可以通过 **LV_CHART_PART_SERIES** 引用。
对于柱状图,使用以下属性:
  * **radius** 柱的半径。
  * **padding_inner** 相同 x 坐标的柱间距。
  如果是折线图,则使用以下属性:
  * **line properties** 线属性来描述线。
  * **size** 点的大小半径。
  * **bg_opa** 线条下方区域的整体不透明度。
  * **bg_main_stop** 在顶部的渐变透明度的百分比(0:在顶部透明,255:bg_opa 在顶部不透明)。
  * **bg_grad_stop** 在底部的渐变透明度的百分比(0:底部透明,255:bg_opa 在底部不透明)。
  * **bg_drag_dir**设置为 **LV_GRAD_DIR_VER** 使能通过 **bg_main_stop** 和 **bg_grad_stop** 进行透明度渐变功能。
==== 二、图表数据 ====
=== 2.1、数据序列 ===
通过 **lv_chart_add_series(chart, color)** 可以在图表中添加多条数据序列。如果不使用外部数组,结构体 **lv_chart_series_t**将包含所选颜色和数据点的数组,如果分配了外部数组,则与该序列关联的任何数据点缩占用的内存都将释放,而数据系列将指向外部数组。
 
=== 2.2、数据类型 ===
数据显示类型有以下几种:
  * **LV_CHART_TYPE_NONE** 不显示任何数据,可用于隐藏系列。
  * **LV_CHART_TYPE_LINE** 在两点之间画线。
  * **LV_CHART_TYPE_COLUMN** 绘制柱。
指定显示类型使用**lv_chart_set_type(chart, LV_CHART_TYPE_...)**。
=== 2.3、修改数据 ===
有几种方式可以设置序列数据值:
  * 使用**ser1->points[3] = 7**在数组中手动设置值,并使用**lv_chart_refresh(chart)**刷新图表。
  * 使用**lv_chart_set_point_id(chart, ser, value, id)**,其中 **id** 是要更新的点的索引。 
  * 使用 **lv_chart_set_next(chart, ser, value)** 在数据末尾添加新值。
  * 将所有点初始化为给定值**lv_chart_init_points(chart, ser, value)**。 
  * 使用**lv_chart_set_points(chart, ser, value_array)**设置数组中的所有点。 
注意:使用** LV_CHART_POINT_DEF** 作为值时,图表将跳过此步骤,不绘制数据。
=== 2.4、修改数列的默认起点 ===
如果希望从默认点(序列的**point[0]**)以外的其他点开始绘图,则可以使用函数 **lv_chart_set_x_start_point(chart, ser, id)** 设置新的起始索引,其中** id** 是开始绘图的新索引位置。
 
=== 2.5、设置外部数据源 ===
使用**lv_chart_set_ext_array(chart, ser, array, point_cnt )** 可以将外部数据源分配给图表数据系列,其中** array** 是 **lv_coord_t** 的外部数组,具有** point_cnt** 个元素。注意:在外部数据源更新后应该调用**lv_chart_refresh(chart)** 以更新图表。
==== 三、图表设置 ====
=== 3.1、获取当前图表信息 ===
有四种方式可获取有关图表的信息:
  * **lv_chart_get_type(chart)** 返回当前图表类型。
  * **lv_chart_get_point_count(chart)** 返回当前图表点数。
  * **lv_chart_get_x_start_point(ser)** 返回指定数据序列的当前绘图索引。
  * **lv_chart_get_point_id(chart, ser, id)** 返回指定数据序列的指定索引处的数据值。
=== 3.2、更新方式 ===
在末尾添加新值的情况下** (lv_chart_set_next)**,有两种更新模式:
  * **LV_CHART_UPDATE_MODE_SHIFT** 将旧数据整体向左移动一位,丢掉第一个,然后在右侧末尾添加新数据。
  * **LV_CHART_UPDATE_MODE_CIRCULAR** 循环添加新数据(类似心电图,总是从前往后逐个更新数据)。
使用 **lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_...)** 可以更改图表的更新模式。 
=== 3.3、点数 ===
数据序列中的点数默认值为 **10**,可以通过 **lv_chart_set_point_count(chart, point_num)** 来修改。注意:将外部缓冲区分配给序列时,也会影响处理点的数量。
 
=== 3.4、垂直范围 ===
使用 **lv_chart_set_range(chart, y_min, y_max)** 可以指定 **y** 轴方向上的最小值和最大值。数据点的值将按比例缩放。默认范围是:**[0,100]**。
=== 3.5、网格线 ===
水平和垂直网格线的数量可以通过**lv_chart_set_div_line_count(chart, hdiv_num, vdiv_num)** 来修改。默认设置为 3 条水平分割线和 5 条垂直分割线。
=== 3.6、刻度线和标签 ===
坐标轴可以添加刻度线和标签。
若要想在 x 轴上设置刻度线和标签文本,可以使用**lv_chart_set_x_tick_text(chart, list_of_values, num_tick_marks, LV_CHART_AXIS_...)**,** list_of_values** 是一个带有 '**\n**' 终止文本(最后一个元素没有)且带有用于刻度的文本的字符串,例如:**const char * list_of_values = "first\nsec\nthird"**。如果设置了**list_of_values**,则**num_tick_marks**为两个标签之间的刻度数。**list_of_values**可以为**NULL**,如果为**NULL**,则它指定总的刻度数。
主刻度线绘制在放置文本的位置,次刻度线绘制在其他位置。要设置 x 轴上刻度线的长度,使用**lv_chart_set_x_tick_length(chart, major_tick_len, minor_tick_len)**。同样的,要设置y 轴也有相同功能的函数 **lv_chart_set_y_tick_text 和 lv_chart_set_y_tick_length** 。
下面的例子实现的功能为,从ADC读取iCore4T电源电压值并以折线图的形式绘制在图表中,上方的文本显示当前电压值,下方的滑块可以调节当前y轴的显示区间[0v,6v]。
{{ :icore4t:icore4t_rtt_lvgl_33_1.gif?direct |}}
// main.c 文件内容
#include 
#include 
#include 
#include "gui.h"
#include "power_adc.h"
#define LED0_PIN GET_PIN(A, 10)                /* 定义LED引脚 */
#define THREAD_PRIORITY         25             /* 线程优先级 */
#define THREAD_STACK_SIZE       1024           /* 线程堆栈大小 */
#define THREAD_TIMESLICE        5              /* 线程时间片 */
static rt_thread_t tid1 = RT_NULL;             /* 定义线程 */
int main(void)
{
	lv_gui_run();                                 /* 绘制图形界面 */
	                                              /* 创建线程,获取AD值更新到图表 */
	tid1 = rt_thread_create("thread1", power_adc_run, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
	if (tid1 != RT_NULL) rt_thread_startup(tid1); /* 启动线程 */
		
	rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);       /* 设置LED引脚为输出模式 */
	while(1){
		rt_pin_write(LED0_PIN, PIN_HIGH);     /* LED闪烁 */
		rt_thread_mdelay(100);	
		rt_pin_write(LED0_PIN, PIN_LOW);
		rt_thread_mdelay(100);	
	}
	return RT_EOK;
}
// power_adc.c 文件内容
#include 
#include 
#include 
#include "lvgl.h"
#include "gui.h"
#include "power_adc.h"
void power_adc_run(void *parameter) {                         /* 电源AD读取线程入口函数 */
	int value = 0;
	int voltage;
	static rt_adc_device_t adc_device = RT_NULL;
	adc_device = (rt_adc_device_t)rt_device_find("adc1"); /* 搜搜索ADC设备 */
	if(adc_device != RT_NULL){
		while(1){
			value = rt_adc_read(adc_device, atoi("16"));/* 读取电源电压,通道16 */ 
			voltage = (int) (value*1500/65535);	    /* 换算电压值*100 */
			lv_chart_set_next(chart, ser1, voltage);    /* 更新数据序列 */
			lv_chart_refresh(chart);                    /* 刷新图标 */
                                                                    /* 更新标签 */
			lv_label_set_text_fmt(label, "The voltage of iCore4T is: %d.%d v", voltage/100, voltage%100);
			rt_thread_mdelay(100);	                    /* 100ms采集一次 */
  		}
	}
}
// gui.c 图形界面绘制函数
void lv_gui_run(void) {
	lvgl2rtt_init("lcd");                                       /* 初始化lvgl2rtt */
	
	chart = lv_chart_create(lv_scr_act(), NULL);                /* 创建图表 */
	lv_obj_set_size(chart, 200, 150);                           /* 设置尺寸 */
	lv_obj_align(chart, NULL, LV_ALIGN_CENTER, 0, 0);           /* 设置位置 */
	lv_chart_set_type(chart, LV_CHART_TYPE_LINE);               /* 选择折线图 */
	lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_SHIFT);/* 更新模式为左移 */
	lv_chart_set_y_tick_texts(chart, list_of_values, NULL, LV_CHART_AXIS_PRIMARY_Y); /* 设置刻度 */
	lv_chart_set_range(chart, 440, 470);                        /* 设置y轴显示范围 */
	lv_chart_set_point_count(chart, 50);                        /* 设置图表点数 */
	
	lv_obj_set_style_local_bg_opa(chart, LV_CHART_PART_SERIES, LV_STATE_DEFAULT, LV_OPA_50); 
	lv_obj_set_style_local_bg_grad_dir(chart, LV_CHART_PART_SERIES, LV_STATE_DEFAULT , LV_GRAD_DIR_VER);
	lv_obj_set_style_local_bg_main_stop(chart, LV_CHART_PART_SERIES, LV_STATE_DEFAULT, 255); /* 顶部透明度 */
	lv_obj_set_style_local_bg_grad_stop(chart, LV_CHART_PART_SERIES, LV_STATE_DEFAULT, 200); /* 底部透明度 */
	
	ser1 = lv_chart_add_series(chart, LV_COLOR_RED);            /* 图表添加红色线 */
	lv_chart_init_points(chart, ser1, 0);                       /* 赋初值为0 */
	lv_chart_refresh(chart);                                    /* 刷新图表 */
	
	label = lv_label_create(lv_scr_act(), NULL);                /* 创建标签 */
	lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, -105, 20);   /* 设置位置 */
	lv_obj_t * slider = lv_slider_create(lv_scr_act(), NULL);   /* 创建滑块 */
	lv_slider_set_value(slider, 30, LV_ANIM_OFF);               /* 设置初始值 */
	lv_obj_set_event_cb(slider, slider_event_cb);               /* 绑定回调函数 */
	lv_slider_set_range(slider, 0, 600);                        /* 设置值范围 */
	lv_obj_set_size(slider, 200, 10);                           /* 设置滑块尺寸 */
	lv_obj_align(slider, NULL, LV_ALIGN_CENTER, 0, 100);        /* 设置滑块位置 */
	lv_slider_set_type(slider, LV_SLIDER_TYPE_RANGE);           /* 设置双点模式 */
	lv_slider_set_left_value(slider, 440, LV_ANIM_OFF);         /* 设置左值位置 */
	lv_slider_set_value(slider, 470, LV_ANIM_OFF);              /* 设置右值位置 */
}
更改样式,显示刻度坐标可以参考下例:
{{ :icore4t:icore4t_rtt_lvgl_33_2.png?direct |}}
// power_adc.c 文件内容
	static lv_style_t style1;                                        /* 新建样式 */
	lv_style_set_bg_color(&style1, LV_CHART_PART_BG, LV_COLOR_BLUE); /* 背景色蓝色*/
	lv_style_set_pad_left(&style1, LV_STATE_DEFAULT, LV_DPX(240));   /* 左填充 */
	
	chart = lv_chart_create(lv_scr_act(), NULL);                     /* 创建图表 */
	lv_obj_set_size(chart, 300, 150);                                /* 设置尺寸 */
	lv_obj_add_style(chart,LV_OBJ_PART_MAIN, &style1);               /* 设置样式 */
	lv_chart_set_div_line_count(chart, 5, 7);                        /* 设置网格线 */
	lv_obj_align(chart, NULL, LV_ALIGN_CENTER, 0, 0);                /* 设置位置 */
	lv_chart_set_type(chart, LV_CHART_TYPE_LINE);                    /* 选择折线图 */
	lv_chart_set_update_mode(chart, LV_CHART_UPDATE_MODE_SHIFT);     /* 更新模式为左移 */
	lv_chart_set_y_tick_texts(chart, list_of_values, NULL, LV_CHART_AXIS_PRIMARY_Y); /* 设置刻度 */
	lv_chart_set_range(chart, 0, 600);                               /* 设置y轴显示范围 */
	lv_chart_set_point_count(chart, 50);                             /* 设置图表点数 */