0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

通過多線程來實(shí)現(xiàn)ADC采集功能和OLED顯示功能

MCU學(xué)習(xí)筆記 ? 來源:MCU學(xué)習(xí)筆記 ? 作者:MCU學(xué)習(xí)筆記 ? 2021-11-20 09:30 ? 次閱讀

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

1.線程的創(chuàng)建

一個(gè)線程要成為可執(zhí)行的對象就必須由操作系統(tǒng)的內(nèi)核來為它創(chuàng)建(初始化)一個(gè)線程 句柄。可以通過如下的函數(shù)接口來創(chuàng)建一個(gè)線程。

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

調(diào)用這個(gè)函數(shù)時(shí),系統(tǒng)會(huì)從動(dòng)態(tài)堆內(nèi)存中分配一個(gè)線程句柄(即TCB,線程控制塊) 以及按照參數(shù)中指定的棧大小從動(dòng)態(tài)堆內(nèi)存中分配相應(yīng)的空間。分配出來的??臻g是按照 rtconfig.h中配置的RT_ALIGN_SIZE方式對齊。

2.參數(shù)介紹:

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

entry 線程入口函數(shù);

parameter 線程入口函數(shù)參數(shù),沒有參數(shù)可設(shè)置為RT_NULL;

stack_size 線程棧大小,單位是字節(jié)。在大多數(shù)系統(tǒng)中需要做??臻g地址對 齊(例如ARM體系結(jié)構(gòu)中需要向4字節(jié)地址對齊)。

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

tick 線程的時(shí)間片大小。時(shí)間片(tick)的單位是操作系統(tǒng)的時(shí)鐘節(jié) 拍。當(dāng)系統(tǒng)中存在相同優(yōu)先級線程時(shí),這個(gè)參數(shù)指定線程一次調(diào) 度能夠運(yùn)行的最大時(shí)間長度。這個(gè)時(shí)間片運(yùn)行結(jié)束時(shí),調(diào)度器自 動(dòng)選擇下一個(gè)就緒態(tài)的同優(yōu)先級線程進(jìn)行運(yùn)行。

3.函數(shù)返回

創(chuàng)建成功返回線程句柄;否則返回RT_NULL。

4.案例應(yīng)用

下面就ADC電壓采集與OLED顯示創(chuàng)建兩個(gè)個(gè)線程加以說明線程的創(chuàng)建方法:上個(gè)項(xiàng)目的main函數(shù)完整代碼如下。

#include

#include

#include

#include

#include"board.h"

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

#defineADC_DEV_NAME "adc0" /* ADC 設(shè)備名稱 */

#defineADC_DEV_CHANNEL 7 /* ADC 通道 */

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

#defineCONVERT_BITS (1 << 10)?? /* 轉(zhuǎn)換位數(shù)為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);//添加代碼,設(shè)置顯示光標(biāo)位置

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;

/* 查找設(shè)備 */

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;

}

/* 使能設(shè)備 */

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

/* 轉(zhuǎn)換為對應(yīng)電壓值 */

vol = value * REFER_VOLTAGE / CONVERT_BITS;

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

/* 關(guān)閉通道 */

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);//添加代碼,設(shè)置顯示光標(biāo)位置

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

ssd1306_SetCursor(40, 40);//添加代碼,設(shè)置顯示光標(biāo)位置

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();

}

}

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

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

第一:將原函數(shù)語句放在while(1)循環(huán)體內(nèi)。

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

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

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);//添加代碼,設(shè)置顯示光標(biāo)位置

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

}

}


//創(chuàng)建oled_display線程,一定主要第二個(gè)參數(shù)入口函數(shù)名一定要上面的入口函數(shù)名字一致

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()函數(shù)改為線程入口函數(shù)如下形式,

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;

/* 查找設(shè)備 */

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)

{

/* 使能設(shè)備 */

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

/* 轉(zhuǎn)換為對應(yīng)電壓值 */

vol = value * REFER_VOLTAGE / CONVERT_BITS;

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

/* 關(guān)閉通道 */

ret = rt_adc_disable(adc_dev,ADC_DEV_CHANNEL);

rt_thread_delay(50);

}

}


//創(chuàng)建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函數(shù)如下,將LED燈閃爍代碼刪除,增加線程創(chuàng)建和啟動(dòng)代碼;

int main(void)

{

//顯示屏初始化

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

ssd1306_SetCursor(2, 6);//添加代碼,設(shè)置顯示光標(biāo)位置

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

ssd1306_SetCursor(40, 40);//添加代碼,設(shè)置顯示光標(biāo)位

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

//線程的創(chuàng)建和啟動(dòng)

adc_voltage_thread_create();

oled_display_thread_create();

}

至此,代碼修改完畢,編譯下載項(xiàng)目運(yùn)行,然后在FinSHshell中通過 list_thread()命令查看線程相關(guān)信息,如下圖所示,adc_voltageoled_display兩個(gè)線程。更多內(nèi)容可關(guān)注MCU學(xué)習(xí)筆記。

poYBAGGYTwyAcCuAACUIG9WRAJM112.pngpoYBAGGYTvSAM_sKAAGbq0rdGVE117.png

編輯:fqj

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • OLED
    +關(guān)注

    關(guān)注

    119

    文章

    6200

    瀏覽量

    224224
  • adc
    adc
    +關(guān)注

    關(guān)注

    98

    文章

    6498

    瀏覽量

    544680
  • 多線程
    +關(guān)注

    關(guān)注

    0

    文章

    278

    瀏覽量

    19964
  • 開發(fā)板
    +關(guān)注

    關(guān)注

    25

    文章

    5052

    瀏覽量

    97494
  • RT-Thread
    +關(guān)注

    關(guān)注

    31

    文章

    1289

    瀏覽量

    40140
收藏 人收藏

    評論

    相關(guān)推薦

    基于TCP/IP協(xié)議和多線程的通信軟件的設(shè)計(jì)與實(shí)現(xiàn)

    】:0引言通信軟件是船舶導(dǎo)航監(jiān)控系統(tǒng)的重要組成部分,集數(shù)據(jù)采集、通信、顯示功能于一體,是實(shí)現(xiàn)水上智能交通的核心環(huán)節(jié)[1]。通信軟件的實(shí)時(shí)性、準(zhǔn)確性和效率直接影響船舶導(dǎo)航監(jiān)控系統(tǒng)的性能。
    發(fā)表于 05-06 09:02

    LABVIEW如何使用ICMP協(xié)議實(shí)現(xiàn)多線程ping的功能

    LABVIEW如何通過ICMP協(xié)議實(shí)現(xiàn)多線程ping的功能?這個(gè)網(wǎng)上沒查到相關(guān)資料。通過cmd同時(shí)ping
    發(fā)表于 11-16 17:31

    【GD32330C-START開發(fā)板申請】基于GD32330C的OLED顯示功能實(shí)現(xiàn)

    I2C接口的OLED屏為顯示器件,顯示實(shí)現(xiàn)功能。此外,配合RTC和A/D的
    發(fā)表于 09-10 09:21

    如何通過ADC實(shí)現(xiàn)功能安全的潛力

    本文旨在從確保數(shù)據(jù)采集系統(tǒng)整體完整性的角度,探討通過ADC實(shí)現(xiàn)功能安全的潛力。
    發(fā)表于 01-29 07:20

    Micropython STM32添加多線程功能

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

    micropython esp32刷固件adc多線程如何去實(shí)現(xiàn)

    micropython esp32刷固件adc多線程如何去實(shí)現(xiàn)呢?
    發(fā)表于 01-25 06:09

    NP多線程防火墻的設(shè)計(jì)與實(shí)現(xiàn)

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

    Delphi教程_實(shí)現(xiàn)多線程共享探測

    Delphi教程實(shí)現(xiàn)多線程共享探測,很好的Delphi學(xué)習(xí)資料。
    發(fā)表于 03-16 14:59 ?3次下載

    基于OPC技術(shù)的多線程數(shù)據(jù)采集系統(tǒng)的實(shí)現(xiàn)_喬富強(qiáng)

    基于OPC技術(shù)的多線程數(shù)據(jù)采集系統(tǒng)的實(shí)現(xiàn)_喬富強(qiáng)
    發(fā)表于 01-12 19:56 ?1次下載

    多線程與聊天室程序的創(chuàng)建

    多線程程序的編寫,多線程應(yīng)用中容易出現(xiàn)的問題?;コ鈱ο蟮闹v解,如何采用互斥對象實(shí)現(xiàn)多線程的同步。如何利用命名互斥對象保證應(yīng)用程序只有一個(gè)實(shí)
    發(fā)表于 05-16 15:22 ?0次下載

    如何使用LabWindows CVI多線程技術(shù)實(shí)現(xiàn)實(shí)時(shí)的數(shù)據(jù)采集詳細(xì)資料說明

    LabWindows/CVI軟件自帶的多線程機(jī)制,采用將線程池和異步定時(shí)器相互結(jié)合的方法實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)采集線程和數(shù)據(jù)處理
    發(fā)表于 07-17 17:02 ?34次下載
    如何使用LabWindows CVI<b class='flag-5'>多線程</b>技術(shù)<b class='flag-5'>實(shí)現(xiàn)</b>實(shí)時(shí)的數(shù)據(jù)<b class='flag-5'>采集</b>詳細(xì)資料說明

    如何通過多線程并發(fā)設(shè)計(jì)提高應(yīng)用程序的性能

    這里我們簡單總結(jié)了一下,在現(xiàn)代多處理器或多內(nèi)核環(huán)境下,如何通過多線程并發(fā)設(shè)計(jì)提高我們應(yīng)用程序的性能和響應(yīng)性。
    的頭像 發(fā)表于 09-28 02:13 ?5310次閱讀

    SpringBoot實(shí)現(xiàn)多線程

    SpringBoot實(shí)現(xiàn)多線程
    的頭像 發(fā)表于 01-12 16:59 ?1831次閱讀
    SpringBoot<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>多線程</b>

    多線程如何保證數(shù)據(jù)的同步

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

    java實(shí)現(xiàn)多線程的幾種方式

    Java實(shí)現(xiàn)多線程的幾種方式 多線程是指程序中包含了兩個(gè)或以上的線程,每個(gè)線程都可以并行執(zhí)行不同的任務(wù)或操作。Java中的
    的頭像 發(fā)表于 03-14 16:55 ?709次閱讀