LED跑馬燈 位操作

2021-07-22 10:14:34 字數 4098 閱讀 8890

之前我們已經介紹了庫函式和暫存器控制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...