这一章开始编写代码,主要是两个方面,一是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开发过程的常见问题