這段時間加班加的厲害,今天很努力的睡覺。。。
復習這些之后,感覺怪怪的,不學吧,又覺得自己沒有系統的去學,學吧,又覺得重復著學舊知識有些浪費時間,蠻矛盾的心理。
抱著“學而時習之,不亦說乎”的心態繼續觀看視頻和實驗,竟然有新的發現,哈哈,正所謂 “溫故而知新,可以為師矣”,古人誠不欺我也。
最后花了一些時間研究宏的 ## 連接符。 有收獲。。。
---------------------------------------------------------------------------------
軟件:MDK V5.12 固件庫 3.5
1、新建文件夾名為 MyProject
2、在該文件夾內分別新建 USER、CORE、OBJ、STM3210x_FWLib
3、CORE 存放核心文件和啟動文件(不同容量需要不同的啟動文件)
將 STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\CoreSupport
中 core_cm3.h 、core_cm3.c 文件拷貝到此目錄
將 startup_stm32f10x_hd.s(大容量啟動文件) 文件拷貝到此目錄
4、OBJ 存放編譯過程文件以及 hex 文件
5、STM32F10x_FWLib 存放 STM32 庫函數文件
將 STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver
中 inc、src 文件夾拷貝到此目錄
6、USER 用來存放工程文件、主函數文件 main.c、以及其他包括 system_stm32f10x.c 等
將 STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x
中 stm32f10x.h、system_stm32f10x.h、system_stm32f10x.c 拷貝到此目錄
將 STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template
中 stm32f10x_it.h、stm32f10x_it.c、stm32f10x_conf.h 拷貝到此目錄
在此目錄中新建 main.c 文件
7、啟動 MDK -> Project -> 選中 MyProject\USER 文件夾 -> 工程名為 MyProject
8、彈出 Select Device for Target 'Target 1' 對話框,選擇 STMicroelectronics
-> STM32F1 Series -> STM32F103 -> STM32F103ZE -> OK
9、右擊 Target 1 -> Mange Project Items -> Project Targets -> Target 1 修改為 MyProject
-> Groups 里新建 USER、CORE、OBJ、STM3210x_FWLib 分組。
10、為每個分組添加相對應目錄里面的.c文件,注意 CORE 需要將 startup_stm32f10x_hd.s 加入。
11、點擊魔術棒工具,Output -> Select Folder for Objects -> 選擇為 OBJ 目錄,勾選 Create HEX File
12、魔術棒工具 -> C/C++ -> Preprocessor Symbols -> Define 寫入 STM32F10X_HD,USE_STDPERIPH_DRIVER
因為 3.5 版本的庫函數在配置和選擇外設的時候是通過宏定義來選擇的,我們需要配置一個全局的宏定義
變量。
13、魔術棒工具 -> C/C++ -> Include Paths 加入頭文件的目錄
MDK,只會從這里定義的目錄去找頭文件,注意,它只會搜索一級目錄。
--------------------------------------------------------------------------------------------------------
基本的IO口操作;
一、初始化函數:
void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct);
功能:
設置IO口為輸入或輸出模式、翻轉速度
參數:
GPIOx:IO組 GPIOA ~ GPIOG
GPIO_InitStruct:
.GPIO_Pin:IO引腳、
.GPIO_Speed:翻轉速度 GPIO_Speed_10MHz、GPIO_Speed_2MHz、GPIO_Speed_50MHz
.GPIO_Mode:模擬輸入、浮空輸入、上下拉輸入、推挽輸出、開漏輸出、復用推挽、復用開漏
返回值:
無
二、讀取函數
1、讀取輸入電平函數(IO口被設置為輸入模式)
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
功能:
當IO口被設置為輸入模式時,讀取指定組指定IO電平狀態 讀取 IDR 寄存器
參數:
GPIOx:GPIO組 GPIOA ~ GPIOG
GPIO_Pin:IO組中某個引腳 GPIO_Pin_0 ~ GPIO_Pin_15
返回值:
0:為低電平
1:為高電平
uint16_t GPIO_ReadInputData(GPIO_TypeDef *GPIOx);
功能:
當IO口被設置為輸入模式時,讀取指定GPIO組的整組IO電平狀態 讀取 IDR 寄存器
參數:
GPIOx:GPIO組 GPIOA ~ GPIOG
GPIO_Pin:IO組中某個引腳 GPIO_Pin_0 ~ GPIO_Pin_15
返回值:
整組IO口的所有狀態集合為一個 16 位的整數,該整數每一位對應一個IO口的狀態
2、讀取輸出電平函數(IO口被設置為輸出模式)
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
功能:
當IO口被設置為輸出模式時,讀取指定GPIO組指定IO電平狀態 讀取 ODR 寄存器
參數:
GPIOx:GPIO組 GPIOA ~ GPIOG
GPIO_Pin:GPIO組中某個引腳 GPIO_Pin_0 ~ GPIO_Pin_15
返回值:
0:為低電平
1:為高電平
uint16_t GPIO_ReadOutputData(GPIO_TypeDef *GPIOx);
功能:
當IO口被設置為輸出模式時,讀取指定GPIO組指定IO電平狀態 讀取 ODR 寄存器
參數:
GPIOx:GPIO組 GPIOA ~ GPIOG
GPIO_Pin:GPIO組中某個引腳 GPIO_Pin_0 ~ GPIO_Pin_15
返回值:
整組IO口的所有狀態集合為一個 16 位的整數,該整數每一位對應一個IO口的狀態
三、設置函數
1、設指定IO口輸出高電平還是低電平
void GPIO_SetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
功能:
設置指定GPIO組指定IO口為高電平 操作 BSRR 寄存器
參數:
GPIOx:GPIO組 GPIOA ~ GPIOG
GPIO_Pin:GPIO組中某個引腳 GPIO_Pin_0 ~ GPIO_Pin_15
返回值:
無
void GPIO_ResetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
功能:
設置指定GPIO組指定IO口為低電平 操作 BRR 寄存器
參數:
GPIOx:GPIO組 GPIOA ~ GPIOG
GPIO_Pin:IO組中某個引腳 GPIO_Pin_0 ~ GPIO_Pin_15
返回值:
無
2、整體操作
void GPIO_WriteBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
功能:
GPIO_SetBits()、GPIO_ResetBits() 的結合體,根據 BitVal 操作 BSRR 或 BRR 寄存器
參數:
GPIOx:GPIO組 GPIOA ~ GPIOG
GPIO_Pin:GPIO組中某個引腳 GPIO_Pin_0 ~ GPIO_Pin_15
BitVal:Bit_RESET 設置為低電平 Bit_SET 設置為高電平
返回值:
無
void GPIO_Write(GPIO_TypeDef *GPIOx, uint16_t PortVal);
功能:
設置指定GPIO組整組IO電平狀態 操作 ODR 寄存器,在設置輸出模式時 ODR 寄存器決定輸入上拉還是下拉
參數:
GPIOx:GPIO組 GPIOA ~ GPIOG
PortVal:16 位整數,每一位對應一個IO口的狀態
返回值:
無
四、GPIO 時鐘
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
功能:
設置掛載在APB2總線上的設備時鐘,GPIOA ~ GPIOG 就是掛載到 APB2 中
參數:
RCC_APB2Periph:選擇外設
NewState:ENABLE 使能、DISABLE 關閉
返回值:
無
五、遇到的問題
1、在編寫流水燈的時候,我是先初始化GPIO,再開啟IO時鐘。發現無法點亮LED燈。
注意,必須先開啟時鐘,再初始化IO
2、想利用宏連接 ## 符號來提高代碼可移植性, 這里花的時間比較長。
有如下宏定義:
#define LED1_GPIO GPIOB
#define __ToRCC(GPIO) RCC_APB2Periph_##GPIO
#define ToRCC(GPIO) __ToRCC(GPIO)
使用方式:
ToRCC(LED1_GPIO)
原以為會擴展為:RCC_APB2Periph_GPIOB 但實際上是 RCC_APB2Periph_
只知道是因為 GPIOB 自身也是一個宏導致這種現象,至于為什么過程中會丟失就不清楚了。
目前的解決方式是再套一個宏,感覺這種方式比較麻煩,不知道還有沒有更好的方法。
#define LED1_GPIO B
#define __GPIOToRCC(GPIO) RCC_APB2Periph_GPIO##GPIO
#define GPIOToRCC(GPIO) __GPIOToRCC(GPIO)
使用方式:
GPIOToRCC(LED1_GPIO) 此時可以正確擴展為 RCC_APB2Periph_GPIOB
六、源文件
---------------------------------------------------------------------------
public.h
---------------------------------------------------------------------------
#include "stm32f10x.h"
// 比較有意思的宏定義 ------------------------------------------------------------
#define __TORCC(group) RCC_APB2Periph_GPIO##group
#define TORCC(group) __TORCC(group)
#define __TOGPIO(group) GPIO##group
#define TOGPIO(group) __TOGPIO(group)
#define __TOPIN(pin) GPIO_Pin_##pin
#define TOPIN(pin) __TOPIN(pin)
// 比較有意思的宏定義 ------------------------------------------------------------
---------------------------------------------------------------------------
led.h
---------------------------------------------------------------------------
#ifndef __LED_H
#define __LED_H
enum en_LED_NUMBER
{
LED_NUMBER_1,
LED_NUMBER_2,
LED_NUMBER_3
};
void LED_Init(void);
char LED_On(enum en_LED_NUMBER number);
char LED_Off(enum en_LED_NUMBER number);
char LED_On_Mutex(enum en_LED_NUMBER number);
char LED_Off_Mutex(enum en_LED_NUMBER number);
void LED_On_ALL(void);
void LED_Off_ALL(void);
#endif
---------------------------------------------------------------------------
led.h
---------------------------------------------------------------------------
#include "public.h"
#include "led.h"
// 移植部分 ------------------------------------------------------------
#define LED1_GPIO B
#define LED1_GPIO_Pin 0
#define LED2_GPIO F
#define LED2_GPIO_Pin 7
#define LED3_GPIO F
#define LED3_GPIO_Pin 8
#define LEDON(GPIOx, GPIO_Pin) GPIO_ResetBits(GPIOx, GPIO_Pin)
#define LEDOFF(GPIOx, GPIO_Pin) GPIO_SetBits(GPIOx, GPIO_Pin)
// 移植部分 ------------------------------------------------------------
/* 點亮指定 LED 燈 */
char LED_On(enum en_LED_NUMBER number)
{
switch((int)number)
{
case LED_NUMBER_1:
LEDON(TOGPIO(LED1_GPIO), TOPIN(LED1_GPIO_Pin));
break;
case LED_NUMBER_2:
LEDON(TOGPIO(LED2_GPIO), TOPIN(LED2_GPIO_Pin));
break;
case LED_NUMBER_3:
LEDON(TOGPIO(LED3_GPIO), TOPIN(LED3_GPIO_Pin));
break;
default:
return 1;
}
return 0;
}
/* 熄滅指定 LED 燈 */
char LED_Off(enum en_LED_NUMBER number)
{
switch((int)number)
{
case LED_NUMBER_1:
LEDOFF(TOGPIO(LED1_GPIO), TOPIN(LED1_GPIO_Pin));
break;
case LED_NUMBER_2:
LEDOFF(TOGPIO(LED2_GPIO), TOPIN(LED2_GPIO_Pin));
break;
case LED_NUMBER_3:
LEDOFF(TOGPIO(LED3_GPIO), TOPIN(LED3_GPIO_Pin));
break;
default:
return 1;
}
return 0;
}
/* 只允許其中一個 LED 亮 ,其余皆滅 */
char LED_On_Mutex(enum en_LED_NUMBER number)
{
switch((int)number)
{
case LED_NUMBER_1:
LED_On(LED_NUMBER_1);
LED_Off(LED_NUMBER_2);
LED_Off(LED_NUMBER_3);
break;
case LED_NUMBER_2:
LED_Off(LED_NUMBER_1);
LED_On(LED_NUMBER_2);
LED_Off(LED_NUMBER_3);
break;
case LED_NUMBER_3:
LED_Off(LED_NUMBER_1);
LED_Off(LED_NUMBER_2);
LED_On(LED_NUMBER_3);
break;
default:
return 1;
}
return 0;
}
/* 只允許其中一個 LED 滅 ,其余皆亮 */
char LED_Off_Mutex(enum en_LED_NUMBER number)
{
switch((int)number)
{
case LED_NUMBER_1:
LED_Off(LED_NUMBER_1);
LED_On(LED_NUMBER_2);
LED_On(LED_NUMBER_3);
break;
case LED_NUMBER_2:
LED_On(LED_NUMBER_1);
LED_Off(LED_NUMBER_2);
LED_On(LED_NUMBER_3);
break;
case LED_NUMBER_3:
LED_On(LED_NUMBER_1);
LED_On(LED_NUMBER_2);
LED_Off(LED_NUMBER_3);
break;
default:
return 1;
}
return 0;
}
void LED_On_ALL(void)
{
LED_On(LED_NUMBER_1);
LED_On(LED_NUMBER_2);
LED_On(LED_NUMBER_3);
return ;
}
void LED_Off_ALL(void)
{
LED_Off(LED_NUMBER_1);
LED_Off(LED_NUMBER_2);
LED_Off(LED_NUMBER_3);
return ;
}
/* 初始化 LED */
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 初始化IO時鐘
RCC_APB2PeriphClockCmd(TORCC(LED1_GPIO), ENABLE);
RCC_APB2PeriphClockCmd(TORCC(LED2_GPIO), ENABLE);
RCC_APB2PeriphClockCmd(TORCC(LED3_GPIO), ENABLE);
// 初始化 GPIO
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = TOPIN(LED1_GPIO_Pin);
GPIO_Init(TOGPIO(LED1_GPIO), &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = TOPIN(LED2_GPIO_Pin);
GPIO_Init(TOGPIO(LED2_GPIO), &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = TOPIN(LED3_GPIO_Pin);
GPIO_Init(TOGPIO(LED3_GPIO), &GPIO_InitStructure);
LED_Off_ALL();
}
---------------------------------------------------------------------------
main.c
---------------------------------------------------------------------------
#include "public.h"
#include "delay.h"
#include "led.h"
int main(void)
{
delay_init();
LED_Init();
while(1)
{
delay_ms(500);
LED_On_Mutex(LED_NUMBER_1);
delay_ms(500);
LED_On_Mutex(LED_NUMBER_2);
delay_ms(500);
LED_On_Mutex(LED_NUMBER_3);
}
}
---------------------------------------------------------------------------
|