在Beetle ESP32 C6迷你开发板实现消息队列通讯
<div class='showpostmsg'> 本帖最后由 aramy 于 2024-7-31 09:42 编辑<p style="text-align: center;"> </p>
<p>Beetle ESP32 C6迷你开发板搭载了160MHz的高性能RISC-V 32位处理器。如果使用单任务处理问题,大多数时间都会浪费在各类传感器和外设的等待上,为了更好地利用处理器,引入了操作系统,可以让用户使用多任务处理问题,提升了处理器的利用率。ESP32 C6中使用了FreeRTOS操作系统。用户可以在FreeRTOS操作系统创建多个任务去处理不同的问题。这里实现了在FreeRTOS操作系统上创建两个任务,两个任务之间使用消息队列进行通讯的功能。</p>
<p style="text-align: center;"> </p>
<p><strong>需求描述</strong>:通过Beetle ESP32 C6开发板上的按键,控制板载的LED灯的亮灭。需求很简单,但是是使用两个任务来实现的。</p>
<p>任务1:LED控制任务,负责控制LED灯的亮灭。任务阻塞在读取消息队列上,当读取到消息时,通过消息内容进行判断。当消息内容为0时,关闭LED灯,为1时,点亮LED灯。</p>
<p>任务2:按键读取任务。负责读取按键值。设置一个状态位,当按键按下时,就取反状态位的值,然后将状态位封装进消息队列,丢到消息队列中发送出去。</p>
<p><strong>具体实现:</strong>实习使用了esp-idf编程。这里我使用的esp-idf版本是5.1.2。使用vscode作为编辑器。使用官方例程blink作为项目基础进行修改。</p>
<p style="text-align: center;"></p>
<p>第一步:先修改芯片类型,将芯片类型修改为esp32c6,然后修改串口号,选中Beetle ESP32 C6迷你开发板插入电脑后分配的串口号。参考开发板的电路图定义好LED的管脚和按键的管脚。</p>
<pre>
<code>#define LED1_IO 15
#define BUTTON_PIN 9</code></pre>
<p>第二步:定义多个任务。</p>
<pre>
<code>void buttontask(void *arg)
{
gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT);
gpio_set_pull_mode(BUTTON_PIN, GPIO_PULLUP_ONLY);
char s_led_state;
while (1)
{
if (gpio_get_level(BUTTON_PIN) == 0)
{
xQueueSend(queue1, &s_led_state, portMAX_DELAY);
s_led_state = !s_led_state;
ESP_LOGI(TAG, "Button Pressed!\n");
}
vTaskDelay(200 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL); // 在本函数中删除,不需要传递句柄
}
void ledBlinkTask(void *pvParam)
{
char led_state;
gpio_set_direction(LED1_IO, GPIO_MODE_OUTPUT);
while (1)
{
if (xQueueReceive(queue1, &led_state, portMAX_DELAY))
{
gpio_set_level(LED1_IO, led_state);
ESP_LOGI(TAG, "Get mesage %d!",led_state);
}
}
vTaskDelete(NULL); // 在本函数中删除,不需要传递句柄
}</code></pre>
<p>这里定义了两个任务。一个是用来接收按键的任务,一个是用来控制LED的任务。可以看出任务首先对GPIO进行初始化,设置GPIO方向为为输入或输出。然后就是一个死循环,任务将在这个循环内一直执行,直至退出或被杀死。在按键任务中定义了一个s_led_state的变量,当检测到按键有按下后,就将这个变量发送到消息队列中。然后将s_led_state取反。在led控制任务中,任务会阻塞在接收消息队列位置,当消息队列中有消息了,就取出消息,并修改LED灯的状态。</p>
<p>第三步:启动任务。</p>
<pre>
<code>void app_main(void)
{
queue1 = xQueueCreate(5, sizeof(char));
xTaskCreate(ledBlinkTask, "ledBlinkTask", 2048, NULL, 1, NULL); // 传出任务句柄
xTaskCreate(buttontask, "buttontask", 2048, NULL, 1, NULL);
while (1)
{
vTaskDelay(10000 / portTICK_PERIOD_MS);
}
}</code></pre>
<p>在main方法中首先是定义了一个消息队列,这里消息队列的最大容量为5,意味着最多可以容纳5个消息。当消息队列中消息数量等于5时,就无法在容纳新的消息了。消息队列使用了一个全局变量名称,这样在所有的任务中都能直接通过变量名访问到这个消息队列了。然后是启动子任务。主函数自身也是一个任务,但是这个任务没有做任何功能。</p>
<p>第四步:效果展示.。通过vscode编译,然后烧录。按板子右下角的按键即可控制LED灯的亮灭。</p>
<p style="text-align: center;"> </p>
<p style="text-align: center;"> </p>
<p style="text-align: center;">90829fbfa5d3f38bf08dfb754c1a024c<br />
</p>
<div></div>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> 点赞 <p>消息队列是RTOS比较常用的一个功能。</p>
页:
[1]