启明云端分享|干货来了,怎么用ESP32-S2驱动断码屏呢?更多干货欢迎关注启明云端CSDN技术社区!
一、基礎理論
ESP32-S2具有43個GPIO,理論上可以支持835=280段,但實際上,受限于刷新率和保持時間的限制,按刷新時間20ms,保持時間1ms計算,大概能支持的上限為820=160段。
ESP32-S2 IO拉電流可以達到40mA,但是灌電流只有28mA,所以對于常見的共陰段碼顯示屏,如果亮度不夠,需要加共陰極 二極管驅動。本DEMO僅供演示,IO口直接驅動。軟件架構上,先創建一個定時器任務,設置為20mS刷一次屏,按每條陰極線保持800us~1ms時間順序刷新顯示數據。
本文的目的是演示如何用ESP32-S2驅動段碼屏,所寫代碼僅適合特定的顯示屏,用戶需要根據選用的段碼屏,編寫匹配的程序。
二、代碼實現
1.框架
建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);
}
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);
}
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;
}
}
4.按每根陰極線為一個單元,動態刷新數據
/段碼顯示APP****/
void user_display_temperature(void) //顯示溫度,全局變量display_temperature_88傳遞溫度值
{
uint8_t temp_High;//溫度高位數
uint8_t temp_Low;//溫度低位數
}
void user_display_capacitance(void) //顯示容量,全局變量display_capacitance_88傳遞容量值
{
uint8_t Cap_High;//溫度高位數
uint8_t Cap_Low;//溫度低位數
}
void user_display_time(void) //顯示時間,全局變量display_time_88傳遞時間值
{
uint8_t time_High;//溫度高位數
uint8_t time_Low;//溫度低位數
}
void user_display_line8(void) //陰極8線顯示,變量line8_sw控制火焰圖標的顯示,0=不顯示,1=顯示
{
}
void user_display_line9(void) //陰極9線顯示,變量line9_sw控制風扇圖標的顯示,0=不顯示,1=顯示
{
}
void user_display_line10(void) //陰極10線顯示,變量line10_water花灑圖標,0=不顯示,1=顯示,變量line10_cap控制容量的,0=不顯示,1=8L,2=10L,3=12L
{
}
void user_display_decorate(void) //陰極11、12線顯示,變量decorate_sw控制裝飾條,0=不顯示,1=顯示
{
}
void user_display_lineH(void) //陽極H線顯示,變量lineH_sw控制裝飾條,0=不顯示,1=顯示
{
}
void user_display_line13() //陰極13線顯示,變量line13_sw控制顯示時間還是故障代碼,0=關閉,1=時間,2=故障代碼
{
}
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;
}
/*
-
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 1
extern 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_time_num++; if(display_time_num>=101){display_time_num=0;}if(display_time_num/100){display_temperature_88++; //溫度+1if(display_temperature_88>99){display_temperature_88=0;}display_capacitance_88++; //容量+1if(display_capacitance_88>12){display_capacitance_88=0;}display_time_88++; //時間+1if(display_time_88>60){display_time_88=0;}}vTaskDelay(20 / portTICK_PERIOD_MS); //每隔20ms刷新一次顯示數據,所以,應用不能刷得太快}
void app_main(void)
{
user_display_app(TIMER_INTERVAL1_ms); //刷屏函數,至少運行一次即可
}
三、程序優化
顯示函數里LED點亮需要保持一定時間,大致在600us~1ms,DEMO是直接采用延遲函數來保持。用戶可以在延遲函數里插入一些應用,例如ADC采樣,按鍵掃描,數據發送等等。
調試時,可以修改以下2個時間,獲得最佳的顯示效果#define user_delay_time_us 800 //LED保持時間
#define TIMER_INTERVAL1_ms 20 // 刷屏時間,ms
總結
以上是生活随笔為你收集整理的启明云端分享|干货来了,怎么用ESP32-S2驱动断码屏呢?更多干货欢迎关注启明云端CSDN技术社区!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 启明云端分享|SSD201_自动升级固件
- 下一篇: 字少事大|两张表格教你快速选择适合的MC