[{"data":1,"prerenderedAt":4951},["ShallowReactive",2],{"wiki-page-/en-us/wiki/2026-01-07-esp32-jiao-cheng/ch4-jiao-cheng":3,"wiki-doc-items-/en-us/wiki/2026-01-07-esp32-jiao-cheng/ch4-jiao-cheng":4912,"language-switcher-data-/en-us/wiki/2026-01-07-esp32-jiao-cheng/ch4-jiao-cheng":4935,"wiki-i18n-paths-/en-us/wiki/2026-01-07-esp32-jiao-cheng/ch4-jiao-cheng":4950},{"id":4,"title":5,"body":6,"canonicalPath":4893,"chapter":4894,"chapterSort":4895,"date":4896,"description":12,"docI18nKey":4897,"docKey":4898,"docRoot":4899,"docTitle":4900,"extension":4901,"i18nKey":4902,"isBlogPost":4903,"isWikiDoc":425,"isWikiIndex":4903,"layout":4904,"legacyPath":4904,"locale":4905,"localeSlug":4906,"meta":4907,"navigation":425,"path":4893,"seo":4908,"sourcePath":4909,"sourceStem":4902,"stem":4910,"wikiDepth":359,"__hash__":4911},"content/_i18n/en-us/wiki/2026-01-07-ESP32教程/ch4-教程.md","Tutorial",{"type":7,"value":8,"toc":4885},"minimark",[9,13,19,24,29,36,43,52,56,65,70,76,81,84,89,93,98,115,126,133,138,144,149,156,161,166,171,177,195,222,228,241,246,252,258,264,269,272,277,281,284,289,294,299,304,308,312,315,320,323,326,331,335,338,343,346,377,380,385,390,393,398,441,444,449,547,553,556,561,565,577,583,586,591,594,599,602,607,613,617,619,623,637,641,645,648,711,714,717,740,743,751,754,1345,1351,1357,1360,1365,1368,1373,1382,1388,1393,1403,1408,1413,1418,1542,1545,1554,1559,1569,1575,1591,1598,1628,1631,1658,1661,1665,1668,1674,1677,1681,1686,1691,1694,1699,1704,1708,1712,1715,1718,1723,1726,1731,1734,1739,1742,1749,1753,1760,1763,1793,1804,1929,1949,1963,2082,2088,2098,2106,2113,2187,2207,2213,2467,2474,2513,2527,2530,2534,2544,2555,2562,2598,2612,2708,2727,2892,2898,2903,3050,3073,3076,3081,3085,3088,3093,3096,3101,3104,3109,3112,3117,3120,3125,3135,3222,3229,3234,3256,3267,3280,3286,3340,3352,3365,3372,3504,3507,3843,3850,3884,3887,3905,3911,4153,4161,4633,4718,4721,4726,4731,4736,4749,4755,4760,4764,4768,4790,4795,4800,4803,4808,4812,4815,4820,4823,4831,4834,4838,4843,4850,4855,4858,4872,4876,4881],[10,11,12],"p",{},"Below, I'll use the ESP32S3 and Fedora Linux as an example for this tutorial.",[10,14,15],{},[16,17,18],"strong",{},"This tutorial is unique in that, while it is largely based on the Zhengdian Atom tutorial, that tutorial uses a lot of macro definitions, which is not suitable for beginners to read. This tutorial will minimize the use of macro definitions and try to teach you the most original code as much as possible.",[20,21,23],"h3",{"id":22},"basic-project-creation","Basic project creation",[25,26,28],"h4",{"id":27},"preparation-work","Preparation Work",[10,30,31,32],{},"(Some older versions must move this folder)\nCopy this folder ",[33,34,35],"code",{},"esp-idf/tools/templates/sample_project",[10,37,38],{},[39,40],"img",{"alt":41,"src":42},"alt text","https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768314488557.webp",[10,44,45,46,49],{},"Copy here ",[33,47,48],{},"esp-idf/examples/get-started/sample_project",[39,50],{"alt":41,"src":51},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768314551666.webp",[25,53,55],{"id":54},"create-a-new-project","Create a new project",[10,57,58,59,62],{},"Click on ",[33,60,61],{},"New Projects",[39,63],{"alt":41,"src":64},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768314732108.webp",[10,66,67],{},[39,68],{"alt":41,"src":69},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768314940430.webp",[10,71,72,73],{},"Either of the following two options works. Some older versions don't have the bottom option. (For the latest version, just select the bottom one.)\n",[39,74],{"alt":41,"src":75},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768315043852.webp",[10,77,78],{},[39,79],{"alt":41,"src":80},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768315170936.webp",[10,82,83],{},"Created successfully",[10,85,86],{},[39,87],{"alt":41,"src":88},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768316173024.webp",[25,90,92],{"id":91},"menuconfig-configuration","menuconfig configuration",[10,94,95],{},[39,96],{"alt":41,"src":97},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768316263151.webp",[99,100,101,112],"ol",{},[102,103,104,105,108,109],"li",{},"Configure the main frequency\nSearch for ",[33,106,107],{},"CPU",", find the CPU frequency setting, and set the CPU frequency to 240MHz (maximum).\n",[39,110],{"alt":41,"src":111},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768316286100.webp",[102,113,114],{},"Configure Flash and RAM",[10,116,117,118,121,122,125],{},"Search for ",[33,119,120],{},"Flash",", set ",[33,123,124],{},"Flash SPI mode"," to QIO. This mode provides the fastest speed.",[10,127,128,129,132],{},"Check the ESP32S3 model purchased on Taobao. ",[33,130,131],{},"ESP32-S3 N16R8"," I found that my Flash is 16M and RAM is 8M.",[10,134,135],{},[39,136],{"alt":41,"src":137},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768316646459.webp",[10,139,117,140,143],{},[33,141,142],{},"PSRAM"," and check the box.",[10,145,146],{},[39,147],{"alt":41,"src":148},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768316691252.webp",[10,150,151,152,155],{},"Looking at the official PSRAM introduction, we should select ",[33,153,154],{},"Octal SPI",".",[10,157,158],{},[39,159],{"alt":41,"src":160},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768316801358.webp",[10,162,163],{},[39,164],{"alt":41,"src":165},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768316830677.webp",[10,167,168],{},[39,169],{"alt":41,"src":170},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768316860867.webp",[99,172,174],{"start":173},3,[102,175,176],{},"Configure FreeRTOS",[10,178,179,180,183,184,187,188,191,192],{},"Configure ",[33,181,182],{},"configTICK_RATE_HZ"," as ",[33,185,186],{},"1000",", so the period is 1ms, and the unit of the ",[33,189,190],{},"vTaskDelay()"," function becomes ms.\n",[39,193],{"alt":41,"src":194},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768316998368.webp",[99,196,198,216],{"start":197},4,[102,199,200,201,204,205,208,209,212,213],{},"Configure the partition table\nSearch for ",[33,202,203],{},"partition",", find ",[33,206,207],{},"partition table",", and configure it as ",[33,210,211],{},"自定义分区表CSV",".\n",[39,214],{"alt":41,"src":215},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768317232438.webp",[102,217,218,219],{},"Save\n",[39,220],{"alt":41,"src":221},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768317262632.webp",[10,223,224,225],{},"Old backups can be deleted.\n",[39,226],{"alt":41,"src":227},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768317292811.webp",[99,229,231],{"start":230},6,[102,232,233,234,237,238,155],{},"Edit the partition table\nPress ctrl shift P together, type ",[33,235,236],{},"Partition Table",", and find ",[33,239,240],{},"Open Partition Table Eidtors UI",[10,242,243],{},[39,244],{"alt":41,"src":245},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768317456014.webp",[10,247,248,249],{},"按照下面一点都别抄错的抄下来\n",[39,250],{"alt":41,"src":251},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768317821742.webp",[10,253,254,255],{},"You can see that everything has been generated.\n",[39,256],{"alt":41,"src":257},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768317884257.webp",[99,259,261],{"start":260},7,[102,262,263],{},"Compile and test",[10,265,266],{},[39,267],{"alt":41,"src":268},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768317920177.webp",[10,270,271],{},"As shown in the figure, the compilation was successful.",[10,273,274],{},[39,275],{"alt":41,"src":276},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768317956841.webp",[20,278,280],{"id":279},"introduction-to-partition-tables","Introduction to Partition Tables",[10,282,283],{},"The partition table divides Flash into multiple storage areas, recording the specific functions and purposes of each area.",[10,285,286],{},[39,287],{"alt":41,"src":288},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768364806657.webp",[10,290,291],{},[39,292],{"alt":41,"src":293},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768364833756.webp",[10,295,296],{},[39,297],{"alt":41,"src":298},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768364863022.webp",[10,300,301],{},[39,302],{"alt":41,"src":303},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768364885473.webp",[20,305,307],{"id":306},"custom-project-architecture-and-adding-components","Custom project architecture and adding components",[25,309,311],{"id":310},"introduces-the-engineering-architecture","Introduces the engineering architecture.",[10,313,314],{},"Here is the official project structure from Espressif:",[10,316,317],{},[39,318],{"alt":41,"src":319},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768364924079.webp",[10,321,322],{},"This is clearly very mixed.",[10,324,325],{},"The following is the project structure of Zhengdian Atom, which is more modular, offers greater scalability, and has clearer layering.",[10,327,328],{},[39,329],{"alt":41,"src":330},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768365242442.webp",[25,332,334],{"id":333},"create-the-project-architecture","Create the project architecture.",[10,336,337],{},"Copy the basic project, paste it into the folder where you store your code, and rename it to N01_LED.",[10,339,340],{},[39,341],{"alt":41,"src":342},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768365712006.webp",[10,344,345],{},"Open the newly created folder with VSCode.",[347,348,353],"pre",{"className":349,"code":350,"language":351,"meta":352,"style":352},"language-bash shiki shiki-themes github-light github-dark","cd ~/UserFolder/MySource/ESP32_Projects/N01_LED\ncode .\n","bash","",[33,354,355,368],{"__ignoreMap":352},[356,357,360,364],"span",{"class":358,"line":359},"line",1,[356,361,363],{"class":362},"sj4cs","cd",[356,365,367],{"class":366},"sZZnC"," ~/UserFolder/MySource/ESP32_Projects/N01_LED\n",[356,369,371,374],{"class":358,"line":370},2,[356,372,33],{"class":373},"sScJk",[356,375,376],{"class":366}," .\n",[10,378,379],{},"Create the following files",[10,381,382],{},[39,383],{"alt":41,"src":384},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768374450746.webp",[10,386,387],{},[39,388],{"alt":41,"src":389},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768374502096.webp",[10,391,392],{},"Open the top-level CMakeLists",[10,394,395],{},[39,396],{"alt":41,"src":397},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768373817706.webp",[347,399,403],{"className":400,"code":401,"language":402,"meta":352,"style":352},"language-cmake shiki shiki-themes github-light github-dark","# Set the extra component directories\nset(EXTRA_COMPONENT_DIRS components/Middlewares)\n\n# Add compile options,warning has color.\nadd_compile_options(-fdiagnostics-color=always)\n","cmake",[33,404,405,411,421,427,432],{"__ignoreMap":352},[356,406,407],{"class":358,"line":359},[356,408,410],{"class":409},"sJ8bj","# Set the extra component directories\n",[356,412,413,417],{"class":358,"line":370},[356,414,416],{"class":415},"szBVR","set",[356,418,420],{"class":419},"sVt8B","(EXTRA_COMPONENT_DIRS components/Middlewares)\n",[356,422,423],{"class":358,"line":173},[356,424,426],{"emptyLinePlaceholder":425},true,"\n",[356,428,429],{"class":358,"line":197},[356,430,431],{"class":409},"# Add compile options,warning has color.\n",[356,433,435,438],{"class":358,"line":434},5,[356,436,437],{"class":415},"add_compile_options",[356,439,440],{"class":419},"(-fdiagnostics-color=always)\n",[10,442,443],{},"Modify the CMakeLists in the BSP.",[10,445,446],{},[39,447],{"alt":41,"src":448},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768374173407.webp",[347,450,452],{"className":400,"code":451,"language":402,"meta":352,"style":352},"set(src_dirs\n            LED)\n\nset(include_dirs\n            LED)\n\n# GPIO的一些组件在driver里\nset(requires\n            driver)\n\nidf_component_register(SRC_DIRS ${src_dirs}\n                      INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})\n\ncomponent_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)\n",[33,453,454,461,466,470,477,481,485,490,498,504,509,518,536,541],{"__ignoreMap":352},[356,455,456,458],{"class":358,"line":359},[356,457,416],{"class":415},[356,459,460],{"class":419},"(src_dirs\n",[356,462,463],{"class":358,"line":370},[356,464,465],{"class":419},"            LED)\n",[356,467,468],{"class":358,"line":173},[356,469,426],{"emptyLinePlaceholder":425},[356,471,472,474],{"class":358,"line":197},[356,473,416],{"class":415},[356,475,476],{"class":419},"(include_dirs\n",[356,478,479],{"class":358,"line":434},[356,480,465],{"class":419},[356,482,483],{"class":358,"line":230},[356,484,426],{"emptyLinePlaceholder":425},[356,486,487],{"class":358,"line":260},[356,488,489],{"class":409},"# GPIO的一些组件在driver里\n",[356,491,493,495],{"class":358,"line":492},8,[356,494,416],{"class":415},[356,496,497],{"class":419},"(requires\n",[356,499,501],{"class":358,"line":500},9,[356,502,503],{"class":419},"            driver)\n",[356,505,507],{"class":358,"line":506},10,[356,508,426],{"emptyLinePlaceholder":425},[356,510,512,515],{"class":358,"line":511},11,[356,513,514],{"class":419},"idf_component_register(SRC_DIRS ",[356,516,517],{"class":415},"${src_dirs}\n",[356,519,521,524,527,530,533],{"class":358,"line":520},12,[356,522,523],{"class":419},"                      INCLUDE_DIRS ",[356,525,526],{"class":415},"${include_dirs}",[356,528,529],{"class":419}," REQUIRES ",[356,531,532],{"class":415},"${requires}",[356,534,535],{"class":419},")\n",[356,537,539],{"class":358,"line":538},13,[356,540,426],{"emptyLinePlaceholder":425},[356,542,544],{"class":358,"line":543},14,[356,545,546],{"class":419},"component_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)\n",[10,548,549,550],{},"Clean and rebuild to see.\n",[39,551],{"alt":41,"src":552},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768374290311.webp",[10,554,555],{},"Successfully compiled",[10,557,558],{},[39,559],{"alt":41,"src":560},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768374519751.webp",[25,562,564],{"id":563},"add-component","Add component",[10,566,117,567,570,571,212,574],{},[33,568,569],{},"esp component"," using ctrl shift P, then find ",[33,572,573],{},"esp component registry",[39,575],{"alt":41,"src":576},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768374757763.webp",[10,578,579,580],{},"Select the model\n",[39,581],{"alt":41,"src":582},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768374798596.webp",[10,584,585],{},"For example, to install OpenAI, search for OpenAI.",[10,587,588],{},[39,589],{"alt":41,"src":590},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768374854035.webp",[10,592,593],{},"Click Install.",[10,595,596],{},[39,597],{"alt":41,"src":598},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768374870553.webp",[10,600,601],{},"Installation successful",[10,603,604],{},[39,605],{"alt":41,"src":606},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768374895177.webp",[10,608,609,610],{},"The image below shows a successful installation.\n",[39,611],{"alt":41,"src":612},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768374968925.webp",[10,614,549,615],{},[39,616],{"alt":41,"src":552},[10,618,555],{},[10,620,621],{},[39,622],{"alt":41,"src":560},[10,624,625,626,629,630,633,634,155],{},"Note: In ",[33,627,628],{},"main.c",", you can directly call the added components, but in the files under the ",[33,631,632],{},"components"," folder, you cannot use them directly; you need to modify ",[33,635,636],{},"CMakeLists.txt",[20,638,640],{"id":639},"downloading-and-debugging-the-esp32","Downloading and debugging the ESP32",[25,642,644],{"id":643},"download","Download",[10,646,647],{},"First, write a program. Add a hello world in main.c.",[347,649,653],{"className":650,"code":651,"language":652,"meta":352,"style":352},"language-c shiki shiki-themes github-light github-dark","#include \u003Cstdio.h>\n\nvoid app_main(void)\n{\n    printf(\"Hello World!\\n\");\n}\n","c",[33,654,655,663,667,682,687,706],{"__ignoreMap":352},[356,656,657,660],{"class":358,"line":359},[356,658,659],{"class":415},"#include",[356,661,662],{"class":366}," \u003Cstdio.h>\n",[356,664,665],{"class":358,"line":370},[356,666,426],{"emptyLinePlaceholder":425},[356,668,669,672,675,678,680],{"class":358,"line":173},[356,670,671],{"class":415},"void",[356,673,674],{"class":373}," app_main",[356,676,677],{"class":419},"(",[356,679,671],{"class":415},[356,681,535],{"class":419},[356,683,684],{"class":358,"line":197},[356,685,686],{"class":419},"{\n",[356,688,689,692,694,697,700,703],{"class":358,"line":434},[356,690,691],{"class":373},"    printf",[356,693,677],{"class":419},[356,695,696],{"class":366},"\"Hello World!",[356,698,699],{"class":362},"\\n",[356,701,702],{"class":366},"\"",[356,704,705],{"class":419},");\n",[356,707,708],{"class":358,"line":230},[356,709,710],{"class":419},"}\n",[10,712,713],{},"You use a USB-A to USB-C cable, plugging one end into the computer and the other end into the development board's USB port, not the UART port.",[10,715,716],{},"As shown in the figure",[99,718,719],{},[102,720,721,722,734,737],{},"Find device",[99,723,724],{},[102,725,726,727,730,731,155],{},"Windows\nIf you are on Windows, right-click ",[33,728,729],{},"此电脑",", then click ",[33,732,733],{},"管理",[735,736],"br",{},[39,738],{"alt":41,"src":739},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768375429763.webp",[10,741,742],{},"You can see that it has been detected normally below.",[347,744,749],{"className":745,"code":747,"language":748},[746],"language-text","![alt text](https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768375466417.webp)\n\n2. Linux\n","text",[33,750,747],{"__ignoreMap":352},[10,752,753],{},"If you are using Linux, open the terminal.",[347,755,757],{"className":349,"code":756,"language":351,"meta":352,"style":352},"ls /dev | grep USB\n# 或者\n ls /dev | grep ACM\n```\n![alt text](https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768449184448.webp)\n\nCheck if any device is detected. As shown in the image above, mine is `/dev/ttyACM0`.\n\n2. Download\n1. Windows\nIf you are on Windows, first select the mode as `JTAG`, the port as the detected port `COM4`, and the chip model as `esp32s3`. Then click `清理`, `构建`, and `烧录`.\n\n![alt text](https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768375800452.webp)\n\nThen select yes.\n\n![alt text](https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768375960461.webp)\n\n\nAs shown, the flashing is complete.\n\n![alt text](https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768376077047.webp)\n\n2. Linux\nIf you are on Linux, first select the mode as `JTAG`, the port as the detected port `/dev/ttyACM0`, and the chip model as `esp32s3`. Then click `清理`, `构建`, `烧录`.\n\n![alt text](https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768449239886.webp)\n\n![alt text](https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768449318480.webp)\n\nSelect yes here.\n![alt text](https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768449382096.webp)\n\nThe image below shows a successful flash (if you are unable to download normally, please refer to `常见问题` below).\n![alt text](https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768539121456.webp)\n\n#### Debugging\n\nFirst, write a program.\n\n```c\n//包含FreeRTOS头文件(为了用vTaskDelay)\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n\nint32_t i = 0;\n\nvoid app_main(void)\n{\n\n\n//死循环,等同于while(1),但效率比while(1)更高\nfor(;;)\n{\n    i++;\n    vTaskDelay(500 / portTICK_PERIOD_MS);  //延时500ms\n}\n}\n",[33,758,759,776,781,795,800,813,817,833,837,845,853,919,923,934,938,947,952,964,969,974,983,988,1000,1005,1013,1067,1072,1084,1089,1101,1106,1115,1127,1132,1153,1165,1170,1176,1181,1190,1195,1204,1212,1218,1224,1229,1247,1252,1265,1270,1275,1280,1295,1304,1309,1317,1335,1340],{"__ignoreMap":352},[356,760,761,764,767,770,773],{"class":358,"line":359},[356,762,763],{"class":373},"ls",[356,765,766],{"class":366}," /dev",[356,768,769],{"class":415}," |",[356,771,772],{"class":373}," grep",[356,774,775],{"class":366}," USB\n",[356,777,778],{"class":358,"line":370},[356,779,780],{"class":409},"# 或者\n",[356,782,783,786,788,790,792],{"class":358,"line":173},[356,784,785],{"class":373}," ls",[356,787,766],{"class":366},[356,789,769],{"class":415},[356,791,772],{"class":373},[356,793,794],{"class":366}," ACM\n",[356,796,797],{"class":358,"line":197},[356,798,799],{"class":366},"```\n",[356,801,802,805,808,811],{"class":358,"line":434},[356,803,804],{"class":415},"!",[356,806,807],{"class":366},"[alt text](",[356,809,810],{"class":373},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768449184448.webp",[356,812,535],{"class":366},[356,814,815],{"class":358,"line":230},[356,816,426],{"emptyLinePlaceholder":425},[356,818,819,822,825,828,831],{"class":358,"line":260},[356,820,821],{"class":373},"Check",[356,823,824],{"class":366}," if any device is detected. As shown in the image above, mine is `",[356,826,827],{"class":373},"/dev/ttyACM0",[356,829,830],{"class":366},"`",[356,832,212],{"class":362},[356,834,835],{"class":358,"line":492},[356,836,426],{"emptyLinePlaceholder":425},[356,838,839,842],{"class":358,"line":500},[356,840,841],{"class":373},"2.",[356,843,844],{"class":366}," Download\n",[356,846,847,850],{"class":358,"line":506},[356,848,849],{"class":373},"1.",[356,851,852],{"class":366}," Windows\n",[356,854,855,858,861,864,866,869,872,875,877,879,882,885,887,889,892,895,897,899,902,905,907,909,912,915,917],{"class":358,"line":511},[356,856,857],{"class":373},"If",[356,859,860],{"class":366}," you are on Windows, first select the mode as `",[356,862,863],{"class":373},"JTAG",[356,865,830],{"class":366},[356,867,868],{"class":373},",",[356,870,871],{"class":366}," the port as the detected port `",[356,873,874],{"class":373},"COM4",[356,876,830],{"class":366},[356,878,868],{"class":373},[356,880,881],{"class":366}," and the chip model as `",[356,883,884],{"class":373},"esp32s3",[356,886,830],{"class":366},[356,888,155],{"class":362},[356,890,891],{"class":366}," Then click `",[356,893,894],{"class":373},"清理",[356,896,830],{"class":366},[356,898,868],{"class":373},[356,900,901],{"class":366}," `",[356,903,904],{"class":373},"构建",[356,906,830],{"class":366},[356,908,868],{"class":373},[356,910,911],{"class":366}," and `",[356,913,914],{"class":373},"烧录",[356,916,830],{"class":366},[356,918,212],{"class":362},[356,920,921],{"class":358,"line":520},[356,922,426],{"emptyLinePlaceholder":425},[356,924,925,927,929,932],{"class":358,"line":538},[356,926,804],{"class":415},[356,928,807],{"class":366},[356,930,931],{"class":373},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768375800452.webp",[356,933,535],{"class":366},[356,935,936],{"class":358,"line":543},[356,937,426],{"emptyLinePlaceholder":425},[356,939,941,944],{"class":358,"line":940},15,[356,942,943],{"class":373},"Then",[356,945,946],{"class":366}," select yes.\n",[356,948,950],{"class":358,"line":949},16,[356,951,426],{"emptyLinePlaceholder":425},[356,953,955,957,959,962],{"class":358,"line":954},17,[356,956,804],{"class":415},[356,958,807],{"class":366},[356,960,961],{"class":373},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768375960461.webp",[356,963,535],{"class":366},[356,965,967],{"class":358,"line":966},18,[356,968,426],{"emptyLinePlaceholder":425},[356,970,972],{"class":358,"line":971},19,[356,973,426],{"emptyLinePlaceholder":425},[356,975,977,980],{"class":358,"line":976},20,[356,978,979],{"class":373},"As",[356,981,982],{"class":366}," shown, the flashing is complete.\n",[356,984,986],{"class":358,"line":985},21,[356,987,426],{"emptyLinePlaceholder":425},[356,989,991,993,995,998],{"class":358,"line":990},22,[356,992,804],{"class":415},[356,994,807],{"class":366},[356,996,997],{"class":373},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768376077047.webp",[356,999,535],{"class":366},[356,1001,1003],{"class":358,"line":1002},23,[356,1004,426],{"emptyLinePlaceholder":425},[356,1006,1008,1010],{"class":358,"line":1007},24,[356,1009,841],{"class":373},[356,1011,1012],{"class":366}," Linux\n",[356,1014,1016,1018,1021,1023,1025,1027,1029,1031,1033,1035,1037,1039,1041,1043,1045,1047,1049,1051,1053,1055,1057,1059,1061,1063,1065],{"class":358,"line":1015},25,[356,1017,857],{"class":373},[356,1019,1020],{"class":366}," you are on Linux, first select the mode as `",[356,1022,863],{"class":373},[356,1024,830],{"class":366},[356,1026,868],{"class":373},[356,1028,871],{"class":366},[356,1030,827],{"class":373},[356,1032,830],{"class":366},[356,1034,868],{"class":373},[356,1036,881],{"class":366},[356,1038,884],{"class":373},[356,1040,830],{"class":366},[356,1042,155],{"class":362},[356,1044,891],{"class":366},[356,1046,894],{"class":373},[356,1048,830],{"class":366},[356,1050,868],{"class":373},[356,1052,901],{"class":366},[356,1054,904],{"class":373},[356,1056,830],{"class":366},[356,1058,868],{"class":373},[356,1060,901],{"class":366},[356,1062,914],{"class":373},[356,1064,830],{"class":366},[356,1066,212],{"class":362},[356,1068,1070],{"class":358,"line":1069},26,[356,1071,426],{"emptyLinePlaceholder":425},[356,1073,1075,1077,1079,1082],{"class":358,"line":1074},27,[356,1076,804],{"class":415},[356,1078,807],{"class":366},[356,1080,1081],{"class":373},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768449239886.webp",[356,1083,535],{"class":366},[356,1085,1087],{"class":358,"line":1086},28,[356,1088,426],{"emptyLinePlaceholder":425},[356,1090,1092,1094,1096,1099],{"class":358,"line":1091},29,[356,1093,804],{"class":415},[356,1095,807],{"class":366},[356,1097,1098],{"class":373},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768449318480.webp",[356,1100,535],{"class":366},[356,1102,1104],{"class":358,"line":1103},30,[356,1105,426],{"emptyLinePlaceholder":425},[356,1107,1109,1112],{"class":358,"line":1108},31,[356,1110,1111],{"class":373},"Select",[356,1113,1114],{"class":366}," yes here.\n",[356,1116,1118,1120,1122,1125],{"class":358,"line":1117},32,[356,1119,804],{"class":415},[356,1121,807],{"class":366},[356,1123,1124],{"class":373},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768449382096.webp",[356,1126,535],{"class":366},[356,1128,1130],{"class":358,"line":1129},33,[356,1131,426],{"emptyLinePlaceholder":425},[356,1133,1135,1138,1141,1144,1147,1150],{"class":358,"line":1134},34,[356,1136,1137],{"class":373},"The",[356,1139,1140],{"class":366}," image below shows a successful flash (if you are unable to download normally, please refer to `",[356,1142,1143],{"class":373},"常见问题",[356,1145,1146],{"class":366},"` ",[356,1148,1149],{"class":373},"below",[356,1151,1152],{"class":366},").\n",[356,1154,1156,1158,1160,1163],{"class":358,"line":1155},35,[356,1157,804],{"class":415},[356,1159,807],{"class":366},[356,1161,1162],{"class":373},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768539121456.webp",[356,1164,535],{"class":366},[356,1166,1168],{"class":358,"line":1167},36,[356,1169,426],{"emptyLinePlaceholder":425},[356,1171,1173],{"class":358,"line":1172},37,[356,1174,1175],{"class":409},"#### Debugging\n",[356,1177,1179],{"class":358,"line":1178},38,[356,1180,426],{"emptyLinePlaceholder":425},[356,1182,1184,1187],{"class":358,"line":1183},39,[356,1185,1186],{"class":373},"First,",[356,1188,1189],{"class":366}," write a program.\n",[356,1191,1193],{"class":358,"line":1192},40,[356,1194,426],{"emptyLinePlaceholder":425},[356,1196,1198,1201],{"class":358,"line":1197},41,[356,1199,1200],{"class":366},"```",[356,1202,1203],{"class":373},"c\n",[356,1205,1207,1210],{"class":358,"line":1206},42,[356,1208,1209],{"class":373},"//包含FreeRTOS头文件(为了用vTaskDelay",[356,1211,535],{"class":419},[356,1213,1215],{"class":358,"line":1214},43,[356,1216,1217],{"class":409},"#include \"freertos/FreeRTOS.h\"\n",[356,1219,1221],{"class":358,"line":1220},44,[356,1222,1223],{"class":409},"#include \"freertos/task.h\"\n",[356,1225,1227],{"class":358,"line":1226},45,[356,1228,426],{"emptyLinePlaceholder":425},[356,1230,1232,1235,1238,1241,1244],{"class":358,"line":1231},46,[356,1233,1234],{"class":373},"int32_t",[356,1236,1237],{"class":366}," i",[356,1239,1240],{"class":366}," =",[356,1242,1243],{"class":362}," 0",[356,1245,1246],{"class":419},";\n",[356,1248,1250],{"class":358,"line":1249},47,[356,1251,426],{"emptyLinePlaceholder":425},[356,1253,1255,1257,1259,1261,1263],{"class":358,"line":1254},48,[356,1256,671],{"class":373},[356,1258,674],{"class":366},[356,1260,677],{"class":419},[356,1262,671],{"class":373},[356,1264,535],{"class":419},[356,1266,1268],{"class":358,"line":1267},49,[356,1269,686],{"class":419},[356,1271,1273],{"class":358,"line":1272},50,[356,1274,426],{"emptyLinePlaceholder":425},[356,1276,1278],{"class":358,"line":1277},51,[356,1279,426],{"emptyLinePlaceholder":425},[356,1281,1283,1286,1289,1292],{"class":358,"line":1282},52,[356,1284,1285],{"class":373},"//死循环,等同于while(1",[356,1287,1288],{"class":419},"),但效率比while(",[356,1290,1291],{"class":373},"1",[356,1293,1294],{"class":419},")更高\n",[356,1296,1298,1301],{"class":358,"line":1297},53,[356,1299,1300],{"class":415},"for",[356,1302,1303],{"class":419},"(;;)\n",[356,1305,1307],{"class":358,"line":1306},54,[356,1308,686],{"class":419},[356,1310,1312,1315],{"class":358,"line":1311},55,[356,1313,1314],{"class":373},"    i++",[356,1316,1246],{"class":419},[356,1318,1320,1323,1326,1329,1332],{"class":358,"line":1319},56,[356,1321,1322],{"class":373},"    vTaskDelay(500",[356,1324,1325],{"class":366}," /",[356,1327,1328],{"class":366}," portTICK_PERIOD_MS",[356,1330,1331],{"class":419},");  ",[356,1333,1334],{"class":373},"//延时500ms\n",[356,1336,1338],{"class":358,"line":1337},57,[356,1339,710],{"class":419},[356,1341,1343],{"class":358,"line":1342},58,[356,1344,710],{"class":419},[10,1346,1347,1348],{},"Just click Debug.\n",[39,1349],{"alt":41,"src":1350},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768376418125.webp",[10,1352,1353,1354],{},"This means you've successfully entered debug mode.\n",[39,1355],{"alt":41,"src":1356},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768539536501.webp",[10,1358,1359],{},"The image below,\nThe first one is to start running.\nThe second is step over, running one function at a time.\nThe third one is single-step debugging, which executes by stepping into the function.\nThe fourth one is step out, which will exit this function.\nThe fifth one is the restart program, but there's a bug in the ESP32 where it doesn't seem to restart. Not sure if this will be fixed in a future update.\nThe sixth is to disconnect the link and exit debugging.",[10,1361,1362],{},[39,1363],{"alt":41,"src":1364},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768376495953.webp",[10,1366,1367],{},"You can also set breakpoints, so the program will stop running when it reaches a breakpoint.\nAs shown in the figure",[10,1369,1370],{},[39,1371],{"alt":41,"src":1372},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768539606348.webp",[10,1374,1375,1376,1379],{},"You can also right-click a variable to add it to Watch, set a breakpoint at a certain line in the program, and then check the value of that variable before the program reaches that line (note: the breakpoint is placed at the line where execution has just arrived, meaning that line hasn't run yet).\nAs shown in the figure\nFor example, right-click this ",[33,1377,1378],{},"i",[39,1380],{"alt":41,"src":1381},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768539649374.webp",[10,1383,1384,1385],{},"Click this ",[33,1386,1387],{},"添加到监视(Add to Watch)",[10,1389,1390],{},[39,1391],{"alt":41,"src":1392},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768539673552.webp",[10,1394,1395,1396,1399,1400,1402],{},"Every time you ",[33,1397,1398],{},"开始运行(F5)"," to a breakpoint, this ",[33,1401,1378],{}," increments by 1.",[10,1404,1405],{},[39,1406],{"alt":41,"src":1407},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768539891853.webp",[1409,1410,1412],"h5",{"id":1411},"frequently-asked-questions","Frequently Asked Questions",[99,1414,1415],{},[102,1416,1417],{},"If you are using Linux and encounter the following issue",[347,1419,1421],{"className":349,"code":1420,"language":351,"meta":352,"style":352},"Open On-Chip Debugger v0.12.0-esp32-20250707 (2025-07-06-17:37) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html [OpenOCD] Open On-Chip Debugger v0.12.0-esp32-20250707 (2025-07-06-17:37) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html debug_level: 2 Info : esp_usb_jtag: VID set to 0x303a and PID to 0x1001 Info : esp_usb_jtag: capabilities descriptor set to 0x2000 Info : Listening on port 6666 for tcl connections Info : Listening on port 4444 for telnet connections ❌ Error: libusb_open() failed with LIBUSB_ERROR_ACCESS Error: libusb_open() failed with LIBUSB_ERROR_ACCESS ❌ Error: esp_usb_jtag: could not find or open device! /home/tungchiahui/.espressif/tools/openocd-esp32/v0.12.0-esp32-20250707/openocd-esp32/share/openocd/scripts/target/esp_common.cfg:9: Error: Traceback (most recent call last): File \"/home/tungchiahui/.espressif/tools/openocd-esp32/v0.12.0-esp32-20250707/openocd-esp32/share/openocd/scripts/target/esp_common.cfg\", line 9, in script Error: esp_usb_jtag: could not find or open device! /home/tungchiahui/.espressif/tools/openocd-esp32/v0.12.0-esp32-20250707/openocd-esp32/share/openocd/scripts/target/esp_common.cfg:9: Error: Traceback (most recent call last): File \"/home/tungchiahui/.espressif/tools/openocd-esp32/v0.12.0-esp32-20250707/openocd-esp32/share/openocd/scripts/target/esp_common.cfg\", line 9, in script For assistance with OpenOCD errors, please refer to our Troubleshooting FAQ: https://github.com/espressif/openocd-esp32/wiki/Troubleshooting-FAQ OpenOCD Exit with non-zero error code 1 [Stopped] : OpenOCD Server [/OpenOCD] [Flash] Can't perform JTAG flash, because OpenOCD server is not running! Flash has finished. You can monitor your device with 'ESP-IDF: Monitor command'然后tungchiahui@Dell-G15-5511:~/UserFolder/MySource/ESP32_Projects/N01_LED$ ls /dev | grep ACM ttyACM0 tungchiahui@Dell-G15-5511:~/UserFolder/MySource/ESP32_Projects/N01_LED$ lsusb Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 003 Device 002: ID 0416:b23c Winbond Electronics Corp. Gaming Keyboard Bus 003 Device 003: ID 046d:c539 Logitech, Inc. Lightspeed Receiver Bus 003 Device 004: ID 0c45:6720 Microdia Integrated_Webcam_HD Bus 003 Device 005: ID 8087:0026 Intel Corp. AX201 Bluetooth Bus 003 Device 006: ID 303a:1001 Espressif USB JTAG/serial debug unit Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub tungchiahui@Dell-G15-5511:~/UserFolder/MySource/ESP32_Projects/N01_LED\n",[33,1422,1423],{"__ignoreMap":352},[356,1424,1425,1428,1431,1434,1437,1440,1443,1446,1449,1452,1454,1457,1459,1462,1464,1467,1469,1472,1475,1478,1480,1483,1486,1489,1492,1495,1498,1501,1504,1506,1508,1510,1512,1514,1516,1518,1520,1523,1525,1528,1530,1533,1536,1539],{"class":358,"line":359},[356,1426,1427],{"class":373},"Open",[356,1429,1430],{"class":366}," On-Chip",[356,1432,1433],{"class":366}," Debugger",[356,1435,1436],{"class":366}," v0.12.0-esp32-20250707",[356,1438,1439],{"class":419}," (2025-07-06-17:37) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html [OpenOCD] Open On-Chip Debugger v0.12.0-esp32-20250707 (",[356,1441,1442],{"class":373},"2025-07-06-17:37",[356,1444,1445],{"class":419},") Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html debug_level: 2 Info ",[356,1447,1448],{"class":362},":",[356,1450,1451],{"class":419}," esp_usb_jtag: VID set to 0x303a and PID to 0x1001 Info ",[356,1453,1448],{"class":362},[356,1455,1456],{"class":419}," esp_usb_jtag: capabilities descriptor set to 0x2000 Info ",[356,1458,1448],{"class":362},[356,1460,1461],{"class":419}," Listening on port 6666 ",[356,1463,1300],{"class":415},[356,1465,1466],{"class":419}," tcl connections Info ",[356,1468,1448],{"class":362},[356,1470,1471],{"class":419}," Listening on port ",[356,1473,1474],{"class":362},"4444",[356,1476,1477],{"class":419}," for telnet connections ❌ Error: libusb_open() failed with LIBUSB_ERROR_ACCESS Error: libusb_open() failed with LIBUSB_ERROR_ACCESS ❌ Error: esp_usb_jtag: could not find or open device",[356,1479,804],{"class":415},[356,1481,1482],{"class":419}," /home/tungchiahui/.espressif/tools/openocd-esp32/v0.12.0-esp32-20250707/openocd-esp32/share/openocd/scripts/target/esp_common.cfg:9: Error: Traceback (",[356,1484,1485],{"class":373},"most",[356,1487,1488],{"class":366}," recent",[356,1490,1491],{"class":366}," call",[356,1493,1494],{"class":366}," last",[356,1496,1497],{"class":419},"): File ",[356,1499,1500],{"class":366},"\"/home/tungchiahui/.espressif/tools/openocd-esp32/v0.12.0-esp32-20250707/openocd-esp32/share/openocd/scripts/target/esp_common.cfg\"",[356,1502,1503],{"class":419},", line 9, in script Error: esp_usb_jtag: could not find or open device",[356,1505,804],{"class":415},[356,1507,1482],{"class":419},[356,1509,1485],{"class":373},[356,1511,1488],{"class":366},[356,1513,1491],{"class":366},[356,1515,1494],{"class":366},[356,1517,1497],{"class":419},[356,1519,1500],{"class":366},[356,1521,1522],{"class":419},", line 9, in script For assistance with OpenOCD errors, please refer to our Troubleshooting FAQ: https://github.com/espressif/openocd-esp32/wiki/Troubleshooting-FAQ OpenOCD Exit with non-zero error code ",[356,1524,1291],{"class":362},[356,1526,1527],{"class":419}," [Stopped] ",[356,1529,1448],{"class":362},[356,1531,1532],{"class":419}," OpenOCD Server [/OpenOCD] [Flash] Can",[356,1534,1535],{"class":366},"'t perform JTAG flash, because OpenOCD server is not running! Flash has finished. You can monitor your device with '",[356,1537,1538],{"class":419},"ESP-IDF: Monitor command",[356,1540,1541],{"class":366},"'然后tungchiahui@Dell-G15-5511:~/UserFolder/MySource/ESP32_Projects/N01_LED$ ls /dev | grep ACM ttyACM0 tungchiahui@Dell-G15-5511:~/UserFolder/MySource/ESP32_Projects/N01_LED$ lsusb Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 003 Device 002: ID 0416:b23c Winbond Electronics Corp. Gaming Keyboard Bus 003 Device 003: ID 046d:c539 Logitech, Inc. Lightspeed Receiver Bus 003 Device 004: ID 0c45:6720 Microdia Integrated_Webcam_HD Bus 003 Device 005: ID 8087:0026 Intel Corp. AX201 Bluetooth Bus 003 Device 006: ID 303a:1001 Espressif USB JTAG/serial debug unit Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub tungchiahui@Dell-G15-5511:~/UserFolder/MySource/ESP32_Projects/N01_LED\n",[10,1543,1544],{},"Most likely it's a permission issue.",[347,1546,1548],{"className":349,"code":1547,"language":351,"meta":352,"style":352},"lsusb\n",[33,1549,1550],{"__ignoreMap":352},[356,1551,1552],{"class":358,"line":359},[356,1553,1547],{"class":373},[10,1555,1556],{},[39,1557],{"alt":41,"src":1558},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768538777147.webp",[10,1560,1561,1562,1565,1566,155],{},"Find the device that follows ",[33,1563,1564],{},"1001",", and remember the device ID before it. For example, mine is ",[33,1567,1568],{},"303a",[10,1570,1571,1572,155],{},"Next, edit ",[33,1573,1574],{},"udev",[347,1576,1578],{"className":349,"code":1577,"language":351,"meta":352,"style":352},"sudo vim /etc/udev/rules.d/99-esp32-usb-jtag.rules\n",[33,1579,1580],{"__ignoreMap":352},[356,1581,1582,1585,1588],{"class":358,"line":359},[356,1583,1584],{"class":373},"sudo",[356,1586,1587],{"class":366}," vim",[356,1589,1590],{"class":366}," /etc/udev/rules.d/99-esp32-usb-jtag.rules\n",[10,1592,1593,1594,1597],{},"Please provide the content you'd like me to translate, and I'll fill in the ",[33,1595,1596],{},"idVendor"," placeholder as needed.",[347,1599,1601],{"className":349,"code":1600,"language":351,"meta":352,"style":352},"SUBSYSTEM==\"usb\", ATTR{idVendor}==\"303a\", MODE=\"0666\"\n",[33,1602,1603],{"__ignoreMap":352},[356,1604,1605,1608,1611,1614,1617,1620,1623,1625],{"class":358,"line":359},[356,1606,1607],{"class":419},"SUBSYSTEM",[356,1609,1610],{"class":415},"=",[356,1612,1613],{"class":366},"=\"usb\",",[356,1615,1616],{"class":373}," ATTR",[356,1618,1619],{"class":366},"{idVendor}==",[356,1621,1622],{"class":373},"\"303a\"",[356,1624,868],{"class":373},[356,1626,1627],{"class":366}," MODE=\"0666\"\n",[10,1629,1630],{},"After saving, first type the following command",[347,1632,1634],{"className":349,"code":1633,"language":351,"meta":352,"style":352},"sudo udevadm control --reload-rules\nsudo udevadm trigger\n",[33,1635,1636,1649],{"__ignoreMap":352},[356,1637,1638,1640,1643,1646],{"class":358,"line":359},[356,1639,1584],{"class":373},[356,1641,1642],{"class":366}," udevadm",[356,1644,1645],{"class":366}," control",[356,1647,1648],{"class":362}," --reload-rules\n",[356,1650,1651,1653,1655],{"class":358,"line":370},[356,1652,1584],{"class":373},[356,1654,1642],{"class":366},[356,1656,1657],{"class":366}," trigger\n",[10,1659,1660],{},"Then plug and unplug the USB, and the programming will succeed.",[20,1662,1664],{"id":1663},"the-clock-tree-of-the-esp32-s3","The clock tree of the ESP32-S3",[25,1666,1667],{"id":1667},"clock",[10,1669,1670,1671],{},"A clock is a signal that toggles periodically.\n",[39,1672],{"alt":41,"src":1673},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768377363665.webp",[10,1675,1676],{},"Each time a clock edge arrives, the entire circuit undergoes a complete state update.\nThis way, the entire system will move forward one step.",[25,1678,1680],{"id":1679},"clock-tree","Clock tree",[10,1682,1683],{},[39,1684],{"alt":41,"src":1685},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768377731446.webp",[10,1687,1688],{},[39,1689],{"alt":41,"src":1690},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768377775953.webp",[10,1692,1693],{},"OSC is a high-speed crystal oscillator, CLK is the clock, PLL is a phase-locked loop, DIV in the diagram is a frequency divider, and MUX is a multiplexer.\nThe OSC needs to be connected to a crystal oscillator.\nCLK is an available clock signal.\nPLL is used for the clock frequency that is to be multiplied or divided.\nTo save power and conserve resources.\nMUX selects which clock source.",[10,1695,1696],{},[39,1697],{"alt":41,"src":1698},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768378403104.webp",[10,1700,1701],{},[39,1702],{"alt":41,"src":1703},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768378429705.webp",[20,1705,1707],{"id":1706},"gpio","GPIO",[25,1709,1711],{"id":1710},"gpio-theory","GPIO Theory",[10,1713,1714],{},"Actually, it refers to General Purpose Input/Output ports, which can output high or low levels and also read high or low levels.",[10,1716,1717],{},"The input principle is as shown in the figure below: if pressing KEY causes the circuit level to go low, a pull-up resistor is needed, and the falling edge is used to determine whether the button is pressed.\nDue to the pull-up resistor, when the KEY is not pressed, the IO port in the lower circuit is at a high level. Once the KEY is pressed, it becomes low, creating a falling edge (the level transitions from high to low).",[10,1719,1720],{},[39,1721],{"alt":41,"src":1722},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768390289518.webp",[10,1724,1725],{},"Output, as shown in the figure below: when the IO is at a high level, the LED (light-emitting diode) conducts and turns on; when the IO is at a low level, the LED does not conduct and turns off.",[10,1727,1728],{},[39,1729],{"alt":41,"src":1730},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768390481849.webp",[10,1732,1733],{},"Here is the ESP32's IO:",[10,1735,1736],{},[39,1737],{"alt":41,"src":1738},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768391351684.webp",[10,1740,1741],{},"They are highly reusable, and each one can be reused as an interface for other peripherals.",[10,1743,1744,1745,1748],{},"But there are some exceptions: certain pins cannot be used as inputs or outputs — they can only be used to connect to the FLASH or PSRAM on the module.\nYou can refer to the detailed explanation in the ",[33,1746,1747],{},"esp32-s3_datasheet_cn.pdf"," from Zhengdian Atom.",[25,1750,1752],{"id":1751},"gpio-related-functions","GPIO-related functions",[99,1754,1755],{},[102,1756,1757],{},[16,1758,1759],{},"gpio_config",[10,1761,1762],{},"This is the GPIO initialization function.",[347,1764,1766],{"className":650,"code":1765,"language":652,"meta":352,"style":352},"esp_err_t gpio_config(const gpio_config_t *pGPIOConfig)\n",[33,1767,1768],{"__ignoreMap":352},[356,1769,1770,1773,1776,1778,1781,1784,1787,1791],{"class":358,"line":359},[356,1771,1772],{"class":362},"esp_err_t",[356,1774,1775],{"class":373}," gpio_config",[356,1777,677],{"class":419},[356,1779,1780],{"class":415},"const",[356,1782,1783],{"class":362}," gpio_config_t",[356,1785,1786],{"class":415}," *",[356,1788,1790],{"class":1789},"s4XuR","pGPIOConfig",[356,1792,535],{"class":419},[10,1794,1795,1796,1799,1800,1803],{},"Then right-click to select ",[33,1797,1798],{},"gpio_config_t",", click ",[33,1801,1802],{},"go to definition",", and the following struct will appear — this is the entry parameter struct inside the GPIO initialization function.",[347,1805,1807],{"className":650,"code":1806,"language":652,"meta":352,"style":352},"/**\n * @brief Configuration parameters of GPIO pad for gpio_config function\n */\ntypedef struct {\n    uint64_t pin_bit_mask;          /*!\u003C GPIO pin: set with bit mask, each bit maps to a GPIO */\n    gpio_mode_t mode;               /*!\u003C GPIO mode: set input/output mode                     */\n    gpio_pullup_t pull_up_en;       /*!\u003C GPIO pull-up                                         */\n    gpio_pulldown_t pull_down_en;   /*!\u003C GPIO pull-down                                       */\n    gpio_int_type_t intr_type;      /*!\u003C GPIO interrupt type                                  */\n#if SOC_GPIO_SUPPORT_PIN_HYS_FILTER\n    gpio_hys_ctrl_mode_t hys_ctrl_mode;       /*!\u003C GPIO hysteresis: hysteresis filter on slope input    */\n#endif\n} gpio_config_t;\n",[33,1808,1809,1814,1825,1830,1841,1852,1863,1874,1885,1896,1904,1915,1920],{"__ignoreMap":352},[356,1810,1811],{"class":358,"line":359},[356,1812,1813],{"class":409},"/**\n",[356,1815,1816,1819,1822],{"class":358,"line":370},[356,1817,1818],{"class":409}," * ",[356,1820,1821],{"class":415},"@brief",[356,1823,1824],{"class":409}," Configuration parameters of GPIO pad for gpio_config function\n",[356,1826,1827],{"class":358,"line":173},[356,1828,1829],{"class":409}," */\n",[356,1831,1832,1835,1838],{"class":358,"line":197},[356,1833,1834],{"class":415},"typedef",[356,1836,1837],{"class":415}," struct",[356,1839,1840],{"class":419}," {\n",[356,1842,1843,1846,1849],{"class":358,"line":434},[356,1844,1845],{"class":415},"    uint64_t",[356,1847,1848],{"class":419}," pin_bit_mask;",[356,1850,1851],{"class":409},"          /*!\u003C GPIO pin: set with bit mask, each bit maps to a GPIO */\n",[356,1853,1854,1857,1860],{"class":358,"line":230},[356,1855,1856],{"class":362},"    gpio_mode_t",[356,1858,1859],{"class":419}," mode;",[356,1861,1862],{"class":409},"               /*!\u003C GPIO mode: set input/output mode                     */\n",[356,1864,1865,1868,1871],{"class":358,"line":260},[356,1866,1867],{"class":362},"    gpio_pullup_t",[356,1869,1870],{"class":419}," pull_up_en;",[356,1872,1873],{"class":409},"       /*!\u003C GPIO pull-up                                         */\n",[356,1875,1876,1879,1882],{"class":358,"line":492},[356,1877,1878],{"class":362},"    gpio_pulldown_t",[356,1880,1881],{"class":419}," pull_down_en;",[356,1883,1884],{"class":409},"   /*!\u003C GPIO pull-down                                       */\n",[356,1886,1887,1890,1893],{"class":358,"line":500},[356,1888,1889],{"class":362},"    gpio_int_type_t",[356,1891,1892],{"class":419}," intr_type;",[356,1894,1895],{"class":409},"      /*!\u003C GPIO interrupt type                                  */\n",[356,1897,1898,1901],{"class":358,"line":506},[356,1899,1900],{"class":415},"#if",[356,1902,1903],{"class":373}," SOC_GPIO_SUPPORT_PIN_HYS_FILTER\n",[356,1905,1906,1909,1912],{"class":358,"line":511},[356,1907,1908],{"class":362},"    gpio_hys_ctrl_mode_t",[356,1910,1911],{"class":419}," hys_ctrl_mode;",[356,1913,1914],{"class":409},"       /*!\u003C GPIO hysteresis: hysteresis filter on slope input    */\n",[356,1916,1917],{"class":358,"line":520},[356,1918,1919],{"class":415},"#endif\n",[356,1921,1922,1925,1927],{"class":358,"line":538},[356,1923,1924],{"class":419},"} ",[356,1926,1798],{"class":362},[356,1928,1246],{"class":419},[10,1930,1931,1934,1935,1938,1939,1942,1943,1946,1947],{},[33,1932,1933],{},"pin_bit_mask"," is used to set the GPIO pin you want to configure, typically ",[33,1936,1937],{},"1ull \u003C\u003C x",". Here, ",[33,1940,1941],{},"x"," is the ",[33,1944,1945],{},"IOx"," number of the GPIO you want to set.",[735,1948],{},[10,1950,1951,1954,1955,1957,1958,155,1961],{},[33,1952,1953],{},"mode"," is the mode for configuring input or output. You can check ",[33,1956,1802],{}," by looking at ",[33,1959,1960],{},"gpio_mode_t",[735,1962],{},[347,1964,1966],{"className":650,"code":1965,"language":652,"meta":352,"style":352},"typedef enum {\n    GPIO_MODE_DISABLE = GPIO_MODE_DEF_DISABLE,                                                         /*!\u003C GPIO mode : disable input and output             */\n    GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT,                                                             /*!\u003C GPIO mode : input only                           */\n    GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT,                                                           /*!\u003C GPIO mode : output only mode                     */\n    GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)),                               /*!\u003C GPIO mode : output only with open-drain mode     */\n    GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT) | (GPIO_MODE_DEF_OD)), /*!\u003C GPIO mode : output and input with open-drain mode*/\n    GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT) | (GPIO_MODE_DEF_OUTPUT)),                         /*!\u003C GPIO mode : output and input mode                */\n} gpio_mode_t;\n",[33,1967,1968,1977,1990,2003,2016,2035,2057,2074],{"__ignoreMap":352},[356,1969,1970,1972,1975],{"class":358,"line":359},[356,1971,1834],{"class":415},[356,1973,1974],{"class":415}," enum",[356,1976,1840],{"class":419},[356,1978,1979,1982,1984,1987],{"class":358,"line":370},[356,1980,1981],{"class":419},"    GPIO_MODE_DISABLE ",[356,1983,1610],{"class":415},[356,1985,1986],{"class":419}," GPIO_MODE_DEF_DISABLE,",[356,1988,1989],{"class":409},"                                                         /*!\u003C GPIO mode : disable input and output             */\n",[356,1991,1992,1995,1997,2000],{"class":358,"line":173},[356,1993,1994],{"class":419},"    GPIO_MODE_INPUT ",[356,1996,1610],{"class":415},[356,1998,1999],{"class":419}," GPIO_MODE_DEF_INPUT,",[356,2001,2002],{"class":409},"                                                             /*!\u003C GPIO mode : input only                           */\n",[356,2004,2005,2008,2010,2013],{"class":358,"line":197},[356,2006,2007],{"class":419},"    GPIO_MODE_OUTPUT ",[356,2009,1610],{"class":415},[356,2011,2012],{"class":419}," GPIO_MODE_DEF_OUTPUT,",[356,2014,2015],{"class":409},"                                                           /*!\u003C GPIO mode : output only mode                     */\n",[356,2017,2018,2021,2023,2026,2029,2032],{"class":358,"line":434},[356,2019,2020],{"class":419},"    GPIO_MODE_OUTPUT_OD ",[356,2022,1610],{"class":415},[356,2024,2025],{"class":419}," ((GPIO_MODE_DEF_OUTPUT) ",[356,2027,2028],{"class":415},"|",[356,2030,2031],{"class":419}," (GPIO_MODE_DEF_OD)),",[356,2033,2034],{"class":409},"                               /*!\u003C GPIO mode : output only with open-drain mode     */\n",[356,2036,2037,2040,2042,2045,2047,2050,2052,2054],{"class":358,"line":230},[356,2038,2039],{"class":419},"    GPIO_MODE_INPUT_OUTPUT_OD ",[356,2041,1610],{"class":415},[356,2043,2044],{"class":419}," ((GPIO_MODE_DEF_INPUT) ",[356,2046,2028],{"class":415},[356,2048,2049],{"class":419}," (GPIO_MODE_DEF_OUTPUT) ",[356,2051,2028],{"class":415},[356,2053,2031],{"class":419},[356,2055,2056],{"class":409}," /*!\u003C GPIO mode : output and input with open-drain mode*/\n",[356,2058,2059,2062,2064,2066,2068,2071],{"class":358,"line":260},[356,2060,2061],{"class":419},"    GPIO_MODE_INPUT_OUTPUT ",[356,2063,1610],{"class":415},[356,2065,2044],{"class":419},[356,2067,2028],{"class":415},[356,2069,2070],{"class":419}," (GPIO_MODE_DEF_OUTPUT)),",[356,2072,2073],{"class":409},"                         /*!\u003C GPIO mode : output and input mode                */\n",[356,2075,2076,2078,2080],{"class":358,"line":492},[356,2077,1924],{"class":419},[356,2079,1960],{"class":362},[356,2081,1246],{"class":419},[10,2083,2084,2085,2087],{},"The same goes for the rest — you can all ",[33,2086,1802],{}," to see what this struct can actually hold.",[10,2089,2090,2093,2094,2097],{},[33,2091,2092],{},"pull_up_en"," indicates whether to enable the pull-up resistor, meaning it adds a circuit in parallel to the IO line that has a resistor connected to VCC.\n",[33,2095,2096],{},"pull_down_en"," is whether to enable the pull-down resistor, meaning it adds a circuit in parallel to the IO line that has a resistor and GND.",[10,2099,2100,2103,2104],{},[33,2101,2102],{},"intr_type"," is whether to enable the interrupt type.",[735,2105],{},[99,2107,2108],{"start":370},[102,2109,2110],{},[16,2111,2112],{},"gpio_set_level",[347,2114,2116],{"className":650,"code":2115,"language":652,"meta":352,"style":352},"esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)\n{\n    GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), \"GPIO output gpio_num error\", ESP_ERR_INVALID_ARG);\n    gpio_hal_set_level(gpio_context.gpio_hal, gpio_num, level);\n    return ESP_OK;\n}\n",[33,2117,2118,2144,2148,2167,2175,2183],{"__ignoreMap":352},[356,2119,2120,2122,2125,2127,2130,2133,2136,2139,2142],{"class":358,"line":359},[356,2121,1772],{"class":362},[356,2123,2124],{"class":373}," gpio_set_level",[356,2126,677],{"class":419},[356,2128,2129],{"class":362},"gpio_num_t",[356,2131,2132],{"class":1789}," gpio_num",[356,2134,2135],{"class":419},", ",[356,2137,2138],{"class":415},"uint32_t",[356,2140,2141],{"class":1789}," level",[356,2143,535],{"class":419},[356,2145,2146],{"class":358,"line":370},[356,2147,686],{"class":419},[356,2149,2150,2153,2155,2158,2161,2164],{"class":358,"line":173},[356,2151,2152],{"class":373},"    GPIO_CHECK",[356,2154,677],{"class":419},[356,2156,2157],{"class":373},"GPIO_IS_VALID_OUTPUT_GPIO",[356,2159,2160],{"class":419},"(gpio_num), ",[356,2162,2163],{"class":366},"\"GPIO output gpio_num error\"",[356,2165,2166],{"class":419},", ESP_ERR_INVALID_ARG);\n",[356,2168,2169,2172],{"class":358,"line":197},[356,2170,2171],{"class":373},"    gpio_hal_set_level",[356,2173,2174],{"class":419},"(gpio_context.gpio_hal, gpio_num, level);\n",[356,2176,2177,2180],{"class":358,"line":434},[356,2178,2179],{"class":415},"    return",[356,2181,2182],{"class":419}," ESP_OK;\n",[356,2184,2185],{"class":358,"line":230},[356,2186,710],{"class":419},[10,2188,2189,2192,2193,2195,2196,1938,2199,2201,2202,2204,2205],{},[33,2190,2191],{},"gpio_num"," is which IO port to select. You can take a look at ",[33,2194,1802],{},". As shown in the code below, it can be filled with ",[33,2197,2198],{},"GPIO_NUM_x",[33,2200,1941],{}," is used to select which ",[33,2203,1945],{}," to initialize (i.e., which pin/IO to initialize).",[735,2206],{},[10,2208,2209,2212],{},[33,2210,2211],{},"level"," determines whether the output level is high or low; fill in 0 for low and 1 for high.",[347,2214,2216],{"className":650,"code":2215,"language":652,"meta":352,"style":352},"/**\n * @brief GPIO number\n */\ntypedef enum {\n    GPIO_NUM_NC = -1,    /*!\u003C Use to signal not connected to S/W */\n    GPIO_NUM_0 = 0,     /*!\u003C GPIO0, input and output */\n    GPIO_NUM_1 = 1,     /*!\u003C GPIO1, input and output */\n    GPIO_NUM_2 = 2,     /*!\u003C GPIO2, input and output */\n    GPIO_NUM_3 = 3,     /*!\u003C GPIO3, input and output */\n    GPIO_NUM_4 = 4,     /*!\u003C GPIO4, input and output */\n    GPIO_NUM_5 = 5,     /*!\u003C GPIO5, input and output */\n    GPIO_NUM_6 = 6,     /*!\u003C GPIO6, input and output */\n    GPIO_NUM_7 = 7,     /*!\u003C GPIO7, input and output */\n    GPIO_NUM_8 = 8,     /*!\u003C GPIO8, input and output */\n    GPIO_NUM_9 = 9,     /*!\u003C GPIO9, input and output */\n    GPIO_NUM_10 = 10,   /*!\u003C GPIO10, input and output */\n    GPIO_NUM_11 = 11,   /*!\u003C GPIO11, input and output */\n    GPIO_NUM_12 = 12,   /*!\u003C GPIO12, input and output */\n    GPIO_NUM_MAX,\n} gpio_num_t;\n",[33,2217,2218,2222,2231,2235,2243,2260,2274,2289,2304,2319,2334,2349,2364,2379,2394,2409,2424,2439,2454,2459],{"__ignoreMap":352},[356,2219,2220],{"class":358,"line":359},[356,2221,1813],{"class":409},[356,2223,2224,2226,2228],{"class":358,"line":370},[356,2225,1818],{"class":409},[356,2227,1821],{"class":415},[356,2229,2230],{"class":409}," GPIO number\n",[356,2232,2233],{"class":358,"line":173},[356,2234,1829],{"class":409},[356,2236,2237,2239,2241],{"class":358,"line":197},[356,2238,1834],{"class":415},[356,2240,1974],{"class":415},[356,2242,1840],{"class":419},[356,2244,2245,2248,2250,2253,2255,2257],{"class":358,"line":434},[356,2246,2247],{"class":419},"    GPIO_NUM_NC ",[356,2249,1610],{"class":415},[356,2251,2252],{"class":415}," -",[356,2254,1291],{"class":362},[356,2256,868],{"class":419},[356,2258,2259],{"class":409},"    /*!\u003C Use to signal not connected to S/W */\n",[356,2261,2262,2265,2267,2269,2271],{"class":358,"line":230},[356,2263,2264],{"class":419},"    GPIO_NUM_0 ",[356,2266,1610],{"class":415},[356,2268,1243],{"class":362},[356,2270,868],{"class":419},[356,2272,2273],{"class":409},"     /*!\u003C GPIO0, input and output */\n",[356,2275,2276,2279,2281,2284,2286],{"class":358,"line":260},[356,2277,2278],{"class":419},"    GPIO_NUM_1 ",[356,2280,1610],{"class":415},[356,2282,2283],{"class":362}," 1",[356,2285,868],{"class":419},[356,2287,2288],{"class":409},"     /*!\u003C GPIO1, input and output */\n",[356,2290,2291,2294,2296,2299,2301],{"class":358,"line":492},[356,2292,2293],{"class":419},"    GPIO_NUM_2 ",[356,2295,1610],{"class":415},[356,2297,2298],{"class":362}," 2",[356,2300,868],{"class":419},[356,2302,2303],{"class":409},"     /*!\u003C GPIO2, input and output */\n",[356,2305,2306,2309,2311,2314,2316],{"class":358,"line":500},[356,2307,2308],{"class":419},"    GPIO_NUM_3 ",[356,2310,1610],{"class":415},[356,2312,2313],{"class":362}," 3",[356,2315,868],{"class":419},[356,2317,2318],{"class":409},"     /*!\u003C GPIO3, input and output */\n",[356,2320,2321,2324,2326,2329,2331],{"class":358,"line":506},[356,2322,2323],{"class":419},"    GPIO_NUM_4 ",[356,2325,1610],{"class":415},[356,2327,2328],{"class":362}," 4",[356,2330,868],{"class":419},[356,2332,2333],{"class":409},"     /*!\u003C GPIO4, input and output */\n",[356,2335,2336,2339,2341,2344,2346],{"class":358,"line":511},[356,2337,2338],{"class":419},"    GPIO_NUM_5 ",[356,2340,1610],{"class":415},[356,2342,2343],{"class":362}," 5",[356,2345,868],{"class":419},[356,2347,2348],{"class":409},"     /*!\u003C GPIO5, input and output */\n",[356,2350,2351,2354,2356,2359,2361],{"class":358,"line":520},[356,2352,2353],{"class":419},"    GPIO_NUM_6 ",[356,2355,1610],{"class":415},[356,2357,2358],{"class":362}," 6",[356,2360,868],{"class":419},[356,2362,2363],{"class":409},"     /*!\u003C GPIO6, input and output */\n",[356,2365,2366,2369,2371,2374,2376],{"class":358,"line":538},[356,2367,2368],{"class":419},"    GPIO_NUM_7 ",[356,2370,1610],{"class":415},[356,2372,2373],{"class":362}," 7",[356,2375,868],{"class":419},[356,2377,2378],{"class":409},"     /*!\u003C GPIO7, input and output */\n",[356,2380,2381,2384,2386,2389,2391],{"class":358,"line":543},[356,2382,2383],{"class":419},"    GPIO_NUM_8 ",[356,2385,1610],{"class":415},[356,2387,2388],{"class":362}," 8",[356,2390,868],{"class":419},[356,2392,2393],{"class":409},"     /*!\u003C GPIO8, input and output */\n",[356,2395,2396,2399,2401,2404,2406],{"class":358,"line":940},[356,2397,2398],{"class":419},"    GPIO_NUM_9 ",[356,2400,1610],{"class":415},[356,2402,2403],{"class":362}," 9",[356,2405,868],{"class":419},[356,2407,2408],{"class":409},"     /*!\u003C GPIO9, input and output */\n",[356,2410,2411,2414,2416,2419,2421],{"class":358,"line":949},[356,2412,2413],{"class":419},"    GPIO_NUM_10 ",[356,2415,1610],{"class":415},[356,2417,2418],{"class":362}," 10",[356,2420,868],{"class":419},[356,2422,2423],{"class":409},"   /*!\u003C GPIO10, input and output */\n",[356,2425,2426,2429,2431,2434,2436],{"class":358,"line":954},[356,2427,2428],{"class":419},"    GPIO_NUM_11 ",[356,2430,1610],{"class":415},[356,2432,2433],{"class":362}," 11",[356,2435,868],{"class":419},[356,2437,2438],{"class":409},"   /*!\u003C GPIO11, input and output */\n",[356,2440,2441,2444,2446,2449,2451],{"class":358,"line":966},[356,2442,2443],{"class":419},"    GPIO_NUM_12 ",[356,2445,1610],{"class":415},[356,2447,2448],{"class":362}," 12",[356,2450,868],{"class":419},[356,2452,2453],{"class":409},"   /*!\u003C GPIO12, input and output */\n",[356,2455,2456],{"class":358,"line":971},[356,2457,2458],{"class":419},"    GPIO_NUM_MAX,\n",[356,2460,2461,2463,2465],{"class":358,"line":976},[356,2462,1924],{"class":419},[356,2464,2129],{"class":362},[356,2466,1246],{"class":419},[99,2468,2469],{"start":173},[102,2470,2471],{},[16,2472,2473],{},"gpio_get_level",[347,2475,2477],{"className":650,"code":2476,"language":652,"meta":352,"style":352},"int gpio_get_level(gpio_num_t gpio_num)\n{\n    return gpio_hal_get_level(gpio_context.gpio_hal, gpio_num);\n}\n",[33,2478,2479,2495,2499,2509],{"__ignoreMap":352},[356,2480,2481,2484,2487,2489,2491,2493],{"class":358,"line":359},[356,2482,2483],{"class":415},"int",[356,2485,2486],{"class":373}," gpio_get_level",[356,2488,677],{"class":419},[356,2490,2129],{"class":362},[356,2492,2132],{"class":1789},[356,2494,535],{"class":419},[356,2496,2497],{"class":358,"line":370},[356,2498,686],{"class":419},[356,2500,2501,2503,2506],{"class":358,"line":173},[356,2502,2179],{"class":415},[356,2504,2505],{"class":373}," gpio_hal_get_level",[356,2507,2508],{"class":419},"(gpio_context.gpio_hal, gpio_num);\n",[356,2510,2511],{"class":358,"line":197},[356,2512,710],{"class":419},[10,2514,2515,2192,2517,2195,2519,1938,2521,2201,2523,2204,2525],{},[33,2516,2191],{},[33,2518,1802],{},[33,2520,2198],{},[33,2522,1941],{},[33,2524,1945],{},[735,2526],{},[10,2528,2529],{},"The returned int data indicates whether the read level is high or low: 0 means low, 1 means high.",[25,2531,2533],{"id":2532},"led-light-practical","LED light practical",[10,2535,2536,2537,2540,2541],{},"Two types of physical LEDs:\n",[39,2538],{"alt":41,"src":2539},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768393817874.webp","\nSMD LED\n",[39,2542],{"alt":41,"src":2543},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768393873412.webp",[10,2545,2546,2547,2550,2551,2554],{},"In the circuit below, the LED only lights up when the IO port is at a high level.\n",[39,2548],{"alt":41,"src":2549},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768394340551.webp","\nIn the circuit below, the LED only lights up when the IO port is at a low level.\n",[39,2552],{"alt":41,"src":2553},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768394377192.webp","\nThe two drawbacks above are that the current flows directly through the MCU. There is another method using a transistor that is better—you can search for it yourself, or take a look at the schematic of the DJI STM32C board (STM32F407IGH6).",[10,2556,2557,2558,2561],{},"Let's start by writing the code for ",[33,2559,2560],{},"led.h",". This is the minimal framework. You should have learned about conditional compilation in C — it's used to prevent the header file from being included multiple times.",[347,2563,2565],{"className":650,"code":2564,"language":652,"meta":352,"style":352},"#ifndef __LED_H_\n#define __LED_H_\n\n\n\n#endif\n",[33,2566,2567,2575,2582,2586,2590,2594],{"__ignoreMap":352},[356,2568,2569,2572],{"class":358,"line":359},[356,2570,2571],{"class":415},"#ifndef",[356,2573,2574],{"class":373}," __LED_H_\n",[356,2576,2577,2580],{"class":358,"line":370},[356,2578,2579],{"class":415},"#define",[356,2581,2574],{"class":373},[356,2583,2584],{"class":358,"line":173},[356,2585,426],{"emptyLinePlaceholder":425},[356,2587,2588],{"class":358,"line":197},[356,2589,426],{"emptyLinePlaceholder":425},[356,2591,2592],{"class":358,"line":434},[356,2593,426],{"emptyLinePlaceholder":425},[356,2595,2596],{"class":358,"line":230},[356,2597,1919],{"class":415},[10,2599,2600,2601,2603,2604,2607,2608,2611],{},"Next, continue to improve ",[33,2602,2560],{},". The following enum is designed to make the code more readable by giving names to high and low logic levels. ",[33,2605,2606],{},"PIN_RESET"," represents a low level, and ",[33,2609,2610],{},"PIN_SET"," represents a high level.",[347,2613,2615],{"className":650,"code":2614,"language":652,"meta":352,"style":352},"#ifndef __LED_H_\n#define __LED_H_\n\n//包含ESP32的gpio组件的头文件\n#include \"driver/gpio.h\"\n\ntypedef enum {\n    PIN_RESET = 0,     \n    PIN_SET      \n} gpio_output_state_t;\n\nvoid led_init(void);\n\n#endif\n",[33,2616,2617,2623,2629,2633,2638,2645,2649,2657,2669,2674,2683,2687,2700,2704],{"__ignoreMap":352},[356,2618,2619,2621],{"class":358,"line":359},[356,2620,2571],{"class":415},[356,2622,2574],{"class":373},[356,2624,2625,2627],{"class":358,"line":370},[356,2626,2579],{"class":415},[356,2628,2574],{"class":373},[356,2630,2631],{"class":358,"line":173},[356,2632,426],{"emptyLinePlaceholder":425},[356,2634,2635],{"class":358,"line":197},[356,2636,2637],{"class":409},"//包含ESP32的gpio组件的头文件\n",[356,2639,2640,2642],{"class":358,"line":434},[356,2641,659],{"class":415},[356,2643,2644],{"class":366}," \"driver/gpio.h\"\n",[356,2646,2647],{"class":358,"line":230},[356,2648,426],{"emptyLinePlaceholder":425},[356,2650,2651,2653,2655],{"class":358,"line":260},[356,2652,1834],{"class":415},[356,2654,1974],{"class":415},[356,2656,1840],{"class":419},[356,2658,2659,2662,2664,2666],{"class":358,"line":492},[356,2660,2661],{"class":419},"    PIN_RESET ",[356,2663,1610],{"class":415},[356,2665,1243],{"class":362},[356,2667,2668],{"class":419},",     \n",[356,2670,2671],{"class":358,"line":500},[356,2672,2673],{"class":419},"    PIN_SET      \n",[356,2675,2676,2678,2681],{"class":358,"line":506},[356,2677,1924],{"class":419},[356,2679,2680],{"class":362},"gpio_output_state_t",[356,2682,1246],{"class":419},[356,2684,2685],{"class":358,"line":511},[356,2686,426],{"emptyLinePlaceholder":425},[356,2688,2689,2691,2694,2696,2698],{"class":358,"line":520},[356,2690,671],{"class":415},[356,2692,2693],{"class":373}," led_init",[356,2695,677],{"class":419},[356,2697,671],{"class":415},[356,2699,705],{"class":419},[356,2701,2702],{"class":358,"line":538},[356,2703,426],{"emptyLinePlaceholder":425},[356,2705,2706],{"class":358,"line":543},[356,2707,1919],{"class":415},[10,2709,2710,2711,2714,2715,2718,2719,2722,2723,2726],{},"Next, write the content for ",[33,2712,2713],{},"led.c",":\nSince I looked at the schematic of my board, IO43 is the control pin for the LED, so I initialize IO43 below. (I only have IO43 here; IO44 is connected to a regular light, so I have no choice but to first replace ",[33,2716,2717],{},"Channel for console output"," in ",[33,2720,2721],{},"menuconfig"," with ",[33,2724,2725],{},"none",", but you don't need to change this for your light.)",[347,2728,2730],{"className":650,"code":2729,"language":652,"meta":352,"style":352},"#include \"led.h\"\n\nvoid led_init(void)\n{   \n    //给结构体清零(C语言知识,要给局部变量清零,防止未被初始化的地方出现很奇怪的事情)\n    gpio_config_t gpio_init_struct = {0}; \n\n    gpio_init_struct.pin_bit_mask = (1ULL \u003C\u003C GPIO_NUM_43);    //初始化IO43\n    gpio_init_struct.mode = GPIO_MODE_OUTPUT;                 //设置为输出模式\n    gpio_init_struct.pull_up_en = GPIO_PULLUP_DISABLE;        //禁用上拉电阻\n    gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE;    //禁用下拉电阻\n    gpio_init_struct.intr_type = GPIO_INTR_DISABLE;           //禁用中断\n\n    gpio_config(&gpio_init_struct);        //配置GPIO\n\n}\n",[33,2731,2732,2739,2743,2755,2760,2765,2784,2788,2812,2825,2838,2851,2864,2868,2884,2888],{"__ignoreMap":352},[356,2733,2734,2736],{"class":358,"line":359},[356,2735,659],{"class":415},[356,2737,2738],{"class":366}," \"led.h\"\n",[356,2740,2741],{"class":358,"line":370},[356,2742,426],{"emptyLinePlaceholder":425},[356,2744,2745,2747,2749,2751,2753],{"class":358,"line":173},[356,2746,671],{"class":415},[356,2748,2693],{"class":373},[356,2750,677],{"class":419},[356,2752,671],{"class":415},[356,2754,535],{"class":419},[356,2756,2757],{"class":358,"line":197},[356,2758,2759],{"class":419},"{   \n",[356,2761,2762],{"class":358,"line":434},[356,2763,2764],{"class":409},"    //给结构体清零(C语言知识,要给局部变量清零,防止未被初始化的地方出现很奇怪的事情)\n",[356,2766,2767,2770,2773,2775,2778,2781],{"class":358,"line":230},[356,2768,2769],{"class":362},"    gpio_config_t",[356,2771,2772],{"class":419}," gpio_init_struct ",[356,2774,1610],{"class":415},[356,2776,2777],{"class":419}," {",[356,2779,2780],{"class":362},"0",[356,2782,2783],{"class":419},"}; \n",[356,2785,2786],{"class":358,"line":260},[356,2787,426],{"emptyLinePlaceholder":425},[356,2789,2790,2793,2795,2798,2800,2803,2806,2809],{"class":358,"line":492},[356,2791,2792],{"class":419},"    gpio_init_struct.pin_bit_mask ",[356,2794,1610],{"class":415},[356,2796,2797],{"class":419}," (",[356,2799,1291],{"class":362},[356,2801,2802],{"class":415},"ULL",[356,2804,2805],{"class":415}," \u003C\u003C",[356,2807,2808],{"class":419}," GPIO_NUM_43);",[356,2810,2811],{"class":409},"    //初始化IO43\n",[356,2813,2814,2817,2819,2822],{"class":358,"line":500},[356,2815,2816],{"class":419},"    gpio_init_struct.mode ",[356,2818,1610],{"class":415},[356,2820,2821],{"class":419}," GPIO_MODE_OUTPUT;",[356,2823,2824],{"class":409},"                 //设置为输出模式\n",[356,2826,2827,2830,2832,2835],{"class":358,"line":506},[356,2828,2829],{"class":419},"    gpio_init_struct.pull_up_en ",[356,2831,1610],{"class":415},[356,2833,2834],{"class":419}," GPIO_PULLUP_DISABLE;",[356,2836,2837],{"class":409},"        //禁用上拉电阻\n",[356,2839,2840,2843,2845,2848],{"class":358,"line":511},[356,2841,2842],{"class":419},"    gpio_init_struct.pull_down_en ",[356,2844,1610],{"class":415},[356,2846,2847],{"class":419}," GPIO_PULLDOWN_DISABLE;",[356,2849,2850],{"class":409},"    //禁用下拉电阻\n",[356,2852,2853,2856,2858,2861],{"class":358,"line":520},[356,2854,2855],{"class":419},"    gpio_init_struct.intr_type ",[356,2857,1610],{"class":415},[356,2859,2860],{"class":419}," GPIO_INTR_DISABLE;",[356,2862,2863],{"class":409},"           //禁用中断\n",[356,2865,2866],{"class":358,"line":538},[356,2867,426],{"emptyLinePlaceholder":425},[356,2869,2870,2873,2875,2878,2881],{"class":358,"line":543},[356,2871,2872],{"class":373},"    gpio_config",[356,2874,677],{"class":419},[356,2876,2877],{"class":415},"&",[356,2879,2880],{"class":419},"gpio_init_struct);",[356,2882,2883],{"class":409},"        //配置GPIO\n",[356,2885,2886],{"class":358,"line":940},[356,2887,426],{"emptyLinePlaceholder":425},[356,2889,2890],{"class":358,"line":949},[356,2891,710],{"class":419},[10,2893,2894,2895,2897],{},"You can find out what values to fill in for the above parameters by querying the struct type through ",[33,2896,1802],{},".\nIf you don't understand, carefully watch the Zhengdian Atom video on how to look up structs.",[10,2899,2900,2901,1448],{},"Then edit ",[33,2902,628],{},[347,2904,2906],{"className":650,"code":2905,"language":652,"meta":352,"style":352},"//包含FreeRTOS头文件(为了用vTaskDelay)\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n//包含LED头文件,为了初始化LED和使用GPIO\n#include \"led.h\"\n\nvoid app_main(void)\n{\n    //初始化led的GPIO\n    led_init();\n    //死循环,等同于while(1),但效率比while(1)更高\n    for(;;)\n    {\n        gpio_set_level(GPIO_NUM_43, PIN_SET);   //设置为高电平\n        vTaskDelay(500 / portTICK_PERIOD_MS);  //延时500ms\n        gpio_set_level(GPIO_NUM_43, PIN_RESET); //设置为低电平\n        vTaskDelay(500 / portTICK_PERIOD_MS);  //延时500ms\n    }\n}\n",[33,2907,2908,2913,2920,2927,2932,2938,2942,2954,2958,2963,2971,2976,2983,2988,2999,3017,3027,3041,3046],{"__ignoreMap":352},[356,2909,2910],{"class":358,"line":359},[356,2911,2912],{"class":409},"//包含FreeRTOS头文件(为了用vTaskDelay)\n",[356,2914,2915,2917],{"class":358,"line":370},[356,2916,659],{"class":415},[356,2918,2919],{"class":366}," \"freertos/FreeRTOS.h\"\n",[356,2921,2922,2924],{"class":358,"line":173},[356,2923,659],{"class":415},[356,2925,2926],{"class":366}," \"freertos/task.h\"\n",[356,2928,2929],{"class":358,"line":197},[356,2930,2931],{"class":409},"//包含LED头文件,为了初始化LED和使用GPIO\n",[356,2933,2934,2936],{"class":358,"line":434},[356,2935,659],{"class":415},[356,2937,2738],{"class":366},[356,2939,2940],{"class":358,"line":230},[356,2941,426],{"emptyLinePlaceholder":425},[356,2943,2944,2946,2948,2950,2952],{"class":358,"line":260},[356,2945,671],{"class":415},[356,2947,674],{"class":373},[356,2949,677],{"class":419},[356,2951,671],{"class":415},[356,2953,535],{"class":419},[356,2955,2956],{"class":358,"line":492},[356,2957,686],{"class":419},[356,2959,2960],{"class":358,"line":500},[356,2961,2962],{"class":409},"    //初始化led的GPIO\n",[356,2964,2965,2968],{"class":358,"line":506},[356,2966,2967],{"class":373},"    led_init",[356,2969,2970],{"class":419},"();\n",[356,2972,2973],{"class":358,"line":511},[356,2974,2975],{"class":409},"    //死循环,等同于while(1),但效率比while(1)更高\n",[356,2977,2978,2981],{"class":358,"line":520},[356,2979,2980],{"class":415},"    for",[356,2982,1303],{"class":419},[356,2984,2985],{"class":358,"line":538},[356,2986,2987],{"class":419},"    {\n",[356,2989,2990,2993,2996],{"class":358,"line":543},[356,2991,2992],{"class":373},"        gpio_set_level",[356,2994,2995],{"class":419},"(GPIO_NUM_43, PIN_SET);",[356,2997,2998],{"class":409},"   //设置为高电平\n",[356,3000,3001,3004,3006,3009,3011,3014],{"class":358,"line":940},[356,3002,3003],{"class":373},"        vTaskDelay",[356,3005,677],{"class":419},[356,3007,3008],{"class":362},"500",[356,3010,1325],{"class":415},[356,3012,3013],{"class":419}," portTICK_PERIOD_MS);",[356,3015,3016],{"class":409},"  //延时500ms\n",[356,3018,3019,3021,3024],{"class":358,"line":949},[356,3020,2992],{"class":373},[356,3022,3023],{"class":419},"(GPIO_NUM_43, PIN_RESET);",[356,3025,3026],{"class":409}," //设置为低电平\n",[356,3028,3029,3031,3033,3035,3037,3039],{"class":358,"line":954},[356,3030,3003],{"class":373},[356,3032,677],{"class":419},[356,3034,3008],{"class":362},[356,3036,1325],{"class":415},[356,3038,3013],{"class":419},[356,3040,3016],{"class":409},[356,3042,3043],{"class":358,"line":966},[356,3044,3045],{"class":419},"    }\n",[356,3047,3048],{"class":358,"line":971},[356,3049,710],{"class":419},[10,3051,3052,3053,3056,3057,3060,3061,3063,3064,3067,3068,3070,3071],{},"The code above makes the LED blink once every 1 second.\nHere\n",[33,3054,3055],{},"vTaskDelay(500 / portTICK_PERIOD_MS);"," can actually be simplified to ",[33,3058,3059],{},"vTaskDelay(500);",", because we previously configured ",[33,3062,182],{}," to 1000, which will cause the value of ",[33,3065,3066],{},"portTICK_PERIOD_MS"," to be 1.",[735,3069],{},"\nHowever, the above approach is more standardized. If others want to use your code, they won't run into unit errors with delays. It's still recommended to avoid the simplified method. Zhengdian Atom uses the simplified version, but if someone copies and migrates your code, it could cause major issues.",[735,3072],{},[10,3074,3075],{},"The usual three steps, press them in order, and then you'll see the lights on the board flash.",[10,3077,3078],{},[39,3079],{"alt":41,"src":3080},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768396481018.webp",[25,3082,3084],{"id":3083},"key-practical","KEY Practical",[10,3086,3087],{},"Below is a circuit for a KEY. When the KEY is pressed, it conducts.",[10,3089,3090],{},[39,3091],{"alt":41,"src":3092},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768656614098.webp",[10,3094,3095],{},"Actually, pressing a button can cause bouncing, which is typically caused by mechanical materials, structure, or the environment.",[10,3097,3098],{},[39,3099],{"alt":41,"src":3100},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768656707523.webp",[10,3102,3103],{},"However, the middle section is normal, as shown in the figure below.",[10,3105,3106],{},[39,3107],{"alt":41,"src":3108},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768656860971.webp",[10,3110,3111],{},"For everyday use, the delay method in software debouncing is sufficient.",[10,3113,3114],{},[39,3115],{"alt":41,"src":3116},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768657220549.webp",[10,3118,3119],{},"Actual wiring",[10,3121,3122],{},[39,3123],{"alt":41,"src":3124},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768657369280.webp",[10,3126,3127,3128,3130,3131,3134],{},"First, modify ",[33,3129,636],{}," in the ",[33,3132,3133],{},"BSP"," folder:",[347,3136,3138],{"className":400,"code":3137,"language":402,"meta":352,"style":352},"set(src_dirs\n            LED\n            KEY)\n\nset(include_dirs\n            LED\n            KEY)\n\n# GPIO的一些组件在driver里\nset(requires\n            driver)\n\nidf_component_register(SRC_DIRS ${src_dirs}\n                      INCLUDE_DIRS ${include_dirs} REQUIRES ${requires})\n\ncomponent_compile_options(-ffast-math -O3 -Wno-error=format=-Wno-format)\n\n",[33,3139,3140,3146,3151,3156,3160,3166,3170,3174,3178,3182,3188,3192,3196,3202,3214,3218],{"__ignoreMap":352},[356,3141,3142,3144],{"class":358,"line":359},[356,3143,416],{"class":415},[356,3145,460],{"class":419},[356,3147,3148],{"class":358,"line":370},[356,3149,3150],{"class":419},"            LED\n",[356,3152,3153],{"class":358,"line":173},[356,3154,3155],{"class":419},"            KEY)\n",[356,3157,3158],{"class":358,"line":197},[356,3159,426],{"emptyLinePlaceholder":425},[356,3161,3162,3164],{"class":358,"line":434},[356,3163,416],{"class":415},[356,3165,476],{"class":419},[356,3167,3168],{"class":358,"line":230},[356,3169,3150],{"class":419},[356,3171,3172],{"class":358,"line":260},[356,3173,3155],{"class":419},[356,3175,3176],{"class":358,"line":492},[356,3177,426],{"emptyLinePlaceholder":425},[356,3179,3180],{"class":358,"line":500},[356,3181,489],{"class":409},[356,3183,3184,3186],{"class":358,"line":506},[356,3185,416],{"class":415},[356,3187,497],{"class":419},[356,3189,3190],{"class":358,"line":511},[356,3191,503],{"class":419},[356,3193,3194],{"class":358,"line":520},[356,3195,426],{"emptyLinePlaceholder":425},[356,3197,3198,3200],{"class":358,"line":538},[356,3199,514],{"class":419},[356,3201,517],{"class":415},[356,3203,3204,3206,3208,3210,3212],{"class":358,"line":543},[356,3205,523],{"class":419},[356,3207,526],{"class":415},[356,3209,529],{"class":419},[356,3211,532],{"class":415},[356,3213,535],{"class":419},[356,3215,3216],{"class":358,"line":940},[356,3217,426],{"emptyLinePlaceholder":425},[356,3219,3220],{"class":358,"line":949},[356,3221,546],{"class":419},[10,3223,3224,3225,3228],{},"Let's open the schematic and see which pin the button is connected to.\nSince my board doesn't have custom buttons, I chose to use the ",[33,3226,3227],{},"BOOT"," button as a button.",[10,3230,3231],{},[39,3232],{"alt":41,"src":3233},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768658484350.webp",[10,3235,3236,3237,3240,3241,3244,3245,3247,3248,3250,3251,3253,3254],{},"As shown in the image above, one side of this button is connected to ",[33,3238,3239],{},"GND"," and the other side is connected to ",[33,3242,3243],{},"GPIO0",". So initially, the ",[33,3246,3243],{}," side must be in a high-level state. When the button is pressed, the entire line will be pulled to a low level by ",[33,3249,3239],{},". Therefore, ",[33,3252,3243],{}," detects the level changing from high to low, which is called detecting a falling edge, and the opposite is called a rising edge.",[735,3255],{},[10,3257,3258,3259,3261,3262,3264,3265],{},"How do we make ",[33,3260,3243],{}," start at a high level? We need to connect ",[33,3263,3243],{}," to a pull-up resistor.",[735,3266],{},[10,3268,3269,3270,3272,3273,3276,3277,3279],{},"Conversely, if ",[33,3271,3227],{}," has ",[33,3274,3275],{},"VCC"," on its left side, then ",[33,3278,3243],{}," needs a pull-down resistor and should detect the rising edge.",[10,3281,3282,3283,155],{},"First, create the content of ",[33,3284,3285],{},"key.h",[347,3287,3289],{"className":650,"code":3288,"language":652,"meta":352,"style":352},"#ifndef __KEY_H_\n#define __KEY_H_\n\n//包含ESP32的gpio组件的头文件\n#include \"driver/gpio.h\"\n\n#define BOOT_PRES 1\n\n#endif\n",[33,3290,3291,3298,3304,3308,3312,3318,3322,3332,3336],{"__ignoreMap":352},[356,3292,3293,3295],{"class":358,"line":359},[356,3294,2571],{"class":415},[356,3296,3297],{"class":373}," __KEY_H_\n",[356,3299,3300,3302],{"class":358,"line":370},[356,3301,2579],{"class":415},[356,3303,3297],{"class":373},[356,3305,3306],{"class":358,"line":173},[356,3307,426],{"emptyLinePlaceholder":425},[356,3309,3310],{"class":358,"line":197},[356,3311,2637],{"class":409},[356,3313,3314,3316],{"class":358,"line":434},[356,3315,659],{"class":415},[356,3317,2644],{"class":366},[356,3319,3320],{"class":358,"line":230},[356,3321,426],{"emptyLinePlaceholder":425},[356,3323,3324,3326,3329],{"class":358,"line":260},[356,3325,2579],{"class":415},[356,3327,3328],{"class":373}," BOOT_PRES",[356,3330,3331],{"class":362}," 1\n",[356,3333,3334],{"class":358,"line":492},[356,3335,426],{"emptyLinePlaceholder":425},[356,3337,3338],{"class":358,"line":500},[356,3339,1919],{"class":415},[10,3341,3342,3343,3346,3347,3349,3350,155],{},"Here, ",[33,3344,3345],{},"BOOT_PRES"," is an identifier. When the BOOT button is pressed, the value ",[33,3348,3345],{}," will be detected, which is ",[33,3351,1291],{},[10,3353,3354,3355,3358,3359,3361,3362,155],{},"Then in ",[33,3356,3357],{},"key.c",", first initialize the ",[33,3360,1706],{}," of ",[33,3363,3364],{},"gpio0",[10,3366,3367,3368,3371],{},"It's similar to ",[33,3369,3370],{},"led",". However, note that the mode here is input mode, and the pull-up resistor must be enabled.",[347,3373,3375],{"className":650,"code":3374,"language":652,"meta":352,"style":352},"void key_init(void)\n{   \n    //给结构体清零(C语言知识,要给局部变量清零,防止未被初始化的地方出现很奇怪的事情)\n    gpio_config_t gpio_init_struct = {0}; \n\n    gpio_init_struct.pin_bit_mask = (1ULL \u003C\u003C GPIO_NUM_0);    //初始化IO0\n    gpio_init_struct.mode = GPIO_MODE_INPUT;                 //设置为输入模式\n    gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE;        //启用上拉电阻\n    gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE;    //禁用下拉电阻\n    gpio_init_struct.intr_type = GPIO_INTR_DISABLE;           //禁用中断\n\n    gpio_config(&gpio_init_struct);        //配置GPIO\n\n}\n",[33,3376,3377,3390,3394,3398,3412,3416,3436,3448,3460,3470,3480,3484,3496,3500],{"__ignoreMap":352},[356,3378,3379,3381,3384,3386,3388],{"class":358,"line":359},[356,3380,671],{"class":415},[356,3382,3383],{"class":373}," key_init",[356,3385,677],{"class":419},[356,3387,671],{"class":415},[356,3389,535],{"class":419},[356,3391,3392],{"class":358,"line":370},[356,3393,2759],{"class":419},[356,3395,3396],{"class":358,"line":173},[356,3397,2764],{"class":409},[356,3399,3400,3402,3404,3406,3408,3410],{"class":358,"line":197},[356,3401,2769],{"class":362},[356,3403,2772],{"class":419},[356,3405,1610],{"class":415},[356,3407,2777],{"class":419},[356,3409,2780],{"class":362},[356,3411,2783],{"class":419},[356,3413,3414],{"class":358,"line":434},[356,3415,426],{"emptyLinePlaceholder":425},[356,3417,3418,3420,3422,3424,3426,3428,3430,3433],{"class":358,"line":230},[356,3419,2792],{"class":419},[356,3421,1610],{"class":415},[356,3423,2797],{"class":419},[356,3425,1291],{"class":362},[356,3427,2802],{"class":415},[356,3429,2805],{"class":415},[356,3431,3432],{"class":419}," GPIO_NUM_0);",[356,3434,3435],{"class":409},"    //初始化IO0\n",[356,3437,3438,3440,3442,3445],{"class":358,"line":260},[356,3439,2816],{"class":419},[356,3441,1610],{"class":415},[356,3443,3444],{"class":419}," GPIO_MODE_INPUT;",[356,3446,3447],{"class":409},"                 //设置为输入模式\n",[356,3449,3450,3452,3454,3457],{"class":358,"line":492},[356,3451,2829],{"class":419},[356,3453,1610],{"class":415},[356,3455,3456],{"class":419}," GPIO_PULLUP_ENABLE;",[356,3458,3459],{"class":409},"        //启用上拉电阻\n",[356,3461,3462,3464,3466,3468],{"class":358,"line":500},[356,3463,2842],{"class":419},[356,3465,1610],{"class":415},[356,3467,2847],{"class":419},[356,3469,2850],{"class":409},[356,3471,3472,3474,3476,3478],{"class":358,"line":506},[356,3473,2855],{"class":419},[356,3475,1610],{"class":415},[356,3477,2860],{"class":419},[356,3479,2863],{"class":409},[356,3481,3482],{"class":358,"line":511},[356,3483,426],{"emptyLinePlaceholder":425},[356,3485,3486,3488,3490,3492,3494],{"class":358,"line":520},[356,3487,2872],{"class":373},[356,3489,677],{"class":419},[356,3491,2877],{"class":415},[356,3493,2880],{"class":419},[356,3495,2883],{"class":409},[356,3497,3498],{"class":358,"line":538},[356,3499,426],{"emptyLinePlaceholder":425},[356,3501,3502],{"class":358,"line":543},[356,3503,710],{"class":419},[10,3505,3506],{},"Now for the main event: the key scanning function. The comments below explain it in great detail, so you can analyze the code carefully on your own.",[347,3508,3510],{"className":650,"code":3509,"language":652,"meta":352,"style":352},"/**\n * @brief       按键扫描函数\n * @note        无\n * @param       mode:0 / 1, 具体含义如下:\n *   @arg       0,  不支持连续按(当按键按下不放时, 只有第一次调用会返回键值,\n *                  必须松开以后, 再次按下才会返回其他键值)\n *   @arg       1,  支持连续按(当按键按下不放时, 每次调用该函数都会返回键值)\n * @retval      键值, 定义如下:\n *              BOOT_PRES, 1, BOOT按键按下\n */\nuint8_t key_scan(uint8_t mode)\n{\n    static uint8_t key_up = 1;  /* 按键按松开标志 */\n    uint8_t keyval = 0;\n\n    if (mode)       /* 支持连按 */\n    {\n        key_up = 1;\n    }\n\n    if (key_up && (gpio_get_level(GPIO_NUM_0) == 0))  /* 按键松开标志为1, 且有任意一个按键按下了 */\n    {\n        vTaskDelay(10 / portTICK_PERIOD_MS);           /* 去抖动 */\n        key_up = 0;\n\n        if (gpio_get_level(GPIO_NUM_0) == 0)  keyval = BOOT_PRES;\n\n\n    }\n    else if (gpio_get_level(GPIO_NUM_0) == 1)         /* 没有任何按键按下, 标记按键松开 */\n    {\n        key_up = 1;\n    }\n\n    return keyval;              /* 返回键值 */\n}\n",[33,3511,3512,3516,3525,3535,3548,3559,3564,3573,3583,3588,3592,3609,3613,3634,3648,3652,3663,3667,3678,3682,3686,3714,3718,3734,3744,3748,3771,3775,3779,3783,3807,3811,3821,3825,3829,3839],{"__ignoreMap":352},[356,3513,3514],{"class":358,"line":359},[356,3515,1813],{"class":409},[356,3517,3518,3520,3522],{"class":358,"line":370},[356,3519,1818],{"class":409},[356,3521,1821],{"class":415},[356,3523,3524],{"class":409},"       按键扫描函数\n",[356,3526,3527,3529,3532],{"class":358,"line":173},[356,3528,1818],{"class":409},[356,3530,3531],{"class":415},"@note",[356,3533,3534],{"class":409},"        无\n",[356,3536,3537,3539,3542,3545],{"class":358,"line":197},[356,3538,1818],{"class":409},[356,3540,3541],{"class":415},"@param",[356,3543,3544],{"class":1789},"       mode",[356,3546,3547],{"class":409},":0 / 1, 具体含义如下:\n",[356,3549,3550,3553,3556],{"class":358,"line":434},[356,3551,3552],{"class":409}," *   ",[356,3554,3555],{"class":415},"@arg",[356,3557,3558],{"class":409},"       0,  不支持连续按(当按键按下不放时, 只有第一次调用会返回键值,\n",[356,3560,3561],{"class":358,"line":230},[356,3562,3563],{"class":409}," *                  必须松开以后, 再次按下才会返回其他键值)\n",[356,3565,3566,3568,3570],{"class":358,"line":260},[356,3567,3552],{"class":409},[356,3569,3555],{"class":415},[356,3571,3572],{"class":409},"       1,  支持连续按(当按键按下不放时, 每次调用该函数都会返回键值)\n",[356,3574,3575,3577,3580],{"class":358,"line":492},[356,3576,1818],{"class":409},[356,3578,3579],{"class":415},"@retval",[356,3581,3582],{"class":409},"      键值, 定义如下:\n",[356,3584,3585],{"class":358,"line":500},[356,3586,3587],{"class":409}," *              BOOT_PRES, 1, BOOT按键按下\n",[356,3589,3590],{"class":358,"line":506},[356,3591,1829],{"class":409},[356,3593,3594,3597,3600,3602,3604,3607],{"class":358,"line":511},[356,3595,3596],{"class":415},"uint8_t",[356,3598,3599],{"class":373}," key_scan",[356,3601,677],{"class":419},[356,3603,3596],{"class":415},[356,3605,3606],{"class":1789}," mode",[356,3608,535],{"class":419},[356,3610,3611],{"class":358,"line":520},[356,3612,686],{"class":419},[356,3614,3615,3618,3621,3624,3626,3628,3631],{"class":358,"line":538},[356,3616,3617],{"class":415},"    static",[356,3619,3620],{"class":415}," uint8_t",[356,3622,3623],{"class":419}," key_up ",[356,3625,1610],{"class":415},[356,3627,2283],{"class":362},[356,3629,3630],{"class":419},";",[356,3632,3633],{"class":409},"  /* 按键按松开标志 */\n",[356,3635,3636,3639,3642,3644,3646],{"class":358,"line":543},[356,3637,3638],{"class":415},"    uint8_t",[356,3640,3641],{"class":419}," keyval ",[356,3643,1610],{"class":415},[356,3645,1243],{"class":362},[356,3647,1246],{"class":419},[356,3649,3650],{"class":358,"line":940},[356,3651,426],{"emptyLinePlaceholder":425},[356,3653,3654,3657,3660],{"class":358,"line":949},[356,3655,3656],{"class":415},"    if",[356,3658,3659],{"class":419}," (mode)",[356,3661,3662],{"class":409},"       /* 支持连按 */\n",[356,3664,3665],{"class":358,"line":954},[356,3666,2987],{"class":419},[356,3668,3669,3672,3674,3676],{"class":358,"line":966},[356,3670,3671],{"class":419},"        key_up ",[356,3673,1610],{"class":415},[356,3675,2283],{"class":362},[356,3677,1246],{"class":419},[356,3679,3680],{"class":358,"line":971},[356,3681,3045],{"class":419},[356,3683,3684],{"class":358,"line":976},[356,3685,426],{"emptyLinePlaceholder":425},[356,3687,3688,3690,3693,3696,3698,3700,3703,3706,3708,3711],{"class":358,"line":985},[356,3689,3656],{"class":415},[356,3691,3692],{"class":419}," (key_up ",[356,3694,3695],{"class":415},"&&",[356,3697,2797],{"class":419},[356,3699,2473],{"class":373},[356,3701,3702],{"class":419},"(GPIO_NUM_0) ",[356,3704,3705],{"class":415},"==",[356,3707,1243],{"class":362},[356,3709,3710],{"class":419},"))",[356,3712,3713],{"class":409},"  /* 按键松开标志为1, 且有任意一个按键按下了 */\n",[356,3715,3716],{"class":358,"line":990},[356,3717,2987],{"class":419},[356,3719,3720,3722,3724,3727,3729,3731],{"class":358,"line":1002},[356,3721,3003],{"class":373},[356,3723,677],{"class":419},[356,3725,3726],{"class":362},"10",[356,3728,1325],{"class":415},[356,3730,3013],{"class":419},[356,3732,3733],{"class":409},"           /* 去抖动 */\n",[356,3735,3736,3738,3740,3742],{"class":358,"line":1007},[356,3737,3671],{"class":419},[356,3739,1610],{"class":415},[356,3741,1243],{"class":362},[356,3743,1246],{"class":419},[356,3745,3746],{"class":358,"line":1015},[356,3747,426],{"emptyLinePlaceholder":425},[356,3749,3750,3753,3755,3757,3759,3761,3763,3766,3768],{"class":358,"line":1069},[356,3751,3752],{"class":415},"        if",[356,3754,2797],{"class":419},[356,3756,2473],{"class":373},[356,3758,3702],{"class":419},[356,3760,3705],{"class":415},[356,3762,1243],{"class":362},[356,3764,3765],{"class":419},")  keyval ",[356,3767,1610],{"class":415},[356,3769,3770],{"class":419}," BOOT_PRES;\n",[356,3772,3773],{"class":358,"line":1074},[356,3774,426],{"emptyLinePlaceholder":425},[356,3776,3777],{"class":358,"line":1086},[356,3778,426],{"emptyLinePlaceholder":425},[356,3780,3781],{"class":358,"line":1091},[356,3782,3045],{"class":419},[356,3784,3785,3788,3791,3793,3795,3797,3799,3801,3804],{"class":358,"line":1103},[356,3786,3787],{"class":415},"    else",[356,3789,3790],{"class":415}," if",[356,3792,2797],{"class":419},[356,3794,2473],{"class":373},[356,3796,3702],{"class":419},[356,3798,3705],{"class":415},[356,3800,2283],{"class":362},[356,3802,3803],{"class":419},")",[356,3805,3806],{"class":409},"         /* 没有任何按键按下, 标记按键松开 */\n",[356,3808,3809],{"class":358,"line":1108},[356,3810,2987],{"class":419},[356,3812,3813,3815,3817,3819],{"class":358,"line":1117},[356,3814,3671],{"class":419},[356,3816,1610],{"class":415},[356,3818,2283],{"class":362},[356,3820,1246],{"class":419},[356,3822,3823],{"class":358,"line":1129},[356,3824,3045],{"class":419},[356,3826,3827],{"class":358,"line":1134},[356,3828,426],{"emptyLinePlaceholder":425},[356,3830,3831,3833,3836],{"class":358,"line":1155},[356,3832,2179],{"class":415},[356,3834,3835],{"class":419}," keyval;",[356,3837,3838],{"class":409},"              /* 返回键值 */\n",[356,3840,3841],{"class":358,"line":1167},[356,3842,710],{"class":419},[10,3844,3845,3846,3849],{},"Mainly using the function ",[33,3847,3848],{},"int gpio_get_level(gpio_num_t gpio_num)",", which we covered in the first section.",[347,3851,3852],{"className":650,"code":2476,"language":652,"meta":352,"style":352},[33,3853,3854,3868,3872,3880],{"__ignoreMap":352},[356,3855,3856,3858,3860,3862,3864,3866],{"class":358,"line":359},[356,3857,2483],{"class":415},[356,3859,2486],{"class":373},[356,3861,677],{"class":419},[356,3863,2129],{"class":362},[356,3865,2132],{"class":1789},[356,3867,535],{"class":419},[356,3869,3870],{"class":358,"line":370},[356,3871,686],{"class":419},[356,3873,3874,3876,3878],{"class":358,"line":173},[356,3875,2179],{"class":415},[356,3877,2505],{"class":373},[356,3879,2508],{"class":419},[356,3881,3882],{"class":358,"line":197},[356,3883,710],{"class":419},[10,3885,3886],{},"Then also define a global variable to serve as the key variable, storing the key result.",[347,3888,3890],{"className":650,"code":3889,"language":652,"meta":352,"style":352},"uint8_t key_value = 0;\n",[33,3891,3892],{"__ignoreMap":352},[356,3893,3894,3896,3899,3901,3903],{"class":358,"line":359},[356,3895,3596],{"class":415},[356,3897,3898],{"class":419}," key_value ",[356,3900,1610],{"class":415},[356,3902,1243],{"class":362},[356,3904,1246],{"class":419},[10,3906,3907,3908,3910],{},"Write the main logic in ",[33,3909,628],{},", which is to toggle the level when the button is pressed.",[347,3912,3914],{"className":650,"code":3913,"language":652,"meta":352,"style":352},"//包含FreeRTOS头文件(为了用vTaskDelay)\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n//包含LED头文件,为了初始化LED和使用GPIO\n#include \"led.h\"\n//包含KEY头文件,为了初始化KEY和使用GPIO\n#include \"key.h\"\n\n//按键外部变量声明;\nextern uint8_t key_value;\n\n\nvoid app_main(void)\n{\n    //初始化led的GPIO\n    led_init();\n    //初始化key的GPIO\n    key_init();\n\n    //死循环,等同于while(1),但效率比while(1)更高\n    for(;;)\n    {\n        key_value = key_scan(0);\n\n        switch (key_value)\n        {\n        case BOOT_PRES:\n            gpio_set_level(GPIO_NUM_43, !gpio_get_level(GPIO_NUM_43));   //翻转电平\n            break;\n        \n        default:\n            break;\n        }\n\n        vTaskDelay(10 / portTICK_PERIOD_MS);  //延时10ms\n    }\n}\n",[33,3915,3916,3920,3926,3932,3936,3942,3947,3954,3958,3963,3973,3977,3981,3993,3997,4001,4007,4012,4019,4023,4027,4033,4037,4052,4056,4064,4069,4077,4095,4102,4107,4115,4121,4126,4130,4145,4149],{"__ignoreMap":352},[356,3917,3918],{"class":358,"line":359},[356,3919,2912],{"class":409},[356,3921,3922,3924],{"class":358,"line":370},[356,3923,659],{"class":415},[356,3925,2919],{"class":366},[356,3927,3928,3930],{"class":358,"line":173},[356,3929,659],{"class":415},[356,3931,2926],{"class":366},[356,3933,3934],{"class":358,"line":197},[356,3935,2931],{"class":409},[356,3937,3938,3940],{"class":358,"line":434},[356,3939,659],{"class":415},[356,3941,2738],{"class":366},[356,3943,3944],{"class":358,"line":230},[356,3945,3946],{"class":409},"//包含KEY头文件,为了初始化KEY和使用GPIO\n",[356,3948,3949,3951],{"class":358,"line":260},[356,3950,659],{"class":415},[356,3952,3953],{"class":366}," \"key.h\"\n",[356,3955,3956],{"class":358,"line":492},[356,3957,426],{"emptyLinePlaceholder":425},[356,3959,3960],{"class":358,"line":500},[356,3961,3962],{"class":409},"//按键外部变量声明;\n",[356,3964,3965,3968,3970],{"class":358,"line":506},[356,3966,3967],{"class":415},"extern",[356,3969,3620],{"class":415},[356,3971,3972],{"class":419}," key_value;\n",[356,3974,3975],{"class":358,"line":511},[356,3976,426],{"emptyLinePlaceholder":425},[356,3978,3979],{"class":358,"line":520},[356,3980,426],{"emptyLinePlaceholder":425},[356,3982,3983,3985,3987,3989,3991],{"class":358,"line":538},[356,3984,671],{"class":415},[356,3986,674],{"class":373},[356,3988,677],{"class":419},[356,3990,671],{"class":415},[356,3992,535],{"class":419},[356,3994,3995],{"class":358,"line":543},[356,3996,686],{"class":419},[356,3998,3999],{"class":358,"line":940},[356,4000,2962],{"class":409},[356,4002,4003,4005],{"class":358,"line":949},[356,4004,2967],{"class":373},[356,4006,2970],{"class":419},[356,4008,4009],{"class":358,"line":954},[356,4010,4011],{"class":409},"    //初始化key的GPIO\n",[356,4013,4014,4017],{"class":358,"line":966},[356,4015,4016],{"class":373},"    key_init",[356,4018,2970],{"class":419},[356,4020,4021],{"class":358,"line":971},[356,4022,426],{"emptyLinePlaceholder":425},[356,4024,4025],{"class":358,"line":976},[356,4026,2975],{"class":409},[356,4028,4029,4031],{"class":358,"line":985},[356,4030,2980],{"class":415},[356,4032,1303],{"class":419},[356,4034,4035],{"class":358,"line":990},[356,4036,2987],{"class":419},[356,4038,4039,4042,4044,4046,4048,4050],{"class":358,"line":1002},[356,4040,4041],{"class":419},"        key_value ",[356,4043,1610],{"class":415},[356,4045,3599],{"class":373},[356,4047,677],{"class":419},[356,4049,2780],{"class":362},[356,4051,705],{"class":419},[356,4053,4054],{"class":358,"line":1007},[356,4055,426],{"emptyLinePlaceholder":425},[356,4057,4058,4061],{"class":358,"line":1015},[356,4059,4060],{"class":415},"        switch",[356,4062,4063],{"class":419}," (key_value)\n",[356,4065,4066],{"class":358,"line":1069},[356,4067,4068],{"class":419},"        {\n",[356,4070,4071,4074],{"class":358,"line":1074},[356,4072,4073],{"class":415},"        case",[356,4075,4076],{"class":419}," BOOT_PRES:\n",[356,4078,4079,4082,4085,4087,4089,4092],{"class":358,"line":1086},[356,4080,4081],{"class":373},"            gpio_set_level",[356,4083,4084],{"class":419},"(GPIO_NUM_43, ",[356,4086,804],{"class":415},[356,4088,2473],{"class":373},[356,4090,4091],{"class":419},"(GPIO_NUM_43));",[356,4093,4094],{"class":409},"   //翻转电平\n",[356,4096,4097,4100],{"class":358,"line":1091},[356,4098,4099],{"class":415},"            break",[356,4101,1246],{"class":419},[356,4103,4104],{"class":358,"line":1103},[356,4105,4106],{"class":419},"        \n",[356,4108,4109,4112],{"class":358,"line":1108},[356,4110,4111],{"class":415},"        default",[356,4113,4114],{"class":419},":\n",[356,4116,4117,4119],{"class":358,"line":1117},[356,4118,4099],{"class":415},[356,4120,1246],{"class":419},[356,4122,4123],{"class":358,"line":1129},[356,4124,4125],{"class":419},"        }\n",[356,4127,4128],{"class":358,"line":1134},[356,4129,426],{"emptyLinePlaceholder":425},[356,4131,4132,4134,4136,4138,4140,4142],{"class":358,"line":1155},[356,4133,3003],{"class":373},[356,4135,677],{"class":419},[356,4137,3726],{"class":362},[356,4139,1325],{"class":415},[356,4141,3013],{"class":419},[356,4143,4144],{"class":409},"  //延时10ms\n",[356,4146,4147],{"class":358,"line":1167},[356,4148,3045],{"class":419},[356,4150,4151],{"class":358,"line":1172},[356,4152,710],{"class":419},[10,4154,4155,4156,4158,4159,1448],{},"Below is the complete content of ",[33,4157,3285],{}," and ",[33,4160,3357],{},[347,4162,4164],{"className":650,"code":4163,"language":652,"meta":352,"style":352},"#include \"key.h\"\n\n//包含FreeRTOS头文件(为了用vTaskDelay)\n#include \"freertos/FreeRTOS.h\"\n#include \"freertos/task.h\"\n\n\nuint8_t key_value = 0;\n\nvoid key_init(void)\n{   \n    //给结构体清零(C语言知识,要给局部变量清零,防止未被初始化的地方出现很奇怪的事情)\n    gpio_config_t gpio_init_struct = {0}; \n\n    gpio_init_struct.pin_bit_mask = (1ULL \u003C\u003C GPIO_NUM_0);    //初始化IO0\n    gpio_init_struct.mode = GPIO_MODE_INPUT;                 //设置为输入模式\n    gpio_init_struct.pull_up_en = GPIO_PULLUP_ENABLE;        //启用上拉电阻\n    gpio_init_struct.pull_down_en = GPIO_PULLDOWN_DISABLE;    //禁用下拉电阻\n    gpio_init_struct.intr_type = GPIO_INTR_DISABLE;           //禁用中断\n\n    gpio_config(&gpio_init_struct);        //配置GPIO\n\n}\n\n\n/**\n * @brief       按键扫描函数\n * @note        无\n * @param       mode:0 / 1, 具体含义如下:\n *   @arg       0,  不支持连续按(当按键按下不放时, 只有第一次调用会返回键值,\n *                  必须松开以后, 再次按下才会返回其他键值)\n *   @arg       1,  支持连续按(当按键按下不放时, 每次调用该函数都会返回键值)\n * @retval      键值, 定义如下:\n *              BOOT_PRES, 1, BOOT按键按下\n */\nuint8_t key_scan(uint8_t mode)\n{\n    static uint8_t key_up = 1;  /* 按键按松开标志 */\n    uint8_t keyval = 0;\n\n    if (mode)       /* 支持连按 */\n    {\n        key_up = 1;\n    }\n\n    if (key_up && (gpio_get_level(GPIO_NUM_0) == 0))  /* 按键松开标志为1, 且有任意一个按键按下了 */\n    {\n        vTaskDelay(10 / portTICK_PERIOD_MS);           /* 去抖动 */\n        key_up = 0;\n\n        if (gpio_get_level(GPIO_NUM_0) == 0)  keyval = BOOT_PRES;\n\n\n    }\n    else if (gpio_get_level(GPIO_NUM_0) == 1)         /* 没有任何按键按下, 标记按键松开 */\n    {\n        key_up = 1;\n    }\n\n    return keyval;              /* 返回键值 */\n}\n",[33,4165,4166,4172,4176,4180,4186,4192,4196,4200,4212,4216,4228,4232,4236,4250,4254,4272,4282,4292,4302,4312,4316,4328,4332,4336,4340,4344,4348,4356,4364,4374,4382,4386,4394,4402,4406,4410,4424,4428,4444,4456,4460,4468,4472,4482,4486,4490,4512,4516,4530,4540,4544,4564,4568,4572,4576,4596,4600,4610,4614,4619,4628],{"__ignoreMap":352},[356,4167,4168,4170],{"class":358,"line":359},[356,4169,659],{"class":415},[356,4171,3953],{"class":366},[356,4173,4174],{"class":358,"line":370},[356,4175,426],{"emptyLinePlaceholder":425},[356,4177,4178],{"class":358,"line":173},[356,4179,2912],{"class":409},[356,4181,4182,4184],{"class":358,"line":197},[356,4183,659],{"class":415},[356,4185,2919],{"class":366},[356,4187,4188,4190],{"class":358,"line":434},[356,4189,659],{"class":415},[356,4191,2926],{"class":366},[356,4193,4194],{"class":358,"line":230},[356,4195,426],{"emptyLinePlaceholder":425},[356,4197,4198],{"class":358,"line":260},[356,4199,426],{"emptyLinePlaceholder":425},[356,4201,4202,4204,4206,4208,4210],{"class":358,"line":492},[356,4203,3596],{"class":415},[356,4205,3898],{"class":419},[356,4207,1610],{"class":415},[356,4209,1243],{"class":362},[356,4211,1246],{"class":419},[356,4213,4214],{"class":358,"line":500},[356,4215,426],{"emptyLinePlaceholder":425},[356,4217,4218,4220,4222,4224,4226],{"class":358,"line":506},[356,4219,671],{"class":415},[356,4221,3383],{"class":373},[356,4223,677],{"class":419},[356,4225,671],{"class":415},[356,4227,535],{"class":419},[356,4229,4230],{"class":358,"line":511},[356,4231,2759],{"class":419},[356,4233,4234],{"class":358,"line":520},[356,4235,2764],{"class":409},[356,4237,4238,4240,4242,4244,4246,4248],{"class":358,"line":538},[356,4239,2769],{"class":362},[356,4241,2772],{"class":419},[356,4243,1610],{"class":415},[356,4245,2777],{"class":419},[356,4247,2780],{"class":362},[356,4249,2783],{"class":419},[356,4251,4252],{"class":358,"line":543},[356,4253,426],{"emptyLinePlaceholder":425},[356,4255,4256,4258,4260,4262,4264,4266,4268,4270],{"class":358,"line":940},[356,4257,2792],{"class":419},[356,4259,1610],{"class":415},[356,4261,2797],{"class":419},[356,4263,1291],{"class":362},[356,4265,2802],{"class":415},[356,4267,2805],{"class":415},[356,4269,3432],{"class":419},[356,4271,3435],{"class":409},[356,4273,4274,4276,4278,4280],{"class":358,"line":949},[356,4275,2816],{"class":419},[356,4277,1610],{"class":415},[356,4279,3444],{"class":419},[356,4281,3447],{"class":409},[356,4283,4284,4286,4288,4290],{"class":358,"line":954},[356,4285,2829],{"class":419},[356,4287,1610],{"class":415},[356,4289,3456],{"class":419},[356,4291,3459],{"class":409},[356,4293,4294,4296,4298,4300],{"class":358,"line":966},[356,4295,2842],{"class":419},[356,4297,1610],{"class":415},[356,4299,2847],{"class":419},[356,4301,2850],{"class":409},[356,4303,4304,4306,4308,4310],{"class":358,"line":971},[356,4305,2855],{"class":419},[356,4307,1610],{"class":415},[356,4309,2860],{"class":419},[356,4311,2863],{"class":409},[356,4313,4314],{"class":358,"line":976},[356,4315,426],{"emptyLinePlaceholder":425},[356,4317,4318,4320,4322,4324,4326],{"class":358,"line":985},[356,4319,2872],{"class":373},[356,4321,677],{"class":419},[356,4323,2877],{"class":415},[356,4325,2880],{"class":419},[356,4327,2883],{"class":409},[356,4329,4330],{"class":358,"line":990},[356,4331,426],{"emptyLinePlaceholder":425},[356,4333,4334],{"class":358,"line":1002},[356,4335,710],{"class":419},[356,4337,4338],{"class":358,"line":1007},[356,4339,426],{"emptyLinePlaceholder":425},[356,4341,4342],{"class":358,"line":1015},[356,4343,426],{"emptyLinePlaceholder":425},[356,4345,4346],{"class":358,"line":1069},[356,4347,1813],{"class":409},[356,4349,4350,4352,4354],{"class":358,"line":1074},[356,4351,1818],{"class":409},[356,4353,1821],{"class":415},[356,4355,3524],{"class":409},[356,4357,4358,4360,4362],{"class":358,"line":1086},[356,4359,1818],{"class":409},[356,4361,3531],{"class":415},[356,4363,3534],{"class":409},[356,4365,4366,4368,4370,4372],{"class":358,"line":1091},[356,4367,1818],{"class":409},[356,4369,3541],{"class":415},[356,4371,3544],{"class":1789},[356,4373,3547],{"class":409},[356,4375,4376,4378,4380],{"class":358,"line":1103},[356,4377,3552],{"class":409},[356,4379,3555],{"class":415},[356,4381,3558],{"class":409},[356,4383,4384],{"class":358,"line":1108},[356,4385,3563],{"class":409},[356,4387,4388,4390,4392],{"class":358,"line":1117},[356,4389,3552],{"class":409},[356,4391,3555],{"class":415},[356,4393,3572],{"class":409},[356,4395,4396,4398,4400],{"class":358,"line":1129},[356,4397,1818],{"class":409},[356,4399,3579],{"class":415},[356,4401,3582],{"class":409},[356,4403,4404],{"class":358,"line":1134},[356,4405,3587],{"class":409},[356,4407,4408],{"class":358,"line":1155},[356,4409,1829],{"class":409},[356,4411,4412,4414,4416,4418,4420,4422],{"class":358,"line":1167},[356,4413,3596],{"class":415},[356,4415,3599],{"class":373},[356,4417,677],{"class":419},[356,4419,3596],{"class":415},[356,4421,3606],{"class":1789},[356,4423,535],{"class":419},[356,4425,4426],{"class":358,"line":1172},[356,4427,686],{"class":419},[356,4429,4430,4432,4434,4436,4438,4440,4442],{"class":358,"line":1178},[356,4431,3617],{"class":415},[356,4433,3620],{"class":415},[356,4435,3623],{"class":419},[356,4437,1610],{"class":415},[356,4439,2283],{"class":362},[356,4441,3630],{"class":419},[356,4443,3633],{"class":409},[356,4445,4446,4448,4450,4452,4454],{"class":358,"line":1183},[356,4447,3638],{"class":415},[356,4449,3641],{"class":419},[356,4451,1610],{"class":415},[356,4453,1243],{"class":362},[356,4455,1246],{"class":419},[356,4457,4458],{"class":358,"line":1192},[356,4459,426],{"emptyLinePlaceholder":425},[356,4461,4462,4464,4466],{"class":358,"line":1197},[356,4463,3656],{"class":415},[356,4465,3659],{"class":419},[356,4467,3662],{"class":409},[356,4469,4470],{"class":358,"line":1206},[356,4471,2987],{"class":419},[356,4473,4474,4476,4478,4480],{"class":358,"line":1214},[356,4475,3671],{"class":419},[356,4477,1610],{"class":415},[356,4479,2283],{"class":362},[356,4481,1246],{"class":419},[356,4483,4484],{"class":358,"line":1220},[356,4485,3045],{"class":419},[356,4487,4488],{"class":358,"line":1226},[356,4489,426],{"emptyLinePlaceholder":425},[356,4491,4492,4494,4496,4498,4500,4502,4504,4506,4508,4510],{"class":358,"line":1231},[356,4493,3656],{"class":415},[356,4495,3692],{"class":419},[356,4497,3695],{"class":415},[356,4499,2797],{"class":419},[356,4501,2473],{"class":373},[356,4503,3702],{"class":419},[356,4505,3705],{"class":415},[356,4507,1243],{"class":362},[356,4509,3710],{"class":419},[356,4511,3713],{"class":409},[356,4513,4514],{"class":358,"line":1249},[356,4515,2987],{"class":419},[356,4517,4518,4520,4522,4524,4526,4528],{"class":358,"line":1254},[356,4519,3003],{"class":373},[356,4521,677],{"class":419},[356,4523,3726],{"class":362},[356,4525,1325],{"class":415},[356,4527,3013],{"class":419},[356,4529,3733],{"class":409},[356,4531,4532,4534,4536,4538],{"class":358,"line":1267},[356,4533,3671],{"class":419},[356,4535,1610],{"class":415},[356,4537,1243],{"class":362},[356,4539,1246],{"class":419},[356,4541,4542],{"class":358,"line":1272},[356,4543,426],{"emptyLinePlaceholder":425},[356,4545,4546,4548,4550,4552,4554,4556,4558,4560,4562],{"class":358,"line":1277},[356,4547,3752],{"class":415},[356,4549,2797],{"class":419},[356,4551,2473],{"class":373},[356,4553,3702],{"class":419},[356,4555,3705],{"class":415},[356,4557,1243],{"class":362},[356,4559,3765],{"class":419},[356,4561,1610],{"class":415},[356,4563,3770],{"class":419},[356,4565,4566],{"class":358,"line":1282},[356,4567,426],{"emptyLinePlaceholder":425},[356,4569,4570],{"class":358,"line":1297},[356,4571,426],{"emptyLinePlaceholder":425},[356,4573,4574],{"class":358,"line":1306},[356,4575,3045],{"class":419},[356,4577,4578,4580,4582,4584,4586,4588,4590,4592,4594],{"class":358,"line":1311},[356,4579,3787],{"class":415},[356,4581,3790],{"class":415},[356,4583,2797],{"class":419},[356,4585,2473],{"class":373},[356,4587,3702],{"class":419},[356,4589,3705],{"class":415},[356,4591,2283],{"class":362},[356,4593,3803],{"class":419},[356,4595,3806],{"class":409},[356,4597,4598],{"class":358,"line":1319},[356,4599,2987],{"class":419},[356,4601,4602,4604,4606,4608],{"class":358,"line":1337},[356,4603,3671],{"class":419},[356,4605,1610],{"class":415},[356,4607,2283],{"class":362},[356,4609,1246],{"class":419},[356,4611,4612],{"class":358,"line":1342},[356,4613,3045],{"class":419},[356,4615,4617],{"class":358,"line":4616},59,[356,4618,426],{"emptyLinePlaceholder":425},[356,4620,4622,4624,4626],{"class":358,"line":4621},60,[356,4623,2179],{"class":415},[356,4625,3835],{"class":419},[356,4627,3838],{"class":409},[356,4629,4631],{"class":358,"line":4630},61,[356,4632,710],{"class":419},[347,4634,4636],{"className":650,"code":4635,"language":652,"meta":352,"style":352},"#ifndef __KEY_H_\n#define __KEY_H_\n\n//包含ESP32的gpio组件的头文件\n#include \"driver/gpio.h\"\n\n#define BOOT_PRES 1\n\nvoid key_init(void);\n\nuint8_t key_scan(uint8_t mode);\n\n#endif\n",[33,4637,4638,4644,4650,4654,4658,4664,4668,4676,4680,4692,4696,4710,4714],{"__ignoreMap":352},[356,4639,4640,4642],{"class":358,"line":359},[356,4641,2571],{"class":415},[356,4643,3297],{"class":373},[356,4645,4646,4648],{"class":358,"line":370},[356,4647,2579],{"class":415},[356,4649,3297],{"class":373},[356,4651,4652],{"class":358,"line":173},[356,4653,426],{"emptyLinePlaceholder":425},[356,4655,4656],{"class":358,"line":197},[356,4657,2637],{"class":409},[356,4659,4660,4662],{"class":358,"line":434},[356,4661,659],{"class":415},[356,4663,2644],{"class":366},[356,4665,4666],{"class":358,"line":230},[356,4667,426],{"emptyLinePlaceholder":425},[356,4669,4670,4672,4674],{"class":358,"line":260},[356,4671,2579],{"class":415},[356,4673,3328],{"class":373},[356,4675,3331],{"class":362},[356,4677,4678],{"class":358,"line":492},[356,4679,426],{"emptyLinePlaceholder":425},[356,4681,4682,4684,4686,4688,4690],{"class":358,"line":500},[356,4683,671],{"class":415},[356,4685,3383],{"class":373},[356,4687,677],{"class":419},[356,4689,671],{"class":415},[356,4691,705],{"class":419},[356,4693,4694],{"class":358,"line":506},[356,4695,426],{"emptyLinePlaceholder":425},[356,4697,4698,4700,4702,4704,4706,4708],{"class":358,"line":511},[356,4699,3596],{"class":415},[356,4701,3599],{"class":373},[356,4703,677],{"class":419},[356,4705,3596],{"class":415},[356,4707,3606],{"class":1789},[356,4709,705],{"class":419},[356,4711,4712],{"class":358,"line":520},[356,4713,426],{"emptyLinePlaceholder":425},[356,4715,4716],{"class":358,"line":538},[356,4717,1919],{"class":415},[10,4719,4720],{},"Compiled without errors.",[10,4722,4723],{},[39,4724],{"alt":41,"src":4725},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768660585328.webp",[10,4727,4728],{},[39,4729],{"alt":41,"src":4730},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768660637408.webp",[10,4732,4733,4734],{},"You can test it: when the button is pressed, the LED toggles its level.",[735,4735],{},[10,4737,4738,4739,4742,4743,4746,4747],{},"Another testing method is to use debug to monitor the value of ",[33,4740,4741],{},"key_value",", but it requires you to change the button scanning mode to support long presses. In the code above, you only need to modify the ",[33,4744,4745],{},"key_value = key_scan(1);"," line.",[735,4748],{},[10,4750,4751,4752],{},"You can enter debug mode to test it.\nIn the image below, set a breakpoint. Then, when you hold down the button and click \"Continue,\" the monitored value will change to 1. When you release the button and click \"Continue,\" it will change to 0.\n",[39,4753],{"alt":41,"src":4754},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768660931005.webp",[10,4756,4757],{},[39,4758],{"alt":41,"src":4759},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768661121990.webp",[25,4761,4763],{"id":4762},"external-interrupt","External interrupt",[1409,4765,4767],{"id":4766},"introduction-to-interrupts","Introduction to Interrupts",[10,4769,4770,4771,4774,4775,4778,4779,4782,4783,4158,4786,4789],{},"In the previous section, the method of continuously running the key scanning function inside the infinite loop in ",[33,4772,4773],{},"app_main"," is actually called ",[33,4776,4777],{},"轮询",", and this type of function is called ",[33,4780,4781],{},"阻塞式函数",". If you've studied STM32, you definitely know what ",[33,4784,4785],{},"阻塞式",[33,4787,4788],{},"中断式"," are.",[10,4791,4792],{},[39,4793],{"alt":41,"src":4794},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768661633882.webp",[10,4796,4797],{},[39,4798],{"alt":41,"src":4799},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768662329097.webp",[10,4801,4802],{},"What exactly does the interrupt execution process look like? Please refer to the introduction in the link below. You only need to read about the interrupt execution process; everything else is STM32-specific and doesn't need to be reviewed.",[4804,4805,4807],"nuxt-link",{"to":4806},"/wiki/2023-10-09-stm32-freertos-jiao-cheng/ch4-stm32-dan-pian-ji-zhong-dian#中断服务函数的介绍","\nIntroduction to Interrupt Service Functions\n",[1409,4809,4811],{"id":4810},"introduction-to-external-interrupts","Introduction to External Interrupts",[10,4813,4814],{},"From the link above, you'll understand that external interrupt EXIT is just one type of interrupt within IT. In this section, we'll discuss external interrupts in detail.",[10,4816,4817],{},[39,4818],{"alt":41,"src":4819},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768662540872.webp",[10,4821,4822],{},"The ESP32's EXIT has one more level-triggered mode than the STM32.",[10,4824,4825,4826,4828,4829],{},"Level-triggered: High and low level triggering require maintaining the interrupt level state until the CPU responds.",[735,4827],{},"\nEdge-triggered: rising edge and falling edge triggering. Once this type of interrupt is triggered, the CPU can respond immediately.",[735,4830],{},[10,4832,4833],{},"The external interrupt function of the ESP32S3 can capture external event triggers with very high precision. Developers can configure\nSet the interrupt trigger mode (e.g., rising edge, falling edge, any level, low-level hold, high-level hold, etc.) to accommodate different\nExternal events, which immediately interrupt the current program execution when they occur, and instead execute the interrupt service routine.",[1409,4835,4837],{"id":4836},"interrupt-priority","interrupt priority",[10,4839,4840,4841],{},"When multiple interrupts are triggered simultaneously, the CPU executes them in a specific order, handling higher-priority interrupts first and lower-priority ones afterward.",[735,4842],{},[10,4844,4845,4846,4849],{},"ESP32-S3 supports six levels of interrupts and also supports interrupt nesting, meaning a lower-priority interrupt can be preempted by a higher-priority interrupt.\nAs shown in the table below, in the Priority column, ",[16,4847,4848],{},"a larger number indicates a higher priority for that interrupt",". Among them, the NMI interrupt has the highest\nPriority: Once this type of interrupt is triggered, the CPU must handle it.",[10,4851,4852],{},[39,4853],{"alt":41,"src":4854},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768664741979.webp",[10,4856,4857],{},"In the ESP32S3, the interrupt system is used to respond to various internal and external events. These interrupts, based on their trigger method and priority,\nPriorities are classified. The table above lists the interrupt numbers, categories, types, and corresponding priorities for the ESP32S3 in detail. By configuring\nThese interrupts allow developers to achieve timely response and processing of various events, improving system efficiency and real-time performance.",[99,4859,4860,4863,4866,4869],{},[102,4861,4862],{},"Interrupt number: The unique identifier for each interrupt, used to reference and configure a specific interrupt in a program.",[102,4864,4865],{},"Category: Source type of interrupts, divided into external interrupts and internal interrupts. External interrupts are triggered by external devices or signals.\nsuch as buttons and sensors; internal interrupts are triggered by hardware events inside the microcontroller, such as timer overflows and software interrupts.",[102,4867,4868],{},"Types: Interrupt trigger methods include level-triggered and edge-triggered. Level-triggered occurs when the input signal reaches a specific\nInterrupts are triggered by signal levels (such as high or low levels); edge triggering occurs when the input signal changes from one level state to another.\nAn interrupt is triggered when in a certain state.",[102,4870,4871],{},"Priority: Interrupt response priority. When multiple interrupts occur simultaneously, the microcontroller prioritizes them based on their interrupt priority.\nto determine which interrupt to handle first. A higher priority means the interrupt will be processed first.\nDuring development, developers can configure interrupt trigger modes, priorities, and other parameters based on actual needs to achieve high\nEfficient and reliable event handling mechanism.",[1409,4873,4875],{"id":4874},"external-interrupt-in-practice","External Interrupt in Practice",[10,4877,4878],{},[39,4879],{"alt":41,"src":4880},"https://cdn.tungchiahui.cn/tungwebsite/assets/images/2026/01/07/1768664939827.webp",[4882,4883,4884],"style",{},"html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":352,"searchDepth":370,"depth":370,"links":4886},[4887,4888,4889,4890,4891,4892],{"id":22,"depth":173,"text":23},{"id":279,"depth":173,"text":280},{"id":306,"depth":173,"text":307},{"id":639,"depth":173,"text":640},{"id":1663,"depth":173,"text":1664},{"id":1706,"depth":173,"text":1707},"/en-us/wiki/2026-01-07-esp32-jiao-cheng/ch4-jiao-cheng","4",4000000,"2026-01-07","wiki/2026-01-07-esp32-jiao-cheng","en-us:2026-01-07-esp32-jiao-cheng","/en-us/wiki/2026-01-07-esp32-jiao-cheng","ESP32教程","md","wiki/2026-01-07-ESP32教程/ch4-教程",false,null,"en-US","en-us",{},{"title":5,"description":12},"/wiki/2026-01-07-esp32-jiao-cheng/ch4-jiao-cheng","_i18n/en-us/wiki/2026-01-07-ESP32教程/ch4-教程","9wye9fxJX7FOBoftdkUgSgW_bChxBAyQZvO6fDgeC2E",[4913,4918,4924,4930,4931],{"path":4914,"stem":4915,"title":4916,"date":4896,"chapter":1291,"chapterSort":4917,"docKey":4898,"docRoot":4899,"docTitle":4900,"isWikiDoc":425,"isWikiIndex":4903},"/en-us/wiki/2026-01-07-esp32-jiao-cheng/ch1-jian-jie","_i18n/en-us/wiki/2026-01-07-ESP32教程/ch1-简介","Introduction",1000000,{"path":4919,"stem":4920,"title":4921,"date":4896,"chapter":4922,"chapterSort":4923,"docKey":4898,"docRoot":4899,"docTitle":4900,"isWikiDoc":425,"isWikiIndex":4903},"/en-us/wiki/2026-01-07-esp32-jiao-cheng/ch2-esp32-huan-jing-da-jian","_i18n/en-us/wiki/2026-01-07-ESP32教程/ch2-ESP32环境搭建","ESP32 environment setup","2",2000000,{"path":4925,"stem":4926,"title":4927,"date":4896,"chapter":4928,"chapterSort":4929,"docKey":4898,"docRoot":4899,"docTitle":4900,"isWikiDoc":425,"isWikiIndex":4903},"/en-us/wiki/2026-01-07-esp32-jiao-cheng/ch3-can-kao-shi-pin","_i18n/en-us/wiki/2026-01-07-ESP32教程/ch3-参考视频","Reference video","3",3000000,{"path":4893,"stem":4910,"title":5,"date":4896,"chapter":4894,"chapterSort":4895,"docKey":4898,"docRoot":4899,"docTitle":4900,"isWikiDoc":425,"isWikiIndex":4903},{"path":4899,"stem":4932,"title":4933,"date":4896,"chapter":4904,"chapterSort":4934,"docKey":4898,"docRoot":4899,"docTitle":4900,"isWikiDoc":425,"isWikiIndex":425},"_i18n/en-us/wiki/2026-01-07-ESP32教程/index","ESP32 tutorial",0,{"variants":4936},[4937,4938,4941,4944,4947],{"path":4893,"localeSlug":4906,"i18nKey":4902},{"path":4939,"localeSlug":4940,"i18nKey":4902},"/zh-hant/wiki/2026-01-07-esp32-jiao-cheng/ch4-jiao-cheng","zh-hant",{"path":4942,"localeSlug":4943,"i18nKey":4902},"/zh-hk/wiki/2026-01-07-esp32-jiao-cheng/ch4-jiao-cheng","zh-hk",{"path":4945,"localeSlug":4946,"i18nKey":4902},"/zh-tw/wiki/2026-01-07-esp32-jiao-cheng/ch4-jiao-cheng","zh-tw",{"path":4948,"localeSlug":4949,"i18nKey":4902},"/zh-cn/wiki/2026-01-07-esp32-jiao-cheng/ch4-jiao-cheng","zh-cn",[4893,4909,4939,4909,4942,4909,4945,4909,4948,4909],1780663021281]