这里,我们使用STM32CubeMX新建一个工程感受其强大
其中,点击1处为打开已存在的工程,点击2处选择单片机型号建立工程,点击3处选择官方开发板新建工程,点击4处检查更新,点击5处安装单片机软件包
这里,我们点击2处,等待单片机型号更新,完成都自动进入单片机选择器,如下图所示
1处输入单片机型号进行搜索,双击2处即可进入新工程,点亮箭头处五角星可以收藏,收藏后的单片机型号可以在3处快速找到。同时这个界面也可以用来进行单片机筛选,或者安装MCUFinder进行单片机选型,这不是我们讲解的主要内容,请读者自行学习。
这里我们双击2处进入工程,出现下图所示界面
图中各标号(11以上没找到带圆圈的数字。。。)处作用如下:
1、引脚设置界面,新疆工程后的默认界面
2、时钟配置界面,配置单片机时钟树
3、工程设置界面,配置工程属性,如路径、使用LL或HAL库、生成代码的编译器
4、工具界面,可以进行功耗仿真
5、点击后可以选择折叠(Expand All)或展开(Collapse)所有功能标签
6、可以进行功能搜索
7、选择以目录形式(Categories)或列表形式(A->Z)显示功能树
8、功能树
9、点击展开(向右箭头)或折叠(向左箭头)功能配置
10、选择引脚视图(Pinout View,默认)或系统功能视图(System View)
11、放大视图
12、视图居中完全显示
13、缩小视图
14、视图顺时针旋转
15、视图逆时针旋转
16、引脚搜索(15/16之间的按钮是设置开发板工程的上下层)
17、生成代码
在引脚视图中,可以通过鼠标滚轮进行放大和缩小视图,按住鼠标左键拖动可以移动视图
我们可以使用简单的ctrl+s保存工程,但我更加推荐在工程设置界面进行保存
点击图3中3处(Project Manger)进入工程设置界面,如下图所示
在1处输入工程名,在2处选择保存目录,注意保存目录中不应出现中文,系统会在保存目录中新建以工程名为文件夹名称的文件夹,所以不需要自建工程文件夹,这里我选择桌面,在3处选择使用的编译工具,这里我选择MDK-ARM V5,即keil Uvision5。设置完后可以发现系统已经在桌面建立了名为FirstProject的文件夹。此时在ctrl+s便可在此文件夹进行保存,文件夹中的FirstProject.ioc文件即使Cube工程文件。此后工程生成的代码即是keil5工程,保存在该文件夹中
STM32不同型号单片机中的时钟略有差异,具体时钟配置请参见各型号参考手册。
STM32L431拥有多种时钟源,如HSE、LSE、HSI、LSI等,这里不详细讲解,只说如何配置。
点击图3中的2处,进入时钟配置,如下图所示
系统默认使用MSI作为时钟源,在通用应用中,我们倾向于使用外部晶振作为时钟输入,但此时HSE(外部输入高速时钟)和LSE(外部输入低速时钟)显示为灰色,无法设置,这是因为没有设置晶振引脚连接。
回到引脚视图,如下图所示
RCC设置在System Core选项卡中,点击1处展开选项卡,点击2处选择RCC功能,程序自动展开设置功能配置,如没有展开,点击图3中9处右箭头即可。在展开的功能配置中,3和4处均选择晶振即可。此时右侧红框即自动显示对应引脚连接。回到时钟配置界面。如下图所示
如图7所示,PLL Source Mux选择HSE,PLLM选择1分频,N选择20倍频,R选择2分频即可将HCLK设置至stm32l431的最高频率80MHz。随后的外设时钟分频可根据实际进行设置,此处不做分频。此时,基本的时钟设置就完成了。
此节讲解GPIO基本输入输出设置
回到引脚视图,中间位置有选低定的单片机引脚图。将鼠标置于引脚上时会显示引脚当前状态,左键点击引脚可以设置需要的引脚功能,这里我们将PA0设置为输出(GPIO_Output),PA1设置为输入(GPIO_Input)。
通常,我们会给引脚进行自定义命名,编译程序编写。右键需要进行自定义命名的引脚,选择Enter User Label即可输入自己的命名,输入完后回车即可。注意命名应符合C语言变量名命名规则,同时自定义命名时需要再设置过引脚功能后,否则右键没反应。这里我将PA0命名为LED,PA1命名为KEY。如图所示
此时,基本的GPIO输入输出便设置好了,但通常我们处设置工作模式外还需要设置一些其他参数,如初始电平、上下拉、GPIO口速度、工作模式等,下面我们对齐进行设置。如下图所示
与Cube的前期版本不太一样,5.1.0版本的gpio功能设置放到了引脚视图中,点击功能树中的GPIO选项,展开选项框,点击对应引脚,下方便出现了引脚配置。可根据需要自行设置。这样基本的GPIO输入输出变配置完了。
在生成代码前,我们需要对生成的代码进行一些配置,点击图3中3处进入工程设置界面,如下图所示
点击1处进入Code Generator标签,2处选择需要复制的文件,如非特殊需要,选择仅复制炫耀的库文件即可,3处勾选将不同外设初始化代码放在不同的C语言文件和同文件中,同时选择在重新生成时保留用户代码,这样,当功能有修改时便可直接重新生成,不影响自己编写的代码。
系统默认使用HAL库进行代码生成,也可以选择LL库进行生成,需要的点击Advanced Settings进入设置,如下图所示
不同外设可以选择不同库进行生成。个人喜欢使用HAL库。我均使用HAL库进行生成。
设置完之后,直接点击图3中17处,GENERATE CODE按钮进行代码生成即可。
待代码生成成功后选择Open Project打开工程。
官网可以下载到对应型号单片机的HAL_LL库说明。我是用的是stm32l4/l4+的库函数说明。
打开工程后,所有需要的文件均已在工程树中,其中gpio.c文件中包含gpio初始化相关的函数以定义,通常不需要用户修改。main.c中包含主函数,主函数中已经写好了各外设初始化的函数调用,值得注意的是,在main.h中包含有引脚命名的宏定义。如下代码所示
/* Private defines -----------------------------------------------------------*/
#define LED_Pin GPIO_PIN_0
#define LED_GPIO_Port GPIOA
#define KEY_Pin GPIO_PIN_1
#define KEY_GPIO_Port GPIOA
此工程包含完整,可以直接编译通过。
下面是main.c中的一些代码
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
可以看到,代码中有多处USER…BEGIN和USER…END,这是提示用户在对用的开始和结束之中编写代码,卸载对应代码块中的代码不会再重新生成时被覆盖,相当人性化。
下面代码为简单的检测到输入脚为高电平,输出脚就为高电平的程序
while (1)
{
if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET)
{
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
其中HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin)和HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET)函数分别为读取GPIO状态函数和GPIO输出电平设置函数。具体见如下函数说明
除这两个函数之外,还有翻转电平函数HAL_GPIO_TogglePin(GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin)等,详见HAL_LL数据手册
第一次写教程,自己都感觉语无伦次,大家轻喷。。。写的不清楚的地方欢迎共同探讨
下次写串口设置,及串口中断