日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式云IOT技術(shù)圈
[導(dǎo)讀]嵌入式開源項目精選專欄 本專欄由Mculover666創(chuàng)建,主要內(nèi)容為尋找嵌入式領(lǐng)域內(nèi)的優(yōu)質(zhì)開源項目,一是幫助開發(fā)者使用開源項目實現(xiàn)更多的功能,二是通過這些開源項目,學(xué)習(xí)大佬的代碼及背后的實現(xiàn)思想,提升自己的代碼水平,和其它專欄相比,本專欄的優(yōu)勢在于:


嵌入式開源項目精選專欄

本專欄由Mculover666創(chuàng)建,主要內(nèi)容為尋找嵌入式領(lǐng)域內(nèi)的優(yōu)質(zhì)開源項目,一是幫助開發(fā)者使用開源項目實現(xiàn)更多的功能,二是通過這些開源項目,學(xué)習(xí)大佬的代碼及背后的實現(xiàn)思想,提升自己的代碼水平,和其它專欄相比,本專欄的優(yōu)勢在于:

不會單純的介紹分享項目,還會包含作者親自實踐的過程分享,甚至還會有對它背后的設(shè)計思想解讀。

目前本專欄包含的開源項目有:

  • SFUD | 一個簡潔實用的開源項目,幫你輕松搞定SPI Flash
  • cJSON | 一個輕量級C語言JSON解析器
  • paho | 支持10種語言編寫mqtt客戶端,總有一款適合你!
  • MultiButton | 一個小巧簡單易用的事件驅(qū)動型按鍵驅(qū)動模塊
  • letter-shell | 一個功能強(qiáng)大的嵌入式shell

如果您自己編寫或者發(fā)現(xiàn)的開源項目不錯,歡迎留言或者私信投稿到本專欄,分享獲得雙倍的快樂!

1. EasyLogger

本期給大家?guī)淼拈_源項目是 EasyLogger,一款輕量級且高性能的日志庫,作者armink,目前收獲 1.1K 個 star,遵循 MIT 開源許可協(xié)議。

EasyLogger 是一款超輕量級、高性能的 C/C++ 日志庫,非常適合對資源敏感的軟件項目,相比之下, EasyLogger 的功能更加簡單,提供給用戶的接口更少,上手會更快,更多實用功能支持以插件形式進(jìn)行動態(tài)擴(kuò)展。

目前EasyLogger支持以下功能:

  • 日志輸出方式支持串口、Flash、文件等;
  • 日志內(nèi)容可包含級別、時間戳、線程信息、進(jìn)程信息等;
  • 支持多種操作系統(tǒng),支持裸機(jī);
  • 各級別日志支持不同顏色顯示;

項目地址:https://github.com/armink/EasyLogger

2. 移植EasyLogger

2.1. 移植思路

在移植過程中主要參考兩個資料:項目的readme文檔和demo工程。

對于這些開源項目,其實移植起來也就兩步:

  • ① 添加源碼到裸機(jī)工程中;
  • ② 實現(xiàn)需要的接口即可;

2.2. 準(zhǔn)備裸機(jī)工程

本文中我使用的是小熊派IoT開發(fā)套件,主控芯片為STM32L431RCT6:移植之前需要準(zhǔn)備一份裸機(jī)工程,我使用STM32CubeMX生成,使用USART1的查詢方式發(fā)送數(shù)據(jù),并將printf重定向到USART1,具體過程請參考:

  • STM32CubeMX_06 | 使用USART發(fā)送和接收數(shù)據(jù)(查詢模式)
  • STM32CubeMX_09 | 重定向printf函數(shù)到串口輸出的多種方法

串口USART1配置如下:生成工程后printf重定向代碼如下:

#include <stdio.h>

int fputc(int ch, FILE *stream)
{
    /* 堵塞判斷串口是否發(fā)送完成 */
    while((USART1->ISR & 0X40) == 0);

    /* 串口發(fā)送完成,將該字符發(fā)送 */
    USART1->TDR = (uint8_t) ch;

    return ch;
}

裸機(jī)工程準(zhǔn)備好之后開始移植easylogger。

2.3. 添加elog到工程中

① 復(fù)制源碼到工程中:② 在keil中添加easylogger組件的源碼文件:

  • port/elog_port.c:elog移植接口文件;
  • src/elog.c:elog核心功能源碼;
  • src/elog_utils.c:elog所用到的一些c庫工具函數(shù)實現(xiàn);
  • src/elog_buf.c(可選添加):elog緩沖輸出模式源碼;
  • src/elog_async.c(可選添加):elog異步輸出模式源碼;

③ 將easylogger/inc頭文件路徑添加到keil中:

2.4. 實現(xiàn)elog移植接口

elog的移植接口都已經(jīng)寫好了,在elog_port.c文件中,只需要在函數(shù)體中添加代碼即可。

① elog初始化接口

ElogErrCode elog_port_init(void);

如果涉及到后續(xù)elog使用資源的初始化,比如動態(tài)申請分配緩沖區(qū)內(nèi)存,可以放在此接口中,本文中保持默認(rèn)。

② elog日志輸出接口(重點)

//開頭添加
#include <stdio.h>

……

//接口實現(xiàn)
void elog_port_output(const char *logsize_t size) {
 //日志使用printf輸出,printf已經(jīng)重定向到串口USART1
 printf("%.*s", size, log);
}

這兒有個小知識點,%s表示字符串輸出,.<十進(jìn)制數(shù)>是精度控制格式符,輸出字符時表示輸出字符的位數(shù),在精度控制時,小數(shù)點后的十進(jìn)制數(shù)可以使用*來占位,在后面提供一個變量作為精度控制的具體值。

③ 日志輸出上鎖/解鎖接口

該接口可以對日志輸出接口進(jìn)行上鎖/解鎖,以保證日志在并發(fā)輸出時的正確性,本文中使用的是裸機(jī)程序,所以在此使用關(guān)閉全局中斷來加鎖,打開全局中斷來解鎖:

//開頭添加
#include <stm32l4xx_hal.h>

……

//接口實現(xiàn)
void elog_port_output_lock(void) {
    
    //關(guān)閉全局中斷
 __set_PRIMASK(1);
  
}
void elog_port_output_unlock(void) {
    
    //開啟全局中斷
 __set_PRIMASK(0);
    
}

STM32開關(guān)全局中斷的方式很多,本文中直接操作 PRIMASK 寄存器來快速的屏蔽/打開全局中斷,參考文章:

https://blog.csdn.net/working24hours/article/details/88323241

④ 系統(tǒng)信息獲取接口

elog提供了三個接口用來獲取當(dāng)前時間、獲取進(jìn)程號、獲取線程號,因為本文中移植到裸機(jī)工程中,并且沒有提供時間支持,所以這三個接口都返回空字符串,如下:

const char *elog_port_get_time(void) {
    
 return "";
    
}
const char *elog_port_get_p_info(void) {

 return "";
    
}
const char *elog_port_get_t_info(void) {

 return "";
    
}

2.5. 配置elog

elog的核心功能開啟宏定義和核心參數(shù)宏定義都在配置文件elog_cfg.h中,在本文中只講述其中重要的宏定義。

日志輸出總開關(guān):

/* enable log output. */
#define ELOG_OUTPUT_ENABLE

換行符宏定義修改如下:

/* output newline sign */
#define ELOG_NEWLINE_SIGN                        "\r\n"

帶有顏色的日志輸出開關(guān):

/* enable log color */
#define ELOG_COLOR_ENABLE

移植時并沒有添加異步輸出和緩沖區(qū)輸出的源碼,所以將這兩個功能關(guān)掉:至此,移植配置完成,接下來可以開始愉快的使用啦!

3. 使用easylogger

3.1. 初始化elog

elog使用之前需要初始化,過程有三步:① 初始化elog

ElogErrCode elog_init(void);

② 設(shè)置日志輸出格式

void elog_set_fmt(uint8_t level, size_t set);

其中第一個參數(shù)表示設(shè)置哪個日志輸出級別對應(yīng)的輸出格式,從以下宏定義中選擇一個:

/* output log's level */
#define ELOG_LVL_ASSERT                      0
#define ELOG_LVL_ERROR                       1
#define ELOG_LVL_WARN                        2
#define ELOG_LVL_INFO                        3
#define ELOG_LVL_DEBUG                       4
#define ELOG_LVL_VERBOSE                     5

其二個參數(shù)是日志輸出格式,枚舉給出,可以自由組合搭配:

/* all formats index */
typedef enum {
    ELOG_FMT_LVL    = 1 << 0/**< level */
    ELOG_FMT_TAG    = 1 << 1/**< tag */
    ELOG_FMT_TIME   = 1 << 2/**< current time */
    ELOG_FMT_P_INFO = 1 << 3/**< process info */
    ELOG_FMT_T_INFO = 1 << 4/**< thread info */
    ELOG_FMT_DIR    = 1 << 5/**< file directory and name */
    ELOG_FMT_FUNC   = 1 << 6/**< function name */
    ELOG_FMT_LINE   = 1 << 7/**< line number */
} ElogFmtIndex;

/* macro definition for all formats */
#define ELOG_FMT_ALL    (ELOG_FMT_LVL|ELOG_FMT_TAG|ELOG_FMT_TIME|ELOG_FMT_P_INFO|ELOG_FMT_T_INFO| ELOG_FMT_DIR|ELOG_FMT_FUNC|ELOG_FMT_LINE)

③ 啟動elog

void elog_start(void);

接下來在main函數(shù)中的usart1初始化函數(shù)之后,while(1)之前編寫elog初始化代碼:

/* USER CODE BEGIN 2 */
/* 初始化elog */
elog_init();

/* 設(shè)置每個級別的日志輸出格式 */
//輸出所有內(nèi)容
elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
//輸出日志級別信息和日志TAG
elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG);
elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG);
elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG);
//除了時間、進(jìn)程信息、線程信息之外,其余全部輸出
elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~(ELOG_FMT_TIME | ELOG_FMT_P_INFO | ELOG_FMT_T_INFO));
//輸出所有內(nèi)容
elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL);

/* 啟動elog */
elog_start();

/* USER CODE END 2 */

3.2. elog日志輸出

elog中每種級別都有一種完整方式,兩種簡化方式,使用時自行選擇:

#define elog_assert(tag, ...) 
#define elog_a(tag, ...) //簡化方式1,每次需填寫 LOG_TAG
#define log_a(...)       //簡化方式2,LOG_TAG 在文件頂部定義,使用前無需填寫 LOG_TAG

#define elog_error(tag, ...)
#define elog_e(tag, ...)
#define log_e(...)

#define elog_warn(tag, ...)
#define elog_w(tag, ...)
#define log_w(...)

#define elog_info(tag, ...)
#define elog_i(tag, ...)
#define log_i(...)

#define elog_debug(tag, ...)
#define elog_d(tag, ...)
#define log_d(...)

#define elog_verbose(tag, ...)
#define elog_v(tag, ...)
#define log_v(...)

前兩種在使用的時候只需要包含<elog.h>頭文件即可,第三種方式除了包含頭文件之外,還需要在文件開始定義TAG宏定義,使用起來和printf相同,所以這里我使用第三種方法演示。

首先在main.c文件開始定義TAG宏,包含頭文件:

/* USER CODE BEGIN Includes */
#define LOG_TAG    "main"

#include <elog.h>

/* USER CODE END Includes */

然后在main函數(shù)中編寫的elog初始化代碼之后,繼續(xù)添加代碼,測試elog的使用:

log_a("Hello EasyLogger!");
log_e("Hello EasyLogger!");
log_w("Hello EasyLogger!");
log_i("Hello EasyLogger!");
log_d("Hello EasyLogger!");
log_v("Hello EasyLogger!");

編譯,燒寫,使用串口終端(Mobaxterm)查看串口輸出:

3.3. 五彩繽紛的輸出

要想五彩繽紛的日志,僅在elog_cfg.h中使能顏色輸出還不夠,還需要使用API開啟輸出:

void elog_set_text_color_enabled(bool enabled);

在初始化elog的時候使能文字顏色輸出:再次編譯、下載、查看輸出:每個級別日志的前景色、背景色、字體都可以在elog_cfg.h中修改宏定義,宏定義的值在elog.c中給出,可自行查看,比如這里我將ERROR級別的日志修改為閃爍字體:編譯、下載、查看輸出:

3.4. 移植前后內(nèi)存占用情況

移植前的裸機(jī)工程只具有usart1收發(fā)功能,移植easylogger之后兩者內(nèi)存對比如下:

3.5. elog的高級功能

elog除了基本的日志功能之外,還提供了一些高級功能,比如:

  • 日志輸出過濾功能:可以按級別、TAG、關(guān)鍵詞過濾日志;
  • 緩沖輸出模式;
  • 異步輸出模式;

這些功能如何使用,在項目的readme文檔中講述的很詳細(xì),本文限于篇幅,這些高級功能不詳細(xì)講述,如有興趣深入,可以自行研究。

4. 設(shè)計思想解讀

4.1. 數(shù)據(jù)加工

使用日志打印組件與使用printf最基本的區(qū)別在于:輸出了更多有利于調(diào)試的信息,可以理解為對輸出數(shù)據(jù)進(jìn)行了一次加工。

打印語句所在文件、函數(shù)名、行號這些信息是利用了編譯器內(nèi)置宏的功能:

  • __FILE__:文件名
  • __FUNCTION__:函數(shù)名
  • __LINE__:行號

而在終端中輸出有顏色的字符則是利用了ANSI escape code,即Escape 序列屏幕控制碼,關(guān)于這兩個知識點詳細(xì)的解釋和示例請閱讀:

  • 編譯器宏詳解
  • ANSI escape code詳解

在elog中對輸出內(nèi)容進(jìn)行加工處理的函數(shù)為:

/**
 * output the log
 *
 * @param level level
 * @param tag tag
 * @param file file name
 * @param func function name
 * @param line line number
 * @param format output format
 * @param ... args
 *
 */

void elog_output(uint8_t level, const char *tag, const char *file, const char *func,const long line, const char *format, ...) ;

4.2. 日志輸出模式

俗話說,師傅領(lǐng)進(jìn)門,修行在個人,本文所講述的只是日志打印組件的基本功能,使用printf直接實現(xiàn)日志輸出接口,所以在日志輸出模式上和使用printf輸出沒有區(qū)別,只不過多了些信息。

elog支持異步輸出模式,開啟異步輸出模式后,將會提升用戶應(yīng)用程序的執(zhí)行效率。應(yīng)用程序在進(jìn)行日志輸出時,無需等待日志徹底輸出完成,即可直接返回。

elog也支持緩沖輸出模式,開啟緩沖輸出模式后,如果緩沖區(qū)不滿,用戶線程在進(jìn)行日志輸出時,無需等待日志徹底輸出完成,即可直接返回。但當(dāng)日志緩沖區(qū)滿以后,將會占用用戶線程,自動將緩沖區(qū)中的日志全部輸出干凈。

這兩種無需等待,直接返回的日志輸出模式,在打印大量日志信息的時候非常重要,打印日志的代碼對正常應(yīng)用程序的影響越小越好,本文不再講述,還請讀者自行研究。

5. 項目工程源碼獲取和問題交流

目前我將Easylogger源碼、我移植到小熊派STM32L431RCT6開發(fā)板的工程源碼上傳到了QQ群里(包含好幾份HAL庫,QQ相對速度快點),可以在QQ群里下載,有問題也可以在群里交流,當(dāng)然也歡迎大家分享出來自己移植的工程到QQ群里

放上QQ群二維碼:

接收更多精彩文章及資源推送,歡迎訂閱我的微信公眾號:『mculover666』。

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護(hù)是驅(qū)動電源設(shè)計中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設(shè)計成為提升電機(jī)驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設(shè)備的使用壽命。然而,在實際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗。要解決這一問題,需從設(shè)計、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機(jī)驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設(shè)計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉