目次
序文
4 月 22 日(土)、早起きして「2023 RT-Thread Offline Training」に参加するという期待に胸を膨らませて Ariva Hotel Beijing にやってきました。これは、3 年前の流行以来、Open Atom が北京で開催した最初のオフライン イベントです。
会場に入るとビックリ、暑すぎて、白髪のおじいさん、職場のプロ、大学生、6歳のエンジニアなどでいっぱいでした。サイトはよく準備されており、各テーブルには学生がコンピューターを使用するためのプラグイン ストリップが備わっていました。各テーブルには開発ボードが装備されており、誰もが確実に実行できるようになっています。
RTスレッドの紹介
RT-Thread は、最大のインストール容量 (20 億ユニット以上)、最大数の開発者 (150,000 以上)、および最高のソフトウェアとハードウェアのエコロジーを備えた、市場に出ている組み込みオペレーティング システムの 1 つになりました。RT-Thread はマルチスレッドをサポートしており、従来のベアメタル シリアル メソッドやフロントおよびバック割り込みメソッドよりもはるかに効率的です。技術の進化という点では、さまざまなチップ製品について、標準バージョン、Nano バージョン、Smart バージョン (ハイブリッド マイクロカーネル、アプリケーションとカーネルの分離) を含む、RT-Thread の基盤となるコア プラットフォームを使用して一連の差別化されたプラットフォームが構築されています。コンシューマ IoT からインダストリアル IoT まで、さまざまなシーンでご利用いただけます。
RT-Thread Nano リアルタイム オペレーティング システムは、Apache ライセンス バージョン 2.0 に準拠しています. リアルタイム オペレーティング システム カーネルとすべてのオープン ソース コンポーネントは、商用製品で無料で使用できます, アプリケーションのソース コードを公開する必要はありません.商業上のリスク。
rtthread-nano atomGit ソース ウェアハウス
https://atomgit.com/OpenAtomFoundation/rtthread-nano
開発環境を構築する
イベントWeChatグループで提供された資料によると、公式ドキュメントtrain-note・AtomGit_Open Atom Open Source Foundation Code Hosting Platform に従って、全員が事前に 開発環境のダウンロード準備を完了しています。
お昼の1時間の休憩の後、近くの喫茶店でコーヒーを飲み、午後からは元気いっぱい体験講座に参加しました。
実験手順
1. LED使用例
LED ライトは 500ms 間隔で点滅します。コードは次のとおりです。
#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. 鍵の使用例
開発ボードの電源を入れると、ボタンを押すたびに、シリアル ポート ターミナルから RT-Thread! という言葉が出力されます。コードは次のとおりです。
#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.自動実行の例
開発ボードの電源を入れると、ターミナルにexport_app RT-Thread が表示されます。コードは次のとおりです。
#include <rtthread.h>
int export_app(void)
{
rt_kprintf("export_app RT-Thread!\r\n");
return 0;
}
INIT_APP_EXPORT(export_app);
4. msh コマンドのカスタマイズ
ターミナルに hello と入力して Enter キーを押すと、hello RT-Thread! という単語が出力されます。コードは次のとおりです。
void hello(void)
{
rt_kprintf("hello RT-Thread!\n");
}
MSH_CMD_EXPORT(hello , say hello to RT-Thread);
ターミナルで Tab キーを押すと、コマンド リストに hello が表示されることがわかります。hello と入力して、 hello RT-Thread!を出力します。
5. マルチスレッドの例
スレッド 1: 500 ミリ秒ごとの印刷カウント
スレッド 2: 10 カウントを印刷した後、印刷を終了して終了する
この例では、動的スレッドを作成し、静的スレッドを初期化します。一方のスレッドは実行後にシステムによって自動的に削除され、もう一方のスレッドはカウントを出力し続けます。コードは次のとおりです:
#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. タイマーの例
タイマー 1: 定期的なタイマー、10 回後に停止します。
タイマー2:ワンショットタイマー
このルーチンは、2 つの動的タイマーを作成します。1 つは単一のタイミングで、もう 1 つは定期的なタイミングで、定期的なタイマーを一定期間実行してから停止します。コードは以下のように表示されます:
#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. メッセージキューの例
スレッド 1: メッセージを受信し、20 回後に受信を停止し、最後にメッセージ キューを削除します。
スレッド 2: メッセージを送信し、8 回目の緊急メッセージを送信し、20 回後に終了します。
これはメッセージ キューのアプリケーション ルーチンです. 2 つの静的スレッドがルーチンで初期化されます. 1 つのスレッドはメッセージ キューからメッセージを受け取ります. もう 1 つのスレッドは通常のメッセージと緊急メッセージをメッセージ キューに定期的に送信します. コードは次のとおりです. :
#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. モールス符号の使用
現在、モールス信号はソフトウェア パッケージにパッケージ化されており、モールス ソフトウェア パッケージを直接選択してモールス信号を体験できます。
パッケージの構成は次のとおりです。
samples\key\morse-key-example.c ファイルを開き、USER_KEY マクロに対応するピンを開発ボードのキーにマッピングします。
コンパイルして開発ボードに焼き付けて実行することができ、モールス符号の規則に従ってボタンを押すだけで、対応する文字がシリアルポート端末に表示されます。
PKG_USING_MORSE_SHELL が有効な場合、Enter に対応するモールス符号を入力して、入力したコマンドを実行します。
実験の概要
このような体験学習キャンプに参加するのは初めてで、とてもうれしく思いました. とても良い経験でした. 先生は教育環境を整え、例を説明し、自分でそれを行い、授業で質問に答えました.放課後の課題の宿題を手配しました。それぞれの実験が成功した瞬間は、大学の教室に戻ったような達成感があります。
この研究を通じて、なじみのない分野の研究と応用を完了しただけでなく、モノのインターネットのアプリケーション開発ツールについて新たな理解を得ることができ、さまざまなライブラリ機能を簡単に導入できる RT-Thread Studio の便利さを身をもって体験しました。 、実際にはさまざまな基礎となる依存関係に対するワンストップ ソリューションです。
オーガナイザーのおかげで、次の高度なトレーニングを楽しみにしています!