1、工程创建
使用MounRiver集成开发环境可以直接创建带有RT-Thread Nano的工程,步骤如下:
打开MounRiver,点击新建MounRiver工程;
在模板类型处选择RT-Thread,然后选择使用的芯片型号,点击完成工程就创建好了。
创建完的工程如下
2、代码修改与调试
2.1 RT-Thread 配置
首先确认一下RT-Thread的配置情况,根据自己的需要进行修改。
/* RT-Thread config file */
#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__
#if defined(__CC_ARM) || defined(__CLANG_ARM)
#include "RTE_Components.h"
#if defined(RTE_USING_FINSH)
#define RT_USING_FINSH
#endif //RTE_USING_FINSH
#endif //(__CC_ARM) || (__CLANG_ARM)
// <<< Use Configuration Wizard in Context Menu >>>
// <h>Basic Configuration
// <o>Maximal level of thread priority <8-256>
// <i>Default: 32
#define RT_THREAD_PRIORITY_MAX 16 // 优先级最大16
// <o>OS tick per second
// <i>Default: 1000 (1ms)
#define RT_TICK_PER_SECOND 1000 // 每秒1000tick 即1tick = 1ms
// <o>Alignment size for CPU architecture data access
// <i>Default: 4
#define RT_ALIGN_SIZE 4
// <o>the max length of object name<2-16>
// <i>Default: 8
#define RT_NAME_MAX 8
// <c1>Using RT-Thread components initialization
// <i>Using RT-Thread components initialization
#define RT_USING_COMPONENTS_INIT // 开启组件自动初始化功能
// </c>
#define RT_USING_USER_MAIN
// <o>the stack size of main thread<1-4086>
// <i>Default: 512
#define RT_MAIN_THREAD_STACK_SIZE 512 // main线程栈大小为512
// </h>
// <h>Debug Configuration
// <c1>enable kernel debug configuration
// <i>Default: enable kernel debug configuration
//#define RT_DEBUG
// </c>
// <o>enable components initialization debug configuration<0-1>
// <i>Default: 0
#define RT_DEBUG_INIT 0
// <c1>thread stack over flow detect
// <i> Diable Thread stack over flow detect
//#define RT_USING_OVERFLOW_CHECK
// </c>
// </h>
// <h>Hook Configuration
// <c1>using hook
// <i>using hook
#define RT_USING_HOOK
// </c>
// <c1>using idle hook
// <i>using idle hook
#define RT_USING_IDLE_HOOK
// </c>
// </h>
// <e>Software timers Configuration
// <i> Enables user timers
#define RT_USING_TIMER_SOFT 0
#if RT_USING_TIMER_SOFT == 0
#undef RT_USING_TIMER_SOFT
#endif
// <o>The priority level of timer thread <0-31>
// <i>Default: 4
#define RT_TIMER_THREAD_PRIO 4
// <o>The stack size of timer thread <0-8192>
// <i>Default: 512
#define RT_TIMER_THREAD_STACK_SIZE 512
// </e>
// <h>IPC(Inter-process communication) Configuration
// <c1>Using Semaphore
// <i>Using Semaphore
#define RT_USING_SEMAPHORE
// </c>
// <c1>Using Mutex
// <i>Using Mutex
#define RT_USING_MUTEX
// </c>
// <c1>Using Event
// <i>Using Event
#define RT_USING_EVENT
// </c>
// <c1>Using MailBox
// <i>Using MailBox
#define RT_USING_MAILBOX
// </c>
// <c1>Using Message Queue
// <i>Using Message Queue
#define RT_USING_MESSAGEQUEUE
// </c>
// </h>
// <h>Memory Management Configuration
// <c1>Dynamic Heap Management
// <i>Dynamic Heap Management
//#define RT_USING_MEMPOOL
//#define RT_USING_MEMHEAP
#define RT_USING_SMALL_MEM // 使用小内存管理
#define RT_USING_HEAP // 使用内存堆
// </c>
// <c1>using tiny size of memory
// <i>using tiny size of memory
//#define RT_USING_TINY_SIZE
// </c>
// </h>
/* Kernel Device Object */
#define RT_USING_DEVICE // 使用device框架
#if 0 // 使用的MCU RAM空间不是很大,将控制台部分全部注释掉不使用
#define RT_USING_CONSOLE
#define RT_CONSOLEBUF_SIZE 128
#define RT_CONSOLE_DEVICE_NAME "uart5"
#define RT_USING_FINSH
#if defined(RT_USING_FINSH)
#define FINSH_USING_MSH
#define FINSH_USING_MSH_DEFAULT
#define FINSH_USING_MSH_ONLY
#define FINSH_THREAD_NAME "tshell"
#define __FINSH_THREAD_PRIORITY 5
#define FINSH_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 8 * __FINSH_THREAD_PRIORITY + 1)
// <o>the stack of finsh thread <1-4096>
// <i>the stack of finsh thread
// <i>Default: 4096 (4096Byte)
#define FINSH_THREAD_STACK_SIZE 1024
#define FINSH_USING_HISTORY
#define FINSH_HISTORY_LINES 5
#define FINSH_USING_SYMTAB
#define FINSH_USING_DESCRIPTION
#define FINSH_CMD_SIZE 80
// </h>
#endif
#endif
// <<< end of configuration section >>>
#define RT_USING_SERIAL
#define RT_USING_PIN
#define RT_USING_UART5
#define RT_USING_DEVICE_IPC
#endif
2.2 打印串口修改
使用串口5打印log,在debug.c /.h 中进行修改。
debug.h
#define DEBUG_UART5 5
#ifndef DEBUG
#define DEBUG DEBUG_UART5
#endif
debug.c 添加UART5代码
void USART_Printf_Init(uint32_t baudrate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
#if(DEBUG == DEBUG_UART1)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
#elif(DEBUG == DEBUG_UART2)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
#elif(DEBUG == DEBUG_UART3)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
#elif(DEBUG == DEBUG_UART5)
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
GPIO_PinRemapConfig(GPIO_FullRemap_USART5, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOE, &GPIO_InitStructure);
#endif
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
#if(DEBUG == DEBUG_UART1)
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
#elif(DEBUG == DEBUG_UART2)
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
#elif(DEBUG == DEBUG_UART3)
USART_Init(USART3, &USART_InitStructure);
USART_Cmd(USART3, ENABLE);
#elif(DEBUG == DEBUG_UART5)
USART_Init(UART5, &USART_InitStructure);
USART_Cmd(UART5, ENABLE);
#endif
}
__attribute__((used)) int _write(int fd, char *buf, int size)
{
int i;
for(i = 0; i < size; i++)
{
#if(DEBUG == DEBUG_UART1)
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
USART_SendData(USART1, *buf++);
#elif(DEBUG == DEBUG_UART2)
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
USART_SendData(USART2, *buf++);
#elif(DEBUG == DEBUG_UART3)
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
USART_SendData(USART3, *buf++);
#elif(DEBUG == DEBUG_UART5)
while(USART_GetFlagStatus(UART5, USART_FLAG_TC) == RESET);
USART_SendData(UART5, *buf++);
#endif
}
return size;
}
2.3 测试验证
创建2个线程,分别在线程中控制LED闪烁
#define THREAD_STACK_SIZE 512 // 栈大小
#define THREAD_PRIORITY 15 // 线程优先级(值越小优先级越高)
#define THREAD_TIMESLICE 15 // 时间片大小
#define LED_H4_PIN 31
#define LED_H5_PIN 32
rt_thread_t thread1;
rt_thread_t thread2;
// LED初始化
void LED1_BLINK_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure={0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_6);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA,GPIO_Pin_7);
}
static void thread1_entry(void* param)
{
LogI("thread1_entry run\r\n");
rt_pin_mode(LED_H4_PIN, PIN_MODE_OUTPUT);
while(1)
{
rt_pin_write(LED_H4_PIN, PIN_LOW);
rt_thread_mdelay(500);
rt_pin_write(LED_H4_PIN, PIN_HIGH);
rt_thread_mdelay(500);
}
}
static void thread2_entry(void* param)
{
LogI("thread2_entry run\r\n");
rt_pin_mode(LED_H5_PIN, PIN_MODE_OUTPUT);
while(1)
{
rt_pin_write(LED_H5_PIN, PIN_LOW);
rt_thread_mdelay(1000);
rt_pin_write(LED_H5_PIN, PIN_HIGH);
rt_thread_mdelay(1000);
}
}
int main(void)
{
SystemCoreClockUpdate();
USART_Printf_Init(115200);
LogI("CH32V307 SysClk: %dHz,ChipID: %08x\r\n", SystemCoreClock, DBGMCU_GetCHIPID());
LED1_BLINK_INIT();
thread1 = rt_thread_create("thread1", thread1_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
if (thread1!= RT_NULL)
rt_thread_startup(thread1);
thread2 = rt_thread_create("thread2", thread2_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
if (thread1!= RT_NULL)
rt_thread_startup(thread2);
}
编译下载到开发板中运行,可以看到2个LED在以不同的频率闪烁。打印log可以看到2个线程都运行了。
3. RT-Thread 启动流程
la t0, entry // startup_ch32v30x.S
// 主要完成:初始化时钟、配置中断向量表;完成全局 / 静态变量的初始化工作;初始化堆栈;
// 库函数的初始化;程序的跳转等内容
int entry(void) // GCC下的startup_ch32v30x.S 会跳转到 entry()函数
rtthread_startup(); // RT-Thread 启动代码统一入口
rt_hw_board_init();
_SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); // 配置系统时钟
rt_components_board_init(); // INIT_BOARD_EXPORT()的函数,pin驱动、uart驱动等
rt_application_init(void)
rt_thread_create("main", main_thread_entry, RT_NULL,
RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20); // 创建Main线程
rt_thread_idle_init(); // 创建Idle线程
rt_system_scheduler_start(); // 启动调度器
main_thread_entry() // 进入main线程入口函数
int main(void) // 进入main函数
以上是近期使用的一些总结,后续如有需要会继续补充!
To Be Continue …