最近公司事情太多了,將近一個月沒有更新了。 我的想法是把我用到的所有單片機都更新一下(當然不局限于這些,后期也會更新一些其他和嵌入式相關的知識點,我就想著先把STM32這整個更新完,再去更新其他的,包括STM32下 RTOS、UI(emwin,LVGL)還有一些項目上的經驗什么的。 等STM32相關的更新完之后會寫其他的東西。 也會根據實際的情況進行其他內容的更新:我用過STM32 CH32、HC32F4、S32K148等,還有各種傳感器啥的。
從本章節開始我們進行一個STM32實戰操作,為此我還特意畫了個簡單的板子。 是物聯網相關的,后面會設計一個BMS的板子來寫一下。
1-編寫第一個程序點亮LED燈
下面是原理圖,連接的是PC0-PC7引腳:
1static void Led_Cofig(void)
2{
3 /*定義一個GPIO_InitTypeDef類型的結構體*/
4 GPIO_InitTypeDef GPIO_InitStructure;
5 /*開啟LED相關的GPIO外設時鐘*/
6 RCC_APB2PeriphClockCmd(LED_GPIO_CLCK, ENABLE);
7 /*選擇要控制的GPIO引腳*/
8 GPIO_InitStructure.GPIO_Pin = LED1_GPIO_PIN;
9 /*設置引腳模式為通用推挽輸出*/
10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
11 /*設置引腳速率為50MHz */
12 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //(指的是內部驅動電路的響應速度,速度越大越快,一般情況是有多個不同的速度,也可根據自己的需要安排)
13 GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure);
14 /* 關閉led燈 */
15 GPIO_SetBits(LED_GPIO_PORT, LED1_GPIO_PIN);
16}
1/*LED連接GPIO的定義,程序開發者如果要修改引腳只需要修改這里就好*/
2#define LED_GPIO_PORT GPIOC // GPIO端口定義,為了方便修改
3#define LED_GPIO_CLCK RCC_APB2Periph_GPIOC /* GPIO端口時鐘 */
4/*GPIO引腳*/
5#define LED1_GPIO_PIN GPIO_Pin_0
6#define LED2_GPIO_PIN GPIO_Pin_1
7#define LED3_GPIO_PIN GPIO_Pin_2
8#define LED4_GPIO_PIN GPIO_Pin_3
9#define LED5_GPIO_PIN GPIO_Pin_4
10#define LED6_GPIO_PIN GPIO_Pin_5
11#define LED7_GPIO_PIN GPIO_Pin_6
12#define LED8_GPIO_PIN GPIO_Pin_7
2-代碼說明
1:GPIO_InitTypeDef GPIO_InitStructure 語句是聲明一個結構體GPIO_InitStructure結構體原型由GPIO_InitTypeDef確定(這點是C語言的基礎知識)設置完之后就可以對GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure); 進行操作。
2:GPIO_SetBits()是庫函數,可以對多個I/O口同時置1。
這里還有一個GPIO_ResetBits()庫函數,可以對多個I/O口置0。
注釋和工程添加就不說了,網上相關的也挺多的。
GPIO_InitStructure.XXXX后面的speed什么的也不說了,不知道的可以去STM32知識篇看看。 這里主要講述函數配置什么的,畢竟是實戰嘛,指定是不能都介紹的。
3-main函數
1int main()
2{
3 LED_Init();
4 while (1)
5 {
6
7 GPIO_ResetBits(LED_GPIO_PORT, LED1_GPIO_PIN);
8 }
9}
因為接的是正極,點亮LED燈兩端需要電壓差,所以在這里使用GPIO_ResetBits才能點亮,如果你的一端接的是地,則是使用GPIO_SetBits。 這點要知道。 就是不管是哪種器件,只有保持電壓差才能進行一個數據的接收,燈的點亮,我認為是這樣的,可以說是所有的元器件芯片都是這樣的,但不是絕對的,只能說大部分。
上面點亮之后,我們這樣感覺修改太麻煩。 可以在頭文件之后對其設置一個宏定義函數,如下:
1/*標準庫點亮LED燈*/
2/*當a=0時,LED燈滅,當LED=1時,LED燈亮*/
3#define LED1(a) \\
4 if (a) \\
5 { \\
6 GPIO_ResetBits(LED_GPIO_PORT, LED1_GPIO_PIN); \\
7 } \\
8 else \\
9 GPIO_SetBits(LED_GPIO_PORT, LED1_GPIO_PIN);
當a=1時,燈亮,0時燈滅。
1int main()
2{
3 LED_Init();
4 while (1)
5 {
6 //GPIO_ResetBits(LED_GPIO_PORT,LED1_GPIO_PIN);
7 LED1(1);
8 }
9}
下面說一說位操作,這是嵌入式開發中最常用的。
5-位操作
什么是位操作,我認為位操作就是吃羊肉串,從前面吃,從后面吃,從中間吃這樣的。 但是官方說法比我這好聽。 其實位操作操作的是二進制或者十六進制這樣的,你看像不像你在吃羊肉串,比如二進制0b0000 0001,你看從后面讀取就相當于你從后面開始吃羊肉串。 下面說正經的。
我們對上面這個表進行一些介紹和使用說明
- 在不改變其他位的狀況下,對某幾個位賦值
針對這種情況,應該怎么做才能實現對某幾個位賦值呢? 我們可以把“&”和“|” 兩個位操作結合起來使用,步驟如下。
(1)先對需要設置的位用“&”操作符進行清零操作。
(2)再用“|” 操作符賦值。
例如,在初始化時,若配置PD8引腳為推挽輸出、速度為50 MHz,需將GPIOD->CRH的0~3位設置為3(即二進制0011B),這時可先對寄存器的0~3位進行“&”清零操作。
1GPIOD->CRH&=0Xfffffff0; //清掉原來的設置,同時不影響其他位設置
然后再與需要設置的值進行“|” 運算:
1GPIOD->CRH|=0X00000003; //設置0~3 位的值為3,不改變其他位的值
- 使用移位操作,提高代碼的可讀性
移位操作在STM32程序開發中也非常重要。 比如在初始化時,若需要使能GPIOD口的時鐘,就可使用移位操作來實現,使能PORTD時鐘的語句是:
1RCC->APB2ENR|=1<<5;
使能GPIOD和GPIOE口時鐘的語句是:
1RCC->APB2ENR|=3<<5;
這個左移位操作,就是將RCC->APB2ENR寄存器的第5位設置為1,使能PORTD時鐘。 為什么要通過左移而不是直接設置一個固定的值來對寄存器進行操作呢? 其實,這樣做是為了提高代碼的可讀性以及可重用性。 讀者可以很直觀明了地看到,這行代碼是將第5位設置為1。 如果寫成:
1RCC->APB2ENR =0x00000020;
但是這樣代碼寫出來不太友好,首先是不可重復使用,其次真煩呀。 反正這種挺多的,大家可以自己多練練。
- 取反位操作的應用
SR寄存器的每一位都代表一個狀態。 在某個時刻,我們希望設置某一位為0,同時其他位都保留為1,簡單的做法是直接給寄存器設置一個值。
1TIMx->SR=0xF7FF;
上述代碼設置第11位為0,但代碼可讀性不太友好。 但是我們可以這樣寫:
1#define TIM_FLAG_Update ((uint16_t)0x0001)
2TIMx->SR &=~(TIM_FLAG_Update <<11);
從上面的代碼中,我們可以從第一條語句看出,宏定義了TIM_FLAG_Update第0位是1,其他位是0; 第二條語句讓TIM_FLAG_Update左移11位取反,第11位就為0,其他位都為1; 最后通過按位與操作,使第11位為0,其他位保持不變。 這樣,讀者就能很容易地看明白代碼,所以代碼的可讀性也就非常強的。
-
單片機
+關注
關注
6036文章
44556瀏覽量
635029 -
嵌入式
+關注
關注
5082文章
19117瀏覽量
305002 -
led燈
+關注
關注
22文章
1592瀏覽量
107978 -
STM32
+關注
關注
2270文章
10897瀏覽量
355883 -
RTOS
+關注
關注
22文章
811瀏覽量
119615
發布評論請先 登錄
相關推薦
評論