RT-Thread移植到stm32f103保姆级例程

一、下载 RT-Thread Nano 源码
1、RT-Thread Master 的源码可从 RT-Thread GitHub 仓库下载,Nano 就是从里面扣出来的,去掉了一些组件和各种开发板的 BSP,保留了 OS的核心功能,但足够我们使用。点击黄颜色图标下载RT-Thread nano3.1.5安装到keilRT-Thread 文档中心

(二)打开keil随便找一个正点原子的点灯例程

如图所示点击1进入manage run,点击2进入rtos选择三个都打对钩,3点击OK、如下图

(三)复制下面代码到stm32f10x_it.c替换

/*
*********************************************************************************************************
*
*	模块名称 : 中断模块
*	文件名称 : stm32f10x_it.c
*	版    本 : V2.0
*	说    明 : 本文件存放所有的中断服务函数。为了便于他人了解程序用到的中断,我们不建议将中断函数移到其他
*			的文件。
*
*			我们只需要添加需要的中断函数即可。一般中断函数名是固定的,除非您修改了启动文件:startup_stm32f10x_hd.s
*
*			启动文件是汇编语言文件,定了每个中断的服务函数,这些函数使用了WEAK 关键字,表示弱定义,因此如
*			果我们在c文件中重定义了该服务函数(必须和它同名),那么启动文件的中断函数将自动无效。这也就
*			函数重定义的概念,这和C++中的函数重载的意义类似。
*
*********************************************************************************************************
*/

#include "stm32f10x_it.h"
//#include "main.h"

/*
*********************************************************************************************************
*	Cortex-M3 内核异常中断服务程序
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*	函 数 名: NMI_Handler
*	功能说明: 不可屏蔽中断服务程序。
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void NMI_Handler(void)
{
}
/*
*********************************************************************************************************
*	函 数 名: HardFault_Handler
*	功能说明: 硬件失效中断服务程序。
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
//void HardFault_Handler(void)
//{
//  /* 当硬件失效异常发生时进入死循环 */
//  while (1)
//  {
//  }
//}
/*
*********************************************************************************************************
*	函 数 名: MemManage_Handler
*	功能说明: 内存管理异常中断服务程序。
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void MemManage_Handler(void)
{
    /* 当内存管理异常发生时进入死循环 */
    while (1)
    {
    }
}
/*
*********************************************************************************************************
*	函 数 名: BusFault_Handler
*	功能说明: 总线访问异常中断服务程序。
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void BusFault_Handler(void)
{
    /* 当总线异常时进入死循环 */
    while (1)
    {
    }
}
/*
*********************************************************************************************************
*	函 数 名: UsageFault_Handler
*	功能说明: 未定义的指令或非法状态中断服务程序。
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void UsageFault_Handler(void)
{
    /* 当用法异常时进入死循环 */
    while (1)
    {
    }
}
/*
*********************************************************************************************************
*	函 数 名: SVC_Handler
*	功能说明: 通过SWI指令的系统服务调用中断服务程序。
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void SVC_Handler(void)
{
}

/*
*********************************************************************************************************
*	函 数 名: DebugMon_Handler
*	功能说明: 调试监视器中断服务程序。
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void DebugMon_Handler(void)
{
}

/*
*********************************************************************************************************
*	函 数 名: PendSV_Handler
*	功能说明: 可挂起的系统服务调用中断服务程序。
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
//void PendSV_Handler(void)
//{
//}



/*
*********************************************************************************************************
*	STM32F10x内部外设中断服务程序
*	用户在此添加用到外设中断服务函数。有效的中断服务函数名请参考启动文件(startup_stm32f10x_xx.s)
*********************************************************************************************************
*/

四(finsh_config.h)配置如下代码

/* FinSH config file */

#ifndef __MSH_CFG_H__
#define __MSH_CFG_H__

// <<< Use Configuration Wizard in Context Menu >>>
#define RT_USING_FINSH     
#define FINSH_USING_MSH     
#define FINSH_USING_MSH_ONLY 
// <h>FinSH Configuration
// <o>the priority of finsh thread <1-30>
//  <i>the priority of finsh thread
//  <i>Default: 21
#define FINSH_THREAD_PRIORITY       18
// <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_SYMTAB
// <c1>Enable command description
//  <i>Enable command description
#define FINSH_USING_DESCRIPTION
//  </c>
// </h>

// <<< end of configuration section >>>
#endif

(五)rtconfig.h配置代码修改如下面所示

/* RT-Thread config file */

#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__

// <<< 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  32
// <o>OS tick per second
//  <i>Default: 1000   (1ms)
#define RT_TICK_PER_SECOND  1000
// <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     256

// </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>Memory Pool Management
//  <i>Memory Pool Management
#define RT_USING_MEMPOOL
// </c>
// <c1>Dynamic Heap Management(Algorithm: small memory )
//  <i>Dynamic Heap Management
#define RT_USING_HEAP
#define RT_USING_SMALL_MEM
// </c>
// <c1>using tiny size of memory
//  <i>using tiny size of memory
//#define RT_USING_TINY_SIZE
// </c>
// </h>

// <h>Console Configuration
// <c1>Using console
//  <i>Using console
#define RT_USING_CONSOLE
// </c>
// <o>the buffer size of console <1-1024>
//  <i>the buffer size of console
//  <i>Default: 128  (128Byte)
#define RT_CONSOLEBUF_SIZE          256
// </h>

// <h>FinSH Configuration
// <c1>include finsh config
//  <i>Select this choice if you using FinSH 
#include "finsh_config.h"
// </c>
// </h>

// <h>Device Configuration
// <c1>using device framework
//  <i>using device framework
#define RT_USING_DEVICE
// </c>
// </h>

// <<< end of configuration section >>>

#endif

(六)finsh用串口四做控制台,uart4.c,uart4.h

#include "sys.h"
#include "usart.h"	  
#include <rtthread.h>
#if  UART4_RX_ENABLE                   //如果使能接收功能
char Uart4_RxCompleted =
    0;            //定义一个变量 0:表示接收未完成 1:表示接收完成
unsigned int Uart4_RxCounter =
    0;      //定义一个变量,记录串口1总共接收了多少字节的数据
char Uart4_RxBuff[UART4_RXBUFF_SIZE]; //定义一个数组,用于保存串口1接收到的数据
#endif
void UART4_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    // 特别注意:HK32需要先使能AFIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    // UART4时钟使能(在APB1上)
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);

    // PC10(TX) 推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    // PC11(RX) 浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    // USART参数配置
    USART_InitStructure.USART_BaudRate = 115200;
    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_Rx | USART_Mode_Tx;
    USART_Init(UART4, &USART_InitStructure);
    // 特别注意:HK32需要额外使能USART时钟
    USART_Cmd(UART4, ENABLE);
    USART_ITConfig(UART4, USART_IT_RXNE, DISABLE); // 关闭接收中断
}
//*************************************************************//
// 系统rt_kprintf()函数是通过调用 rt_hw_console_output();来实现
// 而rt_hw_console_output();函数系统默认是没有实现的,所以如果要
// 使用rt_kprintf()函数,就需要用户自己实现rt_hw_console_output()函数
// 实现rt_hw_console_output()函数的前提是,要初始化串口功能,串口初始化
// 过程和裸机串口初始化过程完全一样
//************************************************************//
/**
  * @brief  重映射串口DEBUG_USARTx到rt_kprintf()函数
  *   Note:DEBUG_USARTx是在bsp_usart.h中定义的宏,默认使用串口1
  * @param  str:要输出到串口的字符串
  * @retval 无
  *
  * @attention
  *
  */
void rt_hw_console_output(const char *str)
{
    /* 进入临界段 */
    rt_enter_critical();
    /* 直到字符串结束 */
    while (*str != '\0') {
        /* 换行 */
        //RT-Thread 系统中已有的打印均以 \n 结尾,而并非 \r\n,所以在字符输出时,需要在输出 \n 之前输出 \r,完成回车与换行,否则系统打印出来的信息将只有换行
        if (*str == '\n') {
            USART_SendData(UART4, '\r');
            while (USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET);
        }
        USART_SendData(UART4, *str++);
        while (USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET);
    }
    /* 退出临界段 */
    rt_exit_critical();
}

//使用Finsh组件三步骤:
//1.实现该函数及rt_hw_console_output函数;
//2.rtconfig.h中开启RT_USING_FINSH宏;
//3.添加Finsh组件(cmd.c、msh.c、shell.c);
char rt_hw_console_getchar(void)
{
    //查询方式实现,记得将Uart4初始化中的中断接收配置相关代码注释掉
    int ch = -1;
    /*等待串口1输入数据*/
    if (USART_GetFlagStatus(UART4, USART_SR_RXNE) != RESET) {
				ch = ( int )USART_ReceiveData( UART4 );
				USART_ClearFlag( UART4, USART_FLAG_RXNE ); 
    }
    else {
        if (USART_GetFlagStatus(UART4, USART_FLAG_ORE) != RESET) {
            USART_ClearFlag(UART4, USART_FLAG_ORE);
        }
        rt_thread_mdelay(10);
    }
    return ch;

}
#ifndef __USART_H
#define __USART_H
#include "stdio.h"	
#include "sys.h" 
#include "stdio.h"      //包含需要的头文件
#include "stdarg.h"     //包含需要的头文件 
#include "string.h"     //包含需要的头文件

#define UART4_RX_ENABLE     1      //是否开启接收功能  1:开启  0:关闭
#define UART4_TXBUFF_SIZE   256    //定义串口1 发送缓冲区大小 256字节

#if  UART4_RX_ENABLE                          //如果使能接收功能
#define UART4_RXBUFF_SIZE   256               //定义串口1 接收缓冲区大小 256字节
extern char Uart4_RxCompleted ;               //外部声明,其他文件可以调用该变量
extern unsigned int Uart4_RxCounter;          //外部声明,其他文件可以调用该变量
extern char Uart4_RxBuff[UART4_RXBUFF_SIZE]; //外部声明,其他文件可以调用该变量
#endif

void UART4_Init(void);     //串口4 初始化函数
void rt_hw_console_output(const char *str);
#endif

(七)在board.c中rt_hw_board_init()添加串口初始化函数

/*
 * Copyright (c) 2006-2019, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2017-07-24     Tanek        the first version
 * 2018-11-12     Ernest Chen  modify copyright
 */
#include "stm32f10x.h" 
#include <stdint.h>
#include <rthw.h>
#include <rtthread.h>
#include "delay.h"
#include "usart.h"	
#include "sys.h"
#define _SCB_BASE       (0xE000E010UL)
#define _SYSTICK_CTRL   (*(rt_uint32_t *)(_SCB_BASE + 0x0))
#define _SYSTICK_LOAD   (*(rt_uint32_t *)(_SCB_BASE + 0x4))
#define _SYSTICK_VAL    (*(rt_uint32_t *)(_SCB_BASE + 0x8))
#define _SYSTICK_CALIB  (*(rt_uint32_t *)(_SCB_BASE + 0xC))
#define _SYSTICK_PRI    (*(rt_uint8_t  *)(0xE000ED23UL))

// Updates the variable SystemCoreClock and must be called 
// whenever the core clock is changed during program execution.
extern void SystemCoreClockUpdate(void);

// Holds the system core clock, which is the system clock 
// frequency supplied to the SysTick timer and the processor 
// core clock.
extern uint32_t SystemCoreClock;
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE 1024*4
static uint32_t rt_heap[RT_HEAP_SIZE];     // heap default size: 4K(1024 * 4)
RT_WEAK void *rt_heap_begin_get(void)
{
    return rt_heap;
}

RT_WEAK void *rt_heap_end_get(void)
{
    return rt_heap + RT_HEAP_SIZE;
}
#endif
/*******************************************************************************
* 函 数 名         :RCC_Configuration
* 函数功能           :时钟配置
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void RCC_Configuration(void)
{

    ErrorStatus HSEStartUpStatus;                                                           //定义枚举类型变量 HSEStartUpStatus
    RCC_DeInit();                                                                                           //复位系统时钟设置
    RCC_HSEConfig(RCC_HSE_ON);                                                              //开启HSE
    HSEStartUpStatus = RCC_WaitForHSEStartUp();                     //等待HSE起振并稳定
    if (HSEStartUpStatus == SUCCESS)                                                    //判断HSE起是否振成功,是则进入if()内部
    {
        RCC_HCLKConfig(RCC_SYSCLK_Div1);                                    //选择HCLK(AHB)时钟源为SYSCLK 1分频
        RCC_PCLK2Config(RCC_HCLK_Div1);                                             //选择PCLK2时钟源为 HCLK(AHB) 1分频
        RCC_PCLK1Config(RCC_HCLK_Div2);                                             //选择PCLK1时钟源为 HCLK(AHB) 2分频
//        FLASH_SetLatency(FLASH_Latency_2);                                      //设置FLASH延时周期数为2
//        FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //使能FLASH预取缓存
        RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);  //选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz
        RCC_PLLCmd(ENABLE);                                                                 //使能PLL
        while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);  //等待PLL输出稳定

        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);                      //选择SYSCLK时钟源为PLL
        while (RCC_GetSYSCLKSource() != 0x08);                              //等待PLL成为SYSCLK时钟源
    }
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOF, ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
}
RCC_ClocksTypeDef ClockInfo;
/**
 * This function will initial your board.
 */
void rt_hw_board_init()
{
	 RCC_Configuration();	//时钟配置
   SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
	 SysTick_Init(72);
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
	 OSRunning=1;
	 RCC_GetClocksFreq(&ClockInfo); //获取时钟	
	 UART4_Init();        						 //串口4初始化用于finsh组件
    /* 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
}

void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();//表示进入中断,在src/irp.c中定义,中断嵌套计数器rt_interrupt_nest加1

    rt_tick_increase(); //rt_tick加1,并检查当前运行线程的剩余时间片是否耗尽,若耗尽则让出处理器并重新调度线程,接着执行硬件定时器中断模式下的定时器超时检查rt_timer_check();

    /* leave interrupt */
    rt_interrupt_leave();//rt_tick加1,并检查当前运行线程的剩余时间片是否耗尽,若耗尽则让出处理器并重新调度线程,接着执行硬件定时器中断模式下的定时器超时检查rt_timer_check();
}


(八)delay.c  delay.h修改如下

#include "delay.h"
#include "stm32f10x_it.h"
#include "rtthread.h"

static u8  fac_us=0;							//us延时倍乘数			   
static u16 fac_ms=0;							//ms延时倍乘数,在os下,代表每个节拍的ms数
				   

extern volatile rt_uint8_t rt_interrupt_nest;

//在board.c文件的rt_hw_board_init()里面将其置为1
uint8_t OSRunning=0;

#ifdef 	RT_THREAD_PRIORITY_MAX					         //RT_THREAD_PRIORITY_MAX定义了,说明要支持RT-Thread	
#define delay_osrunning		  OSRunning			       //OS是否运行标记,0,不运行;1,在运行
#define delay_ostickspersec	RT_TICK_PER_SECOND	//OS时钟节拍,即每秒调度次数
#define delay_osintnesting 	rt_interrupt_nest		//中断嵌套级别,即中断嵌套次数
#endif

//us级延时时,关闭任务调度(防止打断us级延迟)
void delay_osschedlock(void)
{
#ifdef RT_THREAD_PRIORITY_MAX
	 rt_enter_critical();
#endif	
}

//us级延时时,恢复任务调度
void delay_osschedunlock(void)
{	
#ifdef RT_THREAD_PRIORITY_MAX
	  rt_exit_critical();
#endif	
}

//调用OS自带的延时函数延时
//ticks:延时的节拍数
void delay_ostimedly(u32 ticks)
{
#ifdef RT_THREAD_PRIORITY_MAX
	  rt_thread_delay(ticks);
#endif	
}

//初始化延迟函数
//SYSTICK的时钟固定为AHB时钟的1/8
//SYSCLK:系统时钟频率
void SysTick_Init(u8 SYSCLK)
{
	u32 reload;
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
	fac_us=SYSCLK/8;						//不论是否使用OS,fac_us都需要使用
	reload=SYSCLK/8;				//每秒钟的计数次数	   
	reload*=1000000/delay_ostickspersec;		//根据delay_ostickspersec设定溢出时间
												//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右	
	fac_ms=1000/delay_ostickspersec;			//代表OS可以延时的最少单位	   

	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;   	//开启SYSTICK中断
	SysTick->LOAD=reload; 						//每1/delay_ostickspersec秒中断一次	
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;   	//开启SYSTICK  			   
}								    


//延时nus
//nus为要延时的us数.		    								   
void delay_us(u32 nus)
{		
	u32 ticks;
	u32 told,tnow,tcnt=0;
	u32 reload=SysTick->LOAD;					//LOAD的值	    	 
	ticks=nus*fac_us; 							//需要的节拍数	  		 
	tcnt=0;
	delay_osschedlock();						//阻止OS调度,防止打断us延时
	told=SysTick->VAL;        					//刚进入时的计数器值
	while(1)
	{
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{	    
			if(tnow<told)tcnt+=told-tnow;		//这里注意一下SYSTICK是一个递减的计数器就可以了.
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;				//时间超过/等于要延迟的时间,则退出.
		}  
	};
	delay_osschedunlock();						//恢复OS调度									    
}
//延时nms
//nms:要延时的ms数
void delay_ms(u16 nms)
{	
	if(delay_osrunning&&delay_osintnesting==0)	//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)	    
	{		 
		if(nms>=fac_ms)							//延时的时间大于OS的最少时间周期 
		{ 
   			delay_ostimedly(nms/fac_ms);		//OS延时
		}
		nms%=fac_ms;							//OS已经无法提供这么小的延时了,采用普通方式延时    
	}
	delay_us((u32)(nms*1000));					//普通方式延时  
}
#ifndef __DELAY_H
#define __DELAY_H 			   
#include "sys.h"  
extern u8 OSRunning;
extern void SysTick_Init(u8 SYSCLK);
extern void delay_ms(u16 nms);
extern void delay_us(u32 nus);
extern void delay_s(u16 s);

#endif

main函数

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"

 int main(void)
 {	
	
 }

(九)连接sercurecrt如下图

点击tab或者help出现命令帮助

后续或许会详细解释创建动态静态线程,msh自己创建命令,等一系列操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值