位帶操作:
將一個位重新定義一個字的位帶別名來操作
位帶區一個位對應位帶別名區的四個字節
針對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;
}
}