之前我們已經介紹了庫函式和暫存器控制led跑馬燈,其實無論使用哪一種方法(包括操作bsrr,brr暫存器的方式)最終都是通過操作gpio_odr暫存器(32位暫存器只使用低16位)響應的位為該io口賦值
那麼什麼是位操作?我們知道gpio_odr暫存器的每一位對應乙個io口的電平操作,而每一位實際是乙個io口位址的對映,位操作就是跨越暫存器對映,直接為這個位址進行賦值
在led跑馬燈-位操作的實驗中我們將使用位操作的方式控制io口輸出高低電平
1,支援位操作的兩個記憶體區範圍:
0x2000_0000-0x200f_ffff // sram區中的最低1m
0x4000_0000-0x400f_ffff // 片上外設區中的最低1m
2,位址對映關係計算:
對於sram位帶區某位元,所在位元組位址為a,位n(0<=n<=7),該位元在別名區的位址為:
aliasaddr=0x22000000+((a-0x20000000) * 8+n)*4=0x22000000+(a-0x20000000)*32+n*4
對於片上外設位帶區某位元,所在位元組位址為a,位n(0<=n<=7),該位元在別名區的位址為:
aliasaddr=0x42000000+((a-0x40000000) * 8+n)*4=0x42000000+(a-0x40000000)*32+n*4
暫存器每乙個bit對映為乙個32位位址,修改這個位,可直接修改其對映的位址達到操作位的目的
以前獲取某個位的值:
先獲取整個暫存器的值
掩蓋不需要的位
位操作獲取某個位的值:
從位帶別名區讀取狀態位
位操作對硬體i/o密集型底層程式最有好處
以前的讀-改-寫需要三條指令,導致中間有兩個可能被中斷的空檔
介紹乙個sys.h檔案對位操作進行了封裝
#ifndef __sys_h
#define __sys_h
#include "stm32f10x.h"
//計算暫存器位址addr下,第bitnum位對映的32位位址值
#define bitband(addr, bitnum) ((addr & 0xf0000000)+0x2000000+((addr &0xfffff)<<5)+(bitnum<<2))
#define mem_addr(addr) *((volatile unsigned long *)(addr))
#define bit_addr(addr, bitnum) mem_addr(bitband(addr, bitnum))
//gpiox_odr暫存器位址
#define gpioa_odr_addr (gpioa_base+12) //0x4001080c
#define gpiob_odr_addr (gpiob_base+12) //0x40010c0c
#define gpioc_odr_addr (gpioc_base+12) //0x4001100c
#define gpiod_odr_addr (gpiod_base+12) //0x4001140c
#define gpioe_odr_addr (gpioe_base+12) //0x4001180c
#define gpiof_odr_addr (gpiof_base+12) //0x40011a0c
#define gpiog_odr_addr (gpiog_base+12) //0x40011e0c
//gpiox_idr暫存器位址
#define gpioa_idr_addr (gpioa_base+8) //0x40010808
#define gpiob_idr_addr (gpiob_base+8) //0x40010c08
#define gpioc_idr_addr (gpioc_base+8) //0x40011008
#define gpiod_idr_addr (gpiod_base+8) //0x40011408
#define gpioe_idr_addr (gpioe_base+8) //0x40011808
#define gpiof_idr_addr (gpiof_base+8) //0x40011a08
#define gpiog_idr_addr (gpiog_base+8) //0x40011e08
//位操作封裝
#define paout(n) bit_addr(gpioa_odr_addr,n) // 操作gpioa_odr暫存器的第n個位-輸出
#define pain(n) bit_addr(gpioa_idr_addr,n) // 操作gpioa_idr暫存器的第n個位-輸入
#define pbout(n) bit_addr(gpiob_odr_addr,n)
#define pbin(n) bit_addr(gpiob_idr_addr,n)
#define pcout(n) bit_addr(gpioc_odr_addr,n)
#define pcin(n) bit_addr(gpioc_idr_addr,n)
#define pdout(n) bit_addr(gpiod_odr_addr,n)
#define pdin(n) bit_addr(gpiod_idr_addr,n)
#define peout(n) bit_addr(gpioe_odr_addr,n)
#define pein(n) bit_addr(gpioe_idr_addr,n)
#define pfout(n) bit_addr(gpiof_odr_addr,n)
#define pfin(n) bit_addr(gpiof_idr_addr,n)
#define pgout(n) bit_addr(gpiog_odr_addr,n)
#define pgin(n) bit_addr(gpiog_idr_addr,n)
#endif
stm32f10x.h中找到gpioa基位址gpioa_base
#define gpioa_base (apb2periph_base + 0x0800) // 在apb2匯流排下+偏移量0x0800
再找到apb2periph基位址
#define apb2periph_base (periph_base + 0x10000)
最終操作暫存器的相應的位
連線方式:
led0連線pb5引腳
led1連線pe5引腳
1,使能io時鐘
呼叫函式rcc_apb2periphclockcmd
2,初始化gpio
呼叫函式gpio_init();
3,使用位操作實現操作io口輸出高低電平
#include "stm32f10x.h"
#include "led.h"
#include "delay.h" // 此標頭檔案中間接引用了sys.h標頭檔案
int main(void)
}
LED跑馬燈效果
這個led跑馬燈的效果是怎麼乙個原理,現分析如下 假設有乙個要進行變化的物件陣列,我們稱之為a物件。如下 這個等變化的陣列長度為5,有顏色陣列,我們稱之為b,如下 這個長度為3。要分析出原理,我們要根據事物的表象去分析得到事物內在的規律與原理,根據這個原理與規律我們才能得出解決辦法。我們進行一次模擬...
LED跑馬燈實驗
一 新建工程並新增相應的工程檔案 本實驗需要用到三個韌體庫檔案,分別為stm32f4xx gpio.c stm32f4xx gpio.h stm32f4xx rcc.c stm32f4xx rcc.h misc.c misc.h 二 編寫使用者驅動 1 編寫c檔案 a.使能gpio時鐘,根據電路原理...
Linux下LED跑馬燈驅動
一.驅動程式 include include include include include include include include include include include define device name leds define led major 231 static uns...