rt-thread 开发者能力认证考试(RCEA)复习题

目录

一、问答题

1、RT-Thread的启动流程

2、加载时地址与运行时地址映射

3、MDK环境下各种数据段存储的什么数据

4、自动初始化原理

5、文件系统的使用流程

6、STM32 BSP的制作过程

7、I/O设备管理框架层的意义

8、RAM处理器寄存器

9、RTOS和前后台系统

二、编程题


一、问答题

1、RT-Thread的启动流程

整个启动过程为:startup_xx.s ————> rt-thread启动 ————>main。在rt-thread启动中大概有以下四个部分:

① 初始化与系统相关的硬件

② 初始化系统内核对象,如定时器、调度器、信号

③ 创建main线程,在main线程中依次对各类模块进行初始化

④ 初始化定时器线程、空闲线程,并启动调度器

2、加载时地址与运行时地址映射

image文件

STM32 在上电启动之后默认从 Flash 启动,启动之后会将 RW 段中的 RW-data(初始化的全局变量)搬运到 RAM中,但不会搬运 RO 段,即 CPU 的执行代码从 Flash 中读取,另外根据编译器给出的 ZI 地址和大小分配出 ZI 段,并将这块 RAM 区域清零。

分散装载配置文件里会有配置,关于code的地址,有两个设置,一个是存储地址(这个地址配置的是烧写器把代码段写到flashrom的何处),一个是装载运行地址,也就是你程序在什么地方运行

3、MDK环境下各种数据段存储的什么数据

  • code:代码段,存放程序
  • RO:只读数据段,存放程序中定义的常量
  • RW:读写数据段,存放非0全局变量
  • ZI:0数据段,存放未初始化的全局变量与初始化为0的变量

MDK 在编译完成之后

Total RO Size (Code + RO Data) 53668 ( 52.41kB)

Total RW Size (RW Data + ZI Data) 2728 ( 2.66kB)

Total ROM Size (Code + RO Data + RW Data) 53780 ( 52.52kB)

  • 1)RO Size 包含了 Code 及 RO-data,表示程序占用 Flash 空间的大小;
  • 2)RW Size 包含了 RW-data 及 ZI-data,表示运行时占用的 RAM 的大小;
  • 3)ROM Size 包含了 Code、RO Data 以及 RW Data,表示烧写程序所占用的 Flash 空间的大小;

4、自动初始化原理

rt-thread的知道初始化机制使用了自定义的RTI符号段,将需要在启动时初始化的函数指针放到该段中,形成一张知道初始化函数表,在系统启动过程中会遍历该表,并调用该表中的函数,达到自动初始化的目的。用来实现自动初始化功能的宏定义接口如下:

初始化顺序

宏接口

描述

1

INIT_BOARD_EXPORT(fn)

非常早期的初始化,此时调度器还未启动

2

INIT_PREV_EXPORT(fn)

主要用于纯软件,没有太多依赖的函数

3

INIT_DEVICE_EXPORT(fn)

外设驱动初始化相关,比如网卡驱动

4

INIT_COMPONENT_EXPORT(fn)

组件初始化,比如文件系统或者LWIP

5

INIT_ENV_EXPORT(fn)

系统环境初始化,比如挂载文件系统

6

INIT_APP_EXPORT(fn)

应用初始化,比如GUI应用

5、文件系统的使用流程

1、初始化DFS组件:dfs_init()

2、初始化具体的文件系统:并将具体的文件系统祖册到DFS中:

elm_init() ——> dfs_register(&dfs_elm)

3、在存储器上创建块设备,并将块设备祖册到I/O设备管理器中:rt_sfud_flash_probe()

4、在块设备上创建指定的文件系统,即格式化文件系统:dfs_mkfs("elm", "sd0")

5、挂载块设备到DFS目录中,即挂载文件系统:dfs_mount("sd0", "/", "elm", 0, 0)

6、STM32 BSP的制作过程

1、复制通用模板:将bsp/stm32/libraries/templates 下的通用模板复制到bsp/stm32下

2、使用CUBMX配置工程,生成stm32fxx_hal_msp.c/.h:选择芯片型号、打开外部时钟、选择下载方式、打开串口外设、配置系统时钟

3、修改board.c中的系统时钟初始化函数,修改board.h中的FLASH和RAM大小

4、修改kconfig选项:修改芯片型号与系列

5、修改连接脚本中的FLASH和RAM大小

6、修改sconscript构建脚本,修改芯片型号和启动文件地址

7、修改过程模板,重新生成过程

7、I/O设备管理框架层的意义

使设备的硬件操作与应用程序相互独立,双方只需关心各自的实现,从而降低代码的耦合性、复杂性、提高了系统的稳定性

8、RAM处理器寄存器

R0-R12:通用寄存器

R13:主堆栈指针(MSP)、进程堆栈指针(PSP)

R14:连接寄存器(LR)

R15:程序计数器(PC)

9、RTOS和前后台系统

1、前后台系统是指:包括一个死循环的应用程序的后台系统,和若干个中断服务程序的前台系统

2、RTOS分为硬实时和软实时,硬实时要求在规定的时间内完成必须完成的操作

二、编程题

1、使用信号量的方式,同步LED的亮灭,500ms亮 500ms灭。创建两个线程,线程1使用信号量定时通知LED的亮灭;线程2根据通知执行LED的亮灭

#define LED_PIN   GET_PIN(F, 9)
rt_sem_t led_sem;

static void sem_entry(void *parameter)
{
    while(1)
    {
        rt_sem_release(led_sem);
        rt_thread_mdelay(500);
    }
}
static void sem_entry(void *parameter)
{
    static unsigned char cnt = 0;
    
    while(1)
    {
        rt_sem_take(led_sem, RT_WAITING_FOREVER);
        if(cnt++ % 2)
            rt_pin_write(LED_PIN, PIN_HIGH);
        else
            rt_pin_write(LED_PIN, PIN_LOW);
    }
}

int led_sample(void)
{
    static rt_thread_t tid1 = RT_NULL;
    static rt_thread_t tid2 = RT_NULL;
    
    led_sem = rt_sem_creat("led_sem", 1, RT_IPC_FLAG_FIFO)
    if (led_sem == RT_NULL)
    {
        rt_kprintf("creat led sem fail!\n");
        return -RT_ERROR;
    }
    
    tid1 = rt_thread_creat("ctl_sem",sem_entry,RT_NULL,512,10,0);
    if (tid1 != RT_NULL)
        rt_thread_startup(tid1);
        
    tid2 = rt_thread_creat("ctl_sem",led_entry,RT_NULL,512,d11,0);
    if (tid2 != RT_NULL)
        rt_thread_startup(tid2 );
}
INIT_APP_EXPORT(led_sample, led dample)

2、有一系列文件如:1.txt, 12.txt, 123.txt,从中找出1.txt,并将文件内容输出出来。

static void findfile_sample(void)
{
    DIR *dirp;
    struct dirrnt *d;
    char *f;
    char buffer[100];
    
    /*打开根目录*/
    dirp = opendir("/");
    if (dirp == RT_NULL)
    {
        rt_kprintf("open directory error\n");
    }
    else
    {
        while ((d = readdir(dirp) != RT_NULL))/*读取目录*/
        {
            f = d->d_name;
            if(!strcmp(f, "1.txt"))
            {
                fd = open("1.txt", O_RDONLY);
                if (fd >= 0)
                {
                    read(fd, buffer, sizeof(buffer));
                    rt_kprintf("file 1.txt was found, the content is %s", buffer)
                    close(fd);
                }
            }
        }
        closedir(dirp);
    }
}
MSH_CMD_EXPORT(findfile_sample, find file)

3、创建一个名为rtthread.txt的文本文件,并写入“hello world”到文件中,然后读出打印

void write_read_sample(void)
{
    int fd;
    char *s = "hello world\n";
    char buffer[100] = {0};
    
    fd = open("/rtthread.txt", O_WRONLY | O_CREAT)
    if (fd >= 0)
    {
        write(fd, s, sizeof(s));
        close(fd)
    }
    
    fd = open("/rtthread.txt", O_RDONLY)
    if(fd >= 0)
    {
        size = read(fd, buffer, sizeof(buffer))
        close(fd);
    }
}
MSH_CMD_EXPORT(write_read_sample)

4、tcp客户端

struct sockaddr
{
    uint8_t        sa_len;
    sa_family_t    sa_family;
    char           sa_data[14];
};
/* members are in network byte order */
struct sockaddr_in
{
    uint8_t        sin_len;
    sa_family_t    sin_family;
    in_port_t      sin_port;
    struct in_addr sin_addr;
#define SIN_ZERO_LEN 8
    char            sin_zero[SIN_ZERO_LEN];
};
struct hostent {
    char  *h_name;      /* Official name of the host. */
    char **h_aliases;   /* A pointer to an array of pointers to alternative host names,
                           terminated by a null pointer. */
    int    h_addrtype;  /* Address type. */
    int    h_length;    /* The length, in bytes, of the address. */
    char **h_addr_list; /* A pointer to an array of pointers to network addresses (in
                           network byte order) for the host, terminated by a null pointer. */
#define h_addr h_addr_list[0] /* for backward compatibility */
};
struct in_addr
{
    in_addr_t s_addr;
};

#define BUFSZ 100
int port = 8080;
void tcp_client(void *url)
{
    char *rdata;
    int rdata_bytes;
    int sock = -1;
    struct hostent *host = RT_NULL;
    struct sockaddr_in server_addr;
    struct timeval timeout;
    fd_set readset;
    
    /*地址解析*/
    host = gethostbyname(url)
    if (host == RT_NULL)
        return;
    
    /*分配内存接受数据*/
    rdata = rt_malloc(BUFSZ);
    if (rdata == RT_NULL)
        return;
        
    /*创建socket*/
    sock = socket(AF_INET, SOCKET_STREAM, 0);
    if (sock == -1)
        goto _exit;
        
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_sddr = *((struct in_addr *)host->h_addr);
    rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
    
    /*连接到服务器*/
    if (connect(sock, (struct *)&server_addr, sizeof(struct sockaddr)) == -1)
        goto _exit;
        
    timeout.tv_sec = 3;
    timeout.tv_usec = 0;
    
    while(1)
    {
        FD_ZERO(&readset);
        FD_SET(sock, &readset);
        
        if (select(sock+1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
            continue;
            
        rdata_bytes = recv(sock, rdata, BUFSZ-1, 0)
        if (rdata_bytes < 0)
        {
            goto _exit;
        }
        else if(rdata_bytes == 0)
        {
            continue;
        }
        else
        {
            rdata[rdata_bytes ] = '\0';
            if (rt_strcmp(rdata, "q") == 0 || rt_strcmp(rdata, "Q") == 0)
                goto _exit;
            else
                LOG_D("receive data is %s\n", rdata);
        }
        
        ret = send(sock, send_data, rt_strlen(send_data), 0)
        if (ret < 0)
            goto _exit;
        else if(ret == 0)
        
    }
}

发布了35 篇原创文章 · 获赞 22 · 访问量 1128

猜你喜欢

转载自blog.csdn.net/m0_37845735/article/details/104497806