一、基础理论

ESP32-S2具有43个GPIO,理论上可以支持835=280段,但实际上,受限于刷新率和保持时间的限制,按刷新时间20ms,保持时间1ms计算,大概能支持的上限为820=160段。

ESP32-S2 IO拉电流可以达到40mA,但是灌电流只有28mA,所以对于常见的共阴段码显示屏,如果亮度不够,需要加共阴极   二极管驱动。本DEMO仅供演示,IO口直接驱动。

软件架构上,先创建一个定时器任务,设置为20mS刷一次屏,按每条阴极线保持800us~1ms时间顺序刷新显示数据。
本文的目的是演示如何用ESP32-S2驱动段码屏,所写代码仅适合特定的显示屏,用户需要根据选用的段码屏,编写匹配的程序。

二、代码实现

1.框架

ESP32 LED显示屏圆形表盘 esp32驱动显示屏_乐鑫ESP32驱动断码屏

建components\display\src和components\display\include文件夹,将显示部分代码作为一个部件放在user_display.c和user_display.h,方便维护和扩展。
先看user_display.c的实现
2.IO配置和初始化部分

#include <stdio.h>
 #include “freertos/FreeRTOS.h”
 #include “freertos/task.h”
 #include “freertos/queue.h”
 #include “driver/timer.h”
 #include “driver/gpio.h”
 #include “user_display.h”/LED模块******************/
uint8_t display_temperature_88=0; //温度显示全局变量,00~99
 uint8_t display_temperature_sw=ON; //温度显示开关uint8_t display_capacitance_88=0;//容量显示全局变量,00~99
 uint8_t display_capacitance_sw=ON;//容量显示开关uint8_t display_time_88=60;//时间显示全局变量,00~99
 uint8_t display_time_sw=ON;//时间显示开关uint8_t line8_sw=ON;//阴极线8显示控制开关
 uint8_t line9_sw=ON;//阴极线9显示控制开关
 uint8_t line10_water_sw=ON;//阴极线10花洒显示控制开关
 uint8_t decorate_sw=ON;//阴极线11、12装饰条显示控制开关
 uint8_t lineH_sw=ON;//阳极线H显示控制开关
 uint8_t line13_sw=ON;//阴极线13显示控制开关uint8_t line10_cap=1;//阴极线10容量选择,0=不显示,1=8L,2=10L,3=12L
static uint8_t display_fan_num=0;//风扇状态动态计数器
 static uint8_t display_fire_num=0;//火焰指示动态计数器
 static uint8_t display_water_num=0;//花洒动态计数器#define user_delay_time_us 800 //LED保持时间
/阳极IO/
 #define positive_A 33
 #define positive_B 34
 #define positive_C 35
 #define positive_D 36
 #define positive_E 37
 #define positive_F 38
 #define positive_G 39
 #define positive_H 40/阴极IO/
 #define negative_1 1
 #define negative_2 2
 #define negative_3 3
 #define negative_4 4
 #define negative_5 5
 #define negative_6 6
 #define negative_7 7
 #define negative_8 8
 #define negative_9 9
 #define negative_10 10
 #define negative_11 11
 #define negative_12 12
 #define negative_13 13
 #define negative_14 14
 #define negative_15 15
 #define negative_16 16/IO配置函数*********/
 void user_led_init(void)
 {
 /设置阳极为上拉输出***/
 gpio_pad_select_gpio(positive_A);
 gpio_set_direction(positive_A, GPIO_MODE_OUTPUT);gpio_pad_select_gpio(positive_B);
gpio_set_direction(positive_B, GPIO_MODE_OUTPUT);

gpio_pad_select_gpio(positive_C);
gpio_set_direction(positive_C, GPIO_MODE_OUTPUT);

gpio_pad_select_gpio(positive_D);
gpio_set_direction(positive_D, GPIO_MODE_OUTPUT);

gpio_pad_select_gpio(positive_E);
gpio_set_direction(positive_E, GPIO_MODE_OUTPUT);

gpio_pad_select_gpio(positive_F);
gpio_set_direction(positive_F, GPIO_MODE_OUTPUT);

gpio_pad_select_gpio(positive_G);
gpio_set_direction(positive_G, GPIO_MODE_OUTPUT);

gpio_pad_select_gpio(positive_H);
gpio_set_direction(positive_H, GPIO_MODE_OUTPUT);


/***********设置阴极为开漏输出**************/

gpio_pad_select_gpio(negative_1);
gpio_set_direction(negative_1, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_2);
gpio_set_direction(negative_2, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_3);
gpio_set_direction(negative_3, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_4);
gpio_set_direction(negative_4, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_5);
gpio_set_direction(negative_5, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_6);
gpio_set_direction(negative_6, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_7);
gpio_set_direction(negative_7, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_8);
gpio_set_direction(negative_8, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_9);
gpio_set_direction(negative_9, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_10);
gpio_set_direction(negative_10, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_11);
gpio_set_direction(negative_11, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_12);
gpio_set_direction(negative_12, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_13);
gpio_set_direction(negative_13, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_14);
gpio_set_direction(negative_14, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_15);
gpio_set_direction(negative_15, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

gpio_pad_select_gpio(negative_16);
gpio_set_direction(negative_16, ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)));

/**********IO初始化***********/
gpio_set_level(positive_A, 0);
gpio_set_level(positive_B, 0);
gpio_set_level(positive_C, 0);
gpio_set_level(positive_D, 0);
gpio_set_level(positive_E, 0);
gpio_set_level(positive_F, 0);
gpio_set_level(positive_G, 0);
gpio_set_level(positive_H, 0);

gpio_set_level(negative_1, 1);
gpio_set_level(negative_2, 1);
gpio_set_level(negative_3, 1);
gpio_set_level(negative_4, 1);
gpio_set_level(negative_5, 1);
gpio_set_level(negative_6, 1);
gpio_set_level(negative_7, 1);
gpio_set_level(negative_8, 1);
gpio_set_level(negative_9, 1);
gpio_set_level(negative_10, 1);
gpio_set_level(negative_11, 1);
gpio_set_level(negative_12, 1);
gpio_set_level(negative_13, 1);
gpio_set_level(negative_14, 1);
gpio_set_level(negative_15, 1);
gpio_set_level(negative_16, 1);}
void user_led_on(uint8_t positive_io)
 {
 gpio_set_level(positive_io, 1);
 }void user_led_off(uint8_t positive_io)
 {
 gpio_set_level(positive_io, 0);
 }void user_led_all_off(void)
 {
 gpio_set_level(positive_A, 0);
 gpio_set_level(positive_B, 0);
 gpio_set_level(positive_C, 0);
 gpio_set_level(positive_D, 0);
 gpio_set_level(positive_E, 0);
 gpio_set_level(positive_F, 0);
 gpio_set_level(positive_G, 0);
 gpio_set_level(positive_H, 0);gpio_set_level(negative_1, 1);
gpio_set_level(negative_2, 1);
gpio_set_level(negative_3, 1);
gpio_set_level(negative_4, 1);
gpio_set_level(negative_5, 1);
gpio_set_level(negative_6, 1);
gpio_set_level(negative_7, 1);
gpio_set_level(negative_8, 1);
gpio_set_level(negative_9, 1);
gpio_set_level(negative_10, 1);
gpio_set_level(negative_11, 1);
gpio_set_level(negative_12, 1);
gpio_set_level(negative_13, 1);
gpio_set_level(negative_14, 1);
gpio_set_level(negative_15, 1);
gpio_set_level(negative_16, 1);}

3.8字段码驱动,完成数字0~9的显示

/8字段码驱动****/
 void display_driver_0() //驱动层,显示数字0
 {
 user_led_on(positive_A);
 user_led_on(positive_B);
 user_led_on(positive_C);
 user_led_on(positive_D);
 user_led_on(positive_E);
 user_led_on(positive_F);
 }void display_driver_1() //驱动层,显示数字1
 {
 user_led_on(positive_B);
 user_led_on(positive_C);
 }void display_driver_2() //驱动层,显示数字2
 {
 user_led_on(positive_A);
 user_led_on(positive_B);
 user_led_on(positive_G);
 user_led_on(positive_E);
 user_led_on(positive_D);
 }void display_driver_3() //驱动层,显示数字3
 {
 user_led_on(positive_A);
 user_led_on(positive_B);
 user_led_on(positive_G);
 user_led_on(positive_C);
 user_led_on(positive_D);
 }void display_driver_4() //驱动层,显示数字4
 {
 user_led_on(positive_F);
 user_led_on(positive_G);
 user_led_on(positive_B);
 user_led_on(positive_C);
 }void display_driver_5() //驱动层,显示数字5
 {
 user_led_on(positive_A);
 user_led_on(positive_F);
 user_led_on(positive_G);
 user_led_on(positive_C);
 user_led_on(positive_D);
 }void display_driver_6() //驱动层,显示数字6
 {
 user_led_on(positive_A);
 user_led_on(positive_F);
 user_led_on(positive_G);
 user_led_on(positive_C);
 user_led_on(positive_D);
 user_led_on(positive_E);
 }void display_driver_7() //驱动层,显示数字7
 {
 user_led_on(positive_A);
 user_led_on(positive_B);
 user_led_on(positive_C);
 }void display_driver_8() //驱动层,显示数字8
 {
 user_led_on(positive_A);
 user_led_on(positive_B);
 user_led_on(positive_C);
 user_led_on(positive_D);
 user_led_on(positive_E);
 user_led_on(positive_F);
 user_led_on(positive_G);
 }void display_driver_9() //驱动层,显示数字9
 {
 user_led_on(positive_A);
 user_led_on(positive_F);
 user_led_on(positive_G);
 user_led_on(positive_B);
 user_led_on(positive_C);
 }void display_mid_num(uint8_t display_number) //中间层,显示数字,display_number:要显示的数字,个位数0~9
 {
 switch(display_number)
 {
 case 0:
 display_driver_0();
 break;
 case 1:
 display_driver_1();
 break;
 case 2:
 display_driver_2();
 break;
 case 3:
 display_driver_3();
 break;
 case 4:
 display_driver_4();
 break;
 case 5:
 display_driver_5();
 break;
 case 6:
 display_driver_6();
 break;
 case 7:
 display_driver_7();
 break;
 case 8:
 display_driver_8();
 break;
 case 9:
 display_driver_9();
 break;
 }ets_delay_us(user_delay_time_us); //保持时间,可以用其它时间合适任务来替代
user_led_all_off(); //关,准备显示下一位}

4.按每根阴极线为一个单元,动态刷新数据

/段码显示APP****/
 void user_display_temperature(void) //显示温度,全局变量display_temperature_88传递温度值
 {
 uint8_t temp_High;//温度高位数
 uint8_t temp_Low;//温度低位数if(display_temperature_sw)
{
	if(display_temperature_88>=10&&display_temperature_88<=99)
		{
			temp_High=display_temperature_88/10;
			temp_Low=display_temperature_88%10;
		}
		else
		{
			temp_High=0;
			temp_Low=display_temperature_88;
		}

	gpio_set_level(negative_1, 0); //开高位显示,line1
	display_mid_num(temp_High);

	gpio_set_level(negative_2, 0); //开低位显示,line2
	display_mid_num(temp_Low);
}}
void user_display_capacitance(void) //显示容量,全局变量display_capacitance_88传递容量值
 {
 uint8_t Cap_High;//温度高位数
 uint8_t Cap_Low;//温度低位数if(display_capacitance_sw)
{
	if(display_capacitance_88>=10&&display_capacitance_88<=99)
		{
		   Cap_High=display_capacitance_88/10;
		   Cap_Low=display_capacitance_88%10;
		}
		else
		{
		   Cap_High=0;
		   Cap_Low=display_capacitance_88;
		}

	gpio_set_level(negative_4, 0); //开高位显示,line4
	display_mid_num(Cap_High);

	gpio_set_level(negative_5, 0); //开低位显示,line5
	display_mid_num(Cap_Low);
}}
void user_display_time(void) //显示时间,全局变量display_time_88传递时间值
 {
 uint8_t time_High;//温度高位数
 uint8_t time_Low;//温度低位数if(display_time_sw)
{
	if(display_time_88>=10&&display_time_88<=99)
		{
			time_High=display_time_88/10;
			time_Low=display_time_88%10;
		}
		else
		{
			time_High=0;
			time_Low=display_time_88;
		}

	gpio_set_level(negative_6, 0); //开高位显示,line6
	display_mid_num(time_High);

	gpio_set_level(negative_7, 0); //开低位显示,line7
	display_mid_num(time_Low);
}}
void user_display_line8(void) //阴极8线显示,变量line8_sw控制火焰图标的显示,0=不显示,1=显示
 {if(line8_sw)
{
	display_fire_num++;
	switch(display_fire_num)
	{
	case 4:
		gpio_set_level(positive_H, 1);
		break;
	case 8:
		gpio_set_level(positive_F, 1);
		gpio_set_level(positive_G, 1);
		break;
	}

	if(display_fire_num>=12)   //计数循环
	{
		display_fire_num=0;
	}
}

gpio_set_level(positive_A, 1);
gpio_set_level(positive_B, 1);
gpio_set_level(positive_C, 1);
gpio_set_level(positive_D, 1);
gpio_set_level(positive_E, 1); //开LOGO

gpio_set_level(negative_8, 0);

ets_delay_us(user_delay_time_us);
user_led_all_off();}
void user_display_line9(void) //阴极9线显示,变量line9_sw控制风扇图标的显示,0=不显示,1=显示
 {if(line9_sw)
{
	display_fan_num++;
	switch(display_fan_num)
	{
	case 1:
		gpio_set_level(positive_A, 1);
		break;
	case 2:
		gpio_set_level(positive_B, 1);
		break;
	case 3:
		gpio_set_level(positive_C, 1);
		break;
	case 4:
		gpio_set_level(positive_D, 1);
		break;
	case 5:
		gpio_set_level(positive_E, 1);
		break;
	case 6:
		gpio_set_level(positive_F, 1);
		break;
	}

	if(display_fan_num>=6)   //计数循环
	{
		display_fan_num=0;
	}
}

gpio_set_level(positive_G, 1); //开"'C"

gpio_set_level(positive_H, 1); //"变升"

gpio_set_level(negative_9, 0);

ets_delay_us(user_delay_time_us);
user_led_all_off();}
void user_display_line10(void) //阴极10线显示,变量line10_water花洒图标,0=不显示,1=显示,变量line10_cap控制容量的,0=不显示,1=8L,2=10L,3=12L
 {if(line10_water_sw)
{
	gpio_set_level(positive_A, 1); //开"花洒"
	display_water_num++;
	switch(display_water_num)
	{
	case 3:
		gpio_set_level(positive_B, 1);
		break;
	case 6:
		gpio_set_level(positive_C, 1);
		break;
	case 9:
		gpio_set_level(positive_D, 1);
		break;
	}

	if(display_water_num>=9)   //计数循环
	{
		display_water_num=0;
	}
}

if(line10_cap)
{
	switch(line10_cap)
	{
	case 1:
		gpio_set_level(positive_G, 1);
		break;
	case 2:
		gpio_set_level(positive_F, 1);
		break;
	case 3:
		gpio_set_level(positive_E, 1);
		break;
	}
}

gpio_set_level(positive_H, 1); //"L"

gpio_set_level(negative_10, 0);

ets_delay_us(user_delay_time_us);
user_led_all_off();}
void user_display_decorate(void) //阴极11、12线显示,变量decorate_sw控制装饰条,0=不显示,1=显示
 {if(decorate_sw)
{

	gpio_set_level(positive_A, 1);
	gpio_set_level(positive_B, 1);
	gpio_set_level(positive_C, 1);
	gpio_set_level(positive_D, 1);
	gpio_set_level(positive_E, 1);
	gpio_set_level(positive_F, 1);
	gpio_set_level(positive_G, 1);
	gpio_set_level(positive_H, 1);

	gpio_set_level(negative_11, 0);
	gpio_set_level(negative_12, 0);
	gpio_set_level(negative_13, 0);
	gpio_set_level(negative_14, 0);
	gpio_set_level(negative_15, 0);
	gpio_set_level(negative_16, 0);

	ets_delay_us(user_delay_time_us);
	user_led_all_off();
}}
void user_display_lineH(void) //阳极H线显示,变量lineH_sw控制装饰条,0=不显示,1=显示
 {if(lineH_sw)
{

	gpio_set_level(positive_H, 1);

	gpio_set_level(negative_1, 0);
	gpio_set_level(negative_2, 0);
	gpio_set_level(negative_3, 0);
	gpio_set_level(negative_4, 0);
	gpio_set_level(negative_5, 0);
	gpio_set_level(negative_6, 0);
	gpio_set_level(negative_7, 0);

	ets_delay_us(user_delay_time_us);
	user_led_all_off();
}}
void user_display_line13() //阴极13线显示,变量line13_sw控制显示时间还是故障代码,0=关闭,1=时间,2=故障代码
 {if(line13_sw)
{
	switch(line13_sw)
	{
	case 1:
	    gpio_set_level(positive_G, 1); //"M"

		gpio_set_level(positive_C, 1);
		gpio_set_level(positive_D, 1); //"时 间"
		break;
	case 2:
		gpio_set_level(positive_E, 1);
		gpio_set_level(positive_F, 1); //"故障代码"
		break;
	}
}

gpio_set_level(positive_A, 1);
gpio_set_level(positive_B, 1); //"浴缸注水"

gpio_set_level(negative_13, 0);

ets_delay_us(user_delay_time_us);
user_led_all_off();}


5.至此,屏的驱动编写完成,接下来是建立一个定时器任务,这个代码直接用官方例程即可。

/定时器模块***************/
#define TIMER_DIVIDER 16 // Hardware timer clock divider
 #define TIMER_SCALE (TIMER_BASE_CLK / TIMER_DIVIDER) // convert counter value to seconds
 #define TIMER_INTERVAL0_SEC (3.4179) // sample test interval for the first timer
 #define TEST_WITHOUT_RELOAD 0 // testing will be done without auto reload
 #define TEST_WITH_RELOAD 1 // testing will be done with auto reload/*
• A sample structure to pass events
• from the timer interrupt handler to the main program.
 */
 typedef struct {
 int type; // the type of timer’s event
 int timer_group;
 int timer_idx;
 uint64_t timer_counter_value;
 } timer_event_t;xQueueHandle timer_queue;
 /*• Timer group0 ISR handler
• 
*/
 void IRAM_ATTR timer_group0_isr(void *para)
 {
 timer_spinlock_take(TIMER_GROUP_0);
 int timer_idx = (int) para;/* Retrieve the interrupt status and the counter value
   from the timer that reported the interrupt */
uint32_t timer_intr = timer_group_get_intr_status_in_isr(TIMER_GROUP_0);
uint64_t timer_counter_value = timer_group_get_counter_value_in_isr(TIMER_GROUP_0, timer_idx);

/* Prepare basic event data
   that will be then sent back to the main program task */
timer_event_t evt;
evt.timer_group = 0;
evt.timer_idx = timer_idx;
evt.timer_counter_value = timer_counter_value;

/* Clear the interrupt
   and update the alarm time for the timer with without reload */
if (timer_intr & TIMER_INTR_T0) {
    evt.type = TEST_WITHOUT_RELOAD;
    timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_0);
    timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE);
    timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, timer_idx, timer_counter_value);
} else if (timer_intr & TIMER_INTR_T1) {
    evt.type = TEST_WITH_RELOAD;
    timer_group_clr_intr_status_in_isr(TIMER_GROUP_0, TIMER_1);
} else {
    evt.type = -1; // not supported even type
}

/* After the alarm has been triggered
  we need enable it again, so it is triggered the next time */
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, timer_idx);

/* Now just send the event data back to the main program task */
xQueueSendFromISR(timer_queue, &evt, NULL);
timer_spinlock_give(TIMER_GROUP_0);}
/*
• Initialize selected timer of the timer group 0
/
 void user_tg0_timer_init(int timer_idx,bool auto_reload, double timer_interval_sec)
 {
 / Select and initialize basic parameters of the timer */
 timer_config_t config = {
 .divider = TIMER_DIVIDER,
 .counter_dir = TIMER_COUNT_UP,
 .counter_en = TIMER_PAUSE,
 .alarm_en = TIMER_ALARM_EN,
 .auto_reload = auto_reload,
 }; // default clock source is APB
 timer_init(TIMER_GROUP_0, timer_idx, &config);
/* Timer’s counter will initially start from value below.
 Also, if auto_reload is set, this value will be automatically reload on alarm */
 timer_set_counter_value(TIMER_GROUP_0, timer_idx, 0x00000000ULL);
/* Configure the alarm value and the interrupt on alarm. */
 timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE);
 timer_enable_intr(TIMER_GROUP_0, timer_idx);
 timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr,
 (void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL);
timer_start(TIMER_GROUP_0, timer_idx);
 }/*
• 定时刷屏
 */
 void user_timer_evt_task(void *arg)
 {
 while (1)
 {
 timer_event_t evt;
 xQueueReceive(timer_queue, &evt, portMAX_DELAY);// printf("-------- TASK TIME --------\n");
 /刷数码管*/
 user_display_temperature();
 user_display_capacitance();
 user_display_time();
 /按阴极线刷图标*/
 user_display_line8();
 user_display_line9();
 user_display_line10();
 user_display_lineH();
 user_display_line13();
 user_display_decorate();
 }
 }/*
• 定时器刷屏函数,
• 功能:配置定时器,开定时器任务,刷屏
• 参数:timer_sec,定时器任务运行间隔时间
 */
 void user_display_app(double timer_ms)
 {
 user_led_init(); //配置GPIO
/配置和启用定时器任务*/
 timer_queue = xQueueCreate(10, sizeof(timer_event_t));
 user_tg0_timer_init(TIMER_1, TEST_WITH_RELOAD, timer_ms/1000);
 xTaskCreate(user_timer_evt_task, “user_timer_evt_task”, 2048, NULL, 5, NULL);
 }
  • 6.user_display.C的内容编写完毕,user_display.h比较简单,主要是声明全局变量和外部函数。
•  #ifndef __time_H
 #define __time_H#define OFF 0
 #define ON 1extern uint8_t display_temperature_88;
 extern uint8_t display_capacitance_88;
 extern uint8_t display_time_88;
 extern uint8_t display_temperature_sw;
 extern uint8_t display_capacitance_sw;
 extern uint8_t display_time_sw;
 extern uint8_t line8_sw;
 extern uint8_t line9_sw;
 extern uint8_t line10_water_sw;
 extern uint8_t decorate_sw;
 extern uint8_t lineH_sw;
 extern uint8_t line13_sw;
 extern uint8_t line10_cap;void user_display_app(double timer_sec);
#endif

7.在main.C里面,运行一次user_display_app()即可启动刷屏,用户应用程序user_app()给全局变量赋值可控制显示内容,用户不需要深入了解显示屏的运行,专心做用户逻辑。

#include <stdio.h>
 #include “freertos/FreeRTOS.h”
 #include “freertos/task.h”
 #include “freertos/queue.h”
 #include “driver/timer.h”
 #include “driver/gpio.h”
 #include “user_display.h”#define TIMER_INTERVAL1_ms 20 // 刷屏时间,ms
static uint8_t display_time_num=0;//显示计数器
void user_app() //demo,每隔2秒温度+1,容量+1,时间+1,用户可在此函数里通过对显示全局变量进行赋值来控制显示内容
 {
 /显示buff
 display_temperature_sw=ON; //温度显示开关
 display_capacitance_sw=ON;//容量显示开关
 display_time_sw=ON;//时间显示开关
 line8_sw=ON;//阴极线8显示控制开关
 line9_sw=ON;//阴极线9显示控制开关
 line10_water_sw=ON;//阴极线10花洒显示控制开关
 decorate_sw=ON;//阴极线11、12装饰条显示控制开关
 lineH_sw=ON;//阳极线H显示控制开关
 line13_sw=ON;//阴极线13显示控制开关,0=关闭,1=时间,2=故障代码display_temperature_88=0;  //温度数字
display_capacitance_88=0;  //容量数字
display_time_88=0;  //时间数字**********************************/
display_time_num++;
if(display_time_num>=101)
   {
	  display_time_num=0;
   }

if(display_time_num/100)
   {
	   display_temperature_88++;  //温度+1
	   if(display_temperature_88>99)
	   	 {
	   		 display_temperature_88=0;
	   	 }

	   display_capacitance_88++;  //容量+1
	   if(display_capacitance_88>12)
	   	 {
	   		 display_capacitance_88=0;
	   	 }

	   display_time_88++;  //时间+1
	   if(display_time_88>60)
	   	 {
	   		 display_time_88=0;
	   	 }
	}
  vTaskDelay(20 / portTICK_PERIOD_MS);  //每隔20ms刷新一次显示数据,所以,应用不能刷得太快}
void app_main(void)
 {
 user_display_app(TIMER_INTERVAL1_ms); //刷屏函数,至少运行一次即可while(1)
{
   user_app(); //用户应用函数
}}

三、程序优化

显示函数里LED点亮需要保持一定时间,大致在600us~1ms,DEMO是直接采用延迟函数来保持。用户可以在延迟函数里插入一些应用,例如ADC采样,按键扫描,数据发送等等。

调试时,可以修改以下2个时间,获得最佳的显示效果

#define user_delay_time_us 800 //LED保持时间
 #define TIMER_INTERVAL1_ms 20 // 刷屏时间,ms