STM32是单片机和arm的过渡,之前一直想学习STM32,毕竟是单片机玩的太久了,想更加进一步的加深,但是由于一直下定不了决心和一想到可能会比单片机难就一直搁置着,今天终于静下心来,决定开始学习啦~这个学习的过程就是根据李想老师的视频和在淘宝上随便买的一个stm32的最小系统来学习的。因为觉得看视频很浪费时间,所以我就把视频的步骤一一的写出来,希望能够加快各网友的学习速率。同时写这个博客希望以自己的学习STM32的过程和大家一起学习讨论,同时也督促自己每天不断的进步一点点,好啦,现在就开始啦~~~
STM32编程有2种方法,一个是直接对寄存器进行操作,另一个是调用库函数。
首先第一步当然是安装开发环境,这里就不过多的进行介绍了。
第二,开始我们的第一个学习的步:和单片机学习样,就是点亮第一个LED灯,首先介绍的是直接对寄存器进行操作。我的led的引脚是PC0和PD3,这里我只以PC0为例进行介绍。
在对stm32进行编程的时候,系统时钟初始化函数和延时函数必须要有,对于LED编程的时候,IO口的配置的函数必须要有,所以我们就可以直接拷贝现成的库。
(1)先新建一个文件夹命名为led,这里用来放我们的整个工程(2)将库函数system整个文件夹拷贝到函数里面,这个库里有3个文件分别是与延时有关的函数,与IO口配置有关的函数和与串口有关的函数(3)在我们的led文件夹里面建立一个user的文件夹,用来放我们的工程(4)用keil新建一个工程
再选择我们的CPU型号,我用的型号是STM32F103ZE
点击ok,然后在直接自动加载库文件就可以了。
这个界面是添加启动代码,对于初学者,我就就直接点击是就好了。
就会出现这样的界面,这样我们就建立好了工程。
接下来就是新建文件组。
添加源文件
添加完了之后是这样的。
接下来就是,先建2个组,一个led的组,一个user的组,上面有介绍,是一样的这里就不一一介绍了。最后的图就是这个样子。
接下来:编写我们要实现led灯亮的函数
先建一个led.h和一个led.c的文件,并且把led.c加载在led这个组里面。添加组有2种方法,我们在学习51的时候会和上面也讲了,也不再讲了。关于函数的书写我在这里也解释一下
#ifndef __LED_H//预编译指令
#define __LED_H
#include"sys.h" //这里要用有关IO口的函数,所以要引用这个头文件,之前也有讲过,这个里面是有关IO口的函数
//LED端口定义
#define LED0PCout(0)// PC0设置为输出,如果是输入的话我们就要设置为PCin(0)
#define LED1PBout(1)// PB1设置为输出,如果是输入的话我们就要设置为PCin(0)
voidLED_Init(void);//初始化
#endif
这是led.c
#include
#include "led.h"//引用led.h的头文件
void LED_Init(void) { //led初始化的文件
RCC->APB2ENR|=1<<4; //使能PORTB时钟,这里的4是依据
//APB2ENR这个寄存器来决定的,这是开C脚的时钟
GPIOC->CRL&=0XFFFFFFF0;//配置清0
GPIOC->CRL|=0X00000003;//PC0推挽输出
GPIOC->ODR|=1<<0; //PC0 输出高
GPIOC->ODR|=1<<1; //PC1 输出高
}
这个是APB2ENR寄存器的设置
2 GPIO的配置CRL,有两个0-7用CRL配置,8-15用CRH配置
这是设置GPIOC的输出模式。
这样的话我们就把一切的东西准备好了,这里就可以编写主函数了。这样就要建立一个test.c的文件来保存主函数。
#include
#include"led.h"//引入led.h的头文件
int main(void)
{
Stm32_Clock_Init(9);//系统时钟设置
delay_init(72);//延时初始化
LED_Init(); //LED初始化
LED0=0;
while(1);
}
这样的话,我们的编程工作就算是介绍了,但是编译的话还会有很多很多的错误,这是因为头文件没有加载,按照图所述一个个加载就好了。
最后生成.hex文件就可以下载在我们的stm32上就好了。这样就实现了直接控制寄存器的方法点亮我们的第一个led灯。
接下来就介绍用库函数的方法来点亮led灯。库函数是直接就写好的,我们只需要在这上面进行修改,达到我们的目的。这里也也只是提一提怎么修改led配置,使适应我们的开发板。这里关键的地方就是时钟的配置,IO口的配置和实现功能的main函数。
1、时钟配置
/*************************************************
函数: void RCC_Configuration(void)
功能: 复位和时钟控制 配置
参数: 无
返回: 无
**************************************************/
voidRCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus; //定义外部高速晶体启动状态枚举变量
RCC_DeInit(); //复位RCC外部设备寄存器到默认值
//复位寄存器,和直接操作复位向量表一样
RCC_HSEConfig(RCC_HSE_ON); //打开外部高速晶振
//库函数
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部高速时钟准备好
//判断外部晶振就绪没,等待起振
if(HSEStartUpStatus == SUCCESS) //外部高速时钟已经准别好
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //开启FLASH预读缓冲功能,加速FLASH的读取。所有程序中必须的用法.位置:RCC初始化子函数里面,时钟起振之后
FLASH_SetLatency(FLASH_Latency_2); //flash操作的延时,因为时钟要很快
//配置HB总线
RCC_HCLKConfig(RCC_SYSCLK_Div1); //配置AHB(HCLK)时钟等于==SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1); //配置APB2(PCLK2)钟==AHB时钟
RCC_PCLK1Config(RCC_HCLK_Div2); //配置APB1(PCLK1)钟==AHB1/2时钟
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9); //配置PLL时钟 == 外部高速晶体时钟 * 9 = 72MHz
RCC_PLLCmd(ENABLE); //使能PLL时钟
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) ==RESET) //等待PLL时钟就绪
{
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //配置系统时钟 = PLL时钟
while(RCC_GetSYSCLKSource() != 0x08) //检查PLL时钟是否作为系统时钟
{ //固件库里的0x08锁相环作为系统时钟输入
}
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_AFIO, ENABLE); //允许GPIOB、AFIO时钟
//使能APB2的时钟,功能复用IO口,使能功能复用时钟,使能两个外设时钟,如果使能3个就加或,我们用的是GPIOC,所以要打开这里的时钟
}
GPIO的配置
voidGPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO初始化结构体
//定义GPIO的结构体。
/* ConfigurePE.0,PE.1,PE.2,PE.3,PE.4,PE.5,PE.6,PE.7 as Output push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;//0端口到15端口
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50MHz; //输出的时钟
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP; //工作模式
GPIO_Init(GPIOC, &GPIO_InitStructure); //输出的端口,模拟输出
}
实现功能的主函数
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
delay_init(72);//系统时钟配置为了一个72M
while(1)
{
GPIO_SetBits(GPIOC,GPIO_Pin_0); //PB的0口置1,输出高电平
//哪个口置1,哪一位置1
delay_ms(500);//延时500ms
GPIO_ResetBits(GPIOC,GPIO_Pin_0);//输出推挽输出
delay_ms(500);
}
}
编译完成会需要一段时间,再生成.hex,就好了。
今天就到这里啦~具体的源程序和详细的操作我会上传文件夹,希望对大家有所帮助。
这个是文件地址。
http://download.csdn.net/detail/liaomi520/9689034