この記事では、[WildfireEmbedFire]「RTスレッドカーネルの実装とアプリケーション開発-STM32に基づく」について説明します。これは個人的な学習ノートとしてのみ使用されます。詳細な内容と手順については、元のテキストを確認してください(Wildfire Data Download Centerからダウンロードできます)。
ハードウェアの初期化
この記事ではLED点滅用のスレッドを作成するため、最初にLEDのハードウェア構成を行う必要があります。使用する開発ボードはPunctual Atomic STM32F103ZET6コアボードで、それぞれPB5とPE5に対応する2つのLEDがあります。bspファイルLEDのは次のとおりです:
bsp_led。h
#ifndef __BSP_LED_H
#define __BSP_LED_H
#include "stm32f10x.h"
#define LED0_GPIO_PIN GPIO_Pin_5
#define LED0_GPIO_PORT GPIOB
#define LED0_GPIO_CLK RCC_APB2Periph_GPIOB
#define LED1_GPIO_PIN GPIO_Pin_5
#define LED1_GPIO_PORT GPIOE
#define LED1_GPIO_CLK RCC_APB2Periph_GPIOE
#define ON 1
#define OFF 0
// \ C语言里面叫续行符,后面不能有任何的东西
#define LED0(a) if(a) \
GPIO_ResetBits(LED0_GPIO_PORT, LED0_GPIO_PIN); \
else GPIO_SetBits(LED0_GPIO_PORT, LED0_GPIO_PIN);
#define LED1(a) if(a) \
GPIO_ResetBits(LED1_GPIO_PORT, LED1_GPIO_PIN); \
else GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
// ^ 异或,C语言的一个二进制的运算符
// 与1异或改变,与0异或不变
#define LED0_TOGGLE {LED0_GPIO_PORT->ODR ^= LED0_GPIO_PIN;}
#define LED1_TOGGLE {LED1_GPIO_PORT->ODR ^= LED1_GPIO_PIN;}
void LED_GPIO_Config(void);
#endif /* __BSP_LED_H */
bsp_led.c
// bsp :board support package 板级支持包
#include "bsp_led.h"
void LED_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(LED0_GPIO_CLK, ENABLE);
RCC_APB2PeriphClockCmd(LED1_GPIO_CLK, ENABLE);
// LED0
GPIO_InitStruct.GPIO_Pin = LED0_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED0_GPIO_PORT, &GPIO_InitStruct);
// 默认拉高
GPIO_SetBits(LED0_GPIO_PORT, LED0_GPIO_PIN);
// LED1
GPIO_InitStruct.GPIO_Pin = LED1_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStruct);
// 默认拉高
GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
}
ledの基礎となるドライバーを記述した後、それは関数に追加さLED_GPIO_Config()
れます。board.c
rt_hw_board_init()
void rt_hw_board_init(void)
{
#if 0
/* TODO: OS Tick Configuration */
_SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
#endif
/* 初始化 SysTick */
SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
/* 硬件 BSP 初始化统统放在这里,比如 LED,串口,LCD 等 */
// LED初始化
LED_GPIO_Config();
// 测试
//LED0(1);
//LED1(1);
/* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}
スレッドスタックを定義する
今回作成したスレッドは静的スレッドであるため、独自のスタックスペースがあります。
// 线程栈需要 RT_ALIGN_SIZE 个字节对齐
ALIGN(RT_ALIGN_SIZE)
// 定义线程栈
static rt_uint8_t rt_led0_thread_stack[1024];
ほとんどのシステムでは、スタックスペースアドレスのアラインメントが必要であり、ARMアーキテクチャでは、4バイトアドレスにアラインメントする必要があります。RT_ALIGN_SIZEはのrtconfig.h
マクロです。
スレッド制御ブロックを定義する
スレッド制御ブロックは、スレッドのすべての情報を格納する構造であり、通常はスレッドのIDカードと呼ばれます。
// 定义线程控制块
static struct rt_thread led0_thread;
スレッド関数を定義する
スレッド機能は、スレッドの機能コードであるスレッドエントリ機能です。スレッドは連続して実行する必要があるため、追加する必要がありますwhile(1)
。次のスレッド機能によって実装される機能は、LED0が500ms間隔で点滅することです。
/******************************************************************************
* @ 函数名 : led0_thread_entry
* @ 功 能 : LED0线程入口函数
* @ 参 数 : parameter 外部传入的参数
* @ 返回值 : 无
******************************************************************************/
static void led0_thread_entry(void *parameter)
{
while(1)
{
LED0(1);
rt_thread_delay(500); // 500个tick(500ms)
LED0(0);
rt_thread_delay(500);
}
}
スレッドを初期化します
静的スレッドの3つの要素は、スレッドエントリ関数、スレッドスタック、およびスレッド制御ブロックrt_thread_init()
です。3つを接続して動作するスレッドにするために、関数を使用する必要があります。
// 初始化一个静态线程
rt_thread_init(&led0_thread, // 线程控制块
"led0", // 线程名字
led0_thread_entry, // 线程入口函数
RT_NULL, // 入口函数参数
&rt_led0_thread_stack[0], // 线程栈起始地址
sizeof(rt_led0_thread_stack), // 线程栈大小
5, // 线程优先级
10); // 线程时间片
スレッドの優先度については、必ずrtconfig.h
指定範囲内の数値を入力してください(昨日システムを移植したときは、最大スレッド優先度を8に設定しました)。スレッド初期化時に優先度を高く設定しすぎると、スレッドは機能しません。
スレッドを開始
スレッドが初期化された後、スレッドは初期状態(RT_THREAD_INIT)のみになります。スレッドを準備完了状態(RT_THREAD_READY)にするには、rt_thread_startup()
関数を使用する必要があります。
// 开启线程调度
rt_thread_startup(&led0_thread);
実験効果
完全なコード
静的スレッドに関連するすべての関数をmain.cに配置しました。次のコードには、基になるドライバーコードは含まれていません。
#include "board.h"
#include "rtthread.h"
// 线程栈需要 RT_ALIGN_SIZE 个字节对齐
ALIGN(RT_ALIGN_SIZE)
// 定义线程栈
static rt_uint8_t rt_led0_thread_stack[1024];
// 定义线程控制块
static struct rt_thread led0_thread;
/******************************************************************************
* @ 函数名 : led0_thread_entry
* @ 功 能 : LED0线程入口函数
* @ 参 数 : parameter 外部传入的参数
* @ 返回值 : 无
******************************************************************************/
static void led0_thread_entry(void *parameter)
{
while(1)
{
LED0(1);
rt_thread_delay(500); // 500个tick(500ms)
LED0(0);
rt_thread_delay(500);
}
}
int main(void)
{
// 硬件初始化和RTT的初始化已经在component.c中的rtthread_startup()完成
// 初始化一个静态线程
rt_thread_init(&led0_thread, // 线程控制块
"led0", // 线程名字
led0_thread_entry, // 线程入口函数
RT_NULL, // 入口函数参数
&rt_led0_thread_stack[0], // 线程栈起始地址
sizeof(rt_led0_thread_stack), // 线程栈大小
5, // 线程优先级
10); // 线程时间片
// 开启线程调度
rt_thread_startup(&led0_thread);
}