一、Keil uVision5 MDK软件的安装以及一些问题的解决方案
1.1 软件安装
1.2 注意事项
安装的过程不会出现什么问题,但实际在使用的过程中还会出现一系列的问题,首先要跟随视频学习,其次会遇到视频中没有出现的问题。以下为博主本人遇到的一些问题以及其解决方案。
keil5编译一直有一个报错
1.点魔术棒,选Target选项卡,把右上角那个Code Generation里的use default compiler version 6改成use default compiler version 5,这样就好了。
2.环境变量有问题,可以试试修改环境变量的方法
keil5自动补全代码功能(关于STM32的)
keil5输入中文乱码问题一步解决!详细!
二、 keil5编程与GPIO开发
首先,看过原子哥视频的同学都知道有关IO口的知识是学习整个STM32过程中的重中之重;
其次,虽然原子哥已经讲的很细致了但毕竟“师傅领进门,修行在个人”,本人总结了一些有关基于库函数方向以实验1跑马灯实验为例如何初始化和使用IO口的一些重点知识。
2.1 第一步:使能IO口时钟
IO口时钟其实可以结合数电实验FPGA自带的时钟引脚进行理解,其实就是一个触发条件。重点是要掌握调用时要输入怎样的参数。
时钟使能函数RCC_APB2PeriphClockCmd()共有2个参数。以下模块为可填入的参数,其中加粗部分为分类注释。
时钟使能函数
使能IO口时钟。调用函数
RCC_APB2PeriphColckCmd();
不同的IO组,调用的时钟使能函数不一样。
1.1 assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
:
#define RCC_APB2Periph_AFIO ((uint32_t)0x00000001)
#define RCC_APB2Periph_GPIOA ((uint32_t)0x00000004)
#define RCC_APB2Periph_GPIOB ((uint32_t)0x00000008)
#define RCC_APB2Periph_GPIOC ((uint32_t)0x00000010)
#define RCC_APB2Periph_GPIOD ((uint32_t)0x00000020)
#define RCC_APB2Periph_GPIOE ((uint32_t)0x00000040)
#define RCC_APB2Periph_GPIOF ((uint32_t)0x00000080)
#define RCC_APB2Periph_GPIOG ((uint32_t)0x00000100)
#define RCC_APB2Periph_ADC1 ((uint32_t)0x00000200)
#define RCC_APB2Periph_ADC2 ((uint32_t)0x00000400)
#define RCC_APB2Periph_TIM1 ((uint32_t)0x00000800)
#define RCC_APB2Periph_SPI1 ((uint32_t)0x00001000)
#define RCC_APB2Periph_TIM8 ((uint32_t)0x00002000)
#define RCC_APB2Periph_USART1 ((uint32_t)0x00004000)
#define RCC_APB2Periph_ADC3 ((uint32_t)0x00008000)
#define RCC_APB2Periph_TIM15 ((uint32_t)0x00010000)
#define RCC_APB2Periph_TIM16 ((uint32_t)0x00020000)
#define RCC_APB2Periph_TIM17 ((uint32_t)0x00040000)
#define RCC_APB2Periph_TIM9 ((uint32_t)0x00080000)
#define RCC_APB2Periph_TIM10 ((uint32_t)0x00100000)
#define RCC_APB2Periph_TIM11 ((uint32_t)0x00200000)
1.2 assert_param(IS_FUNCTIONAL_STATE(NewState));
:
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
2.2 第二步:初始化IO口模式。
有关GPIO的初始化底层原理我们了解即可,其实就是不断地调用库函数。重点是要掌握调用时要输入怎样的参数。
初始化函数GPIO_Init()共有2个参数,其中第2个参数为结构体,其中还包含三个参数。以下模块为可填入的参数,其中加粗部分为分类注释。
初始化函数
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
1.GPIOx: GPIOA~GPIOG
2. GPIO_InitTypeDef GPIO_InitStructure;
typedef struct
{
uint16_t GPIO_Pin; //指定要初始化的IO口
GPIOSpeed_TypeDef GPIO_Speed; //设置IO口输出速度
GPIOMode_TypeDef GPIO_Mode; //设置工作模式:8种中的一个
}GPIO_InitTypeDef;
2.1 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置
:
#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */
2.2 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
:
typedef enum
{ GPIO_Mode_AIN = 0x0,
GPIO_Mode_IN_FLOATING = 0x04,
GPIO_Mode_IPD = 0x28,
GPIO_Mode_IPU = 0x48,
GPIO_Mode_Out_OD = 0x14,
GPIO_Mode_Out_PP = 0x10,//推挽
GPIO_Mode_AF_OD = 0x1C,
GPIO_Mode_AF_PP = 0x18
}
2.3 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
:
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
2.3 第三步:操作IO口,输出高低电平
这里主要用到了4个设置输出电平函数,其实就是通过这几个函数控制IO口输出高低电平。重点是要掌握调用时要输入怎样的参数。
设置输出电平函数GPIO_SetBits()共有2个参数。以下模块为可填入的参数,其中加粗部分为分类注释。
1.GPIOx: GPIOA~GPIOG
2.GPIO_Pin:
#define GPIO_Pin_0 ((uint16_t)0x0001) /*!< Pin 0 selected */
#define GPIO_Pin_1 ((uint16_t)0x0002) /*!< Pin 1 selected */
#define GPIO_Pin_2 ((uint16_t)0x0004) /*!< Pin 2 selected */
#define GPIO_Pin_3 ((uint16_t)0x0008) /*!< Pin 3 selected */
#define GPIO_Pin_4 ((uint16_t)0x0010) /*!< Pin 4 selected */
#define GPIO_Pin_5 ((uint16_t)0x0020) /*!< Pin 5 selected */
#define GPIO_Pin_6 ((uint16_t)0x0040) /*!< Pin 6 selected */
#define GPIO_Pin_7 ((uint16_t)0x0080) /*!< Pin 7 selected */
#define GPIO_Pin_8 ((uint16_t)0x0100) /*!< Pin 8 selected */
#define GPIO_Pin_9 ((uint16_t)0x0200) /*!< Pin 9 selected */
#define GPIO_Pin_10 ((uint16_t)0x0400) /*!< Pin 10 selected */
#define GPIO_Pin_11 ((uint16_t)0x0800) /*!< Pin 11 selected */
#define GPIO_Pin_12 ((uint16_t)0x1000) /*!< Pin 12 selected */
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */
#define GPIO_Pin_14 ((uint16_t)0x4000) /*!< Pin 14 selected */
#define GPIO_Pin_15 ((uint16_t)0x8000) /*!< Pin 15 selected */
#define GPIO_Pin_All ((uint16_t)0xFFFF) /*!< All pins selected */
2.4 综合代码
有关led.h led.c main.c这三个文件的关系是:.h文件相当于两个.c文件的衔接,使得main.c能够通过led.h头文件引用led.c文件(C语言的知识,但说实话学校没怎么学有关头文件的内容)。
注:这是基于看过视频以后对程序项目经过初始化后的主程序,详情还需观看配套视频前15讲。
led.h 代码:
#ifndef __LED_H
#define __LED_H
void LED_Init(void);//起到衔接作用
#endif
led.c 代码:
#include "led.h"
#include "stm32f10x.h"
void LED_Init(void)//主函数
{
GPIO_InitTypeDef GPIO_InitStructure;//定义第二步的结构体
//第一步:使能IO口时钟。调用函数 RCC_APB2PeriphColckCmd();不同的IO组,调用的时钟使能函数不一样。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//GPIOB
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);//GPIOE
//第二步:初始化IO口模式。调用函数 GPIO_Init();
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//第三步:操作IO口,输出高低电平。GPIO_SetBits();GPIO_ResetBits();
GPIO_SetBits(GPIOB,GPIO_Pin_5);
//GPIOE同二三步
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOE,&GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
}
main.c 代码:
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
int main(void)
{
delay_init();//延时函数
LED_Init();//初始化IO口,通过led.h调用led.c函数
while(1)
{
GPIO_SetBits(GPIOB,GPIO_Pin_5);//高电平
GPIO_SetBits(GPIOE,GPIO_Pin_5);
delay_ms(500);//延时500ms
GPIO_ResetBits(GPIOB,GPIO_Pin_5);//低电平
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
delay_ms(500);//延时500ms
}
}
注:代码最后结尾时需要加一行回车,否则会报错!
2.5 位操作
有关位操作,在代码上的体现仅仅是main.c不同,更为简单,但底层原理十分复杂,了解即可。
main.c 代码:
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"//该头文件中已包含"sys.h"
int main(void)
{
delay_init();//初始化延时函数
LED_Init();//初始化LED函数
while(1)
{
PBout(5)=1;//PB IO口设置为高电平灯灭(位操作,内嵌函数宏定义)
PEout(5)=1;//PE IO口设置为高电平灯灭(位操作,内嵌函数宏定义)
delay_ms(500);//延时500ms
PBout(5)=0;//PB IO口设置为低电平灯亮(位操作,内嵌函数宏定义)
PEout(5)=0;//PE IO口设置为低电平灯亮(位操作,内嵌函数宏定义)
delay_ms(500);//延时500ms
//LED一端接3.3V,共阳极接法,低电平导通(有电位差),高电平截止(无电位差)
}
}