精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

通過多線程來實現ADC采集功能和OLED顯示功能

MCU學習筆記 ? 來源:MCU學習筆記 ? 作者:MCU學習筆記 ? 2021-11-20 09:30 ? 次閱讀

在之前的一篇推文中,介紹了AB32VG1開發板將模擬量通道7采集到的電壓值實時顯示在OLED顯示屏。雖然之前介紹過AB32VG1采用RT-Thread Studio建立的工程項目基于RT-Thread物聯網操作系統的,但是實時大家看到代碼就會發現,雖然跑了實時操作系統,但是其中的編程方式還是采用的裸機程序編程模式,在main程序while死循環中中調用各種功能函數實現相應功能。具體項目地址:中科藍訊 AB32VG1 開發板ADC采集與顯示實驗。我們知道RTOS編程和裸機編程最大的區別就是RTOS可實現多線程管理,這是RTOS的最大優勢。既然跑了操作系統,為何不用多線程實現ADC采集功能和OLED顯示功能呢?下面我們就重做這個項目,將裸機代碼函數轉換為線程實現這個功能。

1.線程的創建

一個線程要成為可執行的對象就必須由操作系統的內核來為它創建(初始化)一個線程 句柄。可以通過如下的函數接口來創建一個線程。

rt_thread_t rt_thread_create(const char* name, void (*entry)(void* parameter), void* parameter, rt_uint32_t stack_size, rt_uint8_t priority, rt_uint32_t tick);

調用這個函數時,系統會從動態堆內存中分配一個線程句柄(即TCB,線程控制塊) 以及按照參數中指定的棧大小從動態堆內存中分配相應的空間。分配出來的棧空間是按照 rtconfig.h中配置的RT_ALIGN_SIZE方式對齊。

2.參數介紹:

name是線程的名稱;線程名稱的最大長度由rtconfig.h中定義的 RT_NAME_MAX宏指定,多余部分會被自動截掉。

entry 線程入口函數;

parameter 線程入口函數參數,沒有參數可設置為RT_NULL;

stack_size 線程棧大小,單位是字節。在大多數系統中需要做棧空間地址對 齊(例如ARM體系結構中需要向4字節地址對齊)。

priority 線程的優先級。優先級范圍根據系統配置情況(rtconfig.h中的 RT_THREAD_PRIORITY_MAX宏定義),如果支持的是256級優先 級,那么范圍是從0 ~ 255,數值越小優先級越高,0代表最高優 10 先級。

tick 線程的時間片大小。時間片(tick)的單位是操作系統的時鐘節 拍。當系統中存在相同優先級線程時,這個參數指定線程一次調 度能夠運行的最大時間長度。這個時間片運行結束時,調度器自 動選擇下一個就緒態的同優先級線程進行運行。

3.函數返回

創建成功返回線程句柄;否則返回RT_NULL。

4.案例應用

下面就ADC電壓采集與OLED顯示創建兩個個線程加以說明線程的創建方法:上個項目的main函數完整代碼如下。

#include

#include

#include

#include

#include"board.h"

#include"ssd1306.h"//包含SSD1306的頭文件

#defineADC_DEV_NAME "adc0" /* ADC 設備名稱 */

#defineADC_DEV_CHANNEL 7 /* ADC 通道 */

#defineREFER_VOLTAGE 330 /* 參考電壓 3.3V,數據精度乘以100保留2位小數*/

#defineCONVERT_BITS (1 << 10)?? /* 轉換位數為12位 */

void display(int tmp)

{

//330

unsignedchar count;

unsignedchar datas[] = {0, 0, 0, 0, 0};

datas[0] = tmp / 100;

datas[1] = tmp % 100 / 10;

datas[2] = tmp % 100 % 10;

ssd1306_SetCursor(40, 40);//添加代碼,設置顯示光標位置

ssd1306_WriteChar('0'+datas[0], Font_11x18, White);

ssd1306_WriteChar('.', Font_11x18, White);

for(count = 1; count != 3; count++)

{

ssd1306_WriteChar('0'+datas[count], Font_11x18, White);

}

ssd1306_WriteChar('V', Font_11x18, White);

ssd1306_UpdateScreen();////添加代碼,更新顯示屏信息

}

static int adc_vol_sample()

{

rt_adc_device_t adc_dev;

unsignedchar Temp_Disp_Buff[17];

rt_uint32_t value, vol;

rt_err_t ret = RT_EOK;

/* 查找設備 */

adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);

if (adc_dev == RT_NULL)

{

rt_kprintf("adc sample run failed! can'tfind %s device!\n", ADC_DEV_NAME);

return RT_ERROR;

}

/* 使能設備 */

ret = rt_adc_enable(adc_dev,ADC_DEV_CHANNEL);

/* 讀取采樣值 */

value = rt_adc_read(adc_dev,ADC_DEV_CHANNEL);

rt_kprintf("the value is :%d \n", value);

/* 轉換為對應電壓值 */

vol = value * REFER_VOLTAGE / CONVERT_BITS;

rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);

/* 關閉通道 */

ret = rt_adc_disable(adc_dev,ADC_DEV_CHANNEL);

display(vol);

return ret;

}

int main(void)

{

uint8_t pin = rt_pin_get("PE.1");

staticint advlue;

rt_pin_mode(pin, PIN_MODE_OUTPUT);

rt_kprintf("Hello, world\n");

ssd1306_Init();//添加代碼,顯示屏初始化

ssd1306_SetCursor(2, 6);//添加代碼,設置顯示光標位置

ssd1306_WriteString("The voltage", Font_11x18, White);//添加代碼,設置顯示內容

ssd1306_SetCursor(40, 40);//添加代碼,設置顯示光標位置

display(0);

ssd1306_UpdateScreen();////添加代碼,更新顯示屏信息

while (1)

{

rt_pin_write(pin, PIN_LOW);

rt_thread_mdelay(500);

rt_pin_write(pin, PIN_HIGH);

rt_thread_mdelay(500);

advlue=adc_vol_sample();

}

}

下面我們對上面代碼修改實現多線程,首先將static int adc_vol_sample()和void display(int tmp)改為線程的入口函數,線程的入口函數實際是一個無限循環且不帶返回值的C函數。

首先將void display(int tmp)改為線程入口函數如下形式,注意三點:

第一:將原函數語句放在while(1)循環體內。

第二:while語句循環末尾增加rt_thread_delay(50);延時語句。注意這里不能使用裸機那種的延時,必須用這個延時函數,rt_thread_delay是阻塞延時,調用此函數時,該線程會被掛起,調度器會切換到其他就緒的線程,從而實現多線程。

第三:要定義全局變量rt_uint32_t vol;;vol是要顯示的電壓,其實這里用信號量比較合適,暫時用全局變量吧。

static void display_entry(void* parameter)

{

while(1)

{

unsignedchar count;

unsignedchar datas[] = {0, 0, 0, 0, 0};

datas[0] = vol/ 100;

datas[1] = vol% 100 / 10;

datas[2] = vol% 100 % 10;

ssd1306_SetCursor(40, 40);//添加代碼,設置顯示光標位置

ssd1306_WriteChar('0'+datas[0], Font_11x18, White);

ssd1306_WriteChar('.', Font_11x18, White);

for(count = 1; count != 3; count++)

{

ssd1306_WriteChar('0'+datas[count], Font_11x18, White);

}

ssd1306_WriteChar('V', Font_11x18, White);

ssd1306_UpdateScreen();////添加代碼,更新顯示屏信息

rt_thread_delay(50);

}

}


//創建oled_display線程,一定主要第二個參數入口函數名一定要上面的入口函數名字一致

void oled_display_thread_create()
{
rt_thread_t oled_display_thread;
oled_display_thread = rt_thread_create("oled_display",
display_entry,
RT_NULL,
1024,
RT_THREAD_PRIORITY_MAX / 2,
40);
if (oled_display_thread != RT_NULL)
{
rt_thread_startup(oled_display_thread);
}

}

然后將static int adc_vol_sample()函數改為線程入口函數如下形式,

static void adc_vol_entry(void *parameter)

{

rt_adc_device_t adc_dev;

unsignedchar Temp_Disp_Buff[17];

rt_uint32_t value;

rt_err_t ret = RT_EOK;

/* 查找設備 */

adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);

if (adc_dev == RT_NULL)

{

rt_kprintf("adc sample run failed! can'tfind %s device!\n", ADC_DEV_NAME);

return RT_ERROR;

}

while(1)

{

/* 使能設備 */

ret = rt_adc_enable(adc_dev,ADC_DEV_CHANNEL);

/* 讀取采樣值 */

value = rt_adc_read(adc_dev,ADC_DEV_CHANNEL);

rt_kprintf("the value is :%d \n", value);

/* 轉換為對應電壓值 */

vol = value * REFER_VOLTAGE / CONVERT_BITS;

rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);

/* 關閉通道 */

ret = rt_adc_disable(adc_dev,ADC_DEV_CHANNEL);

rt_thread_delay(50);

}

}


//創建ADC采樣線程
void adc_voltage_thread_create()
{
rt_thread_t adc_voltage_thread;
adc_voltage_thread = rt_thread_create("adc_voltage",
adc_vol_entry,
RT_NULL,
1024,
RT_THREAD_PRIORITY_MAX / 2,
40);
if (adc_voltage_thread != RT_NULL)
{
rt_thread_startup(adc_voltage_thread);
}
}

最后修改main函數如下,將LED燈閃爍代碼刪除,增加線程創建和啟動代碼;

int main(void)

{

//顯示屏初始化

ssd1306_Init();//添加代碼,顯示屏初始化

ssd1306_SetCursor(2, 6);//添加代碼,設置顯示光標位置

ssd1306_WriteString("The voltage", Font_11x18, White);//添加代碼,設置顯示內容

ssd1306_SetCursor(40, 40);//添加代碼,設置顯示光標位

ssd1306_UpdateScreen();////添加代碼,更新顯示屏信息

//線程的創建和啟動

adc_voltage_thread_create();

oled_display_thread_create();

}

至此,代碼修改完畢,編譯下載項目運行,然后在FinSHshell中通過 list_thread()命令查看線程相關信息,如下圖所示,adc_voltageoled_display兩個線程。更多內容可關注MCU學習筆記。

poYBAGGYTwyAcCuAACUIG9WRAJM112.pngpoYBAGGYTvSAM_sKAAGbq0rdGVE117.png

編輯:fqj

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • OLED
    +關注

    關注

    119

    文章

    6130

    瀏覽量

    223081
  • adc
    adc
    +關注

    關注

    97

    文章

    6296

    瀏覽量

    542410
  • 多線程
    +關注

    關注

    0

    文章

    275

    瀏覽量

    19850
  • 開發板
    +關注

    關注

    25

    文章

    4771

    瀏覽量

    96155
  • RT-Thread
    +關注

    關注

    31

    文章

    1239

    瀏覽量

    39427
收藏 人收藏

    評論

    相關推薦

    基于TCP/IP協議和多線程的通信軟件的設計與實現

    】:0引言通信軟件是船舶導航監控系統的重要組成部分,集數據采集、通信、顯示功能于一體,是實現水上智能交通的核心環節[1]。通信軟件的實時性、準確性和效率直接影響船舶導航監控系統的性能。
    發表于 05-06 09:02

    LABVIEW如何使用ICMP協議實現多線程ping的功能

    LABVIEW如何通過ICMP協議實現多線程ping的功能?這個網上沒查到相關資料。通過cmd同時ping
    發表于 11-16 17:31

    【GD32330C-START開發板申請】基于GD32330C的OLED顯示功能實現

    I2C接口的OLED屏為顯示器件,顯示實現功能。此外,配合RTC和A/D的
    發表于 09-10 09:21

    如何通過ADC實現功能安全的潛力

    本文旨在從確保數據采集系統整體完整性的角度,探討通過ADC實現功能安全的潛力。
    發表于 01-29 07:20

    Micropython STM32添加多線程功能

    Micropython 官方下載的代碼默認未開啟多線程支持,可用以下方法: Micropython添加多線程功能的STM32目錄下mpconfigport.h中 #define MICROPY_PY_THREAD (1)...
    發表于 08-24 06:08

    micropython esp32刷固件adc多線程如何去實現

    micropython esp32刷固件adc多線程如何去實現呢?
    發表于 01-25 06:09

    NP多線程防火墻的設計與實現

    本文介紹了一種 NP(Network Processor)多線程防火墻的設計方案。首先介紹了NP多線程防火墻的工作原理,然后提出了對該防火墻的體系結構設計,通過對各功能模塊的分析,給出
    發表于 08-06 08:25 ?15次下載

    Delphi教程_實現多線程共享探測

    Delphi教程實現多線程共享探測,很好的Delphi學習資料。
    發表于 03-16 14:59 ?3次下載

    基于OPC技術的多線程數據采集系統的實現_喬富強

    基于OPC技術的多線程數據采集系統的實現_喬富強
    發表于 01-12 19:56 ?1次下載

    多線程與聊天室程序的創建

    多線程程序的編寫,多線程應用中容易出現的問題。互斥對象的講解,如何采用互斥對象實現多線程的同步。如何利用命名互斥對象保證應用程序只有一個實
    發表于 05-16 15:22 ?0次下載

    如何使用LabWindows CVI多線程技術實現實時的數據采集詳細資料說明

    LabWindows/CVI軟件自帶的多線程機制,采用將線程池和異步定時器相互結合的方法實現實時數據采集線程和數據處理
    發表于 07-17 17:02 ?30次下載
    如何使用LabWindows CVI<b class='flag-5'>多線程</b>技術<b class='flag-5'>實現</b>實時的數據<b class='flag-5'>采集</b>詳細資料說明

    如何通過多線程并發設計提高應用程序的性能

    這里我們簡單總結了一下,在現代多處理器或多內核環境下,如何通過多線程并發設計提高我們應用程序的性能和響應性。
    的頭像 發表于 09-28 02:13 ?5191次閱讀

    SpringBoot實現多線程

    SpringBoot實現多線程
    的頭像 發表于 01-12 16:59 ?1707次閱讀
    SpringBoot<b class='flag-5'>實現</b><b class='flag-5'>多線程</b>

    多線程如何保證數據的同步

    。本文將詳細介紹多線程數據同步的概念、問題、以及常見的解決方案。 一、多線程數據同步概念 在多線程編程中,數據同步指的是通過某種機制確保多
    的頭像 發表于 11-17 14:22 ?886次閱讀

    java實現多線程的幾種方式

    Java實現多線程的幾種方式 多線程是指程序中包含了兩個或以上的線程,每個線程都可以并行執行不同的任務或操作。Java中的
    的頭像 發表于 03-14 16:55 ?432次閱讀