Open Atom Training Camp (Second Season) RT-Thread Nano Learning Camp Liu Yukuan

Table of contents

foreword

Introduction to RT-Thread

Build a development environment

experiment procedure

1. LED usage example

2. Examples of key usage

3. Examples of automated execution

4. Customize msh command

5. Multi-threaded example 

6. Timer example 

7. Message queue example 

8. Use of Morse code

Experiment summary


foreword

        On Saturday, April 22, I got up early and came to Ariva Hotel Beijing full of expectations to participate in the "2023 RT-Thread Offline Training". This is the first offline event organized by Open Atom in Beijing since the outbreak three years ago.

        When I entered the meeting place, I was shocked, it was so hot——the room was full of people, including gray-haired old people, professionals in the workplace, college students, and a 6-year-old engineer. The site was well prepared, and each table was equipped with plug-in strips for students to use computers. Each table is equipped with a development board to ensure that everyone can do it.

 

       

Introduction to RT-Thread

        RT-Thread has become one of the embedded operating systems on the market with the largest installed capacity (over 2 billion units), the largest number of developers (over 150,000), and the best software and hardware ecology. RT-Thread supports multi-threading, which is much more efficient than traditional bare-metal serial methods and front and back interrupt methods. In terms of technology evolution, for different chip products, a series of differentiated platforms have been built with the underlying core platform of RT-Thread, including standard version, Nano version, Smart version (hybrid microkernel, separation of application and kernel), which can be applied to Various scenarios of consumer IoT and industrial IoT.

        RT-Thread Nano real-time operating system complies with the Apache license version 2.0. The real-time operating system kernel and all open source components can be used in commercial products for free, without publishing the source code of the application, and without potential commercial risks.

       rtthread-nano atomGit source warehouse
https://atomgit.com/OpenAtomFoundation/rtthread-nano

Build a development environment

  According to the documents provided in the event WeChat group, everyone has completed the download preparation of the development environment          in advance according to the official document train-note · AtomGit_Open Atom Open Source Foundation Code Hosting Platform .


        After an hour's break at noon, I drank a cup of coffee in the nearby coffee shop, and then participated in the hands-on course in the afternoon full of energy.


experiment procedure

1. LED usage example

The LED light flashes at intervals of 500ms , the code is as follows:

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

/* defined the LED0 pin: PA5 */
#define USER_LED_PIN               GET_PIN(A, 5)

int main(void)
{
    int count = 1;
    /* set LED0 pin mode to output */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);

    while (count++)
    {
        rt_pin_write(LED0_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED0_PIN, PIN_LOW);
        rt_thread_mdelay(500);
    }
    return RT_EOK;
}

2. Examples of key usage

Power on the development board, every time you press a button, the serial port terminal will output the words RT-Thread!, the code is as follows:

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#define USER_KEY GET_PIN(C, 13) 

void irq_callback()
{
    rt_kprintf("RT-Thread!\r\n");
}

int main(void)
{
    rt_pin_mode(USER_KEY, PIN_MODE_INPUT_PULLUP);
    rt_pin_attach_irq(USER_KEY, PIN_IRQ_MODE_RISING_FALLING, irq_callback, RT_NULL);
    rt_pin_irq_enable(USER_KEY, PIN_IRQ_ENABLE);
    return 0;
}

3. Examples of automated execution

Power on the development board and you will see export_app RT-Thread  printed on the terminal , the code is as follows:

#include <rtthread.h>

int export_app(void)
{
    rt_kprintf("export_app RT-Thread!\r\n");
    return 0;
}
INIT_APP_EXPORT(export_app);

4. Customize msh command

Enter hello in the terminal and press Enter, the words hello RT-Thread! will be printed , the code is as follows:

void hello(void)
{
    rt_kprintf("hello RT-Thread!\n");
}

MSH_CMD_EXPORT(hello , say hello to RT-Thread);

Press the Tab key in the terminal, and you can see that hello appears in the command list. Enter hello to print out hello RT-Thread!

5. Multi-threaded example 

Thread 1: print count every 500ms

Thread 2: After printing 10 counts, print exits and exit

This example creates a dynamic thread and initializes a static thread. One thread is automatically deleted by the system after running, and the other thread keeps printing the count. The code is as follows:

#include <rtthread.h>

#define THREAD_PRIORITY         25
#define THREAD_STACK_SIZE       512
#define THREAD_TIMESLICE        5

static rt_thread_t tid1 = RT_NULL;

/* 线程 1 的入口函数 */
static void thread1_entry(void *parameter)
{
    rt_uint32_t count = 0;

    while (1)
    {
        /* 线程 1 采用低优先级运行,一直打印计数值 */
        rt_kprintf("thread1 count: %d\n", count ++);
        rt_thread_mdelay(500);
    }
}

ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
/* 线程 2 入口 */
static void thread2_entry(void *param)
{
    rt_uint32_t count = 0;

    /* 线程 2 拥有较高的优先级,以抢占线程 1 而获得执行 */
    for (count = 0; count < 10 ; count++)
    {
        /* 线程 2 打印计数值 */
        rt_kprintf("thread2 count: %d\n", count);
    }
    rt_kprintf("thread2 exit\n");
    /* 线程 2 运行结束后也将自动被系统脱离 */
}

/* 线程示例 */
int thread_sample(void)
{
    /* 创建线程 1,名称是 thread1,入口是 thread1_entry*/
    tid1 = rt_thread_create("thread1",
                            thread1_entry, RT_NULL,
                            THREAD_STACK_SIZE,
                            THREAD_PRIORITY, THREAD_TIMESLICE);

    /* 如果获得线程控制块,启动这个线程 */
    if (tid1 != RT_NULL)
    rt_thread_startup(tid1);

    /* 初始化线程 2,名称是 thread2,入口是 thread2_entry */
    rt_thread_init(&thread2,
                    "thread2",
                    thread2_entry,
                    RT_NULL,
                    &thread2_stack[0],
                    sizeof(thread2_stack),
                    THREAD_PRIORITY - 1, THREAD_TIMESLICE);
    rt_thread_startup(&thread2);

    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(thread_sample, thread sample);

6. Timer example 

Timer 1: Periodic timer, let it stop after 10 times

Timer 2: One-shot timer

This routine will create two dynamic timers, one is single timing, the other is periodic timing and let the periodic timer run for a period of time and then stop running. code show as below:

#include <rtthread.h>

/* 定时器的控制块 */
static rt_timer_t timer1;
static rt_timer_t timer2;
static int cnt = 0;

/* 定时器 1 超时函数 */
static void timeout1(void *parameter)
{
    rt_kprintf("periodic timer is timeout %d\n", cnt);

    /* 运行第 10 次,停止周期定时器 */
    if (cnt++ >= 9)
    {
        rt_timer_stop(timer1);
        rt_kprintf("periodic timer was stopped! \n");
    }
}

/* 定时器 2 超时函数 */
static void timeout2(void *parameter)
{
    rt_kprintf("one shot timer is timeout\n");
}

int timer_sample(void)
{
    /* 创建定时器 1  周期定时器 */
    timer1 = rt_timer_create("timer1", timeout1,
                             RT_NULL, 10,
                             RT_TIMER_FLAG_PERIODIC);

    /* 启动定时器 1 */
    if (timer1 != RT_NULL)
        rt_timer_start(timer1);

    /* 创建定时器 2 单次定时器 */
    timer2 = rt_timer_create("timer2", timeout2,
                             RT_NULL, 30,
                             RT_TIMER_FLAG_ONE_SHOT);

    /* 启动定时器 2 */
    if (timer2 != RT_NULL)
        rt_timer_start(timer2);
    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(timer_sample, timer sample);

7. Message queue example 

Thread 1: Receive messages, stop receiving them after 20 times, and finally delete the message queue.

Thread 2: Send a message, send an urgent message for the 8th time, and exit after 20 times.

This is an application routine of a message queue. Two static threads are initialized in the routine. One thread will receive messages from the message queue; the other thread will regularly send ordinary messages and emergency messages to the message queue. The code is as follows:

#include <rtthread.h>

/* 消息队列控制块 */
static struct rt_messagequeue mq;
/* 消息队列中用到的放置消息的内存池 */
static rt_uint8_t msg_pool[2048];

ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread1;
/* 线程 1 入口函数 */
static void thread1_entry(void *parameter)
{
    char buf = 0;
    rt_uint8_t cnt = 0;

    while (1)
    {
        /* 从消息队列中接收消息 */
        if (rt_mq_recv(&mq, &buf, sizeof(buf), RT_WAITING_FOREVER) == RT_EOK)
        {
            rt_kprintf("thread1: recv msg from msg queue, the content:%c\n", buf);
            if (cnt == 19)
            {
                break;
            }
        }
        /* 延时 50ms */
        cnt++;
        rt_thread_mdelay(50);
    }
    rt_kprintf("thread1: detach mq \n");
    rt_mq_detach(&mq);
}

ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
/* 线程 2 入口 */
static void thread2_entry(void *parameter)
{
    int result;
    char buf = 'A';
    rt_uint8_t cnt = 0;

    while (1)
    {
        if (cnt == 8)
        {
            /* 发送紧急消息到消息队列中 */
            result = rt_mq_urgent(&mq, &buf, 1);
            if (result != RT_EOK)
            {
                rt_kprintf("rt_mq_urgent ERR\n");
            }
            else
            {
                rt_kprintf("thread2: send urgent message - %c\n", buf);
            }
        }
        else if (cnt >= 20) /* 发送 20 次消息之后退出 */
        {
            rt_kprintf("message queue stop send, thread2 quit\n");
            break;
        }
        else
        {
            /* 发送消息到消息队列中 */
            result = rt_mq_send(&mq, &buf, 1);
            if (result != RT_EOK)
            {
                rt_kprintf("rt_mq_send ERR\n");
            }

            rt_kprintf("thread2: send message - %c\n", buf);
        }
        buf++;
        cnt++;
        /* 延时 5ms */
        rt_thread_mdelay(5);
    }
}

/* 消息队列示例的初始化 */
int msgq_sample(void)
{
    rt_err_t result;

    /* 初始化消息队列 */
    result = rt_mq_init(
        &mq,
        "mqt",
        &msg_pool[0],     /* 内存池指向 msg_pool */
        1,                /* 每个消息的大小是 1 字节 */
        sizeof(msg_pool), /* 内存池的大小是 msg_pool 的大小 */
        RT_IPC_FLAG_PRIO  /* 如果有多个线程等待,优先级大小的方法分配消息 */
    );

    if (result != RT_EOK)
    {
        rt_kprintf("init message queue failed.\n");
        return -1;
    }

    rt_thread_init(&thread1,
                   "thread1",
                   thread1_entry,
                   RT_NULL,
                   &thread1_stack[0],
                   sizeof(thread1_stack), 25, 5);
    rt_thread_startup(&thread1);

    rt_thread_init(&thread2,
                   "thread2",
                   thread2_entry,
                   RT_NULL,
                   &thread2_stack[0],
                   sizeof(thread2_stack), 25, 5);
    rt_thread_startup(&thread2);

    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(msgq_sample, msgq sample);

8. Use of Morse code

Morse code has been packaged into a software package at present, you can directly select the morse software package to experience Morse code

The configuration of the package is as follows:

Open the samples\key\morse-key-example.c file, and map the pins corresponding to the USER_KEY macro to the keys of the development board

It can be compiled and burned into the development board to run. You only need to press the button according to the rules of Morse code, and the corresponding characters will be displayed on the serial port terminal.

When PKG_USING_MORSE_SHELL is enabled, enter the Morse code corresponding to Enter to execute the entered command

Experiment summary

        It was the first time to participate in this kind of hands-on learning camp, and I felt very happy. It was a very good experience. The teacher set up the teaching environment, explained examples, did it yourself, answered questions in class, and arranged after-school challenge homework. The moment each experiment is successful, there is a sense of accomplishment, as if returning to the university classroom.

        Through this study, I not only completed the study and application of an unfamiliar field, but also gained a new understanding of the Internet of Things application development tools, and personally experienced the convenience of RT-Thread Studio, which can easily introduce various library functions , is really a one-stop solution to various underlying dependencies.

Thanks to the organizers, looking forward to the next advanced training!

Guess you like

Origin blog.csdn.net/liuyukuan/article/details/130332618