第一點哈,支持位帶操做數組
//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 GPIO0_PIN_Addr (LPC_GPIO0_BASE+20) #define GPIO1_PIN_Addr (LPC_GPIO1_BASE+20)#define GPIO2_PIN_Addr (LPC_GPIO2_BASE+20)#define GPIO3_PIN_Addr (LPC_GPIO3_BASE+20)#define GPIO4_PIN_Addr (LPC_GPIO4_BASE+20)#define GPIO5_PIN_Addr (LPC_GPIO5_BASE+20) #define P0out(n) BIT_ADDR(GPIO0_PIN_Addr,n) //輸出#define P0in(n) BIT_ADDR(GPIO0_PIN_Addr,n) //輸入#define P1out(n) BIT_ADDR(GPIO1_PIN_Addr,n) //輸出#define P1in(n) BIT_ADDR(GPIO1_PIN_Addr,n) //輸入#define P2out(n) BIT_ADDR(GPIO2_PIN_Addr,n) //輸出#define P2in(n) BIT_ADDR(GPIO2_PIN_Addr,n) //輸入#define P3out(n) BIT_ADDR(GPIO3_PIN_Addr,n) //輸出#define P3in(n) BIT_ADDR(GPIO3_PIN_Addr,n) //輸入#define P4out(n) BIT_ADDR(GPIO4_PIN_Addr,n) //輸出#define P4in(n) BIT_ADDR(GPIO4_PIN_Addr,n) //輸入#define P5out(n) BIT_ADDR(GPIO5_PIN_Addr,n) //輸出#define P5in(n) BIT_ADDR(GPIO5_PIN_Addr,n) //輸入
好處就不言而喻了,,簡直太方便了和實用了ide
第二點函數
void GPIO_Conf_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint32_t mode);//配置指定引腳的模式void GPIO_Conf_Bits(uint8_t GPIOx, uint32_t StartPinx,uint32_t PinNum,uint32_t mode);//配置多個連續引腳的模式void GPIO_Init_Bit(GPIO_InitTypeDef * GPIO_InitStruct);//初始化一個引腳的模式--內部調用,用戶不使用void GPIO_Init_Bits(GPIO_InitTypeDef *GPIO_InitStruc,uint32_t PinNum);//初始化多個連續引腳的配置--內部調用,用戶不使用void GPIO_Dir_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t Dir);//設置指定引腳的輸入輸出方向void GPIO_Dir_Bits(uint8_t GPIOx, uint32_t StartPinx,uint32_t PinNum,uint8_t Dir);//設置多個連續引腳的輸入輸出方向void GPIO_Write_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t BitVal);//設置指定引腳輸出高低電平void GPIO_Write_Bits(uint8_t GPIOx,uint32_t BitVal);//將數據寫入指定的GPIO數據端口uint8_t GPIO_Read_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx);//讀取指定引腳的電平狀態uint32_t GPIO_Read_Bits(uint8_t GPIOx);//讀取指定的GPIO端口的電平狀態void GPIO_Mask_Bit(uint8_t GPIOx,uint32_t GPIO_Pinx,uint8_t Mask);//屏蔽或清除屏蔽引腳void GPIO_Mask_Bits(uint8_t GPIOx, uint32_t StartPinx,uint32_t PinNum,uint8_t Mask);//屏蔽或清除屏蔽多個連續引腳
其實有了位帶操做本身感受應該去掉上面的設置一個引腳的電平,,,不過呢!位帶操做我是訪問的PIN寄存器,而函數裏面用的是SET和CLRui
先說第一個函數的實現過程spa
先看內部操作系統
/** * @brief 配置指定引腳的模式 * @param GPIOx:設置的端口0-5 * @param GPIO_Pinx:設置的引腳0-32 * @param mode:引腳的模式 GPIO_Mode_IFT //無上下拉 GPIO_Mode_IPD //內部下拉 GPIO_Mode_IPU //內部上拉 GPIO_Mode_TRA //轉發模式 GPIO_Mode_HYS //遲滯模式 GPIO_Mode_INV //輸入反向 GPIO_Mode_SWI //轉換速率 GPIO_Mode_OOD //開漏輸出 * @retval None * @example GPIO_Conf_Bit(GPIO0,1,GPIO_Mode_IPD);//P0_1下拉 */void GPIO_Conf_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint32_t mode) { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIOx = GPIOx; GPIO_InitStruct.mode = mode; GPIO_InitStruct.Pinx = GPIO_Pinx; GPIO_Init_Bit(&GPIO_InitStruct); }
我定義了一個結構體指針
/* 端口初始化結構體 */typedef struct{ uint8_t GPIOx; //引腳端口號 uint32_t mode; //工做模式 uint32_t Pinx; //引腳號0~31}GPIO_InitTypeDef;
/** * @brief 初始化一個引腳的配置--用戶不使用 * @param *GPIO_InitStruc:端口初始化結構體指針 * @param * @param * @retval None * @example GPIO_Init_Bit(&GPIO_InitStruc); */void GPIO_Init_Bit(GPIO_InitTypeDef *GPIO_InitStruc) { switch(GPIO_InitStruc->GPIOx) { case 0:GPIO_Type->GPIO0_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break; case 1:GPIO_Type->GPIO1_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break; case 2:GPIO_Type->GPIO2_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break; case 3:GPIO_Type->GPIO3_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break; case 4:GPIO_Type->GPIO4_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break; case 5:GPIO_Type->GPIO5_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break; default:break; } }
而後呢code
/* 引腳初始化結構體 */typedef struct{ __IO uint32_t GPIO0_Table[32]; __IO uint32_t GPIO1_Table[32]; __IO uint32_t GPIO2_Table[32]; __IO uint32_t GPIO3_Table[32]; __IO uint32_t GPIO4_Table[32]; __IO uint32_t GPIO5_Table[4]; }GPIO_Type_Config;
LPC_ICON_BASE這個地址到LPC_ICON_BASE+32+32+32+32+32+4這個地址分別對應P0,P1,P2,P3,P4,P5的各個引腳的配置寄存器orm
那麼blog
GPIO_Type->GPIO0_Table[0] 就是配置P0_0引腳
GPIO_Type->GPIO1_Table[1] 就是配置P1_1引腳
GPIO_Type->GPIO2_Table[2] 就是配置P2_2引腳
其實寫成數組也是爲了便於區分是哪一個端口
由於我傳入的是
端口號 還有 引腳號後面的 模式(mode) 一開始用的枚舉,後來一想爲了能一會兒寫入多種配置,因此就宏定義的,這樣的話模式或運算寫入就好啦
/*宏定義引腳的全部配置*/#define GPIO_Mode_IFT (0x0000) /* 無上下拉 */#define GPIO_Mode_IPD (0x0008) /* 內部下拉 */#define GPIO_Mode_IPU (0x0010) /* 內部上拉 */#define GPIO_Mode_TRA (0x0018) /* 轉發模式*/#define GPIO_Mode_HYS (0x0020) /* 遲滯模式*/#define GPIO_Mode_INV (0x0040) /* 輸入反向*/#define GPIO_Mode_SWI (0x0200) /* 轉換速率*/#define GPIO_Mode_OOD (0x0400) /* 開漏輸出 */
看最後一個函數
/** * @brief 設置指定引腳輸出高低電平 * @param GPIOx:設置的端口0-5 * @param GPIO_Pinx:設置的引腳0-32 * @param BitVal:0-輸入低電平,1-輸出高電平 * @retval None * @example GPIO_Write_Bit(GPIO0,1,1);//P0_1輸出高電平 */void GPIO_Write_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t BitVal) { if(BitVal) { PORT_Table[GPIOx]->SET |= (1<<GPIO_Pinx); } else { PORT_Table[GPIOx]->CLR |= (1<<GPIO_Pinx); } }
#define GPIO_BASES {LPC_GPIO0,LPC_GPIO1,LPC_GPIO2,LPC_GPIO3,LPC_GPIO4,LPC_GPIO5}//存儲地址static LPC_GPIO_TypeDef * const PORT_Table[] = GPIO_BASES;
這個呢我是利用的他自帶的結構體實現的
LPC_GPIO_TypeDef
/*------------- General Purpose Input/Output (GPIO) --------------------------*//** @brief General Purpose Input/Output (GPIO) register structure definition */typedef struct{ __IO uint32_t DIR; uint32_t RESERVED0[3]; __IO uint32_t MASK; __IO uint32_t PIN; __IO uint32_t SET; __O uint32_t CLR; } LPC_GPIO_TypeDef;
原先的程序
#define LPC_GPIO0 ((LPC_GPIO_TypeDef *) LPC_GPIO0_BASE )#define LPC_GPIO1 ((LPC_GPIO_TypeDef *) LPC_GPIO1_BASE )#define LPC_GPIO2 ((LPC_GPIO_TypeDef *) LPC_GPIO2_BASE )#define LPC_GPIO3 ((LPC_GPIO_TypeDef *) LPC_GPIO3_BASE )#define LPC_GPIO4 ((LPC_GPIO_TypeDef *) LPC_GPIO4_BASE )#define LPC_GPIO5 ((LPC_GPIO_TypeDef *) LPC_GPIO5_BASE )
這樣的話
若是把P0_12置一隻須要
LPC_GPIO0->SET |= 1<<12;
我爲了讓前面這個LPC_GPIO0是個可變的,,,由於方便控制嘛
因此纔有了
#define GPIO_BASES {LPC_GPIO0,LPC_GPIO1,LPC_GPIO2,LPC_GPIO3,LPC_GPIO4,LPC_GPIO5}//存儲地址static LPC_GPIO_TypeDef * const PORT_Table[] = GPIO_BASES;
這樣的話PORT_Table[0]正好是 LPC_GPIO0 ,
PORT_Table[1]正好是 LPC_GPIO1
這個函數就誕生了....
void GPIO_Write_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t BitVal) { if(BitVal) { PORT_Table[GPIOx]->SET |= (1<<GPIO_Pinx); } else { PORT_Table[GPIOx]->CLR |= (1<<GPIO_Pinx); } }
還有一個地方,我爲了能夠直接設置某些引腳的高低電平狀態呢,,,,因爲SET和CLR實現起來須要作判斷,耽誤時間,我看了下直接PIN就能夠,因此就直接用的PIN
/** * @brief 將數據寫入指定的GPIO數據端口 * @param GPIOx:設置的端口0-5 * @param BitVal:指定端口的值寫入輸出數據寄存器 * @param * @param * @retval None * @example GPIO_Write_Bits(GPIO0,0xffffffff);//P0_0--P0_31輸出高電平 */void GPIO_Write_Bits(uint8_t GPIOx,uint32_t BitVal) { PORT_Table[GPIOx]->PIN = BitVal; }
讀取呢
/** * @brief 讀取指定引腳的電平狀態--若是不先設置引腳方向,讀出來一直是1 * @param GPIOx:初始化的端口0-5 * @param GPIO_Pinx:讀取的引腳0-32 * @param * @retval 1-狀態高,0-狀態低 * @example Value = GPIO_Read_Bit(GPIO0,1,1);//讀取P0_1的電平狀態 */uint8_t GPIO_Read_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx) { return ((PORT_Table[GPIOx]->PIN >>GPIO_Pinx)&0x01); }
/** * @brief 讀取整個端口的電平狀態--若是不先設置引腳方向,讀出來一直是1 * @param GPIOx:初始化的端口0-5 * @param * @param * @retval bit=1--狀態高,bit=0--狀態低 * @example Value = GPIO_Read_Bits(GPIO0);//讀取GPIO0的電平狀態 */uint32_t GPIO_Read_Bits(uint8_t GPIOx) { return (PORT_Table[GPIOx]->PIN); }
其他的就沒有什麼說的了....惋惜....我可能之後再也用不到了
工程呢爲了方便,把Keil和IAR建到了一塊,文件的.c和.h共用,,也是爲了方便實用
對於程序的風格仍是走的當年學操做系統時的代碼風格,沒說的,程序大了提升方便性