国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷)

這篇具有很好參考價值的文章主要介紹了【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

【STM32】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷)

低功耗模式

【STM32筆記】低功耗模式配置及避坑匯總

前文:
blog.csdn.net/weixin_53403301/article/details/128216064
【STM32筆記】HAL庫低功耗模式配置(ADC喚醒無法使用、低功耗模式無法燒錄解決方案)

【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷),STM32筆記,stm32,單片機,嵌入式硬件

__WFI();為匯編指令

/**
  \brief   Wait For Interrupt
  \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs.
 */
#define __WFI                             __wfi

其作用就是設(shè)備休眠 并等待任意中斷實踐喚醒
【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷),STM32筆記,stm32,單片機,嵌入式硬件

實際調(diào)用:

	__WFI();

但是 基本上直接都執(zhí)行不了

最常見的就是中斷沒清理掉

【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷),STM32筆記,stm32,單片機,嵌入式硬件
在Keil的調(diào)試中可以看到活躍的中斷
【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷),STM32筆記,stm32,單片機,嵌入式硬件
EPA分別表示Enable Pending Active

前兩個表示開啟但未發(fā)生 Active表示正在發(fā)生

所以進(jìn)入休眠前需要調(diào)用中斷清理
如:

__disable_irq(); 

或:

__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);	  //清理喚醒標(biāo)志 防止立刻喚醒

等標(biāo)志

另外 實測發(fā)現(xiàn) 即使沒有中斷或喚醒標(biāo)志 也會導(dǎo)致__WFI();無法進(jìn)入 特別是程序剛開始運行的時候 這里其實就是沒消抖 需要延時一會(哪怕1us)

	delay_us(1);
	__WFI();

delay_us中其實是對系統(tǒng)定時器SysTick進(jìn)行賦值并計數(shù) 計數(shù)后會關(guān)閉 其實進(jìn)不了低功耗就是因為這個被開啟了 中斷一直有

直接關(guān)閉/開啟系統(tǒng)定時器也可以

SysTick->CTRL = 0;

再者 在進(jìn)行調(diào)試時 如果采用單步調(diào)試(也相當(dāng)于一種中斷) 則會執(zhí)行__WFI();后立馬執(zhí)行下一句

所以可以在__WFI();之前和之后打一個斷點 用全速跑來判斷是否進(jìn)入

如果開啟了系統(tǒng)滴答定時器,記得關(guān)閉系統(tǒng)滴答定時器,因為系統(tǒng)滴答定時器的中斷也會喚醒CPU。

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	HAL_Delay(1000);//延時1000毫秒
	/* 采用位帶操作實現(xiàn)LED翻轉(zhuǎn) */
	PCout(13) = !PCin(13);
	if(times > 4)
	{
		//HAL_SuspendTick();//停止系統(tǒng)滴答計時器
		CLEAR_BIT(SysTick->CTRL, SysTick_CTRL_ENABLE_Msk);//失能系統(tǒng)滴答定時器
		HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFI);//WFI指令進(jìn)入睡眠模式
		times = 0;
		SET_BIT(SysTick->CTRL, SysTick_CTRL_ENABLE_Msk);//使能系統(tǒng)滴答定時器
		//HAL_ResumeTick();//恢復(fù)系統(tǒng)滴答計時器
	}
	times++;//循環(huán)次數(shù)加一
  }

在我前文進(jìn)入低功耗的函數(shù)中 每個模式都有一個10ms的消抖 其實這個可以省略
但我們用的是HAL庫 HAL庫初始化時鐘以后 會打開SysTick中斷 如果這個開著 就一直無法進(jìn)入低功耗(進(jìn)入就被中斷喚醒) 所以我這里加了個我自己寫的延時函數(shù) 其中就有關(guān)閉SysTick的語句 如果你不用這個消抖 沒啥BUG也行 但我還是建議加上去 畢竟也不差那10ms

附錄:Cortex-M架構(gòu)的SysTick系統(tǒng)定時器精準(zhǔn)延時和MCU位帶操作

SysTick系統(tǒng)定時器精準(zhǔn)延時

延時函數(shù)

SysTick->LOAD中的值為計數(shù)值
計算方法為工作頻率值/分頻值
比如工作頻率/1000 則周期為1ms

以ADuCM4050為例:

#include "ADuCM4050.h"

void delay_ms(unsigned int ms)
{
	SysTick->LOAD = 26000000/1000-1; // Count from 255 to 0 (256 cycles)  載入計數(shù)值 定時器從這個值開始計數(shù)
	SysTick->VAL = 0; // Clear current value as well as count flag  清空計數(shù)值到達(dá)0后的標(biāo)記
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能52MHz的系統(tǒng)定時器
	while(ms--)
	{
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待
	}
	SysTick->CTRL = 0; // Disable SysTick  關(guān)閉系統(tǒng)定時器
}
void delay_us(unsigned int us)
{
	SysTick->LOAD = 26000000/1000/1000-1; // Count from 255 to 0 (256 cycles)  載入計數(shù)值 定時器從這個值開始計數(shù)
	SysTick->VAL = 0; // Clear current value as well as count flag  清空計數(shù)值到達(dá)0后的標(biāo)記
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能52MHz的系統(tǒng)定時器
	while(us--)
	{
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待
	}
	SysTick->CTRL = 0; // Disable SysTick  關(guān)閉系統(tǒng)定時器
}

其中的52000000表示芯片的系統(tǒng)定時器頻率 32系列一般為外部定時器頻率的兩倍

Cortex-M架構(gòu)SysTick系統(tǒng)定時器阻塞和非阻塞延時

阻塞延時

首先是最常用的阻塞延時

void delay_ms(unsigned int ms)
{
	SysTick->LOAD = 50000000/1000-1; // Count from 255 to 0 (256 cycles)  載入計數(shù)值 定時器從這個值開始計數(shù)
	SysTick->VAL = 0; // Clear current value as well as count flag  清空計數(shù)值到達(dá)0后的標(biāo)記
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系統(tǒng)定時器
	while(ms--)
	{
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待
	}
	SysTick->CTRL = 0; // Disable SysTick  關(guān)閉系統(tǒng)定時器
}
void delay_us(unsigned int us)
{
	SysTick->LOAD = 50000000/1000/1000-1; // Count from 255 to 0 (256 cycles)  載入計數(shù)值 定時器從這個值開始計數(shù)
	SysTick->VAL = 0; // Clear current value as well as count flag  清空計數(shù)值到達(dá)0后的標(biāo)記
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系統(tǒng)定時器
	while(us--)
	{
		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待
	}
	SysTick->CTRL = 0; // Disable SysTick  關(guān)閉系統(tǒng)定時器
}

50000000表示工作頻率
分頻后即可得到不同的延時時間
以此類推

那么 不用兩個嵌套while循環(huán) 也可以寫成:

void delay_ms(unsigned int ms)
{
	SysTick->LOAD = 50000000/1000*ms-1; // Count from 255 to 0 (256 cycles)  載入計數(shù)值 定時器從這個值開始計數(shù)
	SysTick->VAL = 0; // Clear current value as well as count flag  清空計數(shù)值到達(dá)0后的標(biāo)記
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系統(tǒng)定時器

	while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待

	SysTick->CTRL = 0; // Disable SysTick  關(guān)閉系統(tǒng)定時器
}
void delay_us(unsigned int us)
{
	SysTick->LOAD = 50000000/1000/1000*us-1; // Count from 255 to 0 (256 cycles)  載入計數(shù)值 定時器從這個值開始計數(shù)
	SysTick->VAL = 0; // Clear current value as well as count flag  清空計數(shù)值到達(dá)0后的標(biāo)記
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系統(tǒng)定時器
	
	while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待

	SysTick->CTRL = 0; // Disable SysTick  關(guān)閉系統(tǒng)定時器
}

但是這種寫法有個弊端
那就是輸入ms后,最大定時不得超過計數(shù)值,也就是不能超過LOAD的最大值,否則溢出以后,則無法正常工作

而LOAD如果最大是32位 也就是4294967295

晶振為50M的話 50M的計數(shù)值為1s 4294967295計數(shù)值約為85s

固最大定時時間為85s

但用嵌套while的話 最大可以支持定時4294967295*85s

非阻塞延時

如果采用非阻塞的話 直接改寫第二種方法就好了:

void delay_ms(unsigned int ms)
{
	SysTick->LOAD = 50000000/1000*ms-1; // Count from 255 to 0 (256 cycles)  載入計數(shù)值 定時器從這個值開始計數(shù)
	SysTick->VAL = 0; // Clear current value as well as count flag  清空計數(shù)值到達(dá)0后的標(biāo)記
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系統(tǒng)定時器

	//while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待

	//SysTick->CTRL = 0; // Disable SysTick  關(guān)閉系統(tǒng)定時器
}
void delay_us(unsigned int us)
{
	SysTick->LOAD = 50000000/1000/1000*us-1; // Count from 255 to 0 (256 cycles)  載入計數(shù)值 定時器從這個值開始計數(shù)
	SysTick->VAL = 0; // Clear current value as well as count flag  清空計數(shù)值到達(dá)0后的標(biāo)記
	SysTick->CTRL = 5; // Enable SysTick timer with processor clock  使能26MHz的系統(tǒng)定時器
	
	//while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set  等待

	//SysTick->CTRL = 0; // Disable SysTick  關(guān)閉系統(tǒng)定時器
}

將等待和關(guān)閉定時器語句去掉
在使用時加上判斷即可變?yōu)樽枞?/p>

delay_ms(500);
while ((SysTick->CTRL & 0x00010000)==0);
SysTick->CTRL = 0;

在非阻塞狀態(tài)下 可以提交定時器后 去做別的事情 然后再來等待

不過這樣又有一個弊端 那就是定時器會自動重載 可能做別的事情以后 定時器跑過了 然后就要等85s才能停下

故可以通過內(nèi)部定時器來進(jìn)行非阻塞延時函數(shù)的編寫

基本上每個mcu的內(nèi)部定時器都可以配置自動重載等功能 網(wǎng)上資料很多 這里就不再闡述了

位帶操作

位帶代碼

M3、M4架構(gòu)的單片機 其輸出口地址為端口地址+20 輸入為+16
M0架構(gòu)的單片機 其輸出口地址為端口地址+12 輸入為+8
以ADuCM4050為列:

位帶宏定義
#ifndef __GPIO_H__
#define __GPIO_H__
#include "ADuCM4050.h"
#include "adi_gpio.h"

#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))

#define GPIO0_ODR_Addr    (ADI_GPIO0_BASE+20) //0x40020014
#define GPIO0_IDR_Addr    (ADI_GPIO0_BASE+16) //0x40020010

#define GPIO1_ODR_Addr    (ADI_GPIO1_BASE+20) //0x40020054
#define GPIO1_IDR_Addr    (ADI_GPIO1_BASE+16) //0x40020050

#define GPIO2_ODR_Addr    (ADI_GPIO2_BASE+20) //0x40020094
#define GPIO2_IDR_Addr    (ADI_GPIO2_BASE+16) //0x40020090

#define GPIO3_ODR_Addr    (ADI_GPIO3_BASE+20) //0x400200D4
#define GPIO3_IDR_Addr    (ADI_GPIO3_BASE+16) //0x400200D0

#define P0_O(n)   	BIT_ADDR(GPIO0_ODR_Addr,n)  //輸出 
#define P0_I(n)    	BIT_ADDR(GPIO0_IDR_Addr,n)  //輸入 

#define P1_O(n)   	BIT_ADDR(GPIO1_ODR_Addr,n)  //輸出 
#define P1_I(n)    	BIT_ADDR(GPIO1_IDR_Addr,n)  //輸入 

#define P2_O(n)   	BIT_ADDR(GPIO2_ODR_Addr,n)  //輸出 
#define P2_I(n)    	BIT_ADDR(GPIO2_IDR_Addr,n)  //輸入 

#define P3_O(n)   	BIT_ADDR(GPIO3_ODR_Addr,n)  //輸出 
#define P3_I(n)    	BIT_ADDR(GPIO3_IDR_Addr,n)  //輸入 

#define Port0			(ADI_GPIO_PORT0)
#define Port1			(ADI_GPIO_PORT1)
#define Port2			(ADI_GPIO_PORT2)
#define Port3			(ADI_GPIO_PORT3)

#define Pin0			(ADI_GPIO_PIN_0)
#define Pin1			(ADI_GPIO_PIN_1)
#define Pin2			(ADI_GPIO_PIN_2)
#define Pin3			(ADI_GPIO_PIN_3)
#define Pin4			(ADI_GPIO_PIN_4)
#define Pin5			(ADI_GPIO_PIN_5)
#define Pin6			(ADI_GPIO_PIN_6)
#define Pin7			(ADI_GPIO_PIN_7)
#define Pin8			(ADI_GPIO_PIN_8)
#define Pin9			(ADI_GPIO_PIN_9)
#define Pin10			(ADI_GPIO_PIN_10)
#define Pin11			(ADI_GPIO_PIN_11)
#define Pin12			(ADI_GPIO_PIN_12)
#define Pin13			(ADI_GPIO_PIN_13)
#define Pin14			(ADI_GPIO_PIN_14)
#define Pin15			(ADI_GPIO_PIN_15)

void GPIO_OUT(unsigned int port,unsigned int pin,unsigned int flag);
void GPIO_BUS_OUT(unsigned int port,unsigned int num);

void P0_BUS_O(unsigned int num);
unsigned int P0_BUS_I(void);

void P1_BUS_O(unsigned int num);
unsigned int P1_BUS_I(void);

void P2_BUS_O(unsigned int num);
unsigned int P2_BUS_I(void);

void P3_BUS_O(unsigned int num);
unsigned int P3_BUS_I(void);

#endif

總線函數(shù)
#include "ADuCM4050.h"
#include "adi_gpio.h"
#include "GPIO.h"

void GPIO_OUT(unsigned int port,unsigned int pin,unsigned int flag)
{
	switch(port)
	{
		case 0:{
			switch(pin)
			{
				case 0:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_0));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_0));};break;
				case 1:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_1));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_1));};break;
				case 2:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_2));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_2));};break;
				case 3:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_3));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_3));};break;
				case 4:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_4));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_4));};break;
				case 5:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_5));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_5));};break;
				case 6:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_6));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_6));};break;
				case 7:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_7));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_7));};break;
				case 8:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_8));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_8));};break;
				case 9:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_9));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_9));};break;
				case 10:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_10));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_10));};break;
				case 11:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_11));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_11));};break;
				case 12:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_12));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_12));};break;
				case 13:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_13));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_13));};break;
				case 14:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_14));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_14));};break;
				case 15:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT0),(ADI_GPIO_PIN_15));}else{adi_gpio_SetLow((ADI_GPIO_PORT0),(ADI_GPIO_PIN_15));};break;
				default:pin=0;break;
			}
		}break;
		
		case 1:{
			switch(pin)
			{
				case 0:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_0));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_0));};break;
				case 1:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_1));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_1));};break;
				case 2:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_2));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_2));};break;
				case 3:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_3));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_3));};break;
				case 4:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_4));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_4));};break;
				case 5:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_5));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_5));};break;
				case 6:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_6));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_6));};break;
				case 7:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_7));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_7));};break;
				case 8:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_8));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_8));};break;
				case 9:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_9));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_9));};break;
				case 10:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_10));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_10));};break;
				case 11:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_11));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_11));};break;
				case 12:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_12));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_12));};break;
				case 13:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_13));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_13));};break;
				case 14:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_14));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_14));};break;
				case 15:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT1),(ADI_GPIO_PIN_15));}else{adi_gpio_SetLow((ADI_GPIO_PORT1),(ADI_GPIO_PIN_15));};break;
				default:pin=0;break;
			}
		}break;
		
		case 2:{
			switch(pin)
			{
				case 0:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_0));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_0));};break;
				case 1:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_1));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_1));};break;
				case 2:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_2));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_2));};break;
				case 3:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_3));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_3));};break;
				case 4:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_4));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_4));};break;
				case 5:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_5));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_5));};break;
				case 6:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_6));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_6));};break;
				case 7:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_7));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_7));};break;
				case 8:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_8));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_8));};break;
				case 9:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_9));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_9));};break;
				case 10:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_10));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_10));};break;
				case 11:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_11));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_11));};break;
				case 12:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_12));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_12));};break;
				case 13:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_13));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_13));};break;
				case 14:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_14));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_14));};break;
				case 15:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT2),(ADI_GPIO_PIN_15));}else{adi_gpio_SetLow((ADI_GPIO_PORT2),(ADI_GPIO_PIN_15));};break;
				default:pin=0;break;
			}
		}break;
		
		case 3:{
			switch(pin)
			{
				case 0:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_0));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_0));};break;
				case 1:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_1));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_1));};break;
				case 2:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_2));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_2));};break;
				case 3:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_3));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_3));};break;
				case 4:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_4));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_4));};break;
				case 5:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_5));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_5));};break;
				case 6:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_6));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_6));};break;
				case 7:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_7));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_7));};break;
				case 8:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_8));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_8));};break;
				case 9:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_9));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_9));};break;
				case 10:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_10));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_10));};break;
				case 11:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_11));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_11));};break;
				case 12:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_12));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_12));};break;
				case 13:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_13));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_13));};break;
				case 14:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_14));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_14));};break;
				case 15:if(flag==1){adi_gpio_SetHigh((ADI_GPIO_PORT3),(ADI_GPIO_PIN_15));}else{adi_gpio_SetLow((ADI_GPIO_PORT3),(ADI_GPIO_PIN_15));};break;
				default:pin=0;break;
			}
		}break;
		
		default:port=0;break;
	}	
}

void GPIO_BUS_OUT(unsigned int port,unsigned int num)  //num最大為0xffff
{
	int i;
	for(i=0;i<16;i++)
	{
		GPIO_OUT(port,i,(num>>i)&0x0001);
	}
}


void P0_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		P0_O(i)=(num>>i)&0x0001;
	}
}
unsigned int P0_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(P0_I(i)<<i)&0xFFFF;
	}
	return num;
}

void P1_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		P1_O(i)=(num>>i)&0x0001;
	}
}
unsigned int P1_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(P1_I(i)<<i)&0xFFFF;
	}
	return num;
}

void P2_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		P2_O(i)=(num>>i)&0x0001;
	}
}
unsigned int P2_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(P2_I(i)<<i)&0xFFFF;
	}
	return num;
}

void P3_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		P3_O(i)=(num>>i)&0x0001;
	}
}
unsigned int P3_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(P3_I(i)<<i)&0xFFFF;
	}
	return num;
}

一、位帶操作理論及實踐

位帶操作的概念其實30年前就有了,那還是 CM3 將此能力進(jìn)化,這里的位帶操作是 8051 位尋址區(qū)的威力大幅加強版

位帶區(qū): 支持位帶操作的地址區(qū)

位帶別名: 對別名地址的訪問最終作 用到位帶區(qū)的訪問上(注意:這中途有一個 地址映射過程)

位帶操作對于硬件 I/O 密集型的底層程序最有用處

支持了位帶操作后,可以使用普通的加載/存儲指令來對單一的比特進(jìn)行讀寫。在CM4中,有兩個區(qū)中實現(xiàn)了位帶。其中一個是SRAM區(qū)的最低1MB范圍,第二個則是片內(nèi)外設(shè)區(qū)的最低1MB范圍。這兩個區(qū)中的地址除了可以像普通的RAM一樣使用外,它們還都有自己的“位帶別名區(qū)”,位帶別名區(qū)把每個比特膨脹成一個32位的字。當(dāng)你通過位帶別名區(qū)訪問這些字時,就可以達(dá)到訪問原始比特的目的。

位操作就是可以單獨的對一個比特位讀和寫,類似與51中sbit定義的變量,stm32中通過訪問位帶別名區(qū)來實現(xiàn)位操作的功能
STM32中有兩個地方實現(xiàn)了位帶,一個是SRAM,一個是片上外設(shè)。
【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷),STM32筆記,stm32,單片機,嵌入式硬件
(1)位帶本質(zhì)上是一塊地址區(qū)(例如每一位地址位對應(yīng)一個寄存器)映射到另一片地址區(qū)(實現(xiàn)每一位地址位對應(yīng)一個寄存器中的一位),該區(qū)域就叫做位帶別名區(qū),將每一位膨脹成一個32位的字。
(2)位帶區(qū)的4個字節(jié)對應(yīng)實際寄存器或內(nèi)存區(qū)的一個位,雖然變大到4個字節(jié),但實際上只有最低位有效(代表0或1)

只有位帶可以直接用=賦值的方式來操作寄存器 位帶是把寄存器上的每一位 膨脹到32位 映射到位帶區(qū) 比如0x4002 0000地址的第0個bit 映射到位帶區(qū)的0地址 那么其對應(yīng)的位帶映射地址為0x00 - 0x04 一共32位 但只有LSB有效 采用位帶的方式用=賦值時 就是把位帶區(qū)對應(yīng)的LSB賦值 然后MCU再轉(zhuǎn)到寄存器對應(yīng)的位里面 寄存器操作時 如果不改變其他位上面的值 那就只能通過&=或者|=的方式進(jìn)行

【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷),STM32筆記,stm32,單片機,嵌入式硬件

要設(shè)置0x2000 0000這個字節(jié)的第二個位bit2為1,使用位帶操作的步驟有:
1、將1寫入位 帶別名區(qū)對應(yīng)的映射地址(即0x22000008,因為1bit對應(yīng)4個byte);
2、將0x2000 0000的值 讀取到內(nèi)部的緩沖區(qū)(這一步驟是內(nèi)核完成的,屬于原子操作,不需要用戶操作);
3、將bit2置1,再把值寫 回到0x2000 0000(屬于原子操作,不需要用戶操作)。

關(guān)于GPIO引腳對應(yīng)的訪問地址,可以參考以下公式
寄存器位帶別名 = 0x42000000 + (寄存器的地址-0x40000000)32 + 引腳編號4

如:端口F訪問的起始地址GPIOF_BASE

#define GPIOF ((GPIO_TypeDef *)GPIOF_BASE)

【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷),STM32筆記,stm32,單片機,嵌入式硬件

但好在官方庫里面都幫我們定義好了 只需要在BASE地址加上便宜即可

例如:

GPIOF的ODR寄存器的地址 = GPIOF_BASE + 0x14

寄存器位帶別名 = 0x42000000 + (寄存器的地址-0x40000000)32 + 引腳編號4

設(shè)置PF9引腳的話:

uint32_t *PF9_BitBand =
*(uint32_t *)(0x42000000 + ((uint32_t )&GPIOF->ODR– 0x40000000) *32 + 9*4)

封裝一下:

#define PFout(x) *(volatile uint32_t *)(0x42000000 + ((uint32_t )&GPIOF->ODR – 0x40000000) *32 + x*4)

現(xiàn)在 可以把通用部分封裝成一個小定義:

#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))

那么 設(shè)置PF引腳的函數(shù)可以定義:

#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414   
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 

#define PF_O(n)   	BIT_ADDR(GPIOF_ODR_Addr,n)  //輸出 
#define PF_I(n)    	BIT_ADDR(GPIOF_IDR_Addr,n)  //輸入

若使PF9輸入輸出則:

PF_O(9)=1;  //輸出高電平
uint8_t dat = PF_I(9);  //獲取PF9引腳的值

總線輸入輸出:

void PF_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PF_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PF_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PF_I(i)<<i)&0xFFFF;
	}
	return num;
}

STM32的可用下面的函數(shù):

#ifndef __GPIO_H__
#define __GPIO_H__
#include "stm32l496xx.h"

#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))

#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 
#define PA_O(n)   	BIT_ADDR(GPIOA_ODR_Addr,n)  //輸出 
#define PA_I(n)    	BIT_ADDR(GPIOA_IDR_Addr,n)  //輸入 

#define PB_O(n)   	BIT_ADDR(GPIOB_ODR_Addr,n)  //輸出 
#define PB_I(n)    	BIT_ADDR(GPIOB_IDR_Addr,n)  //輸入 

#define PC_O(n)   	BIT_ADDR(GPIOC_ODR_Addr,n)  //輸出 
#define PC_I(n)    	BIT_ADDR(GPIOC_IDR_Addr,n)  //輸入 

#define PD_O(n)   	BIT_ADDR(GPIOD_ODR_Addr,n)  //輸出 
#define PD_I(n)    	BIT_ADDR(GPIOD_IDR_Addr,n)  //輸入 

#define PE_O(n)   	BIT_ADDR(GPIOE_ODR_Addr,n)  //輸出 
#define PE_I(n)    	BIT_ADDR(GPIOE_IDR_Addr,n)  //輸入

#define PF_O(n)   	BIT_ADDR(GPIOF_ODR_Addr,n)  //輸出 
#define PF_I(n)    	BIT_ADDR(GPIOF_IDR_Addr,n)  //輸入

#define PG_O(n)   	BIT_ADDR(GPIOG_ODR_Addr,n)  //輸出 
#define PG_I(n)    	BIT_ADDR(GPIOG_IDR_Addr,n)  //輸入

#define PH_O(n)   	BIT_ADDR(GPIOH_ODR_Addr,n)  //輸出 
#define PH_I(n)    	BIT_ADDR(GPIOH_IDR_Addr,n)  //輸入

#define PI_O(n)			BIT_ADDR(GPIOI_ODR_Addr,n)  //輸出 
#define PI_I(n)   	BIT_ADDR(GPIOI_IDR_Addr,n)  //輸入

void PA_BUS_O(unsigned int num);
unsigned int PA_BUS_I(void);

void PB_BUS_O(unsigned int num);
unsigned int PB_BUS_I(void);

void PC_BUS_O(unsigned int num);
unsigned int PC_BUS_I(void);

void PD_BUS_O(unsigned int num);
unsigned int PD_BUS_I(void);

void PE_BUS_O(unsigned int num);
unsigned int PE_BUS_I(void);

void PF_BUS_O(unsigned int num);
unsigned int PF_BUS_I(void);

void PG_BUS_O(unsigned int num);
unsigned int PG_BUS_I(void);

void PH_BUS_O(unsigned int num);
unsigned int PH_BUS_I(void);

void PI_BUS_O(unsigned int num);
unsigned int PI_BUS_I(void);

#endif

#include "GPIO.h"

void PA_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PA_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PA_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PA_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PB_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PB_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PB_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PB_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PC_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PC_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PC_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PC_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PD_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PD_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PD_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PD_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PE_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PE_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PE_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PE_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PF_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PF_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PF_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PF_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PG_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PG_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PG_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PG_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PH_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PH_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PH_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PH_I(i)<<i)&0xFFFF;
	}
	return num;
}

void PI_BUS_O(unsigned int num)  //輸入值num最大為0xFFFF
{
	int i;
	for(i=0;i<16;i++)
	{
		PI_O(i)=(num>>i)&0x0001;
	}
}
unsigned int PI_BUS_I(void)  //輸出值num最大為0xFFFF
{
	unsigned int num;
	int i;
	for(i=0;i<16;i++)
	{
		num=num+(PI_I(i)<<i)&0xFFFF;
	}
	return num;
}

二、如何判斷MCU的外設(shè)是否支持位帶

根據(jù)《ARM Cortex-M3與Cortex-M4權(quán)威指南(第3版)》中第6章第7節(jié)描述
【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷),STM32筆記,stm32,單片機,嵌入式硬件
也就是說 要實現(xiàn)對GPIO的位帶操作 必須保證GPIO位于外設(shè)區(qū)域的第一個1MB中
第一個1MB應(yīng)該是0x4010 0000之前 位帶不是直接操作地址 而是操作地址映射 地址映射被操作以后 MCU自動會修改對應(yīng)寄存器的值

位帶區(qū)只有1MB 所以只能改0x4000 0000 - 0x400F FFFF的寄存器
像F4系列 GPIO的首地址為0x4002 0000 就可以用位帶來更改

STM32L476的GPIO就不行:
【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷),STM32筆記,stm32,單片機,嵌入式硬件
AHB2的都不能用位帶
ABP 還有AHB1都可以用
【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷),STM32筆記,stm32,單片機,嵌入式硬件
但是L476的寄存器里面 GPIO和ADC都是AHB2文章來源地址http://www.zghlxwxcb.cn/news/detail-686111.html

到了這里,關(guān)于【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一直產(chǎn)生中斷)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【STM32筆記】低功耗模式配置及避坑匯總

    【STM32筆記】低功耗模式配置及避坑匯總

    【STM32】低功耗模式配置及配置匯總 自己做的低功耗庫函數(shù): 【STM32】基于HAL庫建立自己的低功耗模式配置庫(STM32L4系列低功耗所有配置匯總) gitee庫 文章總結(jié):(后續(xù)更新以相關(guān)文章為準(zhǔn)) 【STM32筆記】低功耗模式、WFI命令等進(jìn)入不了休眠的可能原因(系統(tǒng)定時器SysTick一

    2024年02月06日
    瀏覽(98)
  • 洋桃電子STM32F407單片機入門教程筆記九:低功耗模式

    洋桃電子STM32F407單片機入門教程筆記九:低功耗模式

    ??此文檔作為對洋桃電子STM32F407單片機視頻的整理,B站鏈接: 第28集)低功耗模式_嗶哩嗶哩_bilibili ????????在之前的程序里應(yīng)用程序在while(1)主循環(huán)中反復(fù)執(zhí)行,ARM內(nèi)核以100%的功率工作。這樣的設(shè)計簡單穩(wěn)定,內(nèi)核全速運行的功耗也只有幾十毫安,對于外接電源的設(shè)備

    2024年01月23日
    瀏覽(21)
  • 【STM32筆記】低功耗模式下的RTC喚醒(非鬧鐘喚醒,而是采用RTC_WAKEUPTIMER)

    【STM32筆記】低功耗模式下的RTC喚醒(非鬧鐘喚醒,而是采用RTC_WAKEUPTIMER)

    【STM32】低功耗模式下的RTC喚醒(非鬧鐘喚醒,而是采用RTC_WAKEUPTIMER) 【STM32筆記】低功耗模式配置及避坑匯總 前文: blog.csdn.net/weixin_53403301/article/details/128216064 【STM32筆記】HAL庫低功耗模式配置(ADC喚醒無法使用、低功耗模式無法燒錄解決方案) 低功耗模式如圖所示 停止模

    2023年04月08日
    瀏覽(19)
  • (stm32)低功耗模式

    (stm32)低功耗模式

    ?執(zhí)行哪個低功耗模式的程序判斷流程 標(biāo)志位設(shè)置操作一定要在WFI/WFE之前,調(diào)用此指令后立即進(jìn)入睡眠判斷流程 ? ? ?

    2024年02月12日
    瀏覽(25)
  • STM32 低功耗-睡眠模式

    STM32 低功耗-睡眠模式

    在 STM32 的正常工作中,具有四種工作模式: 運行、睡眠、停止和待機 模式。 在系統(tǒng)或電源復(fù)位以后,微控制器處于運行狀態(tài),當(dāng)CPU不需繼續(xù)運行時,可以利用多種低功耗模式來節(jié)省功耗。這些低功耗模式電源消耗不同、喚醒時間不同和喚醒源不同。 例如等待某個外部事件

    2024年02月14日
    瀏覽(25)
  • STM32 低功耗-停止模式

    STM32 低功耗-停止模式

    在 STM32 的正常工作中,具有四種工作模式: 運行、睡眠、停止以及待機 模式。 在系統(tǒng)或電源復(fù)位以后,微控制器處于運行狀態(tài),當(dāng)CPU不需繼續(xù)運行時,可以利用多種低功耗模式來節(jié)省功耗。這些低功耗模式電源消耗不同、喚醒時間不同和喚醒源不同。 例如等待某個外部事

    2024年02月13日
    瀏覽(21)
  • STM32--低功耗模式詳解

    STM32--低功耗模式詳解

    正常模式與睡眠模式耗電是mA級,停機模式與待機模式是uA級。 供電區(qū)域有三處,分別是 模擬部分供電(VDDA) ,數(shù)字部分供電,包括 VDD供電區(qū)域和1.8V供電區(qū)域 , 后備供電(VBAT) 。 PDDS 位用來區(qū)分停機還是待機模式。 PDDS = 0,進(jìn)入停機模式,PDDS = 1,進(jìn)入待機模式 ; LPD

    2024年03月26日
    瀏覽(20)
  • STM32 低功耗-待機模式

    STM32 低功耗-待機模式

    在 STM32 的正常工作中,具有四種工作模式: 運行、睡眠、停止和待機模式 。 在系統(tǒng)或電源復(fù)位以后,微控制器處于運行狀態(tài),當(dāng)CPU不需繼續(xù)運行時,可以利用多種低功耗模式來節(jié)省功耗。這些低功耗模式電源消耗不同、喚醒時間不同和喚醒源不同。 例如等待某個外部事件

    2024年02月14日
    瀏覽(17)
  • 【STM32CubeMX】低功耗模式

    【STM32CubeMX】低功耗模式

    ??本文講解STM32F10X的低功耗模式,部分資料參考自STM32手冊。STM32F10X提供了三種低功耗模式:睡眠模式(Sleep mode)、停機模式(Stop mode)和待機模式(Standby mode)。這些低功耗模式可以有效減少系統(tǒng)功耗,延長電池壽命,對于需要長時間運行的電池供電設(shè)備尤為重要。 ST

    2024年02月12日
    瀏覽(21)
  • 理解STM32的低功耗模式

    理解STM32的低功耗模式

    TM32的低功耗模式是特別設(shè)計來減少微控制器在不活躍狀態(tài)下的能耗。這些模式允許STM32在保持核心功能的同時盡可能減少電力消耗,適合用在電池供電或需長期運行的場景。理解各種低功耗模式如何節(jié)能,主要包括以下幾個方面: 關(guān)閉時鐘信號 :在微控制器非活躍階段關(guān)閉

    2024年03月18日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包