RT-Thread Nano入门学习笔记(1)

RT-Thread系列

Keil模拟器 STM32F103上手指南学习笔记

RT-Thread Studio快速上手

RT-Thread Nano入门学习笔记(2)

项目实战:快速打造一个桌面mini网络时钟

使用内置Git插件管理项目

1.RT-Thread Nano-添加源码

已完成,添加源码后进行相应的修改,编译无错误,截图如下:

在这里插入图片描述

在这里插入图片描述

仿真测试如下:

在这里插入图片描述

在这里插入图片描述

仿真显示高低电平如下,说明移植成功!

在这里插入图片描述

在这里插入图片描述

2.RT-Thread Nano-启动运行流程分析

已完成,截图证明如下:

设置断点进行仿真,查看运行流程:

首先是进入$sub$$main ()函数:

在这里插入图片描述

然后进行一些板子的初始化:

在这里插入图片描述

在这里插入图片描述

最后是调用rt_system_scheduler_start ( ) ;整个系统就启动了

总结:

先进入$sub$$main ()函数,然后再跳到rtthread startup()函数进行一些板子的初始化,然后调用rt_system_scheduler_start ();这样整个系统就启动了!

3.RT-Thread Nano-rt_kprintf支持

  • 实现rt_hw_console_output:
    实现finsh 组件输出一个字符,即在该函数中实现uart输出字符,在Usart.c文件中加入如下函数:
void rt_hw_console_output(const char *str)
{
	while(*str != '\0')
	{
		USART_SendData(USART1, *str++);
	
	  while(USART_GetFlagStatus(USART1, USART_FLAG_TC)== RESET);
	}
}

运行仿真可在UART #1中看到打印数据,如下:

在这里插入图片描述

  • 注意:RT-Thread 系统中已有的打印均以 \n 结尾,而并非 \r\n,所以在字符输出时,需要在输出 \n 之前输出 \r,完成回车与换行,否则系统打印出来的信息将只有换行,如下:
void rt_hw_console_output(const char *str)
{
	while(*str != '\0')
	{
		if(*str == '\n')
		{
				USART_SendData(USART1, '\r');
	
	      while(USART_GetFlagStatus(USART1, USART_FLAG_TC)== RESET);
		}
		USART_SendData(USART1, *str++);
	
	  while(USART_GetFlagStatus(USART1, USART_FLAG_TC)== RESET);
	}
}
  • 当rt scheduler lock nest> =1时,调度器停止调度

在这里插入图片描述

输出信息时要尽量禁止调度,那如何实现禁止调度呢?如下:

void rt_hw_console_output(const char *str)
{
	
	rt_enter_critical();

	while(*str != '\0')
	{
		if(*str == '\n')
		{
				USART_SendData(USART1, '\r');
	
	      while(USART_GetFlagStatus(USART1, USART_FLAG_TC)== RESET);
		}
		USART_SendData(USART1, *str++);
	
	  while(USART_GetFlagStatus(USART1, USART_FLAG_TC)== RESET);
	}
	rt_exit_critical();
}

在这里插入图片描述

4.RT-Thread Nano-Finsh组件支持

已完成,证明如下:

  • 前一小节已经完成输出,现在要实现输入,
    增加rt_hw_console_getchar()函数以实现RT-Thread Nano-Finsh组件支持,并且要去除串口1中断初始化。

在这里插入图片描述

char rt_hw_console_getchar(void)
{
    int ch = -1;

    if (USART_GetFlagStatus(USART1,USART_FLAG_RXNE)!=RESET)
    {
        ch = (int)USART_ReceiveData(USART1);
			  USART_ClearFlag(USART1, USART_FLAG_RXNE);
    }
    else
    {
        if(USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET)
        {
            USART_ClearFlag(USART1, USART_FLAG_ORE);
        }
        rt_thread_mdelay(10);
    }
    return ch;
}

按tab键、输入help:

在这里插入图片描述

可以查看版本和线程:

在这里插入图片描述

  • 如果要添加命令,可以自己写一个函数,例如version命令(自带的了),在文件cmd.c中可查找到
MSH_CMD_EXPORT(version, show RT-Thread version information);

在这里插入图片描述

5.RT-Thread Nano-线程创建1和线程讲解2

(1)RT-Thread Nano-线程创建1

已完成线程的创建:

自定义Task.c文件,存放线程:

#include "config.h"
#include "Task.h"

static rt_thread_t led_thread;

void led_thread_entry(void *parameter);

void TaskInit(void)
{
	//返回值还是需要的,否则无法通过rt_thread_startup启动
	led_thread =  rt_thread_create("ledThread",
                             led_thread_entry,
                             RT_NULL,
                             256,
                             2,
                             10);
	if(led_thread != RT_NULL)
	{
		rt_thread_startup(led_thread);
	}

void led_thread_entry(void *parameter)
{
	while(1)
	{
	  LedToggle(GPIOA,GPIO_Pin_1);
	  rt_thread_mdelay(2000);
		rt_kprintf("System running: %d s \n",rt_tick_get()/RT_TICK_PER_SECOND);
	}
}

main.c文件

int main(void)
{
	TaskInit();
	while(1)
	{		
		 LedToggle(GPIOA,GPIO_Pin_0);
	   rt_thread_mdelay(1000);
	}	
}

注意:线程不能强占住CPU,必须有要让出CPU的工作,否则会进入死循环

在这里插入图片描述

可查看当前运行的线程:

在这里插入图片描述

打印当前系统运行时间(每隔两秒打印一次)

void led_thread_entry(void *parameter)
{
	while(1)
	{
	  LedToggle(GPIOA,GPIO_Pin_1);
	  rt_thread_mdelay(2000);
	  rt_kprintf("System running: %d s \n",rt_tick_get()/RT_TICK_PER_SECOND);
	}

}

在这里插入图片描述

(2)RT-Thread Nano-线程讲解2

观察到新创建的线程名称被截断

在这里插入图片描述

此时可将reconfig.h文件中的#define RT_NAME_MAX 8修改为#define RT_NAME_MAX 16即可,如下:

在这里插入图片描述

将堆栈空间设置为4096,仿真运行之后在UART #1中运行list_thread命令没有看到我们建立的线程,说明线程没有建立成功,因为设置的堆栈太大了

在这里插入图片描述

我们实际设置的只有1024

在这里插入图片描述

将board.c中的#define RT_HEAP_SIZE 1024修改成#define RT_HEAP_SIZE 2048之后即可成功创建线程

在这里插入图片描述

6.RT-Thread Nano-自动初始化及MSH-EXPORT-1和2

(1)RT-Thread Nano-自动初始化及MSH-EXPORT-1

ChipInfo.c文件内容如下:

#include "config.h"
#include "ChipInfo.h"

uint32_t ChipUniqueID[3];

void GetChipID(void)
{
	ChipUniqueID[0]=*(volatile uint32_t *)(0x1FFFF7F0);//ID号高32位
	ChipUniqueID[1]=*(volatile uint32_t *)(0x1FFFF7EC);
	ChipUniqueID[2]=*(volatile uint32_t *)(0x1FFFF7E8);//ID号低字节
	rt_kprintf("\nChip ID is:0x%08X-%08X-%08X\n\n",ChipUniqueID[0],ChipUniqueID[1],ChipUniqueID[2]);
	
}
MSH_CMD_EXPORT(GetChipID, Get 96_bit unique Chip ID);

void GetFlashCapacity(void)
{
	rt_kprintf("\nChip Flash capacity is:%dK \n\n",*(volatile uint16_t *)(0x1FFFF7E0));
}
MSH_CMD_EXPORT(GetFlashCapacity, Get Chip Flash Capacity);

ChipInfo.h文件内容如下:

#ifndef __CHIPINFO_H__
#define __CHIPINFO_H__

void GetChipID(void);
void GetFlashCapacity(void);

#endif

还要记得在reconfig.h文件中加入#include "ChipInfo.h",如下:

在这里插入图片描述

连上开发板(stm32f103zet6)下载好程序:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

下载安装好SecureCRT,如下:

在这里插入图片描述

连接

在这里插入图片描述

按下tab键并且运行GetChipID,如下:

在这里插入图片描述

运行GetFlashCapacity,如下:

在这里插入图片描述

可以观察到tshell达到100了,堆栈的利用率太高了,所以我们可以把线程的堆栈调大一点,即把

#define FINSH_THREAD_STACK_SIZE 512调成#define FINSH_THREAD_STACK_SIZE 1024

在这里插入图片描述

在这里插入图片描述

(2)RT-Thread Nano-自动初始化及MSH-EXPORT-1

修改GPIOA——>GPIOB,GPIO_Pin_5——>GPIO_Pin_8

添加BeepOn和BeepOff命令,并进行BeepGpioInit设置,如下:

INIT_BOARD_EXPORT(BeepGpioInit); 
//INIT_DEVICE_EXPORT(BeepGpioInit);
//INIT_ENV_EXPORT(BeepGpioInit);

void BeepOn(void)
{
	GPIO_SetBits(GPIOB,GPIO_Pin_8);
}
MSH_CMD_EXPORT(BeepOn, Control Beep On);

void BeepOff(void)
{
	GPIO_ResetBits(GPIOB,GPIO_Pin_8);
}
MSH_CMD_EXPORT(BeepOff, Control Beep Off);

测试是否成功:

在这里插入图片描述

查看STM32_Proj.map文件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

7.RT-Thread Nano-串口接收(信号量使用)编写1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-67h40myW-1625104968015)(C:\Users\xiaoyan\AppData\Roaming\Typora\typora-user-images\image-20210623191104565.png)]

先定义一个信号量的指针EXT rt_sem_t usart2_recv_sem;,如下:

在这里插入图片描述

然后进行串口的配置

	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);

在这里插入图片描述

创建信号量的函数:

void TaskInit(void)
{
	//返回值还是需要的,否则无法通过rt_thread_startup启动
	led_thread =  rt_thread_create("ledThread",
                             led_thread_entry,
                             RT_NULL,
                             256,
                             5,
                             10);
	if(led_thread != RT_NULL)
	{
		rt_thread_startup(led_thread);
	}
  usart2_recv_thread = rt_thread_create("usart2_recv_thread",
                             usart2_recv_thread_entry,
                             RT_NULL,
                             512,
                             2,
                             10);
	
	
	if(usart2_recv_thread != RT_NULL)
	{
		rt_thread_startup(usart2_recv_thread);
	}
}

添加usart2_recv_thread_entry函数

void usart2_recv_thread_entry(void *parameter)
{
	  rt_err_t uwRet = RT_EOK;
		while(1)
		{
		    uwRet = rt_sem_take(usart2_recv_thread, RT_WAITING_FOREVER);
				if(RT_EOK == uwRet)
				{
					rt_kprintf("Usart2 Receive Data is %s\n",g_USART2_RxBuf);
					if(strstr((char*)g_USART2_RxBuf,"BeepOn") != NULL)
					{
						BeepOn();
					}
					if(strstr((char*)g_USART2_RxBuf,"BeepOff") != NULL)
					{
						BeepOff();
						
					}
					memset(g_USART2_RxBuf,0,USART2_RX_BUF_SIZE);
					g_USART2_RecPos = 0;
				}
		}
}

修改USART2_IRQHandler,串口2中断回调函数,如下图:

void USART2_IRQHandler(void)
{
	
	#if USART2_EN == 1 
		//用户代码
	uint RecCh;
	#endif
	if( USART_GetFlagStatus(USART2,USART_FLAG_RXNE)!=RESET )				// 串口接收数据 
	{		
		#if USART2_EN == 1 
					 //用户代码
		RecCh = (uint8)USART_ReceiveData(USART2);
		g_USART2_RxBuf[g_USART2_RecPos++] == RecCh;
		#endif
		USART_ClearFlag(USART2, USART_FLAG_RXNE);
	}
	if( USART_GetFlagStatus(USART2,USART_FLAG_ORE)==SET ) 				// 串口溢出错误
	{
			USART_ClearFlag(USART2, USART_FLAG_ORE);
	}
	if( USART_GetFlagStatus(USART2,USART_FLAG_IDLE)==SET ) 				// 串口溢出错误
	{
		#if USART2_EN == 1 
					 //用户代码
		g_USART2_RxBuf[g_USART2_RecPos] == '\0';
		rt_sem_release(usart2_recv_sem);
		
		#endif
		
		USART_ReceiveData(USART2);
	}
}

运行无误:

在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是彦歆呀嘻嘻哈哈

你的鼓励将是我的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值