女人荫蒂被添全过程13种图片,亚洲+欧美+在线,欧洲精品无码一区二区三区 ,在厨房拨开内裤进入毛片

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

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

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

如何讓STM32優(yōu)雅地“說”hello world?

GReq_mcu168 ? 來源:嵌入式ARM ? 2020-06-28 17:18 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

01

前言

STM32上hello world,說白了就是使用串口向PC上的上位機(jī)軟件或者串口調(diào)試助手發(fā)送字符串。

串口的使用方法百度一下就能知道了,簡單來說就是下面這樣。

uint8_t buff[BUFF_SIZE];//定義一個(gè)緩存數(shù)組 HAL_UART_Receive_IT(&huart1, (uint8_t *)buff, BUFF_SIZE);//打開串口接收中斷

串口中斷打開之后,當(dāng)接收到BUFF_SIZE個(gè)數(shù)據(jù)后就會(huì)進(jìn)入

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);

然后我們就可以在上面這個(gè)函數(shù)下操作收到的數(shù)據(jù)啦,簡單方便快捷。當(dāng)然實(shí)際操作一遍后大家就會(huì)發(fā)現(xiàn),這個(gè)程序只能進(jìn)入一次中斷,之后就再也收不到數(shù)據(jù)了,這是因?yàn)镠AL庫在每次進(jìn)入串口中斷時(shí)都會(huì)把這個(gè)中斷關(guān)閉,所以我們處理完數(shù)據(jù)之后,要重新打開中斷。

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){ //處理數(shù)據(jù)... HAL_UART_Receive_IT(&huart1, (uint8_t *)buff, BUFF_SIZE);}

而發(fā)送數(shù)據(jù)呢,就用

HAL_UART_Transmit(&huart1, (uint8_t *)buff, BUFF_SIZE,0xffff);

知道串口怎么用了,我們就可以想辦法hello world。重定向printf的方法百度一搜一大片,fputc這個(gè)函數(shù)是_weak定義的,自己寫一個(gè)就可以覆蓋過去了。

int fputc(int ch, FILE *f){ HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1,0xffff); return ch;}

然后寫下終極代碼,完美。

printf("hello world ");

上面的內(nèi)容百度上可以找到很多很多文章,而且講的又詳細(xì)又生動(dòng),這里我只是帶大家復(fù)習(xí)一下,如果你能夠熟練掌握上面的內(nèi)容了,那接下來就可以進(jìn)入正題,看看如何變得更優(yōu)雅。

02

變優(yōu)雅第一步

我們實(shí)際運(yùn)行這個(gè)代碼,發(fā)現(xiàn)在串口接收幾次數(shù)據(jù)之后,又突然會(huì)再也接收不到數(shù)據(jù)了。因?yàn)榧词鼓阌浀迷谔幚硗陻?shù)據(jù)之后及時(shí)打開了接收中斷,開啟中斷的的函數(shù)也不一定總是能正確開啟,我一直覺得這是HAL庫的一個(gè)坑。我翻了很久的百度,終于找到一種解決方案。

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){ //處理數(shù)據(jù)... int i=0; while(HAL_UART_Receive_IT(&huart1,(uint8_t *)&buff,1) != HAL_OK ) { i++; if(i>10000) { huart6.RxState=HAL_UART_STATE_READY; __HAL_UNLOCK(&huart1); i=0; } }}

事情就是這么神奇,單單執(zhí)行一句開中斷不一定能成功的,開完還要檢查一下是不是真的開成功了,不行的話再打開一下試試,試了10000次還不行,生氣了,強(qiáng)制開。

03

變優(yōu)雅第二步

百度上看到的串口教程,大家都是用下面這個(gè)函數(shù)

HAL_UART_Transmit(&huart1, (uint8_t *)buff, BUFF_SIZE,0xffff);

就是說,CPU找到串口,給串口huart1安排好任務(wù):

“從這個(gè)buff的地址開始,挨個(gè)發(fā)BUFF_SIZE個(gè)數(shù)據(jù),我就在邊上守著,等你0XFFFF的時(shí)間,干不完就別給我干了!”

其實(shí)看到這么個(gè)代碼我是很生氣的,CPU作為大領(lǐng)導(dǎo),員工干活的時(shí)候不去喝咖啡?在邊上守著?這成何體統(tǒng)?

優(yōu)雅的辦法肯定是CPU交代好任務(wù)之后,轉(zhuǎn)身去忙自己的事情了,而串口接到命令之后,默默完成任務(wù),然后再跟CPU匯報(bào)一下。所以我們不光接收要用中斷,發(fā)送也要用中斷。

所以我們要用下面這個(gè)串口中斷發(fā)送的函數(shù)

HAL_UART_Transmit_IT(&huart1, (uint8_t *)buff, BUFF_SIZE);

這個(gè)函數(shù)會(huì)使能發(fā)送中斷,然后挨個(gè)發(fā)數(shù)據(jù),發(fā)完之后執(zhí)行一個(gè)回調(diào)函數(shù),然后自己關(guān)掉發(fā)送中斷。一條龍服務(wù),用戶什么都不用管。如果用戶想多管閑事,可以把代碼寫在回調(diào)函數(shù)里。

于是乎,我們優(yōu)雅地把串口發(fā)送改用中斷的方式,那我們重定向的fputc可以寫成

int fputc(int ch, FILE *f){ HAL_UART_Transmit_IT(&huart1, (uint8_t *)&ch, 1); return ch;}

這樣我們可以用先前的方法快樂地hello world了。

printf("hello world ");

愛動(dòng)手的小伙伴一旦嘗試一下就會(huì)發(fā)現(xiàn),這***的文章里的代碼都沒法跑,hello world發(fā)了個(gè)h就不發(fā)了???

那么這是為什么呢?我們來分析一下這個(gè)程序執(zhí)行的過程。printf里是把格式化好的字符一個(gè)一個(gè)交給fputc發(fā)送的,當(dāng)發(fā)送第一個(gè)字符'h'時(shí),串口處于空閑狀態(tài),能夠正確地使能串口發(fā)送中斷。因此,字符'h'正確發(fā)送。

但我們注意到,CPU給串口安排好工作后,并沒有在原地等待,而是去執(zhí)行后續(xù)的任務(wù)了,那后續(xù)的任務(wù)就是發(fā)送字符'e'。CPU再次來到fputc函數(shù)內(nèi),再次執(zhí)行

HAL_UART_Transmit_IT(&huart1, (uint8_t *)&ch, 1);

由于CPU的運(yùn)行速度比串口快得多,此時(shí)串口還沒有完成先前的字符'h'的發(fā)送任務(wù),串口處于忙碌的狀態(tài),因此現(xiàn)在是無法正確打開串口發(fā)送中斷的,因此字符'e'發(fā)送失敗。后續(xù)的字符也是同樣的情況。

這就說明,采用中斷發(fā)送方式時(shí),連續(xù)發(fā)送是會(huì)發(fā)送失敗的,串口就只有這點(diǎn)速度,你槍頂著他腦袋他也快不起來。在每次使用串口發(fā)送中斷時(shí),都要檢查一下是否正確打開了中斷,和先前提到的串口接收中斷一樣,打開中斷并不是總能成功的。于是,我們修改fputc函數(shù)成下面的樣子。

int fputc(int ch, FILE *f){ while(HAL_UART_Transmit_IT(&huart1, (uint8_t *)&ch, 1)!=HAL_OK); return ch;}

這樣子,CPU不斷地嘗試打開串口中斷直至成功為止。由于串口要完成先前的任務(wù)后才會(huì)由BUSY狀態(tài)變成READY狀態(tài),所以這里際就是在等待串口發(fā)送。

仔細(xì)一想這個(gè)過程我們會(huì)發(fā)現(xiàn),這不***嗎?用中斷發(fā)送就是為了不堵塞CPU的工作,結(jié)果搞了半天,還是在這兒堵著?

那我們還是要進(jìn)一步改進(jìn)一下。如果使用了多線程的話,那我們可以進(jìn)行任務(wù)切換,讓CPU切換到別的線程工作一會(huì)兒。

int fputc(int ch, FILE *f){ while(HAL_UART_Transmit_IT(&huart1, (uint8_t *)&ch, 1)!=HAL_OK) { osDelay(1);//ARM CMSIS的API,相當(dāng)于一般理解的sleep_ms(1); } return ch;}

但是這也有一個(gè)很明顯的問題,CPU雖然釋放出來了,但是串口堵了啊。當(dāng)我們連續(xù)發(fā)送字符的時(shí)候,CPU總是會(huì)在前一個(gè)字符發(fā)送完成之前嘗試發(fā)送下一個(gè)字符,然后中斷打開失敗,進(jìn)入osDelay(1),要等1ms之后才會(huì)回來。這其實(shí)是非常慢的,hello world要大約10ms才能發(fā)送完畢,串口以1ms一個(gè)數(shù)據(jù)的速度發(fā)送,這依然不優(yōu)雅。

要么CPU堵,要么串口堵,總有一個(gè)要等待,這可怎么辦呢?我們回顧一下串口中斷的API

AL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

明顯看到這個(gè)函數(shù)的第三個(gè)參數(shù)是一個(gè)size,它可以一次設(shè)置發(fā)送很多個(gè)數(shù)據(jù),但我們在fputc中使用時(shí),由于fputc是單個(gè)字符發(fā)送的,因此我們只能把size設(shè)置成1。如果能夠一口氣把所有要發(fā)送的數(shù)據(jù)都設(shè)置好,我們就不用重復(fù)地打開中斷了,也就避免了前述的尷尬。

所以接下來要做的便是避開fputc這個(gè)令人尷尬的單個(gè)字符發(fā)送的函數(shù),可是printf就是用這個(gè)函數(shù)的呀,要避開fputc,就不能用printf。我們自己搞一個(gè)更加優(yōu)雅的!起一個(gè)好聽的名字叫做debug,當(dāng)然你喜歡的話叫別的也可以。

void debug(const char *format, ...){ static char tmpStr[64]; /*在靜態(tài)區(qū)申請一塊緩存,因?yàn)镃PU開啟中斷之后不會(huì)原地等待,而是退出這個(gè)函數(shù), 如果在棧上申請空間,函數(shù)退出時(shí)緩存區(qū)會(huì)直接釋放掉,導(dǎo)致串口發(fā)送數(shù)據(jù)錯(cuò)誤。 因此把緩存區(qū)申請?jiān)陟o態(tài)區(qū) */ /*等待串口發(fā)送完畢,在串口忙于發(fā)送先前的數(shù)據(jù)時(shí),不能修改緩存區(qū)內(nèi)的數(shù)據(jù), 否則數(shù)據(jù)會(huì)出錯(cuò)。等串口發(fā)送完成后,再把新的數(shù)據(jù)放進(jìn)緩存區(qū)。 */ while(huart6.gState!=HAL_UART_STATE_READY); //把數(shù)據(jù)放進(jìn)緩存區(qū)里 va_list list; va_start(list, format); vsprintf(tmpStr,format, list);//這一部分不懂得同學(xué)請百度這個(gè)API,里的 va_end(list); while(HAL_UART_Transmit_IT(&huart6,(uint8_t*)tmpStr,strlen(tmpStr))!=HAL_OK); //開啟中斷發(fā)送,由于先前已經(jīng)等待過串口發(fā)送完成了,按理說串口肯定是可以打開的 //但為了避免多線程或者中斷等原因在別的地方打開了這個(gè)中斷,依然用while嘗試打開直到成功為止}

上面的函數(shù)接收不定長的輸入,這個(gè)輸入和printf的格式化是一模一樣的,使用方法和printf完全一樣。這樣的話,每執(zhí)行一次debug,只會(huì)開啟一次中斷,只要等待一次中斷開啟就可以了,不必像先前重映射fputc那樣每發(fā)送一個(gè)字符都要開一次中斷。

重映射fputc時(shí),必然會(huì)產(chǎn)生連續(xù)發(fā)送的情形,而用后面這種方法的話,如果你沒有連續(xù)地調(diào)用debug,很少會(huì)出現(xiàn)想發(fā)送卻串口忙碌的情況,while的等待時(shí)間是比較少的。

當(dāng)然如果你使用了多線程,并且串口發(fā)送數(shù)據(jù)沒有那么多,但是又希望CPU一點(diǎn)兒也不堵塞。那就更可以稍微修改一下。

void debug(const char *format, ...){ static char tmpStr[64]; while(huart6.gState!=HAL_UART_STATE_READY) { osDelay(1); } va_list list; va_start(list, format); vsprintf(tmpStr,format, list); va_end(list); while(HAL_UART_Transmit_IT(&huart6,(uint8_t*)tmpStr,strlen(tmpStr))) { osDelay(1); }}

這樣在連續(xù)執(zhí)行debug時(shí),會(huì)進(jìn)行線程切換,好處是CPU不堵了,壞處是串口要延后1ms才能發(fā)送下一個(gè)字符串,但也遠(yuǎn)好于每個(gè)字符都延后1ms的方式,況且連續(xù)地debug也不是特別常見。在實(shí)際應(yīng)用中,根據(jù)需求來使用吧。

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

    關(guān)注

    2291

    文章

    11022

    瀏覽量

    363483
  • 數(shù)組
    +關(guān)注

    關(guān)注

    1

    文章

    419

    瀏覽量

    26455

原文標(biāo)題:如何讓STM32優(yōu)雅地“說”hello world?

文章出處:【微信號:mcu168,微信公眾號:硬件攻城獅】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    Bosch Sensortec亮相Embedded World 2025

    2025年3月11日至13日,全球嵌入式系統(tǒng)盛會(huì) Embedded World 2025在德國紐倫堡展覽中心圓滿落幕。
    的頭像 發(fā)表于 04-15 17:03 ?484次閱讀

    使用RT1060的mcuboot開源sdk示例擦除主插槽中的錯(cuò)誤鏡像怎么解決?

    插槽:未找到圖像 圖像 0 輔助插槽:未找到圖像 沒有要為映像 0 加載的插槽 找不到可啟動(dòng)映像 2. 然后我選擇另一個(gè) sdk 示例,在本例中,我選擇了 hello world sdk 示例,我構(gòu)建
    發(fā)表于 04-10 08:13

    推薦!如何優(yōu)雅地?cái)[好PCB絲印?

    很多畫PCB的人,會(huì)認(rèn)為絲印不影響電路的性能,所以,對絲印并不重視。但是,對于一個(gè)專業(yè)的硬件工程師來說,必須重視這些細(xì)節(jié)。 下面介紹如何優(yōu)雅地弄好PCB絲印。 1 擺放的位置 一般來說,電阻、電容
    發(fā)表于 04-08 14:59

    創(chuàng)建stm32f103c8工程后為什么終端沒有打印Hello RT_Thread?

    創(chuàng)建stm32f103c8工程后為什么終端沒有打印Hello RT_Thread!,程序好像也沒有下載進(jìn)去
    發(fā)表于 04-01 06:55

    顯示器NHD 1.9 176176UBC3顯示“hello world”,怎么不起作用?

    hello world”。但它不起作用...... 我的代碼 : #include “fsl_spi.h” #include “fsl_gpio.h” #include “fsl_clock.h
    發(fā)表于 03-27 06:29

    在mimxrt1170_evk調(diào)試hello_world出現(xiàn)硬件傳輸錯(cuò)誤怎么解決?

    我按照視頻在 cm7 中調(diào)試hello_world示例,我的鏈接服務(wù)器正在運(yùn)行, debug prove 的 FW 也是最新的。 但是我仍然收到這個(gè)錯(cuò)誤。 16:status-poll 中的目標(biāo)
    發(fā)表于 03-25 07:31

    加載示例圖像時(shí),COM7的調(diào)試控制臺(tái)hello_world不顯示消息怎么解決?

    板是 mimxrt1180_evk。 我無法從板中找到 JP5。 使用示例映像進(jìn)行測試時(shí),調(diào)試控制臺(tái)(通過 Windows11 電腦中的 J53、COM7 連接hello_world不顯示任何消息。 但是 gdb 在源文件中顯示了我的簡單代碼更改。 請盡快發(fā)現(xiàn),謝謝!
    發(fā)表于 03-25 07:01

    極海半導(dǎo)體亮相Embedded World 2025

    全球嵌入式技術(shù)與系統(tǒng)領(lǐng)域最具影響力的行業(yè)盛會(huì)——Embedded World 2025在德國紐倫堡展覽中心盛大開幕。
    的頭像 發(fā)表于 03-13 17:09 ?980次閱讀

    嵌入式學(xué)習(xí)-飛凌嵌入式ElfBoard ELF 1板卡-Linux驅(qū)動(dòng)模塊之帶參數(shù)的驅(qū)動(dòng)模塊

    (void) { printk(KERN_INFO \"Hello, World! my_param is %d\\n\",my_param); // 打印消息到內(nèi)核日志
    發(fā)表于 03-13 09:52

    飛凌嵌入式ElfBoard ELF 1板卡-Linux驅(qū)動(dòng)模塊之帶參數(shù)的驅(qū)動(dòng)模塊

    \"Hello, World! my_param is %d\\n\",my_param); // 打印消息到內(nèi)核日志 printk(KERN_INFO \"Hello
    發(fā)表于 03-12 10:34

    用MCUXPresso for VS Code插件 從0開始打造HelloWorld

    上一篇中Zephyr的Hello 2025,Hello World,小編為大家介紹了使用MCUXPresso for VS Code插件來導(dǎo)入一個(gè)Hello
    的頭像 發(fā)表于 01-16 09:20 ?1190次閱讀
    用MCUXPresso for VS Code插件 從0開始打造HelloWorld

    使用MCUXpresso for VS Code插件開發(fā)Zephyr的hello world

    本期來到Zephyr實(shí)戰(zhàn)經(jīng)驗(yàn)演練,小編帶著大家一起使用MCUXpresso for VS Code插件來開發(fā)一個(gè)屬于Zephyr的hello world
    的頭像 發(fā)表于 01-03 09:21 ?1196次閱讀
    使用MCUXpresso for VS Code插件開發(fā)Zephyr的<b class='flag-5'>hello</b> <b class='flag-5'>world</b>

    全志T113雙核異構(gòu)處理器的使用基于Tina Linux5.0——RTOS系統(tǒng)定制開發(fā)

    分組成,源文件,Makefile,Kconfig,如下: hello_world ├──hello_world.c ├──Kconfig └──Makefile 其中Makefile指定該模塊的編譯規(guī)則
    發(fā)表于 11-22 09:36

    如何在i2c中將hello world發(fā)送到LCD屏幕?

    有誰知道如何在 i2c 中告訴這個(gè)以將 hello world 發(fā)送到 LCD 屏幕?當(dāng)我查找我的 4BIT 引腳時(shí),我可以很好地做到這一點(diǎn),但是當(dāng)使用 i2c 時(shí),我似乎在任何地方都找不到協(xié)議的任何細(xì)節(jié),每個(gè)人都只想談?wù)撎炷牡?ardunio,這對杰克有幫助。 謝謝!!
    發(fā)表于 07-11 06:10

    ESP8266_RTOS_SDK-v3.4的構(gòu)建錯(cuò)誤如何解決?

    /examples/get-started/hello_world/build/hello-world.elf d:/程序文件 (x86)/aithinkeride_v1.5.2/msys32/opt
    發(fā)表于 07-08 07:59
    主站蜘蛛池模板: 西畴县| 阳曲县| 克拉玛依市| 定安县| 五台县| 当涂县| 南宁市| 楚雄市| 都兰县| 武清区| 阿尔山市| 肥东县| 安西县| 瑞金市| 东平县| 宝应县| 绵阳市| 大厂| 盱眙县| 文山县| 武强县| 阜南县| 万宁市| 瓮安县| 岳普湖县| 东安县| 洛南县| 南皮县| 灌南县| 金门县| 饶阳县| 铁岭市| 泰和县| 开封县| 随州市| 雷山县| 永寿县| 吉木萨尔县| 望江县| 锡林郭勒盟| 连江县|