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)
        
    }
}

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章