STM32F030系列實現仿位帶操作
1、位帶操作基本知識
關於真正的位帶操作,網上有不的資料,寫得也很詳細,在這裡我只是簡單說一下我的理解。另,不理解真正的位帶操作,也不影響對本文的理解,因此文跟位帶操作沒有任何關係,只是仿仿罷了,不能當真。如果不想了解一下,此節可直接忽略。
如果不使用位帶操作,我們操作一個次數據時,就要動32位(STM32是32位的),做一個不恰當的比喻,這就相當於我們坐在一輛有32節車廂的火車上,但是輛火車只有一個門,如果我們要查看這火車中乘客的信息,或者是乘客想下車,必須從那一個門進出,如下圖1。
圖1 只有1個車門的32節火車
而如果我們有了位帶操作,就相當於,給這輛32節車廂的火車裝上了32個車門,這樣一來,想查看哪個乘客的信息,或都那個乘客要下車,都可以迅速地從指定的車門下車。如下圖2所示。
圖2 有32個車門的32節火車
有了32個門後,速度就快多了,但是硬體成本肯定要起來了,這就是為什麼STM32F030系列沒有位帶操作的原因,就是它的成本低。
2、C言語結構體位段操作
在C語言中,對結構體的聲明,有一個位域,它可以控制,此結構體中的成員占幾個位,關於它的使用,有如下代碼:
1 typedef struct _16_Bits_Struct
2 {
3 u16 bit0 : 1;//佔一個位元組
4 u16 bit1 : 1;
5 u16 bit2 : 1;
6 u16 bit3 : 1;
7 u16 bit4 : 1;
8 u16 bit5 : 1;
9 u16 bit6 : 1;
10 u16 bit7 : 1;
11 u16 bit8 : 1;
12 u16 bit9 : 1;
13 u16 bit10 : 1;
14 u16 bit11 : 2;//佔兩個位元組
15 u16 bit12 : 3;//佔三個位元組
16 } _16_Bits_Struct;
上面的_16_Bits_Struct結構體類型共佔用2個位元組,即16位,但它的13個成員變數所佔用的位數不全都一樣,通過「:」後面的數字可決定它占幾位。代碼如下,操作一個此結構體類型的位。
1 _16_Bits_Struct _16_bits;
2 unsigned short _16bits_data;
3 memset(&_16_bits, 0, sizeof(_16_Bits_Struct));//將其內存清0
4
5 _16_bits.bit2 = 1;
6 _16_bits.bit5 = 1;
7 _16_bits.bit8 = 5;
8
9 _16bits_data = *((unsigned short*)(&_16_bits));
10
11 printf("_16bits_data = %0xH
", _16bits_data);
其輸出結果為:
從結果中可以看出,在結構體,從bit0~bit12依次是從低位到高位。在上面代碼的第7行,雖然給bit8寫入了5,但是因為它只佔一位,所以只取了5(D)=0101(B)的最低位,即為1。因此最終結果為124H,它的內存結構如下圖3所示。
圖3 結構體內存結構圖
3、STM32F030仿位帶操作
有了上面結構體位段操作的基礎後,離實現仿STM32F030的位帶操作就很近了。我打算做一個最簡單的,實現對GPIO的某一個引腳操作,達到亮滅LED的功能。
從STM32F030的參考手冊中,找到GPIO的輸出寄存器ODR,看到它的基本信息如下圖4所示,這個寄存器是可讀可寫的(RW),因此只要作我們給這個寄存器其中的一個位寫入1,那麼這個引腳就會輸出1,寫0就輸出0(當然前提條件是你把它配置成輸出模式,並且使能了它的時鐘)。
圖4 GPIO的ODR寄存器結構圖
我是如何對這個寄存器一次只操作一位的呢,且看下面代碼再來解釋。
1 typedef struct _16_Bits_Struct
2 {
3 u16 bit0 : 1;
4 u16 bit1 : 1;
5 u16 bit2 : 1;
6 u16 bit3 : 1;
7 u16 bit4 : 1;
8 u16 bit5 : 1;
9 u16 bit6 : 1;
10 u16 bit7 : 1;
11 u16 bit8 : 1;
12 u16 bit9 : 1;
13 u16 bit10 : 1;
14 u16 bit11 : 1;
15 u16 bit12 : 1;
16 u16 bit13 : 1;
17 u16 bit14 : 1;
18 u16 bit15 : 1;
19 } Bits_16_TypeDef;
20 #define LED_GPIO_CLK RCC_AHBPeriph_GPIOA
21 #define LED_PORT GPIOA
22 #define LED_PIN GPIO_Pin_4
23 //使用結構體的位段操作, 兼容Cortex-M3的位帶操作.
24 #define LED_PORT_OUT ((Bits_16_TypeDef *)(&(LED_PORT->ODR)))
25 #define LED (LED_PORT_OUT->bit4)
我的硬體連接是:LED接GPIOA的4引腳上。1~19行在前面的結構體知識中已經做出了解釋了,20~22隻是為了代碼更好移植做的一些宏定義,可不要。24行就比較關鍵了:先取出GPIOA->ODR的地址,然後再將它強制轉化為Bits_16_TypeDef *類型(注意,是指針類型)。轉化為此類型後,ODR就有位域的特性了,因此就可以對它進行位操作。25行就是將接在PA.4的LED定義為GPIOA->ODR的第4位。
有了這樣的操作後,想要我們的LED亮滅,就很容易了,代碼如下。
1 LED = 0;//LED亮
2 LED = 1;//LED滅
因硬體的連接不同,效果可能是反的。看到這裡,是不是覺得操作起來很簡單呢。
完整的代碼如下:
led.c
1 /*------------------------------------------------------------------------------
2 風機監測系統(2017年8月12日12:22:38)
3 功能描述:
4 LED的開關功能,主要用於狀態顯示
5
6 使用資源:GPIOA隨板子不用而變化
7
8 文件說明:無
9 作者:Endless 郵箱:endless@139.com 時間:2017年8月10日21:35:38
10 修改:無 時間:
11 ------------------------------------------------------------------------------*/
12 #include "led.h"
13 #include "stm32f0xx.h"
14
15 /*-----------------------------------------------------------------------------
16 函數功能:LED初始化
17 函數參數:無
18 函數返回:無
19 函數說明:調用此函數前,需要在LED.h修改宏定義LED引腳
20 作者:Endless
21 -----------------------------------------------------------------------------*/
22 void LED_Init(void)
23 {
24 GPIO_InitTypeDef GPIO_InitStructure;
25
26 RCC_AHBPeriphClockCmd(LED_GPIO_CLK, ENABLE);
27
28 GPIO_InitStructure.GPIO_Pin = LED_PIN;
29 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
30 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
31 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
32 GPIO_Init(LED_PORT, &GPIO_InitStructure);
33 }
led.h
1 #ifndef __led_H2 #define __led_H
3
4 #include "stm32f0xx.h"
5 #include "mytype.h"
6
7 #define LED_GPIO_CLK RCC_AHBPeriph_GPIOA
8 #define LED_PORT GPIOA
9 #define LED_PIN GPIO_Pin_4
10
11 //使用結構體的位段操作, 兼容Cortex-M3的位帶操作.
12 #define LED_PORT_OUT ((Bits_16_TypeDef *)(&(LED_PORT->ODR)))
13 #define LED (LED_PORT_OUT->bit4)
14
15 void LED_Init(void);
16
17 #endif
mytype.h
1 #ifndef __MYTYPE_H
2 #define __MYTYPE_H
3 #include "stm32f0xx.h"
4
5 #ifndef BIT
6 #define BIT(x) (1 << (x))
7 #endif
8
9 #ifndef u8
10 #define u8 uint8_t
11 #endif
12
13 #ifndef u16
14 #define u16 uint16_t
15 #endif
16
17 #ifndef u32
18 #define u32 uint32_t
19 #endif
20
21 #ifndef NULL
22 #define NULL 0
23 #endif
24
25 /*------------------------------------------------------------------------------
26 用戶自定變數
27 功能描述:使用結構體的位段操作,可以實現位操作
28 作者:Endless 2017年8月13日18:32:37
29 修改:無 時間:
30 ------------------------------------------------------------------------------*/
31 typedef struct _16_Bits_Struct
32 {
33 u16 bit0 : 1;
34 u16 bit1 : 1;
35 u16 bit2 : 1;
36 u16 bit3 : 1;
37 u16 bit4 : 1;
38 u16 bit5 : 1;
39 u16 bit6 : 1;
40 u16 bit7 : 1;
41 u16 bit8 : 1;
42 u16 bit9 : 1;
43 u16 bit10 : 1;
44 u16 bit11 : 1;
45 u16 bit12 : 1;
46 u16 bit13 : 1;
47 u16 bit14 : 1;
48 u16 bit15 : 1;
49 } Bits_16_TypeDef;
如果你想進行更多的位操作,只需多定義幾次就行了,很容易的。到這裡就差不多結束了,希望能夠幫到大家!
更多優質內容推薦:
2017優就業就業促進計劃:http://www.ujiuye.com/zt/jycj/?wt.bd=zdy35845tt
學IT,用周末給自己加薪!
http://www.ujiuye.com/zt/zmb/?wt.bd=zdy35845tt
IT職業教育:http://xue.ujiuye.com/
![](https://pic.pimg.tw/zzuyanan/1488615166-1259157397.png)
![](https://pic.pimg.tw/zzuyanan/1482887990-2595557020.jpg)
TAG:IT優就業 |
※央行開展1560億MLF和801億PSL操作
※修復由於主庫NOLOGGING操作引起的備庫ORA-01578和ORA-26040錯誤
※GTA5 XBOX360手柄鍵位操作指南
※7SR45 操作手冊
※GBPUSD 1月30日操作指南
※央行昨日開展MLF操作4630億元
※DDR4版GT 1030打不過4年前的GT 730顯卡?正常操作而已
※Google I/O 2018:50%操作系統、40% AI、10%物聯網和0%隱私
※IFA2018第三天,華為專門為EMUI9.0操作系統召開了一場媒體溝通會
※新思全球首個USB 3.2操作展示 實測可達1.6 GB/s數據傳輸速率
※Windows10 RS5新版17655增強操作中心 Windows10官方簡版系統:16G硬碟就能運行
※谷歌Pixel 3發布:單手操作無壓力 5500元起售
※2018年1月數據:Windows 10 即將成為全球第一大桌面操作系統
※6萬塊買390km續航 江淮IEV6E這波操作很秀
※華為P20上手實拍:5.8寸P20 Pro「縮小版」,機身小單手操作方便
※EURUSD 3月14日操作指南
※OPPO Find X配置拉滿:驍龍845+8GB 頂配只是基本操作
※強力騷操作!5.86寸全面屏+64GB僅1399元,全面逆襲
※這波操作666!WPS遇上麒麟970,手機照片也能秒變PPT
※神操作!70m2老房爆改成北歐婚房【A963第1469期】