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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

STM32学习之C语言知识复习

發布時間:2025/3/15 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32学习之C语言知识复习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

上一級學會了如何新建一個工程,在文檔中,下一章是一些MDK5的使用技巧,其實說實話,用慣了那些高級傻瓜式的開發工具,例如IDEA,Pycharm,Android Studio等等,用MDK5倒是有點不習慣了,有點像剛學C的時候,不過用慣之后,還是覺得挺好的。
閑話少說,這系列博客主要是用來記錄學習,STM32F407中的一些基礎知識,主要包括,C語言復習,STM32系統與時鐘,IO,中斷等等。
本篇主要復習C語言

這一部分極其枯燥,但是十分重要,望仔細學習

學習資料來自:STM32F407最小系統板開發指南-庫函數版本_V1.1.pdf
正點原子,感謝原子哥的開源奉獻
正點原子資料下載中心

STM32單片機學習資料均來自 正點原子 ,僅用于學習,如有侵權請聯系我刪除
本博客內容原創,創作不易,轉載請注明

本文鏈接
個人博客:https://ronglin.fun/?p=96
PDF鏈接:見博客網站
CSDN: https://blog.csdn.net/RongLin02/article/details/121306695

開發主要用C語言, 這一部分,主要是MDK 下 C 語言基礎復習,那些基礎語法不在復述,主要是一些在初學過程中用的少的部分。

位運算

有過oj刷題經驗的童鞋對位運算應該不陌生,有很多算法基于位運算優化,同時由于計算機的數據存儲是二進制,所以說用位操作二進制數很常見,這里簡單的過一下

C中6種位操作如下

位設值

很多情況下,我們要不改變其他位的值的狀況下,對某幾個位進行設值。
方法就是先對需要設置的位用**&操作符進行清零操作,然后用|操作符設值。
比如要改變 GPIOA-> BSRRL 的狀態,可以先對寄存器的值進行
&**清零操作

GPIOA-> BSRRL &=0XFF0F; //將第 4-7 位清 0

然后再與需要設置的值進行**|**或運算

GPIOA-> BSRRL |=0X0040;//設置相應位的值,不改變其他位的值

移位

移位操作提高代碼的可讀性,移位操作在單片機開發中也非常重要,我們來看看下面一行代碼

GPIOx->ODR = (((uint32_t)0x01) << pinpos);

這個操作就是將 ODR 寄存器的第 pinpos 位設置為 1,為什么要通過左移而不是直接設置一個固定的值呢?
其實,這是為了提高代碼的可讀性以及可重用性。這行代碼可以很直觀明了的知道,是將第 pinpos 位設置為 1。
如果寫成

GPIOx->ODR =0x0030;

這樣的代碼就不好看也不好重用了。

取反

**~**取反操作使用技巧
SR 寄存器的每一位都代表一個狀態,某個時刻我們希望去設置某一位的值為 0,同時
其他位都保留為 1,簡單的作法是直接給寄存器設置一個值:

TIMx->SR=0xFFF7;

這樣的作法設置第 3 位為 0,但是這樣的作法同樣不好看,并且可讀性很差。看看庫函數代碼中怎樣使用的:

TIMx->SR = (uint16_t)~TIM_FLAG;

而 TIM_FLAG 是通過宏定義定義的值:

#define TIM_FLAG_Update ((uint16_t)0x0001) #define TIM_FLAG_CC1 ((uint16_t)0x0002)

看這個應該很容易明白,可以直接從宏定義中看出 TIM_FLAG_Update 就是設置的第 0 位了,可讀性非常強。

define 宏定義

define 是 C 語言中的預處理命令,它用于宏定義,可以提高源代碼的可讀性,為編程提供方便。常見的格式:

#define 標識符 字符串

“標識符”為所定義的宏名。“字符串”可以是常數、表達式、格式串等。例如:

#define PLL_M 8

定義標識符 PLL_M 的值為 8。
至于 define 宏定義的其他一些知識,本質類似于查找替換,比如宏定義帶參數這里我們就不多講解。

ifdef 條件編譯

單片機程序開發過程中,經常會遇到一種情況,當滿足某條件時對一組語句進行編譯,而當條件不滿足時則編譯另一組語句。
條件編譯命令最常見的形式為:

#ifdef 標識符 程序段 1 #else 程序段 2 #endif

它的作用是:當標識符已經被定義過(一般是用#define 命令定義),則對程序段 1 進行編譯,否則編譯程序段 2。 其中#else 部分也可以沒有。
這個條件編譯在MDK里面是用得很多的,在stm32f4xx.h這個頭文件中經常會看到這樣的代碼。

關鍵字

extern 變量申明

extern在我的學習過程中用的很少,因為初學C的時候,就main.c一個文件,沒有其他文件,而且代碼量也很少,所以說這里簡單的說明一下在STM32中C語言extern的用法
C 語言中 extern 可以置于變量或者函數前,以表示變量或者函數的定義在別的文件中,提示編譯器遇到此變量和函數時在其他模塊中尋找其定義。
這里面要注意,對于 extern 申明變量可以多次,但定義只有一次。在原子哥的代碼中經常會看到看到這樣的語句:

extern u16 USART_RX_STA;

這個語句是申明USART_RX_STA變量在其他文件中已經定義了,在這里要使用到。
所以,你肯定可以找到在某個地方有變量定義的語句:

u16 USART_RX_STA;

的出現。
下面通過兩個例子說明一下使用方法。
在 Main.c 定義的全局變量 id,id 的初始化都是在 Main.c 里面進行的。
Main.c 文件

u8 id;//定義只允許一次 main() {id=1;printf("d%",id);//id=1test();printf("d%",id);//id=2 }

但是我們希望在main.c的 changeId(void) 函數中使用變量id,這個時候我們就需要在main.c里面去申明變量 id 是外部定義的了,因為如果不申明,變量 id 的作用域是到不了 main.c 文件中。看下面 main.c 中的代碼:

extern u8 id;//申明變量 id 是在外部定義的,申明可以在很多個文件中進行 void test(void) {id=2; }

在 main.c 中申明變量 id 在外部定義,然后在 main.c 中就可以使用變量 id 了。
再看如下網上的一個例子

#include <stdio.h> int max(int x,int y); int main(void) {int result;/*外部變量聲明*/extern int g_X;extern int g_Y;result = max(g_X,g_Y);printf("the max value is %d\n",result);return 0; } /*定義兩個全局變量*/ int g_X = 10; int g_Y = 20; int max(int x, int y) {return (x>y ? x : y); }

代碼中,全局變量 g_X 與 g_Y 是在 main 函數之后聲明的,因此它的作用范圍不在 main 函數中。如果我們需要在 main 函數中調用它們,就必須使用 extern 來對變量 g_X 與 g_Y 作“外部變量聲明”,以擴展全局變量的作用域。也就是說,如果在變量定義之前要使用該變量,則應在使用之前加 extern 聲明變量,使作用域擴展到從聲明開始到本文件結束。

對于 extern 申明函數在外部定義的應用,這里我們就不多講解了。

typedef 類型別名

typedef 用于為現有類型創建一個新的名字,或稱為類型別名,用來簡化變量的定義。
就是給數據類型起一個另外的名字,例如,我們在c語言定義一個64位整型,用long long,很長,這里我們就可這樣寫

typedef long long ll; ll a = 0;

而在C中,結構體變量的定義前面要加了一個struct關鍵字,很麻煩,用typedef就可以省略。
typedef 在 MDK 用得最多的就是定義結構體的類型別名和枚舉類型了。

struct _GPIO {__IO uint32_t MODER;__IO uint32_t OTYPER;… };

定義了一個結構體 GPIO,這樣我們定義變量的方式為:

struct _GPIO GPIOA;//定義結構體變量 GPIOA

但是這樣很繁瑣,MDK 中有很多這樣的結構體變量需要定義。這里我們可以為結體定義一個別名 GPIO_TypeDef
這樣我們就可以在其他地方通過別名 GPIO_TypeDef 來定義結構體變量了。
方法如下:

typedef struct {__IO uint32_t MODER;__IO uint32_t OTYPER; … } GPIO_TypeDef;

Typedef 為結構體定義一個別名 GPIO_TypeDef,這樣我們可以通過 GPIO_TypeDef 來定義結構體變量:

GPIO_TypeDef _GPIOA,_GPIOB;

這里的 GPIO_TypeDef 就跟 struct _GPIO 是等同的作用了。 在C中方便很多

結構體

在面向對象中,有類的概念,和C的結構體很像,大體上的思想類似,但是沒有那么多的講究
在MDK中太多地方使用結構體以及結構體指針,這里稍微提一下結構體的一些知識。
聲明結構體類型:

Struct 結構體名{ 成員列表; }變量名列表;

例如:

Struct U_TYPE { Int BaudRate Int WordLength; }usart1,usart2;

在結構體申明的時候可以定義變量,也可以申明之后定義,方法是:
Struct 結構體名字 結構體變量列表 ;例如:

struct U_TYPE usart1,usart2;

結構體成員變量的引用方法是:
結構體變量名字.成員名
比如要引用 usart1 的成員 BaudRate,方法是:usart1.BaudRate;
結構體指針變量定義也是一樣的,跟其他變量沒有啥區別。

struct U_TYPE *usart3;//定義結構體指針變量 usart1;

結構體指針成員變量引用方法是通過“->”符號實現,比如要訪問 usart3 結構體指針指向的結構體的成員變量 BaudRate,方法是:

Usart3->BaudRate;

上面講解了結構體和結構體指針的一些知識,其他的什么初始化這里就不多講解了。

總結

沒想到一個C語言復習模塊寫了這么多東西,不過還是很常用的,未完待續,=w=

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的STM32学习之C语言知识复习的全部內容,希望文章能夠幫你解決所遇到的問題。

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