RT-Thread系列
Keil模拟器 STM32F103上手指南学习笔记
RT-Thread Studio快速上手
RT-Thread Nano入门学习笔记(2)
项目实战:快速打造一个桌面mini网络时钟
使用内置Git插件管理项目
已完成,添加源码后进行相应的修改,编译无错误,截图如下:
仿真测试如下:
仿真显示高低电平如下,说明移植成功!
已完成,截图证明如下:
设置断点进行仿真,查看运行流程:
首先是进入$sub$$main ()
函数:
然后进行一些板子的初始化:
最后是调用rt_system_scheduler_start ( ) ;
整个系统就启动了
总结:
先进入$sub$$main ()
函数,然后再跳到rtthread startup()
函数进行一些板子的初始化,然后调用rt_system_scheduler_start ();
这样整个系统就启动了!
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中看到打印数据,如下:
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);
}
}
输出信息时要尽量禁止调度,那如何实现禁止调度呢?如下:
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();
}
已完成,证明如下:
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:
可以查看版本和线程:
MSH_CMD_EXPORT(version, show RT-Thread version information);
已完成线程的创建:
自定义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);
}
}
观察到新创建的线程名称被截断
此时可将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
之后即可成功创建线程
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
修改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文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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);
}
}
运行无误: