我是靠谱客的博主 糊涂大山,这篇文章主要介绍从0学起的esp-idf之旅——外设篇gpio前言官方例程详细注释吐槽解析官方例子总结相关官方资料链接,现在分享给大家,希望可以做个参考。

前言

闲来无事,再开一坑,说是说从零学起,实际上就是分析官方例子。顺便帮助大家总结一波,在此分析一下,不要拿我的博文作为自己的学习esp-idf的”教参“。

官方例程详细注释

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <stdio.h> #include <string.h> #include <stdlib.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "driver/gpio.h" /** * 摘要: * 此代码展示了如何配置 gpio 以及如何使用 gpio 中断。 * * GPIO 状态: * GPIO18: 推挽输出 * GPIO19: 推挽输出 * GPIO4: 上拉输入, 上升沿和下降沿中断 * GPIO5: 上拉输入, 下降沿中断 * * 实验操作: * GPIO18 连接到 GPIO4 * GPIO19 连接到 GPIO5 * 利用GPIO18/19产生信号,触发GPIO4/5上的中断 * */ #define GPIO_OUTPUT_IO_0 18 #define GPIO_OUTPUT_IO_1 19 #define GPIO_OUTPUT_PIN_SEL ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1)) #define GPIO_INPUT_IO_0 4 #define GPIO_INPUT_IO_1 5 #define GPIO_INPUT_PIN_SEL ((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1)) #define ESP_INTR_FLAG_DEFAULT 0 static xQueueHandle gpio_evt_queue = NULL; // 设置消息队列,用于传递中断的信息 // 真正的中断服务函数,这里只干一件事,通过队列把中断信息打包发送出去 static void IRAM_ATTR gpio_isr_handler(void* arg) { uint32_t gpio_num = (uint32_t) arg; xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL); // 中断专属发送信息给队列的函数 } // 实际起作用的gpio中断处理函数,一直等待中断发送信息然后到这里处理信息 static void gpio_task_example(void* arg) { uint32_t io_num; for(;;) { if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) // 堵塞等待中断给信息 { // 打印信息,中断实际上的处理在这里进行 printf("GPIO[%d] intr, val: %dn", io_num, gpio_get_level(io_num)); } } } void app_main(void) { gpio_config_t io_conf1 = { .intr_type = GPIO_INTR_DISABLE, //不启用gpio中断 .mode = GPIO_MODE_OUTPUT,//推挽输出模式 .pin_bit_mask = GPIO_OUTPUT_PIN_SEL,//设置goio,可以同时设置多个 .pull_down_en = 0,// 不下拉 .pull_up_en = 0,// 不上拉 }; gpio_config(&io_conf1); gpio_config_t io_conf2 = { .intr_type = GPIO_INTR_POSEDGE, //启用上升沿中断 .mode = GPIO_MODE_INPUT,//输入模式 .pin_bit_mask = GPIO_INPUT_PIN_SEL,//设置goio,可以同时设置多个 .pull_down_en = 0,// 不下拉 .pull_up_en = 1,// 上拉 }; gpio_config(&io_conf2); //改变gpio中断模式为任意边沿中断(上升沿和下降沿中断) gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE); //创建用于传递中断信息的消息队列 gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t)); //开始gpio中断处理线程 xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL); //安装gpio中断驱动(参数为优先级) gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); //给指定的gpio绑定中断服务函数 gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void*) GPIO_INPUT_IO_0); gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler, (void*) GPIO_INPUT_IO_1); // 打印内存使用情况 printf("Minimum free heap size: %d bytesn", esp_get_minimum_free_heap_size()); int cnt = 0; while(1) { printf("cnt: %dn", cnt++); vTaskDelay(1000 / portTICK_RATE_MS); gpio_set_level(GPIO_OUTPUT_IO_0, cnt % 2); // 设置gpio电平 gpio_set_level(GPIO_OUTPUT_IO_1, cnt % 2); } }

吐槽

本例程总的来说还不错,只不过官方为了尽可能的展示自己的api在绑定好gpio的中断服务函数后,多此一举的remove掉了,然后再次绑定。
官方源码迷惑行为
这里我删掉了这个迷惑行为。还有就是为了大家看起来简洁,我直接使用结构体声明的时候赋值。其余的部分均参照官方例子

解析官方例子

实际上,这个最简单的代码,在没有接触过嵌入式系统的人来说会有点迷惑。我们如果玩裸机编程玩惯了,下意识的情况会选择去直接写中断服务函数。实际上,中断服务函数的作用是再外界的信号来的时候,打断你手头做的事情,去执行它的服务函数,如果该函数的时间很长,则会导致整个程序的其它东西被耽搁。而我们通过全局变量将变量保存后,丢个主循环去处理,则会导致处理的不够及时,整个系统的实时性会变得很差。于是乎,上了嵌入式系统后,我们就结合二者的情况,专门创建一个线程去做。当我们的中断来临的时候,把中断信息打包好,然后交给中断处理的线程去处理这个信息。由于线程之间的并发性,所以不会去耽搁别的线程,这个是不同于裸机的中断编程思维。

总结

gpio总结脑图

相关官方资料链接

gpio例程:https://github.com/espressif/esp-idf/tree/master/examples/peripherals/gpio/generic_gpio
gpio相关api:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/peripherals/gpio.html
freertos相关链接:https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/api-reference/system/freertos.html

最后

以上就是糊涂大山最近收集整理的关于从0学起的esp-idf之旅——外设篇gpio前言官方例程详细注释吐槽解析官方例子总结相关官方资料链接的全部内容,更多相关从0学起内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(74)

评论列表共有 0 条评论

立即
投稿
返回
顶部