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

【STM32】HAL庫ADC測量精度提高方案(利用內(nèi)部參考電壓VREFINT計算VDDA來提高精度)

這篇具有很好參考價值的文章主要介紹了【STM32】HAL庫ADC測量精度提高方案(利用內(nèi)部參考電壓VREFINT計算VDDA來提高精度)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

【STM32】HAL庫ADC測量精度提高方案(利用內(nèi)部參考電壓VREFINT計算VDDA來提高精度)

ADC測量

多數(shù)STM32的MCU 都沒有內(nèi)部基準電壓 如L496系列
但在外接VDDA時(一般與VCC 3.3V連接) 有可能VCC不穩(wěn)定 導(dǎo)致參考電壓不確定 從而使ADC測量不準確

STM32內(nèi)置一個測量VREFINT的ADC通道 且在寄存器VREFINT_CAL中會存儲在3.0V標準電壓的情況下 該VREFINT的ADC測量數(shù)據(jù)結(jié)果(12位精度)

stm32 adc 內(nèi)部基準,STM32筆記(含疑難雜癥),stm32,單片機,嵌入式,mcu,物聯(lián)網(wǎng)
STM32L496的VREFINT_CAL地址如圖 該值為16位數(shù)據(jù)

讀取時:

#define VREFINT_CAL						(uint16_t)(*(__I uint16_t *)(0x1FFF75AA))

我讀出來是1655

該值表示此芯片在30℃ 3.0V的標準電壓下的VREFINT測量結(jié)果

根據(jù)手冊:
stm32 adc 內(nèi)部基準,STM32筆記(含疑難雜癥),stm32,單片機,嵌入式,mcu,物聯(lián)網(wǎng)
由公式3即可校準ADC的測量

比如我對VREFINT的ADC測量出來是1400
我要測的ADC通道是1500
則實際被測ADC通道實測值為:

3.0f*1655*1500/1400/4095

代碼示例:
stm32 adc 內(nèi)部基準,STM32筆記(含疑難雜癥),stm32,單片機,嵌入式,mcu,物聯(lián)網(wǎng)
我用ADC1來測量VREFINT 一定要配置為12位精度 方便計算

stm32 adc 內(nèi)部基準,STM32筆記(含疑難雜癥),stm32,單片機,嵌入式,mcu,物聯(lián)網(wǎng)
另外 ADC2 通道9是我要測的電壓

STM32的ADC最大的轉(zhuǎn)換速率為1MHz,也就是說最快轉(zhuǎn)換時間為1us,為了保證ADC轉(zhuǎn)換結(jié)果的準確性,ADC的時鐘最好不超過14M。

其中 T = 采樣時間 + 12.5個周期,其中1周期為1/ADCCLK

例如,當 ADCCLK=14Mhz 的時候,并設(shè)置 1.5 個周期的采樣時間,則得到: Tcovn=1.5+12.5=14 個周期=1us。

當ADCCLK=50Mhz的時候,設(shè)置37.5個采樣周期 37.5+12.5=50

/*!
 * @brief       	開啟ADC通道,返回ADC值	
 *
 * @param 	[in]	hadc: ADC_HandleTypeDef 變量地址
 *
 * @return				ADC_Value: ADC平均值結(jié)果
 */
uint16_t Get_ADC_Value(ADC_HandleTypeDef *hadc)
{
	uint16_t ADC_Value=0;
	HAL_ADCEx_Calibration_Start(hadc,ADC_SINGLE_ENDED);
	HAL_ADC_Start(hadc);     //啟動ADC轉(zhuǎn)換
	HAL_ADC_PollForConversion(hadc, 5); //等待轉(zhuǎn)換完成,5為最大等待時間,單位為ms
	if(HAL_IS_BIT_SET(HAL_ADC_GetState(hadc), HAL_ADC_STATE_REG_EOC))
	{
		ADC_Value = HAL_ADC_GetValue(hadc);   //獲取AD值
	}
	return ADC_Value;
}

/*!
 * @brief       	計算ADC的真實值,包含VREFINT校準后的結(jié)果
 *
 * @param 	[in]	hadc: ADC_HandleTypeDef 變量地址
 *
 * @return				ADC_Real_Value: ADC校準后的真實值
 */
float Get_Real_ADC_Value(ADC_HandleTypeDef *hadc)
{
	uint16_t VREFINT_DATA = Get_ADC_Value(&hadc1);
	uint16_t ADC_DATA = Get_ADC_Value(hadc);
	float ADC_Real_Value = 3.0f*VREFINT_CAL*ADC_DATA/VREFINT_DATA/4095.0f;
	
	return ADC_Real_Value;
}

兩個通用函數(shù)

float ADC = Get_Real_ADC_Value(&hadc2);

調(diào)用方式

這樣測出來就不用考慮VDDA電壓是否穩(wěn)定了 在一定范圍內(nèi)還是相對來說比較精確的

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

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

延時函數(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ù)值到達0后的標記
	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ù)值到達0后的標記
	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ù)值到達0后的標記
	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ù)值到達0后的標記
	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ù)值到達0后的標記
	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ù)值到達0后的標記
	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ù)值到達0后的標記
	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ù)值到達0后的標記
	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)部定時器來進行非阻塞延時函數(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 將此能力進化,這里的位帶操作是 8051 位尋址區(qū)的威力大幅加強版

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

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

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

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

位操作就是可以單獨的對一個比特位讀和寫,類似與51中sbit定義的變量,stm32中通過訪問位帶別名區(qū)來實現(xiàn)位操作的功能
STM32中有兩個地方實現(xiàn)了位帶,一個是SRAM,一個是片上外設(shè)。
stm32 adc 內(nèi)部基準,STM32筆記(含疑難雜癥),stm32,單片機,嵌入式,mcu,物聯(lián)網(wǎng)
(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)的位里面 寄存器操作時 如果不改變其他位上面的值 那就只能通過&=或者|=的方式進行

stm32 adc 內(nèi)部基準,STM32筆記(含疑難雜癥),stm32,單片機,嵌入式,mcu,物聯(lián)網(wǎng)

要設(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 adc 內(nèi)部基準,STM32筆記(含疑難雜癥),stm32,單片機,嵌入式,mcu,物聯(lián)網(wǎng)

但好在官方庫里面都幫我們定義好了 只需要在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 adc 內(nèi)部基準,STM32筆記(含疑難雜癥),stm32,單片機,嵌入式,mcu,物聯(lián)網(wǎng)
也就是說 要實現(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 adc 內(nèi)部基準,STM32筆記(含疑難雜癥),stm32,單片機,嵌入式,mcu,物聯(lián)網(wǎng)
AHB2的都不能用位帶
ABP 還有AHB1都可以用
stm32 adc 內(nèi)部基準,STM32筆記(含疑難雜癥),stm32,單片機,嵌入式,mcu,物聯(lián)網(wǎng)
但是L476的寄存器里面 GPIO和ADC都是AHB2文章來源地址http://www.zghlxwxcb.cn/news/detail-796052.html

到了這里,關(guān)于【STM32】HAL庫ADC測量精度提高方案(利用內(nèi)部參考電壓VREFINT計算VDDA來提高精度)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

  • stm32——hal庫學(xué)習(xí)筆記(ADC)

    stm32——hal庫學(xué)習(xí)筆記(ADC)

    ADC,全稱:Analog-to-Digital Converter,指模擬/數(shù)字轉(zhuǎn)換器 優(yōu)點:轉(zhuǎn)換速度快 缺點:成本高、功耗高、分辨率低 優(yōu)點:結(jié)構(gòu)簡單、低功耗 缺點:轉(zhuǎn)換速度較慢 特點: 分辨率和采樣速度相互矛盾, 分辨率越高,采樣速率越低 ①參考電壓/模擬部分電壓 ②輸入通道 ③轉(zhuǎn)換序列 ④觸

    2024年02月22日
    瀏覽(20)
  • STM32 HAL庫 ADC+DMA

    STM32 HAL庫 ADC+DMA

    ? ?軟件觸發(fā):STM32 HAL庫 軟件觸發(fā)ADC 多通道連續(xù)轉(zhuǎn)換_隨風(fēng)飄零翼的博客-CSDN博客 配置如圖? ? ??注意采樣周期不要過小,不然頻繁中斷會導(dǎo)致在RTOS中卡死 寫了部分關(guān)鍵代碼,在兩個任務(wù)中OLED和串口打印分別顯示的通道值。 后來發(fā)現(xiàn)使用的杜邦線接觸不良,固定好之后,接

    2024年02月14日
    瀏覽(20)
  • STM32的ADC開發(fā)HAL庫

    STM32的ADC開發(fā)HAL庫

    配置ADC轉(zhuǎn)換通道。 Data Alignment(數(shù)據(jù)對齊)一般默認右對齊 因為只對一個引腳測量ADC因此不用使能掃描模式。 ADC的掃描模式是一種工作模式,用于在單個轉(zhuǎn)換序列中連續(xù)地轉(zhuǎn)換多個輸入通道的模擬信號。 在掃描模式下,ADC會按照預(yù)先配置的順序?qū)Χ鄠€輸入通道上的模擬信號

    2024年01月16日
    瀏覽(21)
  • STM32_HAL庫—ADC采集數(shù)據(jù)

    STM32_HAL庫—ADC采集數(shù)據(jù)

    目錄 一、簡介 二、實例 1. (單通道、阻塞式)配置及實現(xiàn)方式 2. (單通道、中斷式)配置及實現(xiàn)方式 3. (多通道、阻塞式)配置及實現(xiàn)方式 4. (多通道、DMA)配置及實現(xiàn)方式 ???????STM32?的ADC精度為 12 位,且每個 ADC 最多有 16 個外部通道。各通道的A/D轉(zhuǎn)換可以單次、連續(xù)、掃描或

    2024年02月10日
    瀏覽(30)
  • 基于stm32+HAL庫的ADC電壓采集實驗

    基于stm32+HAL庫的ADC電壓采集實驗

    提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔 只會用if的大神提醒您,敵軍還有30秒到達戰(zhàn)場,碾碎他們!白銀局不要怕! 軟件:keil5、stm32cubemx、串口調(diào)試助手 硬件:stm32f103系列的開發(fā)板、杜邦線*1、串口工具 僅此而已?。?!正好6神 1、打開cube

    2023年04月15日
    瀏覽(25)
  • STM32 HAL庫定時器輸入捕獲SlaveMode脈寬測量

    STM32 HAL庫定時器輸入捕獲SlaveMode脈寬測量

    ??SlaveMode模式簡介 ?SlaveMode復(fù)位模式:在發(fā)生一個觸發(fā)輸入事件時,計數(shù)器和它的預(yù)分頻器能夠重新被初始化;同時,如果TIMx_CR1寄存器的URS位為低,還會產(chǎn)生一個更新事件UEV;然后所有的預(yù)裝載寄存器(TIMx_ARR, TIMx_CCRx)都會被更新。 ??當所測頻率低于最小定時器捕獲頻率

    2024年02月16日
    瀏覽(21)
  • STM32CubeMX配置STM32G031多通道ADC采集(HAL庫開發(fā))

    STM32CubeMX配置STM32G031多通道ADC采集(HAL庫開發(fā))

    時鐘配置HSI主頻配置64M ?勾選打開8個通道的ADC ?使能連續(xù)轉(zhuǎn)換模式 ?配置好串口,選擇異步模式 配置好需要的開發(fā)環(huán)境并獲取代碼 ?修改main.c 串口重定向 ?串口重定向一定要勾選Use Micro LIB ?獲取ADC通道值 主函數(shù)? ?串口輸出

    2024年02月15日
    瀏覽(31)
  • STM32+HAL庫使用ADC輪詢模式采集音頻信號

    STM32+HAL庫使用ADC輪詢模式采集音頻信號

    ADC模塊:咪頭聲音采集模塊 缺點:占用CPU的使用率 ????????軟件開始ADC轉(zhuǎn)換后,一直等到轉(zhuǎn)換完成后,才向后執(zhí)行,這個代碼在初始化ADC之后執(zhí)行一次校準(不執(zhí)行這一步也可以,但精度可能會低一些);然后就可以使用ADC輪詢轉(zhuǎn)換了,只需要三步: 啟動轉(zhuǎn)換 、 等待轉(zhuǎn)

    2024年02月15日
    瀏覽(20)
  • STM32(HAL庫)通過ADC讀取MQ2數(shù)據(jù)

    STM32(HAL庫)通過ADC讀取MQ2數(shù)據(jù)

    目錄 1、簡介 2、CubeMX初始化配置 2.1 基礎(chǔ)配置 2.1.1 SYS配置 ?2.1.2 RCC配置 2.2 ADC外設(shè)配置 2.3?串口外設(shè)配置 ?2.4 項目生成 ?3、KEIL端程序整合 3.1 串口重映射 3.2 ADC數(shù)據(jù)采集 3.3 主函數(shù)代 3.4 效果展示 本文通過STM32F103C8T6單片機通過HAL庫方式對MQ2煙霧傳感器進行數(shù)據(jù)的讀取,并通過

    2024年02月16日
    瀏覽(21)
  • Stm32_標準庫_8_ADC_光敏傳感器_測量具體光照強度

    Stm32_標準庫_8_ADC_光敏傳感器_測量具體光照強度

    ADC簡介 測量方式 采用二分法比較數(shù)據(jù) IO通道 ADC基本結(jié)構(gòu)及配置路線 獲取數(shù)字變量需要用到用到光敏電阻的AO口,AO端口接在PA0引腳即可 測得的模擬數(shù)據(jù)與實際光照強度之間的關(guān)系為 代碼: 完整樸素代碼: 效果: 此代碼的不足之處在于每次寫入數(shù)字都會提前占據(jù)固定位置,

    2024年02月04日
    瀏覽(24)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包