天天看點

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

目錄

  • 前言
  • 1. 開發環境搭建
  • 2. RTT Studio建立工程
  • 3. CubeMX配置系統時鐘
  • 4. SConscript建構目錄
  • 5. UART裝置驅動程式
  • 6. 擷取GPS定位資訊
  • 小結

前言

本文基于STM32F429VET6單片機和RT-Thread Studio內建開發環境,使用CubeMX工具配置系統時鐘,SConscript建構目錄,通過RTThread的UART裝置、GPS RMC軟體包,實作了GPS模組ATGM336H定位資訊的實時擷取。

1. 開發環境搭建

  • 硬體平台:STM32F429VET6
  • 軟體版本:rt-thread-v4.1.0
  • 開發環境:RT-Thread Studio 2.2.4
  • GPS模組:ATGM336H-5N-31

2. RTT Studio建立工程

為了更好的了解RT-Thread Studio手動建構工程的過程,建立工程時選擇基于晶片,而不要選擇基于開發闆。根據實際情況選擇一個序列槽作為序列槽終端,按正常流程建立工程後,首先需要對系統時鐘進行配置。

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

遇到問題:在建立的工程裡無法打開CubeMX Setting,輕按兩下後進度條一閃而過!(如果是基于開發闆建立工程,則未遇到此問題。)

此問題應該是RT-Thread Studio在不同作業系統上連結CubeMX.exe時産生的相容性問題,網上查找一番後在RT-Thread社群找到答案,雖然該貼描述的是Win7系統,但我是Win10系統也得到解決,在此感謝社群網友。如果以下連結中的cubemx.exe無法下載下傳,也可以評論區留下郵箱。(也可以嘗試重新安裝最新版RT-Thread Studio)

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結
解決方法:https://club.rt-thread.org/ask/question/136adc86e4d06132.html

3. CubeMX配置系統時鐘

RTT Studio建立的工程預設使用内部高速時鐘HSI,相對于外部晶振産生的時鐘精度更低。配置系統時鐘時有兩種方式:

方式一:直接修改drv_clk.c檔案,此方式适合于對時鐘樹熟練的使用者;

方式二:通過STM32CubeMX配置,此方式适合于熟悉CubeMX工具的使用者。(本文采用)

系統時鐘初始化過程:

hw_board_init() -> clk_init() -> system_clock_config()

1)board.h頭檔案:

定義系統時鐘相關宏,預設使用高速内部時鐘,主頻為最大180MHz。

/*-------------------------- CLOCK CONFIG BEGIN --------------------------*/
#define BSP_CLOCK_SOURCE                  ("HSI")			
#define BSP_CLOCK_SOURCE_FREQ_MHZ         ((int32_t)0)		
#define BSP_CLOCK_SYSTEM_FREQ_MHZ         ((int32_t)180)	
/*-------------------------- CLOCK CONFIG END --------------------------*/
           

2)board.c源檔案:

在hw_board_init初始過程中調用clk_init()。

void hw_board_init(char *clock_src, int32_t clock_src_freq, int32_t clock_target_freq)
{
	...
    /* enable interrupt */
    __set_PRIMASK(0);
    /* System clock initialization */
    clk_init(clock_src, clock_src_freq, clock_target_freq);
    /* disbale interrupt */
    __set_PRIMASK(1);
	...
	前後省略部分代碼
}

           

3)clk_dvr.c源檔案:

在clk_init中調用system_clock_config()。

void clk_init(char *clk_source, int source_freq, int target_freq)
{
    system_clock_config(target_freq);	//在clk_dvr.c中實作
}
           

注:在boad.c中調用rt_hw_board_init時将上述三個參數傳入,由此可見上述三個宏隻使用了一個參數target_freq,即目标頻率

4)CubeMX配置時鐘:

在此使用HSE外部時鐘,系統時鐘設定最大為180MHz。生成代碼時工配置勾選生成單獨的.c和.h檔案,以及隻生需要的庫檔案。

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

生成代碼後,直接關閉CubeMX軟體即可。第一次配置cubemx關閉軟體時會提示産生stm32f4xx_hal_conf_bak.h檔案,點選确認即可,也就是說後續将使用cubemx目錄下的stm32f4xx_hal_conf.h檔案配置。

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

回到RTT Studio項目資料總管,右擊->重新整理,此時使用CubeMX工具生成的完整目錄會自動更新到工程中。這時在項目中存在兩個main.c和兩份HAL驅動庫,需要通過SConscript來建構目錄選擇需要的檔案,是以先不執行編譯。

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

注:項目中bsp目錄是手動添加的,建立工程不存在此目錄。此時,如果直接編譯工程會報出幾百個錯誤!

4)調用系統時鐘配置函數:

有兩種方式:

一種是将SystemClock_Config()函數中的内容替換system_clock_config()函數中的内容,但是如果修改CubeMX時鐘配置後,每次都需要重新再修改一次system_clock_config()函數,是以選擇下面的方式。

另一種方式是外部聲明并直接調用SystemClock_Config()函數,注釋原來的system_clock_config()調用,這樣更新CubeMX配置後也不需要再修改代碼。

void clk_init(char *clk_source, int source_freq, int target_freq)
{
    //注釋原來的時鐘配置,使用CubeMX的時鐘配置
    //system_clock_config(target_freq);	
    extern void SystemClock_Config(void);
    SystemClock_Config();
}
           

注:SystemClock_Config()和system_clock_config()是兩個不同的函數。

4. SConscript建構目錄

1)建構目錄

完成時鐘配置後,通過SConscript檔案重新建構cubemx目錄,以解決main.c和HAL庫重複、以及stm32f4xx_it.c、stm32f4xx_hal_msp.c、system_stm32f4xx.c等檔案無需引用的問題。這裡需要對SCon的内置函數有一些了解,SConscript 檔案使用Python文法,可以實作控制源碼檔案的加入,并且可以指定檔案的Group(類似于MDK5/IAR中的Group)。最快捷的方式是複制工程中其它SConscript檔案進行修改。

SConscript檔案源碼:

import os
from building import *

cwd = GetCurrentDir()
src  = Glob('*.c')
src = Split('''
Src/main.c
''')

path = [cwd]
path += [cwd + '/Inc']

group = DefineGroup('cubemx', src, depend = [''], CPPPATH = path)

Return('group')
           

注:因為編譯時隻需要用到main.c檔案中的函數,是以Src目錄下其它的.c檔案不需要添加建構。

**DefineGroup(name, src, depend,parameters)函數參數描述:

參數 描述
name Group 的名字
src Group 中包含的檔案,一般指的是 C/C++ 源檔案。
depend Group 編譯時所依賴的選項
parameters 配置其他參數

parameters可加入的标志:

标志 描述
CCFLAGS C源檔案編譯參數
CPPPATH 頭檔案路徑
CPPDEFINES 連結時參數
LIBRARY 将元件生成的目标檔案打包成庫檔案

在cubemx目錄下添加SConcript檔案後,右擊->更新軟體包,即可完成目錄建構。建構結果如下:

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

提示:main.c中的SystemClock_Config()函數在clk_init()中調用,即上述配置的系統時鐘初始化;

2)修改main函數

建構目錄後工程中還包含兩個main函數,一個是applications/main.c檔案中的,一個是cubemx/main.c檔案中的。是以我們需要注釋cubemx/main.c中的main函數,或在其前面添加__WEAK關鍵詞将其弱化。但是每次配置CubeMX工具生成代碼後,都會更新cubemx中的main.c檔案,是以每次需要重新修改main函數。

修改main函數:

提示:第一次配置cubemx生成的代碼,自動會在main函數前添加WEAK關鍵字!

3)配置HAL序列槽子產品

如果此時直接編譯工程會提示序列槽結構體未定義,因為在CubeMX配置生成代碼後,工程會在drivers目錄下備份一個stm32f4xx_hal_conf_bak.h檔案(即上述提到的首次關閉cubemx時的提示。),而使用cubemx/Inc目錄下新生成的stm32f4xx_hal_conf.h檔案,但是在配置系統時鐘時并沒有對序列槽進行配置,即未開啟HAL_UART_MODULE_ENABLED宏定義。

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

此時有兩種方式可以解決:

方式一:重新打開cubemx工具配置一個序列槽,即建立工程時選擇的終端序列槽号;

方式二:手動開啟cubemx/stm32f4xx_hal_conf.h頭檔案中的序列槽子產品宏定義。(本文采用)

stm32f4xx_hal_conf.h檔案第78行:

#define HAL_UART_MODULE_ENABLED
           

此時再次編譯工程即可通過,下面進行序列槽驅動裝置程式的開發。

5. UART裝置驅動程式

1)使能UART裝置驅動

在建立工程時預設已經開啟了UART裝置,因為建立工程時已經選擇了一個序列槽作為終端控制的端口。

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

2)定義UART引腳

在board.h檔案配置相應的序列槽引腳,原文中注釋較長的描述了如何定義序列槽引腳和使用DMA方式,在此根據自己的實際情況選擇相應的序列槽引腳。以下定義了兩組序列槽,Console終端序列槽和GPS子產品序列槽。

//終端控制序列槽
#define BSP_USING_UART1
#define BSP_UART1_TX_PIN       "PA9"
#define BSP_UART1_RX_PIN       "PA10"
//GPS控制序列槽
#define BSP_USING_UART8
#define BSP_UART8_TX_PIN       "PE1"
#define BSP_UART8_RX_PIN       "PE0"
/*-------------------------- UART CONFIG END --------------------------*/
           

3)添加GPS軟體包

打開RT-Thread Setting界面,搜尋找到GPS RMC: Analysis of GPS RMC information。開啟此項功能,并修改Uart Port Name為上述定義的GPS子產品序列槽号,儲存并更新軟體包。

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

此時在項目資料總管中會自動添加packages目錄,各檔案功能描述如下:

  • gps_rmc.c:實作GPS RMC資料格式轉換、定位資訊解析等方法;
  • gps_rmc.h:定義GPS RMC資訊解析資料存儲結構體;
  • rtt_gps_rmc_example.c:GPS元件初始化調試例程。
【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

注:在rtt_gps_rmc_example.c檔案中預設定義了GPS序列槽裝置名稱為uart6,而在啟用GPS軟體包時配置了序列槽8,是以在rtconfig.h檔案中已經定義了GPS_RMC_SAMPLE_UART_NAME為“uart8”,兩處二選一并不沖突,避免誤解盡量改為一緻。以下為兩個檔案的定義:

rtconfig.h檔案:

/* tools packages */
#define PKG_USING_GPS_RMC
#define PKG_USING_GPS_RMC_LATEST_VERSION
#define GPS_RMC_USING_SAMPLE
#define GPS_RMC_SAMPLE_UART_NAME "uart8"
/* end of tools packages */
           

rtt_gps_rmc_example.c檔案部分源碼:

/* 定義GPS裝置名稱 */
#ifndef GPS_RMC_SAMPLE_UART_NAME
#define GPS_RMC_SAMPLE_UART_NAME "uart8" //手動修改為uart8,保持一緻。
#endif

/* 接收資料回調函數 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* 序列槽接收到資料後産生中斷,調用此回調函數,然後發送接收信号量 */
    rt_sem_release(&rx_sem);

    return RT_EOK;
}

/* GPS線程入口函數 */
void gps_rmc_sample_entry(void *p)
{
    char buff[128] = {0}, *buff_p = buff, ch = 0;
    struct gps_info info_data = {0};
    gps_info_t info = &info_data;
    while (1)
    {
        /* 從序列槽讀取一個位元組的資料,沒有讀取到則等待接收信号量 */
        while (rt_device_read(uart, -1, &ch, 1) != 1)
        {
            /* 阻塞等待接收信号量,等到信号量後再次讀取資料 */
            rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
        }
        if (ch == '\n')
        {
            /* 在接收資料中查找“RMC字元串” */
            if (rt_strstr((const char *)buff, "RMC"))
            {
                /* 解析并列印定位資訊 */
                if (gps_rmc_parse(info, buff))
                    gps_print_info(info);
            }
            rt_memset(buff, 0, 128);
            rt_memset(info, 0, sizeof(struct gps_info));
            buff_p = buff;
            continue;
        }
        *buff_p++ = ch;
    }
}
/* GPS線程初始化 */
int gps_rmc_sample_entry_init(void)
{
    uart = rt_device_find(GPS_RMC_SAMPLE_UART_NAME);
    if (uart == RT_NULL)
    {
        rt_kprintf("Not find %s device.\r\n", GPS_RMC_SAMPLE_UART_NAME);
        return RT_ERROR;
    }

    /* 初始化信号量 */
    rt_sem_init(&rx_sem, GPS_RMC_SAMPLE_UART_NAME"_rx", 0, RT_IPC_FLAG_FIFO);
	/* 設定GPS序列槽波特率為9600 */
    struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
    config.baud_rate = BAUD_RATE_9600;
    rt_device_control(uart, RT_DEVICE_CTRL_CONFIG, &config);
    /* 中斷接收方式開啟打開序列槽裝置 */
    rt_device_open(uart, RT_DEVICE_FLAG_INT_RX);
    /* 注冊串接收回調函數 */
    rt_device_set_rx_indicate(uart, uart_input);

	/* 建立GPS線程 */
    rt_thread_t t = rt_thread_create("gps_rmc_p", gps_rmc_sample_entry, RT_NULL,2048, 20, 10);
    if (t == RT_NULL)
    {
        rt_kprintf("Failde to create gps rmc info procees thread.\r\n");
        return RT_ERROR;
    }
    /* 啟動GPS線程 */
    if (rt_thread_startup(t) != RT_EOK)
    {
        rt_kprintf("Failde to startup gps rmc info procees thread.\r\n");
        rt_thread_delete(t);
        return RT_ERROR;
    }
    return RT_EOK;
}
/* 應用初始化:該函數傳回值需要為int型,否則會報警告 */
INIT_APP_EXPORT(gps_rmc_sample_entry_init);
           

rtt_gps_rmc_example.c檔案主要内容:

以應用初始化方式建立了“gps_rmc_p”線程,以中斷方式接收序列槽資料(即GPS子產品資料),并對GPS定位資訊進行了解析,通過終端列印出來。也就是說在GPS子產品預設使用9600波特率時,不需要做任何代碼修改,即可實作GPS定位資訊輸出,這也充分展現了使用開源開發方式的高效。

6. 擷取GPS定位資訊

以上工程配置編譯通過後,隻需要連接配接GPS硬體子產品即可輸出GPS定位資訊,實測裝置上電後約10秒為首次擷取定位時間,輸出無效資料,之後每秒更新一次GPS定位有效資料。

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

修改代碼,列印GPS原始資料:

【RT-Thread】STM32的UART裝置讀取GPS資料前言1. 開發環境搭建2. RTT Studio建立工程3. CubeMX配置系統時鐘4. SConscript建構目錄5. UART裝置驅動程式6. 擷取GPS定位資訊小結

GNRMC資料格式說明:

1:$GNRMC, 格式ID,表示該格式為建議的最低特定GPS / TRANSIT資料(RMC)推薦最低定位資訊
2: UTC時間, 格式hhmmss.ssss,代表時分秒.毫秒
3: 狀态 A:代表定位成功 V:代表定位失敗 
4: 緯度 ddmm.mmmmmm 度格式(如果前導位數不足,則用0填充)
5: 緯度 N(北緯)  S(南緯)
6: 經度 dddmm.mmmmmm 度格式(如果前導位數不足,則用0填充)
7: 經度 E(東經) W(西經)
8: 速度(也為1.852 km / h)
9: 方位角,度(二維方向,等效于二維羅盤)
10: UTC日期 DDMMYY 天月年
11: 磁偏角(000-180)度,如果前導位數不足,則用0填充)
12: 磁偏角方向E =東W =西
13: 模式,A=自主模式,E=估算模式,N=資料模式,D=差分模式,M=未定位
14: 校驗和
15: 回車換行符
           

小結

學習RT-Thread裝置驅動時,需要先了解drivers驅動庫與HAL庫之間的關系,兩者之間可以通過CubeMX工具作為橋梁,合理利用CubeMX可有效提高開發效率。此外,RT-Thread Studio中的開源軟體包資源豐富,本文隻對GPS子產品功能進行測試,其它類似外設驅動也可以參照此方法實作快速開發。

繼續閱讀