天天看點

RT-Thread stm32 基礎記錄

準備工作

安裝 RT-Thread Studio。

建立 Nano 工程

打開 IDE,點選【檔案】-【建立】-【RT-Thread 項目】:

RT-Thread stm32 基礎記錄

進入建立工程的配置向導:

RT-Thread stm32 基礎記錄

注:可以通過修改 board.c 的 

SystemClock_Config()

 更改系統時鐘。

工程建立完畢,連接配接硬體,可直接進行編譯下載下傳,如下所示:

RT-Thread stm32 基礎記錄

編寫main.c

将以下代碼直接拷貝至main.c

/* 
 * 2019-09-09     RT-Thread   
 */

#include <rtthread.h>
#include <board.h>
#include <rtdevice.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

/* PLEASE DEFINE the LED0 pin for your board, such as: PA5 */
#define LED0_PIN    GET_PIN(C, 13)



#define THREAD_PRIORITY         25
#define THREAD_STACK_SIZE       512
#define THREAD_TIMESLICE        5

static rt_thread_t tid1 = RT_NULL;

/* 線程1的入口函數 */
static void thread1_entry(void *parameter)
{
    rt_uint32_t count = 0;

    while (1)
    {
        /* 線程1采用低優先級運作,一直列印計數值 */
        rt_kprintf("thread1 count: %d\n", count ++);
        rt_thread_mdelay(500);
    }
}

ALIGN(RT_ALIGN_SIZE)
static char thread2_stack[1024];
static struct rt_thread thread2;
/* 線程2入口 */
static void thread2_entry(void *param)
{
    int count = 1;
       /* set LED0 pin mode to output */
       rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);

       while (count++)
       {
           /* set LED0 pin level to high or low */
           rt_pin_write(LED0_PIN, count % 2);
           LOG_D("Hello RT-Thread!");
           rt_thread_mdelay(100);
       }


//    rt_uint32_t count = 0;
//
//    /* 線程2擁有較高的優先級,以搶占線程1而獲得執行 */
//    for (count = 0; count < 10 ; count++)
//    {
//        /* 線程2列印計數值 */
//        rt_kprintf("thread2 count: %d\n", count);
//        rt_thread_mdelay(500);
//    }
//    rt_kprintf("thread2 exit\n");
//    /* 線程2運作結束後也将自動被系統删除
//    (線程控制塊和線程棧依然在idle線程中釋放) */
}

/* 删除線程示例的初始化 */
int thread_sample(void)
{
    /* 建立線程1,名稱是thread1,入口是thread1_entry*/
    tid1 = rt_thread_create("thread1",
                            thread1_entry, RT_NULL,
                            THREAD_STACK_SIZE,
                            THREAD_PRIORITY-1, THREAD_TIMESLICE);

    /* 如果獲得線程控制塊,啟動這個線程 */
    if (tid1 != RT_NULL)
    {
        //啟動線程
        rt_thread_startup(tid1);
    }

    /* 初始化線程2,名稱是thread2,入口是thread2_entry */
    rt_thread_init(&thread2,
                   "thread2",
                   thread2_entry,
                   RT_NULL,
                   &thread2_stack[0],
                   sizeof(thread2_stack),
                   THREAD_PRIORITY - 1, THREAD_TIMESLICE);
    //啟動線程
    rt_thread_startup(&thread2);

    return 0;
}


int main(void)
{
       thread_sample();
   
    return RT_EOK;
}
           

運作結果

在建立工程向導中配置了控制台序列槽号及其引腳号,是以工程中已經實作了 uart 的驅動以及 

rt_hw_console_output()

 ,預設可以進行列印。打開序列槽終端,可以發現在終端中執行了列印。

RT-Thread stm32 基礎記錄
RT-Thread stm32 基礎記錄

RT-Thread Studio 結合 STM32CubeMx 開發其他外設驅動

使用 

RT-Thread Studio

 建立 RT-Thread 的項目時直接就将 RT-Thread 實時作業系統移植到對應的晶片上了,省去了系統移植的步驟。

使用 

STM32CubeMx

 配置工具可以友善快速的配置晶片外設的時鐘和引腳,使驅動的開發變得簡單。

是以本文将結合這兩個 IDE 的優點,介紹基于 

RT-Thread Studio

 和 

STM32CubeMx

 的驅動開發。

需要注意的是這裡開發的驅動是不基于 RT-Thread 裝置驅動架構的,即直接使用 

STM32CubeMx

 生成的 HAL 庫檔案來開發外設驅動。

簡介

使用 

RT-Thread Studio

 和 

STM32CubeMx

 開發驅動可分為以下幾個步驟

  • 使用 

    RT-Thread Studio

     建立 RT-Thread 工程
  • 使用 

    STM32CubeMx

     配置外設和系統時鐘
  • 複制 

    stm32xxxx_hal_msp.c

     函數
  • 修改 

    stm32xxxx_hal_config.h

     檔案,打開相應外設支援。
  • 替換 

    board.c

     檔案中時鐘配置函數
  • 使用外設

建立 RT-Thread 項目

使用 

RT-Thread Studio

 建立基于 

nano-v3.1.3

 的工程,界面如下圖所示

RT-Thread stm32 基礎記錄

配置過程可總結為以下步驟:

  • 定義自己的工程名及工程生成檔案的存放路徑
  • 選擇 

    基于晶片

     建立工程,選擇的 RT-Thread 版本為 

    nano-v3.1.3

  • 選擇廠商及晶片型号
  • 配置序列槽資訊
  • 配置調試器資訊

工程配置完成後點選下方的 

完成

 按鈕即可建立 RT-Thread 的工程。

基于 Studio 建立 RT-Thread 工程後,就可以基于建立的工程開發自己的驅動。下面将以 

stm32l475-atk-pandora

 開發闆為例,講解如何開發 ADC 驅動。

配置外設

建立基于目标闆卡的 

CubeMx

 工程,并配置自己需要使用的外設。

例如,示例開發闆的 PC2 連接配接的是 ADC1 的通道 3,使用 

CubeMx

 生成 ADC 的驅動代碼的配置結果如下所示:

RT-Thread stm32 基礎記錄

複制 

stm32xxxx_hal_msp.c

 函數

将 

CubeMx

 生成的代碼 

stm32l4xx_hal_msp.c

 函數複制到 RT-Thread Studio 生成的工程中,并參與工程編譯。複制完成後的結果如下圖所示

RT-Thread stm32 基礎記錄

由于我們并沒有使用 CubeMx 生成的工程,是以這裡需要将 

stm32l4xx_hal_msp.c

 檔案中 

#include "main.h"

 替換為 

#include "board.h"

打開 HAL 庫配置檔案對應外設的支援宏

這裡我們使用了 ADC 外設,是以需要在 

stm32l4xx_hal_config.h

 檔案中将 ADC 子產品使能,取消 ADC 子產品的注釋即可,示例代碼如下

#define HAL_ADC_MODULE_ENABLED
           

修改系統時鐘(可選)

使用 RT-Thread Studio 建立 RT-Thread 工程時預設使用的是系統内部時鐘 HSI,這裡需要根據自己的闆卡配置将 

STM32CubeMx

 生成的時鐘配置函數拷貝到 RT-hread 的工程中。步驟如下

  • 使用 CubeMx 配置自己闆卡的系統時鐘,并生成代碼
  • 複制 CubeMx 工程中 

    main.c

     檔案的 

    void SystemClock_Config(void)

     系統時鐘初始化函數
  • 替換 

    RT-Thread Studio

     生成的工程中的 

    drv_clk.c

     檔案中的系統時鐘配置函數

    void system_clock_config(int target_freq_mhz)

     ,如下圖所示。
RT-Thread stm32 基礎記錄
  • 如果使用外部時鐘,則需要更新工程中的

    stm32xxxx_hal_conf.h

     中的對應的外部時鐘頻率的值,以 HSE 為例,需要修改下面的時鐘頻率為實際使用的值:
#define HSE_VALUE ((uint32_t)8000000U) /!< Value of the External oscillator in Hz /
           

使用外設

上述檔案配置完成之後,ADC 外設就可以使用的,在 

main.c

 中添加外設的使用代碼

ADC 外設的使用示例代碼如下

#include <rtthread.h>
#include "board.h"

ADC_HandleTypeDef hadc1;

/* ADC1 init function */
void MX_ADC1_Init(void)
{
  ADC_MultiModeTypeDef multimode = {0};
  ADC_ChannelConfTypeDef sConfig = {0};

  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = DISABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_3;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }

}

rt_uint32_t get_adc_value(void)
{
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, 10);

    return (rt_uint32_t)HAL_ADC_GetValue(&hadc1);
}

int main(void)
{
    int count = 1;
    rt_uint32_t read_value = 0;

    MX_ADC1_Init();
    while (count++)
    {
        read_value = get_adc_value();
        rt_thread_mdelay(1000);
        rt_kprintf("adc value = %d\r\n", read_value);
    }

    return RT_EOK;
}
           

編譯下載下傳工程,将開發闆的 PC2 引腳連接配接到開發闆上的地,終端列印資訊如下

RT-Thread stm32 基礎記錄

将開發闆的 PC2 引腳連接配接到開發闆的 3.3V 引腳,終端列印資訊如下

RT-Thread stm32 基礎記錄

從上面兩個實驗列印結果可以看出我們成功使用了 ADC 外設。

注意事項

  • board.c

     檔案中的系統時鐘配置函數需要根據自己的闆卡進行修改
  • stm32xxxx_hal_msp.c

     函數中主要完成的是外設引腳和時鐘的初始化,是以在使用 

    CubeMx

     生成外設的配置代碼時不能選擇為每個外設都生成 

    .c/.h

     檔案
  • 使用 

    CubeMx

     外設時隻需要配置實際使用的外設,如果 

    stm32xxxx_hal_msp.c

     檔案和 

    drv_uart.c

     檔案或者 

    drv_spi.c

     檔案外設的初始化函數重定義,需要删除 

    stm32xxxx_hal_msp.c

     檔案中外設的初始化函數。

參考連結:

https://www.cnblogs.com/pathfinder-world/p/14672508.html

https://www.rt-thread.org/document/site/tutorial/nano/nano-port-studio/an0047-nano-port-studio/

https://www.rt-thread.org/document/site/rtthread-studio/drivers/cubemx/rtthread-studio-cubemx/