STM32F103C8T6单片机的起始点:使用GPIO输出点亮我们的第一个小灯(尺度库 ...

打印 上一主题 下一主题

主题 1404|帖子 1404|积分 4227

目次

先干!从单片机的实操点灯开始
GPIO:General Purpose IO
第一步:开启GPIO的时钟
第二步,配置我们的GPIO的电气属性
控制我们的准备好的GPIO输出高低电平


我们都说,学习一个型号的单片机的第一个尝试,就是使用这个单片机点亮一个小灯。点亮小灯就意味着我们开始开端把握我们手中的单片机了,我们学会使用单片机来控制最简单的外设了。当然,只会这个还是远远不敷的,我们需要进一步理解单片机的更多知识才能走的更远。
先干!从单片机的实操点灯开始

对于GPIO,你可以认为是单片机无形的大手,他来拨弄最简单的我们外接的外设。一个最经典的例子就是点亮一个LED。我们先看看LED是啥。
笔者简单的说,LED就是一个小灯(你想想,LED小灯,LED小灯),我们这里临时不先容LED本身,只先容我们的LED的外部接口特性.首先,LED是一个简单的拥有正负极的一个发光二极管.笔者这里screenshot下我本身买的LED小模块

你可以看到这些二极管存在两个引脚
   笔者需要告诉你的是:大部门情况下,你更多需要关心的是外延的引脚。这里LED因为特别简单,学过一点点高中物理的朋侪都知道,LED分正负引脚,正极接长的一端,负极接短的一段,如许,LED才会有电流时导通,反接的时间,LED被认为是断路,没有电流流过,自然就会咋样都不亮!,为什么要夸大这个呢?这个跟我们后面的控制LED亮灭的GPIO最简单实行有关系。
  以是,从编程的角度上看,我们只需要包管我们给引脚正确的高低电平,如许就好了,当我们使用电池供电的时间,我们一定会如许做:

很好,初中物理实行,但是呢!我们现在学习的是STM32,因此,现在我们就需要换东西了!就是GND,我们使用单片机的GND引脚就好了,那VCC从哪里来呢?答案是从单片机上来,你看,我们的编程模子就酿成了:

现在,我们的使命逐渐明确了,那就是使用单片机的一个引脚,输出高电平,然后将他链接LED的正极,然后将另一根线连接LED的负极和GND引脚,如许我们的电路就完成了一个逻辑回环。简单吧!
问题现在就转移到了:我们的单片机怎样输出高电平呢?懂行的朋侪说:GPIO嘛!但这就递归的派生了新的问题,我想如果完全没有听说过GPIO这四个字母组合在一起的朋侪也会问的,啥是GPIO呢?
GPIO:General Purpose IO

通用输入输出!这就是GPIO。关于这个名词放到这里,你肯定很不理解,什么叫通用输入输出?我们临时不消理会输入,输出你肯定理解的!我们刚刚的问题就是——怎样使用单片机输出一个高电平呢?答案是使用单片机的引脚输出。嗯,我似乎没有回答这个问题,但请你仔细想象:单片机的作用就是作为一个嵌入式项目标大脑,我们有大脑还不敷,他要把它的想法(这里就是我们誊写的程序)告诉外界(比如说我们现在正在瑟瑟发抖的LED),就需要一个引脚,把我们的想法(比如说我们想要输出一个高电平)输出出去,通过杜邦线(或者是其他导线)给我们的LED上。

(笔者的小私货:笔者顺手拿到的各种各样的板子,严格上讲,哪些板子上最大的一坨芯片,就是单片机本体了,他们被用PCB上的铜线连接到了外部的引脚上)
此时此刻,这个引脚在我们编程的时间,我们就说:“嘿!你这个引脚,你这次当GPIO通用输入输出!我告诉你,你需要做的事变是产生一个高电平输出出去”,怎样做?这就是我们下面要说的。
这里是库函数编程,以是我们的文档也就会使用库函数来完成我们的工作。你可能不知道啥叫库函数(哦天,你知道为什么单片机的门槛云云之高了吧!简单的说,就是人家写好了工具,你用就行,就像你拧螺丝不消重新炼铁做扳手,拿着现成的扳手用就完事了,你需要做的就是正确的使用扳手(正确的调用库函数)!)
很好,我们现在打开了我们的MDK啊,还是CubeIDE啊,还是跟我一起使用PlatformIO完成这个事变啊,无所谓,总而言之你在这里了,说明环境没有问题了。我们下面就来点灯。
第一步:开启GPIO的时钟

笔者同等认为,我们的全部的高端电子装备(单片机之上,包括你现在看我文档的手机/电脑/IPAD七零八落的都算!),时钟是这些装备的生命线,我们全部的这些装备都按照时钟的节拍,一个流水一个流水,一条指令一条指令的实行我们写给它的指令(不然它就会死在哪里,就像你没法指望一个心脏停止跳动的人跟你谈笑风生一个道理,除非他是僵尸)
让我们的GPIO从睡眼朦胧中(上电了,但是你要留意,这个时间他还没起来!你需要做的就是使能时钟,把他叫起来!!!)
   请千万记住,使用任何任何外设的时间,出现了罢工的问题(实际上就是不工作),请你第一反应思考:我是不是没有使能时钟,我是不是没有使能对对应的时钟?然后如果不是这个问题,再去思考其他的事变。
  以是,我们的工作就是叫醒GPIO。问题来了,叫醒哪一个呢?
对于初学者,笔者以开始就建议你先去阅读手册,对于GPIO而言,没有必要,对于我们的文档的主角STM32F103C8T6而言,引脚不多,你现在,拿起你的板子,观察上面的丝印。

看到针脚上面的丝印了嘛:上面依次是G G 3.3 R B11 ....以直到C15 C14 C13 VB...这些就是我们的单片机的引脚的编号。我们的STM32,对我们的引脚分类了。您看!对于哪些最有规律的引脚,比如说上面的PA0, PA1, PA2... PA15,PB0, PB1, PB2, ... PB15和PC0, PC1, ... PC15这三组,每一组16个的引脚,一共48个引脚,是我们一定可以拿来做GPIO的引脚。换而言之,接线的时间,就能拿这里的引脚作为我们的电平输出端口。
选择困难症了?啊哈,笔者给你选一个,PA0怎么样?那就PA0咯!
PA0这个引脚,首先,他就属于A分组的第0个引脚,我们在库编程中,说:PA0的A说明白PA0属于GPIOA分组(为什么如许分,不着急,你会在GPIO中断的子章节对这个概念更深入的理解),而且,PA0属于第0个引脚,也就是GPIO_PIN_0,当我们组合出现GPIOA和GPIO_PIN_0的时间,我们就是在说单片机上的PA0引脚。我们后面的时间,就可不会如许的罗嗦了。
   现在你类比分析道:PC14, PC13, PB3这些引脚是啥意思,我们怎样在库编程中找到他们!
  回到我们的整体,第一步,使能GPIO的时钟,特别的,我们想要操纵PA0,就需要使能GPIOA分组的时钟,那问题来了,咋使能时钟啊?
思考的流程是如许的:“我要使能GPIOA的时钟 ”,因此对于尺度库而言,使能GPIOA的时钟,使用的一个函数调用就是 如下的:
  1. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
复制代码
不要被吓晕了,我来说明一下,以后你阅读代码要怎么阅读。第一件事变,RCC_APB2PeriphClockCmd中的ClockCmd你熟悉:时钟的指令嘛!我们要对时钟下命令(恩!情!),对谁下命令呢?一个叫做RCC_APB2Periph的东西下的,或者说:对于挂载在使用单片机基定时钟作为生命线的,APB2总线上的外设使能这个总线上的外设时钟。好,这个外设可是一大堆的东西啊,你要找谁呢?我们于是提供了第一个参数:RCC_APB2Periph_GPIOA。原来我们要找的是GPIOA啊,你找他做什么呢?答案是,ENABLE(使能)它!以是,这行代码的作用就是使能GPIOA的时钟。完事了
   如果是GPIOB的时钟呢?闻一知十!(提示,GPIOA, GPIOB和GPIOC的时钟都在RCC_APB2Periph上,你很容易想到怎么做的,对吧!)
  第二步,配置我们的GPIO的电气属性

这一步,回答了我们要让GPIO成为谁。通用通用,说明它是一个万能牛马,啥脏活烂货都能干,但是你的告诉他,本日你充当啥样的牛马角色。这个时间,我们要请出我们的一个重要的布局体:GPIO_InitTypeDef
  1. typedef struct
  2. {
  3.  uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
  4.                                      This parameter can be any value of @ref GPIO_pins_define */
  5.  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
  6.                                      This parameter can be a value of @ref GPIOSpeed_TypeDef */
  7.  GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
  8.                                      This parameter can be a value of @ref GPIOMode_TypeDef */
  9. }GPIO_InitTypeDef;
复制代码
这个布局体无非再说本身的负责的三个事变,我纪录了:GPIO的引脚是谁(GPIO_Pin),GPIO的速度是谁GPIO_Speed,GPIO充当了咋样的角色人GPIO_Mode,啥,我咋知道的?看看旁边的解释呗!你瞧,扔进谷歌翻译这个事变多简单啊。
显然,我们现在不穷究原理,我们就说我们准备点亮小灯的PA0。啊哈,显然回到我们上面的引脚分析,就是第0个引脚嘛,这个抽象是啥呢,我告诉你,答案是GPIO_PIN_0,或者说,之后你想问库函数尺度库中,我们怎样找到第N个引脚的时间,一定试试搜出来GPIO_PIN_X,此中X就是N的值,比如说,我们找PC13,那就是GPIO_PIN_13咯!
下一步,就是抓出来速度,啊哈,我们亲爱的尺度库说我们有三个选择(你使用VSCode,那就是摁住Ctrl+右键点击GPIOSpeed_TypeDef跳转,狗屎的Keil5的话,自求多福,先编译你的工程然后点击“Go To the Definition”)
  1. typedef enum
  2. {
  3.   GPIO_Speed_10MHz = 1,
  4.   GPIO_Speed_2MHz,
  5.   GPIO_Speed_50MHz
  6. }GPIOSpeed_TypeDef;
复制代码
很好,速度上可以选择10MHz,2MHz,50MHz,好消息是点个灯,无所谓哪一个,嗯,随便选一个折磨我们的单片机,GPIO_Speed_50MHz就是你了。
如法炮制,我们来到了最后一个
  1. typedef enum
  2. { GPIO_Mode_AIN = 0x0,
  3.  GPIO_Mode_IN_FLOATING = 0x04,
  4.  GPIO_Mode_IPD = 0x28,
  5.  GPIO_Mode_IPU = 0x48,
  6.  GPIO_Mode_Out_OD = 0x14,
  7.  GPIO_Mode_Out_PP = 0x10,
  8.  GPIO_Mode_AF_OD = 0x1C,
  9.  GPIO_Mode_AF_PP = 0x18
  10. }GPIOMode_TypeDef;
复制代码
嗯?这啥玩意,这就是GPIO可以充当的角色了,我们先关心第五个GPIO_Mode_Out_OD和第六个GPIO_Mode_Out_PP,你看到了,有一个Out,说明他是跟外界打交道的,换而言之,输出去东西的。啊哈,我告诉你,你需要让GPIO做一个强势的人,直接塞给LED电平是他的工作,为什么?不要着急,我在下一篇博客会仔细的说明GPIO的8种工作模式,这个8种的工作模式将会伴随我们的单片机学习之旅的终点
给啥呢?就是GPIO_Mode_Out_PP,这里的PP就是,PushPull就是一个非常自动的角色,叫做推挽输出,推是Push,挽就是Pull。关于这个的解释笔者放到后面说明。
以是,我们的编程细节就是
  1. void init_led()
  2. {
  3.     GPIO_InitTypeDef gpio_init;
  4.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  5.     gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
  6.     gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
  7.     gpio_init.GPIO_Pin = GPIO_Pin_0;
  8.     GPIO_Init(GPIOA, &gpio_init);
  9. }
复制代码
最后的GPIO_Init,就是让我们的单片机正眼看我们的工作,将我们对GPIO的设置角色成为实际,参数上,需要给出的是GPIO的分组和你的GPIO_InitTypeDef布局体的指针。
非常好,到这里,你调用下init_led,PA0就会从睡梦种醒来,站好军姿准备就位了。
控制我们的准备好的GPIO输出高低电平

咱不能让他门外竖着,干活啊对吧,我们下面就是用GPIO_WriteBit函数完成控制GPIO高低电平的工作。来,我们说在数字天下里,高电平是1,低电平是0(奥,一些大佬跳出来说这是错的,对!这是错的,一些场景下是反过来的,但是在这里,让单片机输出高电平给1完事,低电平给0完事,这符合我们的逻辑语义的)。
请留意,单片机程序最后是要进入一个死循环的(这个说法还不对,但是感兴趣的朋侪看看RTOS,你会高兴的发现死循环丢了单片机没跑飞,这个说法请到笔者展开的对STM32F407ZGT6的FreeRTOS框架编程中理解)
  1.     while (1)
  2.     {
  3.         GPIO_WriteBit(GPIOA, GPIO_Pin_0, 1);
  4.         system_delay_ms(500);
  5.         GPIO_WriteBit(GPIOA, GPIO_Pin_0, 0);
  6.         system_delay_ms(500);
  7.     }
复制代码
你猜也猜到了,system_delay_ms是笔者的延时封装,我们延时500ms,将我们的PA0依次输出高电平低电平高电平低电平。。。嗯,灯会怎么样?一闪一闪的!这里我们就不说明白。
整个代码流程如偕行云流水板的简单。
  1. #include "system_clock.h"#include "stm32f10x.h"​void init_led()
  2. {
  3.     GPIO_InitTypeDef gpio_init;
  4.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
  5.     gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
  6.     gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
  7.     gpio_init.GPIO_Pin = GPIO_Pin_0;
  8.     GPIO_Init(GPIOA, &gpio_init);
  9. }​int main(void){    init_led();        while (1)
  10.     {
  11.         GPIO_WriteBit(GPIOA, GPIO_Pin_0, 1);
  12.         system_delay_ms(500);
  13.         GPIO_WriteBit(GPIOA, GPIO_Pin_0, 0);
  14.         system_delay_ms(500);
  15.     }}
复制代码
此中,system_delay_ms是本身写的:
  1. #include "stm32f10x.h"
  2. #include "system_clock.h"
  3. /**
  4. * @brief the delay function for the system clock, delay in us
  5. *
  6. * @param xus
  7. */
  8. void system_delay_us(uint32_t xus)
  9. {
  10.     SysTick->LOAD = 72 * xus;               
  11.     SysTick->VAL = 0x00;                    
  12.     SysTick->CTRL = 0x00000005;            
  13.     while(!(SysTick->CTRL & 0x00010000));   
  14.     SysTick->CTRL = 0x00000004;            
  15. }
  16. /**
  17. * @brief the delay function for the system clock, delay in ms
  18. *
  19. * @param xms
  20. */
  21. void system_delay_ms(uint32_t xms)
  22. {
  23.     volatile uint32_t ready_delay = xms;
  24.     while(ready_delay--)
  25.     {
  26.         system_delay_us(1000);
  27.     }
  28. }
复制代码
烧录上电,恭喜你完成成就:单片机的历史性第一步:点亮一个LED灯!!!




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

大连全瓷种植牙齿制作中心

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表