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文件的串口中斷服務函數部分改為如下:
(3)將主函數main.c改為如下:
(4)編譯生成hex文件
(5)將上述HEX文件燒錄到助手當中,進行編程后,打開串口調試助手,點擊打開串口,即可以看到stm32發給電腦的信息了
燒錄成功:
串口助手調試:
停止發送:
三.學習C語言程序里全局變量、局部變量、堆、棧等概念,并在ubuntu系統中編程,輸出信息進行驗證;
1.C語言在內存中有哪幾個區域?
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為全局變量,它們儲存到了靜態區,地址依次增加。
我們用下面的主函數來定義了靜態變量和指針
運行結果如下所示:
前三個靜態變量儲存到了靜態區,地址依次增加。
后三個指針儲存到了堆中,地址依次增加。
結合兩次結果看(針對于測試的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串口通讯初步学习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言之指针与数组总结
- 下一篇: 大学物理质点动力学思维导图_高中物理思维