日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32串口通讯初步学习

發布時間:2023/12/9 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32串口通讯初步学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文目錄

  • 一.說明基于寄存器與基于固件庫的stm32 LED流水燈例子的編程方式有什么差異?
  • 二.完成STM32的USART窗口通訊程序,要求如下:
    • 1.如何進行燒錄
    • 2.代碼執行及其運行結果
  • 三.學習C語言程序里全局變量、局部變量、堆、棧等概念,并在ubuntu系統中編程,輸出信息進行驗證;
    • 1.C語言在內存中有哪幾個區域?
    • 2.一個由c/C++編譯的程序占用的內存有哪幾個部分?
    • 3.例子程序如下:
    • 4.關于C語言中關鍵字volatile的相關問題
  • 四.在Keil中針對stm32系統進行編程,調試變量,進行驗證; 通過串口輸出信息到上位機,進行驗證。

一.說明基于寄存器與基于固件庫的stm32 LED流水燈例子的編程方式有什么差異?

1.寄存器是中央處理器內的組成部分。寄存器是有限存貯容量的高速存貯部件,它們可用來暫存指令、數據和地址?;诩拇嫫鱽磉M行流水燈的編程,它更貼近底層,對外設的工作原理和運行機理會有更深的理解。
2.STM32標準外設庫之前的版本也稱固件函數庫或簡稱固件庫,是一個固件函數包,它由程序、數據結構和宏組成,包括了微控制器所有外設的性能特征?;谶@種方式進行流水燈的編程,會比較簡單,易于編程,因為目前比較多的例程是使用固件庫編寫的。

二.完成STM32的USART窗口通訊程序,要求如下:

1)設置波特率為115200,1位停止位,無校驗位。

2)STM32系統給上位機(win10)連續發送“hello windows!”,上位機接收程序可以使用“串口調試助手“,也可自己編程。

3)當上位機給stm32發送“Stop,stm32”后,stm32停止發送。

1.如何進行燒錄

(1)我們使用的是野火指南針開發板,配套有相應的教程,其板子連接電腦如下所示:

(2)打開mcuisp助手


(3)進行如下操作即可將文件燒錄進去
1.搜索串口
2.選擇要下載的HEX文件
3.校驗、編程后執行
4.DTR 低電平復位,RTS 高電平進入 bootloader
5.開始進行串口執行

2.代碼執行及其運行結果

(1)打開開發板附贈教程中的相應工程


(2)將其中stm32f10x_it.c文件的串口中斷服務函數部分改為如下:

int i=0; uint8_t ucTemp[50]; void DEBUG_USART_IRQHandler(void) {if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET){ucTemp[i] = USART_ReceiveData(USART1); }if(ucTemp[i] == '!'){if(ucTemp[i-1] == '2'&&ucTemp[i-2] == '3'&&ucTemp[i-3] == 'm'&&ucTemp[i-4] == 't'&&ucTemp[i-5] == 's'&&ucTemp[i-6] == ' ')if(ucTemp[i-7] == 'p'&&ucTemp[i-8] == 'o'&&ucTemp[i-9] == 't'&&ucTemp[i-10] == 's'){printf("收到");while(1);}}i++; }


(3)將主函數main.c改為如下:

#include "stm32f10x.h" #include "bsp_usart.h"void delay(uint32_t count) {while(count--); } int main(void) { USART_Config();while(1){ printf("hello windows 10!\n");delay(5000000);} }


(4)編譯生成hex文件

(5)將上述HEX文件燒錄到助手當中,進行編程后,打開串口調試助手,點擊打開串口,即可以看到stm32發給電腦的信息了
燒錄成功:

串口助手調試:

停止發送:

三.學習C語言程序里全局變量、局部變量、堆、棧等概念,并在ubuntu系統中編程,輸出信息進行驗證;

1.C語言在內存中有哪幾個區域?

  • 內存棧區: 存放局部變量名;
  • 內存堆區: 存放new或者malloc出來的對象;
  • 常數區: 存放局部變量或者全局變量的值;
  • 靜態區: 用于存放全局變量或者靜態變量;
  • 代碼區:二進制代碼。
  • 2.一個由c/C++編譯的程序占用的內存有哪幾個部分?

    1、棧區(stack)— 由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似于數據結構中的棧。
    2、堆區(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似于鏈表,呵呵。
    3、全局區(靜態區)(static)—,全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域(RW), 未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域(ZI)。 - 程序結束后有系統釋放
    4、文字常量區 —常量字符串就是放在這里的。 程序結束后由系統釋放 (RO)
    5、程序代碼區—存放函數體的二進制代碼。 (RO)

    3.例子程序如下:

    例子程序如下:

    #include <stdio.h> #include <string.h> #include <stdlib.h>void before() {}char g_buf[16]; char g_buf2[16]; char g_buf3[16]; char g_buf4[16]; char g_i_buf[]="123"; char g_i_buf2[]="123"; char g_i_buf3[]="123";void after() {}int main(int argc, char **argv) {char l_buf[16];char l_buf2[16];char l_buf3[16];static char s_buf[16];static char s_buf2[16];static char s_buf3[16];char *p_buf;char *p_buf2;char *p_buf3;p_buf = (char *)malloc(sizeof(char) * 16);p_buf2 = (char *)malloc(sizeof(char) * 16);p_buf3 = (char *)malloc(sizeof(char) * 16);printf("g_buf: 0x%x\n", g_buf);printf("g_buf2: 0x%x\n", g_buf2);printf("g_buf3: 0x%x\n", g_buf3);printf("g_buf4: 0x%x\n", g_buf4);printf("g_i_buf: 0x%x\n", g_i_buf);printf("g_i_buf2: 0x%x\n", g_i_buf2);printf("g_i_buf3: 0x%x\n", g_i_buf3);printf("l_buf: 0x%x\n", l_buf);printf("l_buf2: 0x%x\n", l_buf2);printf("l_buf3: 0x%x\n", l_buf3);printf("s_buf: 0x%x\n", s_buf);printf("s_buf2: 0x%x\n", s_buf2);printf("s_buf3: 0x%x\n", s_buf3);printf("p_buf: 0x%x\n", p_buf);printf("p_buf2: 0x%x\n", p_buf2);printf("p_buf3: 0x%x\n", p_buf3);printf("before: 0x%x\n", before);printf("after: 0x%x\n", after);printf("main: 0x%x\n", main);if (argc > 1){strcpy(l_buf, argv[1]);}return 0; }

    源代碼如上,其在ubantu中運行結果如下所示:

    我們可以看到從低地址到高地址,如圖:

    4.關于C語言中關鍵字volatile的相關問題

    Volatile這個關鍵字的必要性(真正意義之所在)
    但其他程序(例如內核程序或一個中斷)修改了內存中該變量的值,此時寄存器R中的值并不會隨之改變而更新,由于優化器的作用編譯器仍然去利用之前存放在寄存器R中的值,而不去尋址內存中的值(但我們必須改變這個變量的值)。為了解決這種情況C語言就引入了volatile限定詞,讓代碼在引用該變量時多費一點勁兒,再去內存中取出該變量的值。
    Volatile和register的對比
    volatile 跟以前的 register 相反。 register 告訴編譯器盡量將變量放到寄存器中使用, 而volatile 強制將更改后的值寫回內存。如果不寫回內存,對于一些全局共享的變量,可能導致不一致問題。
    Volatile關鍵字應用的三個地方
    1、 修改硬件寄存器,尤其是狀態寄存器
    大家都知道,在硬件級別,如果寄存器值自動改變了,編譯器是不會主動發現的。經過編譯器的自動優化,我們讀到的都是寄存器中存儲的舊的狀態寄存器的值, 而非最新的狀態寄存器值。
    2、 多線程中被幾個線程共享的變量
    線程修改共享變量var是不會通知編譯器的。所以線程A堅持不懈地讀著var在寄存器或者cache中的副本,讀出來的內容是0, 但很可惜,線程B早就把var變量給修改為1了。鑒于此,我們必須加上volatile這個關鍵字來解決這個問題。
    3、 中斷服務程序ISR當中用
    ISR:中斷服務程序 (interrupt service routine)

    四.在Keil中針對stm32系統進行編程,調試變量,進行驗證; 通過串口輸出信息到上位機,進行驗證。

    用第二大點的串口通信模板,我們將main.c主函數改為如下所示:

    #include "stm32f10x.h" #include "bsp_usart.h"char global1[16]; char global2[16]; char global3[16];int main(void) { char part1[16];char part2[16];char part3[16];USART_Config();printf("part1: 0x%p\n", part1);printf("part2: 0x%p\n", part2);printf("part3: 0x%p\n", part3);printf("global1: 0x%p\n", global1);printf("global2: 0x%p\n", global2);printf("global3: 0x%p\n", global3);while(1){ } }


    其運行結果如下所示:

    我們可以看到:
    前3個part變量為局部變量,它們儲存到了棧中,地址依次減小。
    后三個global為全局變量,它們儲存到了靜態區,地址依次增加。
    我們用下面的主函數來定義了靜態變量和指針

    #include "stm32f10x.h" #include "bsp_usart.h" #include <stdlib.h>int main(void) { static char st1[16];static char st2[16];static char st3[16];char *p1;char *p2;char *p3;USART_Config();printf("st1: 0x%p\n", st1);printf("st2: 0x%p\n", st2);printf("st3: 0x%p\n", st3);p1 = (char *)malloc(sizeof(char) * 16);p2 = (char *)malloc(sizeof(char) * 16);p3 = (char *)malloc(sizeof(char) * 16);printf("p1: 0x%p\n", p1);printf("p2: 0x%p\n", p2);printf("p3: 0x%p\n", p3);while(1){ } }

    運行結果如下所示:

    前三個靜態變量儲存到了靜態區,地址依次增加。
    后三個指針儲存到了堆中,地址依次增加。
    結合兩次結果看(針對于測試的3個區域),可以大概看出棧在頂層(地址最大),然后依次是堆,靜態區。
    總結:
    在一個STM32程序代碼中,從內存高地址到內存低地址,依次分布著棧區、堆區、全局區(靜態區)、常量區、代碼區,其中全局區中高地址分布著.bss段,低地址分布著.data段。
    總的分布如下所示:

    一、棧區(stack)

    臨時創建的局部變量存放在棧區。

    函數調用時,其入口參數存放在棧區。

    函數返回時,其返回值存放在棧區。

    const定義的局部變量存放在棧區。

    2、堆區(heap)

    堆區用于存放程序運行中被動態分布的內存段,可增可減。

    可以有malloc等函數實現動態分布內存。

    有malloc函數分布的內存,必須用free進行內存釋放,否則會造成內存泄漏。

    3、全局區(靜態區)

    全局區有.bss段和.data段組成,可讀可寫。

    4、.bss段

    未初始化的全局變量存放在.bss段。

    初始化為0的全局變量和初始化為0的靜態變量存放在.bss段。

    .bss段不占用可執行文件空間,其內容有操作系統初始化。

    5、.data段

    已經初始化的全局變量存放在.data段。

    靜態變量存放在.data段。

    .data段占用可執行文件空間,其內容有程序初始化。

    const定義的全局變量存放在.rodata段。

    6、常量區

    字符串存放在常量區。

    常量區的內容不可以被修改。

    7、代碼區

    程序執行代碼存放在代碼區。

    字符串常量也有可能存放在代碼區。

    總結

    以上是生活随笔為你收集整理的STM32串口通讯初步学习的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。