這一章開始編寫代碼,主要是兩個方面,一是C++,二是進行簡單的IO封裝。其它教程一般是用C語言,從按鍵或LED燈開始,比較直觀,容易上手,但與實際應用有一定的區別,這裏要做的是實用控制程序,開始就比較正規,C++是發展趨勢,所以就從這裏開始。
說是C++,實際是C和C++的混合程序,系統提供的都是C,新寫的代碼是C++,先從簡單的IO開始,添加兩個文件IO.cpp和IO.h代碼如下:
IO.h
#ifndef __IO__
#define __IO__
extern "C" { // 按C語言編譯,Keil5中的包含文件已經加入了C++兼容,不用再加這一段
#pragma diag_remark 368 //消除 warning: #368-D: class "<unnamed>" defines no constructor to initialize the following:
#include "stm32f10x.h"
#pragma diag_default 368 // 恢復368號警告
}
// 通用IO
class IO
{
// Construction
public:
IO(GPIO_TypeDef* GPIOx, u16 nPin, GPIOMode_TypeDef GPIO_Mode, u16 nLevel); // 輸出時設置初始電平,0低,1高,其它不設置
// Properties
public:
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_TypeDef* m_GPIOx;
u16 m_nPin;
private:
// Methods
public:
// Overwrite
public:
};
#endif
IO.cpp
/**
******************************************************************************
* @file IO.cpp
* @author Mr. Hu
* @version V1.0.0 STM32F103VET6
* @date 05/19/2019
* @brief 通用端口初始化
*
******************************************************************************
* @remarks
*
*/
extern "C" { // 兼容C,按C語言編譯,Keil5中的包含文件已經加入了C++兼容,不用再加這一段
#pragma diag_remark 368 //消除 warning: #368-D: class "<unnamed>" defines no constructor to initialize the following:
#include "stm32f10x_tim.h"
#pragma diag_default 368 // 恢復368號警告
}
#include "IO.h"
/**
* @date 05/19/2019
* @brief 初始化端口.
* @param GPIOx: where x can be (A..G) to select the GPIO peripheral.
* @param nPin_x: specifies the port bits to be written.
* This parameter can be any combination of nPin_x where
* x can be (0..15).
* @param GPIO_Mode: 輸入輸出模式.
* @param nLevel: 輸出時初始電平0低,1高,其它無效,初始化端口之前設置,避免開機跳動.
* @retval None
*/
IO::IO(GPIO_TypeDef* GPIOx, u16 nPin_x, GPIOMode_TypeDef GPIO_Mode, u16 nLevel)
: m_GPIOx( GPIOx )
, m_nPin( nPin_x )
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(nPin_x));
u32 RCC_APB2Periph_GPIOx = // 獲取對應的RCC參數
GPIOx != GPIOA ? GPIOx != GPIOB ? GPIOx != GPIOC ? GPIOx != GPIOD ? GPIOx != GPIOE
? 0 : RCC_APB2Periph_GPIOE : RCC_APB2Periph_GPIOD : RCC_APB2Periph_GPIOC : RCC_APB2Periph_GPIOB : RCC_APB2Periph_GPIOA;
// 使能端口, 開啓按鍵端口時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);
// 先設置輸出狀態,避免開機時跳動。
if(nLevel == 0)
GPIO_ResetBits(GPIOx, nPin_x); // 設置低電平
else if(nLevel == 1)
GPIO_SetBits(GPIOx, nPin_x); // 設置高電平
// 輸入狀態不設置
// 配置端口,用最低的採樣頻率,過濾高頻干擾,延長壽命,需要高頻時在外部重設
GPIO_InitStructure.GPIO_Pin = nPin_x;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // 用最低的採樣頻率
GPIO_Init(GPIOx, &GPIO_InitStructure); // 初始化端口
}
所有與C語言有關的代碼用extern "C" { ... ... } 包括起來,告訴編譯器是C語言,只能從C++中調用C語言,不能從C中調用C++。
還有一個要改動的地方,stm32f10x.h 中240行,原語句是 typedef enum {FALSE = 0, TRUE = !FALSE} bool; 修改成:
// C++ 編譯時出現錯誤:..\CMSIS\stm32f10x.h(240): error: #65: expected a ";"
// 增加C++兼容代碼,如果是C++用BOOL,否則用原來的bool
#ifdef __cplusplus
typedef enum {FALSE = 0, TRUE = !FALSE} BOOL;
#else
typedef enum {FALSE = 0, TRUE = !FALSE} bool;
#endif
需要說明的是,上面的封裝不太完善,勉強能用,以後再修改。
STM32實戰系列源碼,按鍵/定時器/PWM/ADC/DAC/DMA/濾波
STM32實戰一 初識單片機
STM32實戰二 新建工程
STM32實戰三 C++ IO.cpp
STM32實戰四 定時器和按鍵
STM32實戰五 板載LED顯示數據
STM32實戰六 PWM加移相正交
STM32實戰七 數字濾波
STM32實戰八 DAC/ADC
STM32實戰九 編碼器
STM32開發過程的常見問題