几台哥 发表于 2018-12-19 21:08:37

【持续更新】《stm32,我来了》原创小白教程

本帖最后由 几台哥 于 2019-1-16 23:13 编辑

写在前面:本教程是基于野火指南者这个开发板的,当然,你也可以去淘宝买个单片机最小系统来购买相应的模块,来结合面包板进行单片机的学习。




关于野火及其官方资料:



         在此之前请确定KEIL 5这个软件安装完毕。(资料盘里有所需要的驱动,软件,注册机这些,群里面也有,网上也有很多现成的安装教程)      通常,市面上的教程都是从搭建一个工程文件开始的,本教程想用一种“超越”的方式,来快速入门,有问题?先放下,我们要在最短的时间里,通过简单的C语言编程,出现一个成果。让我们先从点亮一个LED灯开始!      我打算的是从浅入深地学习,在最短的时间内和保证大家能够理解的情况下,点亮LED 灯,实现这样的一个实验效果,或许你在编程的过程中有疑问,别着急,在点亮LED灯之后,我将详细讲解每个细节。注意:此教程是基于野火指南者这个开发板,如果是其他的开发板需要改变配置文件,请参照这篇文章: 链接:https://pan.baidu.com/s/1Kx6mJJYX_1w1c4LkumLBHg 提取码:9gqj





第一章:点亮LED灯


**** Hidden Message *****
跟我一步一步来操作,干就完了!

首先,我们到01点亮LED灯\项目模板\Project\RVMDK(uv5)这个文件夹里找到1、打开项目文件2、打开main主函数3、正式打代码咯! 1、定义一个GPIO(通用的输入输出头文件)的结构体变量。
对于结构体关键字是不是有点看不懂?实际上他就是一个重定义过的关键字而已,本质上还是struct,我们可以去看看他的源代码:
选中那个代码,然后点击右键,如下图所示 英文好的同学可以试着翻译一下,我们可以看到这个结构体一共有三个结构体成员:Pin引脚,Speed速率和模式,我们即将要给他们赋值。
2、打开相关GPIO的时钟

<font face="Calibri">   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); </font>


3、配置GPIO并初始化。模式为推挽输出
      GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;

根据原理图我们知道这个电路板LED挂载在PB5的引脚上。
PB5的含义是GPIOB端口的第5个引脚
      GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
GPIO的速率      GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
这个初始化函数
<font face="Calibri">   GPIO_Init(GPIOB,&GPIO_InitStructure);</font>

效果是这样的:

上图的GPIO_Pin_5等赋的值不知道哪里来的,还可以像之前的操作一样,直接Go To Defination of “XXX”,找到代码的定义部分。
到这里或许你不懂推挽输出,速率这些词是啥意思,别急,都说别急了哦,请跟着我打完代码,之后我会做出解释。
4、将相关的引脚拉低<font face="Calibri">    GPIO_ResetBits(GPIOB,GPIO_Pin_5); </font>

另一端接3.3V的电源,另一边和GPIO相连的那一端应该拉低才能使LED导通从而点亮。



成功啦!!!!

第二章:LED灯闪烁和颜色变换

      **** Hidden Message *****       上一节课已经简简单单地成功点亮了一个LED灯,那么如何控制LED灯闪烁呢?
我们打算用软件延时,当然,用STM32自带的Systick也可以做精准延时,在之后的篇幅中会有一章是专门来讲Systick,我们现在使用的是软件延时。      野火指南者用的8MHz的晶振,经过9倍频,最后的时钟频率达到72MHz,所以执行一段语句的时间为频率的倒数,即1/72 000 000 s,等同于1/72 us,那么,如果要延时一秒的话,就需要执行约14000次语句。

一、定义一个延时函数Delay
(当然函数名按自己的来随便改也是可以的)
void Delay(unsigned int i)
{
while(i--);
}

然后在main函数中加入Delay(14000000),就可以达到延时一秒。还有,我们知道之前

引脚的那一端拉低就可以点亮LED灯,那么拉高的话,就会使LED灯熄灭,再结合我们之前所讲的延时函数就可以实现一个”LED灯闪烁”的现象了。二、main主函数中添加一个while循环来让LED灯持续闪烁while(1)
      {
      GPIO_SetBits(GPIOB, GPIO_Pin_5);
      Delay(14000000);
      GPIO_ResetBits(GPIOB, GPIO_Pin_5);
      Delay(14000000);
      }

三、最后的效果

所以,我们在上一节课的代码上要修改为:GPIO_InitTypeDef GPIO_InitStructure;
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
      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);
      GPIO_ResetBits(GPIOB, GPIO_Pin_5);
      //将相关的引脚置位,拉高,默认为熄灭
      while(1)
      {
                        GPIO_ResetBits(GPIOB, GPIO_Pin_5);//点亮红灯
                        Delay(14000000);
                        GPIO_SetBits(GPIOB, GPIO_Pin_5);//熄灭红灯
                        Delay(14000000);
      }

LED灯颜色变换
从原理图我们可以发现,这是一个RGB灯,之前我们只是点亮了他的一种颜色,如果需要改变颜色,初始化对应的GPIO即可,所以需要修改:端口号
引脚号

到代码中所要修改的就是(红色的部分):同理,因为这个开发板RGB灯都是挂载到GPIOB这个IO口,所以初始化不同灯的GPIO的时候,只需要改变引脚即可,在以上的代码中追加:然后main函数中的while中修改代码,使每间隔1秒灯交换亮:      <font size="3">while(1)
      {
                        GPIO_ResetBits(GPIOB, GPIO_Pin_5);//点亮红灯
                        GPIO_SetBits(GPIOB, GPIO_Pin_0);//熄灭绿灯
                        GPIO_SetBits(GPIOB, GPIO_Pin_1);//熄灭蓝灯
                        Delay(14000000);
                        GPIO_ResetBits(GPIOB, GPIO_Pin_0);//点亮绿灯
                        GPIO_SetBits(GPIOB, GPIO_Pin_5);//熄灭红灯
                        GPIO_SetBits(GPIOB, GPIO_Pin_1);//熄灭蓝灯
                        Delay(14000000);
                        GPIO_ResetBits(GPIOB, GPIO_Pin_1);//点亮蓝灯
                        GPIO_SetBits(GPIOB, GPIO_Pin_0);//熄灭绿灯
                        GPIO_SetBits(GPIOB, GPIO_Pin_5);//熄灭红灯
                        Delay(14000000);
      }</font>


至此,我们将02LED灯闪烁和颜色变换\点灯项目源代码\Output\led.hex文件利用mcuisp下载到板子里就可会发现三种色灯交替闪亮!

第三章:小项目大学问-1
原文:链接:https://pan.baidu.com/s/12MKCVQ7mwsGtuZlDAGu8gw 提取码:xu9p

想必,在之前的两节课之中,即便是我多次提到放轻松,但未免感到懵逼,好多名词不懂,但,我想说的是:如果不懂,请暂从字面上来理解,还不懂?
本节课主要是给前面的点亮LED的超小项目来理解STM32的架构,首先,我们先来解决前面的疑问。
提醒:下面的内容是由以下两个官方资料整理所得,我们写代码的依据也都是根据这两本资料:
1、STM32F10x-参考手册
2、STM32F103xCDE_数据手册1>STM32F103VET6
    指南者所用的单片机是STM32F103VET6,一大串符号,有点迷,那么请看下面的两张图:          通过查图,这个单片机属于基础版,主频72MHz(最高的时钟频率),100个引脚,512Kbytes,QFP封装,-40℃到85℃的工作温度。2>GPIO

         GPIO是通用的输入输出口(General Purpose Input Output),如果会英语就很好记了,每个GPIO端口有两个32位配置寄存器,两个32位数据寄存器,一个32位置位/复位寄存器,一个16位复位寄存器和一个32位锁定寄存器。如果使用固件库的话,我们不讲底层的寄存器是如何配置的,只要简单知道的他的构成即可。 //每个GPIO是由寄存器和相关的控制电路构成。
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);          还记得之前的这几行代码么?通过初始化结构体变量来配置相关的寄存器,配置的有:
1、工作模式
   这是C语言中typedef(重定义)的enum(枚举类型),枚举类似于批量的define宏定义,我们还可以看到有两种输入和输出两种工作模式,因为STM32的GPIO是复用的,也就是每一个IO口都有第二功能可以使用。

1-输入1-输入模式(模拟/浮空/上拉/下拉)

模拟输入:常用于电压采集
浮空输入:输入的电平不是固定的,由外部器件的输入决定。
上拉/下拉输入:默认为低电平/高电平,例如获取按键的状态如果设置浮空输入,就不清楚是高电平还是低电平,必须加个上拉或者下拉电阻来保持稳定的电平状态,如果是下拉输入的话,就会方便很多。

2-输出模式(推挽/开漏)
推挽输出:可以通过单片机编程来控制IO的高低电平状态,底层是FET电路实现的。
开漏输出:可以通过单片机编程来控制IO的低电平状态和高阻态,底层是FET电路实现的。
3-复用功能(推挽/开漏)
唯一不同的是,上文所说的都是由单片机控制,复用功能的信号源来自于其它外设
2、引脚
选中挂载的指定引脚,之前学51的时候听过管脚的概念,其实引脚和管脚是一个东西,需要注意的是STM32的GPIO有16个引脚。
3、时钟速率 typedef enum
{
GPIO_Speed_10MHz = 1,

    GPIO_Speed_2MHz,

    GPIO_Speed_50MHz

}GPIOSpeed_TypeDef;时钟速率设置的越快,响应的速度就越快,如果对于功耗有要求的话,需要关注下配置的时钟速率。



第三章:小项目大学问-2
在上一讲,我主要讲了几个主要名词的含义,这一讲我主要讲1、如何搭建project2、一些编写代码的好习惯。链接:https://pan.baidu.com/s/15Jstp_JR6vYjffJHZAId_w 提取码:8wz7


一、 搭建最基本的project项目文件
我们知道,我对单片机编程是操作寄存器的,但直接去操作寄存器,很难理解和开发的效率也不是很高,stm32官方给出的固件库就让代码编写的效率大大提高,我们不再关心具体实现,是要关心业务逻辑的开发就可以了!
本教程也主要是讲基于固件库的,而且我觉得未来嵌入式开发的方向,也将会是各种“库”的天下,而不是面对那些晦涩难懂的寄存器。(当然,如果了解寄存器的配置也是极好的呀!)

1、如何获取固件库?
a)      配套的资料获取:./
b)      官网获取http://www.stmcu.org.cn/document/list/index/sort-name/category-544注意:要从相关的选项卡里找固件,比如说F1的就去F1的选项卡里面找资料。
2、Stm32官网固件库文件分析
3、搭建工程文件
话说在前头,我们也可以直接将固件库都放在项目文件里,但是,一定要分类,否则以后修改个东西,也很麻烦,我们从下载的固件库文件也可以发现,stm官方的资料都做了分类,而不是无序的。
         我们正式开始!
         参照之前我们的工程文件

a)新建一个工程文件
b)创建工程文件
                                             
c)选择芯片包d)将下载的固件库配置到项目文件的根目录下e)配置项目参数,并按如下图配置。二、 代码习惯1、每一个外设,都会创建一个文件夹,来存放代码文件。例如LED2、在根目录下放置keilkill.bat,这是一个批处理文件,可以删除编译等产生的过程文件。



配套资料链接:https://pan.baidu.com/s/1ei_vHAtadq4VBAKJMHyBBA
提取码:1j81



第四章:EXTI-使用按键点亮LED灯
在之前的几讲中,我讲过了如果通过编程来点亮LED灯,今天这节课,我要将另一种点亮LED灯的方法:通过独立按键来控制LED灯的亮灭。本质上,还是点亮LED灯,改变的只是触发方式,之前用的是程序触发从而点亮LED灯,咱们这次用的是按键了,当然也不仅仅是按键,你也可以使用其它的外设来控制LED灯亮灭,按键只是我们学习EXTI(外部中断/事件控制器来举的一个例子,仅此而已。


一、 神马是EXTI
STM32F10x-中文参考手册:对于互联型产品,外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成,对于其它产品,则有19个能产生事件/中断请求的边沿检测器。每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏蔽。挂起寄存器保持着状态线的中断请求。         EXTI(External interrupt/event controller)外部中断/事件控制器,即外部设备产生中断或者事件,然后再通过编程来控制中断优先级和触发方式,每一个控制器都由一个边沿检测器构成,一共有19个,当然这是对于除了互联型产品而言,也就是说这样的触发可以由相关IO口的16个引脚(线0-15)来控制。(线16:连接到 PVD 输出。线 17:连接到 RTC 闹钟事件。线 18:连接到USB 唤醒事件。)
         边沿检测的含义实际上就高低电平的变化过程,当高电平转向低电平为下降沿,低电平转向高电平为上升沿,我们接下来要说的这个按键实际上就是利用了按下和松开就可以改变电平的变化来触发外部中断的。
STM32 (非互联型)供 IO 口使用的中断线只有 16 个,但是 STM32 的 IO 口却远远不止16 个,那么 STM32 是怎么把 16 个中断线和 IO 口一一对应起来的呢?于是 STM32 就这样设计,GPIO 的管教 GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G)分别对应中断线 15~0。这样每个中断线对应了最多 7 个 IO 口,以线 0 为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0。而中断线每次只能连接到 1 个 IO 口上,这样就需要通过配置来决定对应的中断线配置到哪个 GPIO 上了。下面我们看看 GPIO 跟中断线的映射关系图:



二、按键!   我们再来介绍一下按键。指南者上面的按键是叫轻触开关(独立按键\微动按键),当按键按下,电路导通。我们再来看一下指南者这个板子上他的按键电路:我们可以清晰地看到,指南者开发板具有两个按键(KEY1和KEY2),分别连到了单片机(STM32F103VET6)的PA0和PC13两个引脚上,当按键被按下,1、3处导通,相关单片机的引脚被拉高,而之前默认是接地的,为低电平,所以,按键按下有一个低电平到高电平的一个上升沿的跳变沿。 这个时候EXTI就会开始起作用了,通过他的控制,会触发一个中断或者事件。三、EXTI功能框图上图画圈的部分,是20条线路,为了简写,所以有用那样的标号来代替,我们其实只需要了解一条线的运行过程就可以了。(具体与数字电路相关的知识这里先不讲,学过的,看图应该也可以理解)三、中断/事件线EXTI 有 20 个中断/事件线,每个 GPIO 都可以被设置为输入线,占用 EXTI0 至EXTI15,还有另外七根用于特定的外设事件,见表 18-1。4 根特定外设中断/事件线由外设触发,具体用法参考《STM32F10X-中文参考手册》中对外设的具体说明。EXTI0 至 EXTI15 用于 GPIO,通过编程控制可以实现任意一个 GPIO 作为 EXTI 的输入源。         按键挂载到哪个引脚上了,就要选择对应的输入线。比如我们指南者的按键KEY1是挂载到PA0这个口上了,那么相对应的,他的输入线就应该是EXTI0,我们配置EXTI0就可以了。三、中断配置:NVIC(嵌套向量中断控制器)我们这个EXTI也属于中断的子集,所以要对中断的优先级进行配置,因为不可能同时触发多个中断,这涉及到优先级排队的问题。NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。(和NVIC相关的函数和结构体定义都在misc.h/c中)为了方便起见,我们直接从代码简单讲一下NVIC,后面的章节会做详细补充:

<font size="4"><span lang="EN-US"><o:p></o:p></span></font>
typedef struct
{
uint8_t NVIC_IRQChannel;//配置中断源,在stm32f10x.h中,如果用的是EXTI0 就是EXTI0_IRQn(186行)
uint8_t NVIC_IRQChannelPreemptionPriority;//配置抢占优先级
uint8_t NVIC_IRQChannelSubPriority;//配置子优先级
FunctionalState NVIC_IRQChannelCmd; //中断源使能
} NVIC_InitTypeDef;
注意:优先级配置的越小,优先级越高。当然,也不要忘记对优先级进行分组(父子优先级的个数配置):

<span style="font-family: 宋体; mso-ascii-font-family: Calibri; mso-ascii-theme-font: minor-latin; mso-fareast-theme-font: minor-fareast; mso-hansi-font-family: Calibri; mso-hansi-theme-font: minor-latin;"><span lang="EN-US"><o:p></o:p></span></span>
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
<font size="3">

</font>ST已经给了这个函数详细的注释:/**
* @briefConfigures the priority grouping: pre-emption priority and subpriority.
* @paramNVIC_PriorityGroup: specifies the priority grouping bits length.
*   This parameter can be one of the following values:
*   @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority
*                              4 bits for subpriority
*   @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority
*                              3 bits for subpriority
*   @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority
*                              2 bits for subpriority
*   @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority
*                              1 bits for subpriority
*   @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority
*                              0 bits for subpriority
* @retval None
*/
三、说了这么多,终于要开始编程啦~还是要说一句:
         在正式打代码之前,我们将外设led和EXTI都封装到user目录的一个文件夹中,并且创建c文件和头文件,并且记得将新建的外设文件夹添加到工程的头文件包含路径中,如图:1、 初始化LED的GPIO因为在前面的教程里面讲过如何点亮LED灯,所以这里不再次讲解,记住看原理图然后配置IO即可。2、 中断优先级分组3、 初始化KEY1的GPIO记得GPIO的模式配置为浮空输入模式。4、 初始化EXTI
//选择EXTI的信号源和输入线,函数参数可以直接调到它的定义处,有详细说明。
GPIO_EXTILineConfig(KEY1_EXTI_PORTSOURCE, KEY1_EXTI_PINSOURCE);
EXTI_InitStructure.EXTI_Line = KEY1_EXTI_LINE;
      

//配置为中断模式,还有一种是事件模式是传输一个脉冲信号给其他外设使用
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
//上升沿中断,也就是按键被按下的时候才触发中断(看原理图),执行中断服务程序
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
//使能中断
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
             EXTI_Init(&EXTI_InitStructure);
5、 编写中断服务函数为了简单一点,不涉及到寄存器级别的编程,所以我直接用了一个保存led亮灭的标志i,来实现反转LED灯static int i=0;//定义一个静态变量,初始化为0
void KEY1_IRQHandler(void)
{
//确保是否产生了EXTI Line中断

      if(EXTI_GetITStatus(KEY1_EXTI_LINE) != RESET)
      {
                if(i==0)
                {      
                        GPIO_ResetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);//点亮
                        i=1;
                }
                else
                {      
                        GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);//熄灭
                        i=0;
                }
    //清除中断标志位
                EXTI_ClearITPendingBit(KEY1_EXTI_LINE);   
      }
}



















Yuffie 发表于 2019-3-6 17:48:58

请问为什么我一直搜索不到我的设备呢?用的stm32因为没有按钮直接在main里面加了gizwitsSetMode(WIFI_AIRLINK_MODE);

几台哥 发表于 2019-3-7 22:29:54

Yuffie 发表于 2019-3-6 17:48
请问为什么我一直搜索不到我的设备呢?用的stm32因为没有按钮直接在main里面加了gizwitsSetMode(WIFI_AIRLI ...

http://club.gizwits.com/forum.php?mod=viewthread&tid=9559&page=1&extra=#pid41305

几台哥 发表于 2018-12-21 20:28:40

半妖倾城 发表于 2018-12-21 07:51
亮度。话说调节亮度和调节颜色不一样吗?

当然不一样的,调节亮度需要调PWM,颜色的话直接配置IO就可以。PWM我会在后面的课程中讲到。

老宋2018 发表于 2018-12-20 15:10:11

呜呜呜呜呜呜呜

半妖倾城 发表于 2018-12-20 17:36:23

点亮了怎么调光呢。

几台哥 发表于 2018-12-20 22:07:33

半妖倾城 发表于 2018-12-20 17:36
点亮了怎么调光呢。

你说的是调光的颜色,还是亮度?

半妖倾城 发表于 2018-12-21 07:51:32

几台哥 发表于 2018-12-20 22:07
你说的是调光的颜色,还是亮度?

亮度。话说调节亮度和调节颜色不一样吗?

罗婷大傻逼 发表于 2018-12-27 19:28:28

几台哥牛逼~

Solarworker 发表于 2019-1-2 12:02:32

:loveliness::loveliness:多谢分享。。

刚哥 发表于 2019-1-4 16:39:13

初学者受教了,谢谢。

几台哥 发表于 2019-1-16 22:57:33

刚哥 发表于 2019-1-4 16:39
初学者受教了,谢谢。

一起努力吧

初善 发表于 2019-2-18 16:48:41

要学习要学习要学习要学习要学习要学习要学习要学习要学习要学习要学习

hzau110 发表于 2019-2-21 19:35:17

看看!!!!!!!!!!!!!!!!!!

龙的传人PXN 发表于 2019-4-1 00:40:35

57554456456456

My5tery 发表于 2019-4-2 13:52:27

大佬有mcu教程吗

几台哥 发表于 2019-4-21 15:11:23

My5tery 发表于 2019-4-2 13:52
大佬有mcu教程吗

等有时间的话,会出的

yangge2333 发表于 2019-5-31 12:26:42

6666666666666

Seasonic 发表于 2019-7-24 09:23:18

stm32的生态系统很完善,值得学习。

iskun 发表于 2019-10-8 17:47:46

6666666666666
页: [1] 2
查看完整版本: 【持续更新】《stm32,我来了》原创小白教程