STM32位帶操作

位帶操作:
將一個位重新定義一個字的位帶別名來操作
位帶區一個位對應位帶別名區的四個字節
在這裏插入圖片描述
在這裏插入圖片描述
針對stm32f10的代碼實現:

頭文件:

#ifndef __SYS_H_
#define __SYS_H_	 
#include <stm32f10x_lib.h>
//IO口操作宏定義
#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)) 
//IO口地址映射
#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    

#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 
 
//IO口操作,只對單一的IO口!
//確保n的值小於16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //輸出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,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)  //輸入
/////////////////////////////////////////////////////////////////
//Ex_NVIC_Config專用定義
#define GPIO_A 0
#define GPIO_B 1
#define GPIO_C 2
#define GPIO_D 3
#define GPIO_E 4
#define GPIO_F 5
#define GPIO_G 6 
#define FTIR   1  //下降沿觸發
#define RTIR   2  //上升沿觸發
/////////////////////////////////////////////////////////////////
//JTAG模式設置定義
#define JTAG_SWD_DISABLE   0X02
#define SWD_ENABLE         0X01
#define JTAG_SWD_ENABLE    0X00	
/////////////////////////////////////////////////////////////////  
#define u32 unsigned int
#define u8 unsigned char

//void BKP_Write(u8 reg,u16 dat);	//寫入後備寄存器
void Stm32_Clock_Init(u8 PLL);  //時鐘初始化  
void Sys_Soft_Reset(void);      //系統軟復位
void Sys_Standby(void);         //待機模式 	
void MY_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset);//設置偏移地址
void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group);//設置NVIC分組
void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group);//設置中斷
void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM);//外部中斷配置函數(只對GPIOA~G)
void JTAG_Set(u8 mode);
void SystemInit(void);//定義復位中斷函數-空
void MYRCC_DeInit(void);
void Hex_Tran_Char_8bit(u8* hex_str,u8* char_str,u8 tran_num);
void Hex_Tran_Char_16bit(u16* hex_str,u8* char_str,u8 tran_num);
#endif

C文件:

#include "sys.h"
//////////////////////////////////////////////////////////////////////////////////	 
//V1.4修改說明
//把NVIC KO了,沒有使用任何庫文件!
//加入了JTAG_Set函數
////////////////////////////////////////////////////////////////////////////////// 	  

//函數說明:十六進制轉字符串函數	(8bit)
//參數:hex_str:要轉換的十六進制數組
//      char_str:轉換後存放的字符數組
//      tran_num:轉換的個數
//返回值:無
void Hex_Tran_Char_8bit(u8* hex_str,u8* char_str,u8 tran_num)
{
   	u8 i,model[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
	for(i=0;i<tran_num;i++)
	{
	   	char_str[2*i]=model[(hex_str[i]>>4)&0x0F];
		char_str[2*i+1]=model[hex_str[i]&0x0F];
	}
	char_str[2*i]=0;//字符串結束符

}


//函數說明:十六進制轉字符串函數(16bit)
//參數:hex_str:要轉換的十六進制數組
//      char_str:轉換後存放的字符數組
//      tran_num:轉換的個數
//返回值:無
void Hex_Tran_Char_16bit(u16* hex_str,u8* char_str,u8 tran_num)
{
   	u8 i,model[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
	for(i=0;i<tran_num;i++)
	{
	   	char_str[4*i]=model[(hex_str[i]>>12)&0x0F];
		char_str[4*i+1]=model[(hex_str[i]>>8)&0x0F];
		char_str[4*i+2]=model[(hex_str[i]>>4)&0x0F];
		char_str[4*i+3]=model[hex_str[i]&0x0F];

	}
	char_str[4*i]=0;//字符串結束符

}

//函數說明:設置向量表偏移地址
//參數:NVIC_VectTab - 基址
//      Offset - 偏移量
//返回值:無
void MY_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset)	 
{ 
  	//檢查參數合法性
	assert_param(IS_NVIC_VECTTAB(NVIC_VectTab));
	assert_param(IS_NVIC_OFFSET(Offset));  	 
	SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80);//設置NVIC的向量表偏移寄存器
	//用於標識向量表是在CODE區還是在RAM區
}

//函數說明:設置NVIC分組
//參數:NVIC_Group - NVIC分組 0~4 總共5組 
//返回值:無
void MY_NVIC_PriorityGroupConfig(u8 NVIC_Group)	 
{ 
	u32 temp,temp1;	  
	temp1=(~NVIC_Group)&0x07;//取後三位
	temp1<<=8;
	temp=SCB->AIRCR;  //讀取先前的設置
	temp&=0X0000F8FF; //清空先前分組
	temp|=0X05FA0000; //寫入鑰匙
	temp|=temp1;	   
	SCB->AIRCR=temp;  //設置分組	    	  				   
}

//函數說明:設置NVIC 
//參數:NVIC_PreemptionPriority - 搶佔優先級
//      NVIC_SubPriority        - 響應優先級
//		NVIC_Channel            - 中斷編號
//		NVIC_Group              - 中斷分組 0~4
// 		注意優先級不能超過設定的組的範圍!否則會死機
//		組劃分:
//		組0:0位搶佔優先級,4位響應優先級
//		組1:1位搶佔優先級,3位響應優先級
//		組2:2位搶佔優先級,2位響應優先級
//		組3:3位搶佔優先級,1位響應優先級
//		組4:4位搶佔優先級,0位響應優先級
//		NVIC_SubPriority和NVIC_PreemptionPriority的原則是,數值越小,越優先
//返回值:無
void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)	 
{ 
	u32 temp;	
	u8 IPRADDR=NVIC_Channel/4;  //每組只能存4個,得到組地址 
	u8 IPROFFSET=NVIC_Channel%4;//在組內的偏移
	IPROFFSET=IPROFFSET*8+4;    //得到偏移的確切位置
	MY_NVIC_PriorityGroupConfig(NVIC_Group);//設置分組
	temp=NVIC_PreemptionPriority<<(4-NVIC_Group);	  
	temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
	temp&=0xf;//取低四位

	if(NVIC_Channel<32)NVIC->ISER[0]|=1<<NVIC_Channel;//使能中斷位(要清除的話,相反操作就OK)
	else NVIC->ISER[1]|=1<<(NVIC_Channel-32);    
	NVIC->IPR[IPRADDR]|=temp<<IPROFFSET;//設置響應優先級和搶斷優先級   	    	  				   
}

//函數說明:外部中斷配置函數
//          只針對GPIOA~G;不包括PVD,RTC和USB喚醒這三個
//參數:GPIOx:0~6,代表GPIOA~G;
//     BITx:需要使能的位;
//     TRIM:觸發模式,1,下降沿;2,上升沿;3,任意電平觸發
//     該函數一次只能配置1個IO口,多個IO口,需多次調用
//     該函數會自動開啓對應中斷,以及屏蔽線   
//返回值:無
void Ex_NVIC_Config(u8 GPIOx,u8 BITx,u8 TRIM) 
{
	u8 EXTADDR;
	u8 EXTOFFSET;
	EXTADDR=BITx/4;//得到中斷寄存器組的編號
	EXTOFFSET=(BITx%4)*4;

	RCC->APB2ENR|=0x01;//使能io複用時鐘

	AFIO->EXTICR[EXTADDR]&=~(0x000F<<EXTOFFSET);//清除原來設置!!!
	AFIO->EXTICR[EXTADDR]|=GPIOx<<EXTOFFSET;//EXTI.BITx映射到GPIOx.BITx
	
	//自動設置
	EXTI->IMR|=1<<BITx;//  開啓line BITx上的中斷
	//EXTI->EMR|=1<<BITx;//不屏蔽line BITx上的事件 (如果不屏蔽這句,在硬件上是可以的,但是在軟件仿真的時候無法進入中斷!)
 	if(TRIM&0x01)EXTI->FTSR|=1<<BITx;//line BITx上事件下降沿觸發
	if(TRIM&0x02)EXTI->RTSR|=1<<BITx;//line BITx上事件上升降沿觸發
} 


//函數說明:開機所有時鐘寄存器復位		    
//參數:無
//返回值:無
void MYRCC_DeInit(void)
{										  					   
	RCC->APB1RSTR = 0x00000000;//復位結束			 
	RCC->APB2RSTR = 0x00000000; 
	  
  	RCC->AHBENR = 0x00000014;  //睡眠模式閃存和SRAM時鐘使能.其他關閉.	  
  	RCC->APB2ENR = 0x00000000; //外設時鐘關閉.			   
  	RCC->APB1ENR = 0x00000000;   
	RCC->CR |= 0x00000001;     //使能內部高速時鐘HSION	 															 
	RCC->CFGR &= 0xF8FF0000;   //復位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]					 
	RCC->CR &= 0xFEF6FFFF;     //復位HSEON,CSSON,PLLON
	RCC->CR &= 0xFFFBFFFF;     //復位HSEBYP	   	  
	RCC->CFGR &= 0xFF80FFFF;   //復位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE 
	RCC->CIR = 0x00000000;     //關閉所有中斷
	//配置向量表				  
#ifdef  VECT_TAB_RAM
	MY_NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else   
	MY_NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
}

//函數說明:THUMB指令不支持彙編內聯,實現執行彙編指令WFI
//參數:無
//返回值:無
__asm void WFI_SET(void)
{
	WFI;    
}
//函數說明:進入待機模式	 
//參數:無 
//返回值:無
void Sys_Standby(void)
{
	SCB->SCR|=1<<2;//使能SLEEPDEEP位 (SYS->CTRL)	   
  	RCC->APB1ENR|=1<<28;     //使能電源時鐘	    
 	PWR->CSR|=1<<8;          //設置WKUP用於喚醒
	PWR->CR|=1<<2;           //清除Wake-up 標誌
	PWR->CR|=1<<1;           //PDDS置位		  
	WFI_SET();				 //執行WFI指令		 
}
	  
//後備寄存器寫入操作
//reg:寄存器編號
//reg:要寫入的數值 
////check ok
////091202
//void BKP_Write(u8 reg,u16 dat)
//{
//  RCC->APB1ENR|=1<<28;     //使能電源時鐘	    
//	RCC->APB1ENR|=1<<27;     //使能備份時鐘	    
//	PWR->CR|=1<<8;           //取消備份區寫保護 
//	switch(reg)
//	{
//		case 1:
//			BKP->DR1=dat;
//			break;
//		case 2:
//			BKP->DR2=dat;
//			break;
//		case 3:
//			BKP->DR3=dat;
//			break; 
//		case 4:
//			BKP->DR4=dat;
//			break;
//		case 5:
//			BKP->DR5=dat;
//			break;
//		case 6:
//			BKP->DR6=dat;
//			break;
//		case 7:
//			BKP->DR7=dat;
//			break;
//		case 8:
//			BKP->DR8=dat;
//			break;
//		case 9:
//			BKP->DR9=dat;
//			break;
//		case 10:
//			BKP->DR10=dat;
//			break;
//	} 
//}	  
  
//函數說明:系統軟復位
//參數:無
//返回值:無
void Sys_Soft_Reset(void)
{   
	SCB->AIRCR =0X05FA0000|(u32)0x04;	  
} 

//函數說明:JTAG模式設置,用於設置JTAG的模式
//參數:mode - jtag,swd模式設置;00,全使能;01,使能SWD;10,全關閉;
//返回值:無		  
void JTAG_Set(u8 mode)
{
	u32 temp;
	temp=mode;
	temp<<=25;
	RCC->APB2ENR|=1<<0;     //開啓輔助時鐘	   
	AFIO->MAPR&=0XF8FFFFFF; //清除MAPR的[26:24]
	AFIO->MAPR|=temp;       //設置jtag模式
} 

//函數說明:系統時鐘初始化函數
//參數: pll - 選擇的倍頻數,從2開始,最大值爲16	
//返回值:無
void Stm32_Clock_Init(u8 PLL)
{
	unsigned char temp=0;   
	MYRCC_DeInit();		  //復位並配置向量表
	RCC->CR|=0x00010000;  //外部高速時鐘使能HSEON。 默認使用內部晶振,關閉外部晶振。
	while(!(RCC->CR>>17));//等待外部時鐘就緒
	RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
	PLL-=2;//抵消2個單位
	RCC->CFGR|=PLL<<18;   //設置PLL值 2~16
	RCC->CFGR|=1<<16;	  //PLLSRC ON 
	FLASH->ACR|=0x32;	  //FLASH 2個延時週期

	RCC->CR|=0x01000000;  //PLLON
	while(!(RCC->CR>>25));//等待PLL鎖定
	RCC->CFGR|=0x00000002;//PLL作爲系統時鐘	 
	while(temp!=0x02)     //等待PLL作爲系統時鐘設置成功
	{   
		temp=RCC->CFGR>>2;
		temp&=0x03;
	}    
}		    


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章