参考教程:STM32系列BSP官方制作教程
参考教程:个人博客教程
#define LED_PIN_NUM 23 /* LED PIN脚编号,查看驱动文件drv_gpio.c确定 */
#define PWM_DEV_NAME "pwm4" /* PWM设备名称 */
#define PWM_DEV_CHANNEL 3 /* PWM通道 */
struct rt_device_pwm *pwm_dev; /* PWM设备句柄 */
/*
说明:led闪烁线程的入口函数
功能:实现红色LED的亮度渐变
*/
static void tid_ledflash_entry(void *parameter)
{
rt_uint32_t period, pulse;
period = 50000; /* 周期为0.5ms,单位为纳秒ns */
pulse = 0; /* PWM脉冲宽度值,单位为纳秒ns */
/* 查找设备 */
pwm_dev = (struct rt_device_pwm *)rt_device_find(PWM_DEV_NAME);
if (pwm_dev == RT_NULL)
{
// return RT_ERROR;
}
/* 设置PWM周期和脉冲宽度默认值 */
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
/* 使能设备 */
rt_pwm_enable(pwm_dev, PWM_DEV_CHANNEL);
while (1)
{
rt_thread_mdelay(10);
pulse += 100; /* 从0值开始每次增加5000ns */
if (pulse >= period)
{
pulse = 0;
}
/* 设置PWM周期和脉冲宽度 */
rt_pwm_set(pwm_dev, PWM_DEV_CHANNEL, period, pulse);
}
}
实现过程:建立两个线程,一个每隔500ms释放一个信号量,另一个线程以永久等待的方式获取信号量,一旦获取成功,翻转LED灯的亮灭状态。
#define LED_PIN_NUM 24
#define THREAD_PRIORITY 6
#define THREAD_TIMESLICE 10
/* 指向信号量的指针 */
static rt_sem_t dynamic_sem = RT_NULL;
ALIGN(RT_ALIGN_SIZE)
static char thread1_stack[1024];
static struct rt_thread thread1;
static void rt_thread1_entry(void *parameter)
{
while(1)
{
rt_sem_release(dynamic_sem);
rt_thread_mdelay(500);
}
}
ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
static void rt_thread2_entry(void *parameter)
{
static rt_err_t result;
static rt_uint8_t reversal_flag = 0;
rt_pin_mode(LED_PIN_NUM, PIN_MODE_OUTPUT);
while(1)
{
/* 永久方式等待信号量,获取到信号量,则执行number自加的操作 */
result = rt_sem_take(dynamic_sem, RT_WAITING_FOREVER);
if (result != RT_EOK)
{
rt_kprintf("t2 take a dynamic semaphore, failed.\n");
rt_sem_delete(dynamic_sem);
return;
}
if(reversal_flag)
{
rt_pin_write(LED_PIN_NUM, PIN_LOW);
reversal_flag = 0;
}
else
{
rt_pin_write(LED_PIN_NUM, PIN_HIGH);
reversal_flag = 1;
}
}
}
/* 信号量示例的初始化 */
void ledthread_init(void)
{
/* 创建一个动态信号量,初始值是0 */
dynamic_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_FIFO);
if (dynamic_sem == RT_NULL)
{
rt_kprintf("create dynamic semaphore failed.\n");
}
rt_thread_init(&thread1,
"thread1",
rt_thread1_entry,
RT_NULL,
&thread1_stack[0],
sizeof(thread1_stack),
THREAD_PRIORITY, THREAD_TIMESLICE);
rt_thread_startup(&thread1);
rt_thread_init(&thread2,
"thread2",
rt_thread2_entry,
RT_NULL,
&thread2_stack[0],
sizeof(thread2_stack),
THREAD_PRIORITY-1, THREAD_TIMESLICE);
rt_thread_startup(&thread2);
}
int rtthread_startup(void)
{
rt_hw_interrupt_disable();
/* 板 级 初 始 化: 需 在 该 函 数 内 部 进 行 系 统 堆 的 初 始 化 */
rt_hw_board_init();
/* 打 印 RT-Thread 版 本 信 息 */
rt_show_version();
/* 定 时 器 初 始 化 */
rt_system_timer_init();
/* 调 度 器 初 始 化 */
rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
/* 信 号 初 始 化 */
rt_system_signal_init();
#endif
/* 由 此 创 建 一 个 用 户 main() 线 程 */
rt_application_init();
/* 定 时 器 线 程 初 始 化 */
rt_system_timer_thread_init();
/* 空 闲 线 程 初 始 化 */
rt_thread_idle_init();
/* 启 动 调 度 器 */
rt_system_scheduler_start();
/* 不 会 执 行 至 此 */
return 0;
}
开启的位置是在:
->int rtthread_startup(void)
-> rt_system_scheduler_start();
->rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);
在rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp)函数中的如下位置:
自动初始化机制是指初始化函数不需要被显式调用,只需要在函数定义处通过宏定义的方式进行申明,就会在系统启动过程中的rt_components_board_init() 与 rt_components_init()被执行。
RT-Thread 的自动初始化机制使用了自定义 RTI 符号段,将需要在启动时进行初始化的函数指针放到了该段中,形成一张初始化函数表,在系统启动过程中会遍历该表,并调用表中的函数,达到自动初始化的目的。
初始化函数主动通过这些宏接口进行申明,如 INIT_BOARD_EXPORT(rt_hw_usart_init),链接器会自动收集所有被申明的初始化函数,放到 RTI 符号段中,该符号段位于内存分布的 RO 段中,该 RTI符号段中的所有函数在系统初始化时会被自动调用。
1. 复制对应系列 BSP 模板文件夹。
2. 使用 CubeMX 配置工程,配置系统时钟和需要的外设引脚功能。拷贝初始化函数到相关位置。
3. 修改board.h 文件,配置 FLASH 和 RAM 的相关参数。
4. 修改 Kconfig 选项,该选项是为了裁剪rt-thread。
5. 修改工程构建的脚本文件。
6. 修改工程模板,该工程模板对应不同的软件。
7. env 界面输入命令 menuconfig 对工程进行配置,并生成新的 rtconfig.h 文件。
8. 使用ENV工具重新生成工程文件。
9. BSP制作完成。