STM32跑马灯例程总结

发布者:咖啡小熊最新更新时间:2017-10-07 来源: eefocus关键字:STM32  跑马灯 手机看文章 扫描二维码
随时随地手机看文章

//======================================================//
**基于学习STM32有一段时间了,特意写下一篇关于一个简单的跑马灯
的例程,梳理思路,也希望我自己的理解能帮到一些学习STM32的初学者
/**再此,鸣谢余师傅在学习上的大力帮助!!**/
//======================================================//


首先,GPIO的配置种类有8种。分别为模拟输入、浮空输入,上拉输入、下拉输入、开漏输出、推挽输出、复用开漏输出、复用推挽输出。
下面将以实例的方式讲解GPIO的设置及实现过程。


事例1:跑马灯实验
跑马灯实验的功能:LED灯进行有规律闪烁。(下面的LED灯的数量都为2个,所以关于寄存器的配置也将以两组的方式进行讲解)


首先要知道普通的IO就两种功能一个为输入,一个为输出。然后再以输入和输出细分为以哪种模式输出、以哪种模式输入。要设置IO的模式这时就要使用到寄存器进行设置,STM32的IO端口一般由7个寄存器来进行控制。
分别为
(1)配置模式的2个32位的端口配置寄存器 CRL 和 CRH;
(2)2 个 32 位的数据寄存器 IDR 和 ODR;
(3)1 个 32 位的置位/复位寄存器BSRR;
(4)1个 16 位的复位寄存器 BRR;
(5)1 个 32 位的锁存寄存器 LCKR;
而我们常用的 IO 端口寄存器只有 4 个:CRL、CRH、IDR、ODR。


首先,一般一个程序的开始都会从入口main函数开始执行,而一个功能的实现之前都需要做一些准备工作,当然跑马灯也不例外,在程序执行前,IO需要初始化,而初始化要做的就是对程序需要用到的GPIO的寄存器进行配置。然后设定输出设备的初始状态,即跑马灯的初始状态。一般程序在执行前,输出设备都会是处于关闭状态。最后增加延时函数,让LED灯在亮与灭之间有一段时间的状态保留,不然时间过快,人类的视觉根本捕抓它的状态变化。


下面来讲一下实现跑马灯效果的IO要怎么配置。首先先说一下使用LED来进行跑马功能的话只需要用到RCC->APB2ENR、GPIOX->CRL、GPIOX->ODR三个寄存器(GPIOX中的X表示为GPIO的组别,例如GPIOB表示在GPIO的B组上,因为一般单片机上的GPIO一般都会有很多组的,这样也只是为了区分这些IO罢了)
CRL 和 CRH 控制着每个 IO 口的模式及输出速率。


这里需要注意的是在配置GPIO前,都需要先使能该GPIO的时钟!(可能有人会问“为什么一定要是使能时钟呢?”答案是:GPIO也是外设的一种,然后外设是需要提供时钟信号工作,以便于设置GPIO的数据传输速度的高速/低速输出,所以有关数据的传输都是在时钟信号的基础上的。51单片的IO口也有时钟,只是为了方便,默认开启的,ST的为了更好的控制功耗,电路上做的可以选择开关时钟,降低功耗。补充网友的答案:“寄存器是基于触发器的,触发器的赋值是一定需要时钟的,而寄存器的时钟是由总线时钟提供的,就是说没有总线时钟的话,你给寄存器值它是不会读入的”)
然后设置两个LED的GPIO的模式,因为LED是输出设备,所以GPIO将设置成输出模式,其中配置模式要用到的寄存器为配置寄存器CRL和CRH。其中CRH为高位寄存器,CRL为低位寄存器。(有人可能有疑问为什么用的是32位的寄存器为什么还要为两个寄存器来管理呢?难道是32位还不够配置吗?答案是:是的,不够用。配置寄存器对一个GPIO的配置要用4个位来完成。一组GPIO有16个引脚,一个引脚要4位的话,那么16个引脚就要16*4=64,那么就要2个32位的寄存器来实现,所以就干脆把高八位给一个寄存器,低八位给另外一个寄存器,这就出现了CRL和CRH。也许有人还会有疑问说为什么一定要用4位来对一个引脚的配置呢?答案是肯定的,因为前面说了,对GPIO的配置首先配置为输入模式或者输出模式,然后再对输入、输出配置为哪种输出,哪种输入,是推挽输出呢,还是开漏输入呢,这都是需要至少2个位来进行配置,而且输入、输出模式各有4种模式,共8中,这样要以最少的资源来实现的话,用00、01、10、11这种2个位来实现是最省资源的,所以2*2=4,所以对于1个GPIO的模式的配置至少也就要4位了。)
接着就是查看LED的GPIO的引脚接在IC哪个引脚上。怎么查看LED的引脚到底接在哪呢?这个要看开发板的原理图,不同的板子来说或者对于不同的商家来说在GPIO的引脚接线上会有不同,以我的开发板的原理图可以发现LED灯的GPIO分别接在了GPIOB的pin5和GPIOE的pin5上,根据电路性质,一般会将LED设置为推挽输出模式(可能这时就会有人问了,为什么就是推挽呢?为什么不是开漏呢?我的理解是:这是有电路性质决定的,推挽顾名思义就是灌电流与拉电流都可以输出,通俗地讲就是输出高低电平。而开漏是一直输出低电平,当你要输出高电平的时候需要加上拉)
通过查阅寄存器的数据手册可知,00位通用推挽模式,那么
//======================================================//
GPIOB->CRL |= 3 << 20;//设置模数数据传输速率
GPIOB->CRL &=~(3 << 22);//设置GPIO模式
//======================================================//
这样就把GPIOB组的pin5设置成了通用推挽模式,前面说了一个引脚需要4个位来配置,查看寄存器数据手册可看到,前面2个位是设置通用推挽模式的,后面2个位是基于这种模式的数据传输速率,在这里我们悬着的是“最大速度50MHz”,而GPIOB->CRL|=3<<20;就是设置数据传输速率为最大速度50MHz,GPIOB->CRL&=~(3<<22);为设置GPIOB的pin5为通用推挽模式。


最后就是设置LED的初始状态了,再说之前先说一下ODR寄存器。
ODR是一个端口输出数据寄存器,也只用了低16位。该寄存器为可读写,从该寄存器读出来的数据可以用于判断当前IO 口的输出状态。而向该寄存器写数据,则可以控制某个 IO 口的输出电平。
所以在配置LED初始化的时候就需要调用这个寄存器设置LED的初始状态。
//======================================================//
GPIOE->ODR|=1<<5;//设置LED的初始化状态为1(1为到电平,亮灭有其电路决定,我的开发板由于接了上拉,使得低电平才是有效的,即0为LED灯亮,1为LED灯灭)
//======================================================//
这样初始化函数就完成了。


具体初始化代码如下:
//=======================led.c===============================//
/**************************************************************
**为了使得程序的模块化,所以把LED的初始化代码独立写成一个源文件
**当然这样也使得需要写一个头文件进行声明,这样才能让main函数或者其他函数调用
**************************************************************/
#include "stm32f10x.h"
#include "led.h"


void led_Init(void)
{
RCC ->APB2ENR |= 1 << 3;//使能 PORTB 时钟
RCC ->APB2ENR |= 1 << 6;//使能 PORTE 时钟 

GPIOB ->CRL   |= 3 << 20;
GPIOB ->CRL   &=~ (3 << 22);//PB.5 推挽输出
GPIOB ->ODR   |= 1 << 5;//PB.5 输出高

GPIOE ->CRL   |= 3 << 20; 
GPIOE ->CRL   &= ~(3 << 22);//PE.5 推挽输出
GPIOE ->ODR   |= 1 << 5;//PE.5 输出高
}
//======================================================//


其头文件如下:
//=========================led.h=============================//
#ifndef __LED_H_
#define __LED_H_


extern void led_Init(void);


#endif
//======================================================//


接下来说一下初始化好了,主函数要怎么写。
第一需要的是点亮LED的语句,在初始化中有提到,设置LED初始化状态即:GPIOB ->ODR   |= 1 << 5;//PB.5 输出高
那么同时也能使用这句来进行LED的亮灭控制。代码如下:
//==========================main.c============================//
#include "stm32f10x.h"
#include "led.h"




int main(void)
{
int i=0;
led_Init();  //LED初始化
while(1)
{

GPIOB ->ODR   &= ~ (1 << 5);//PB.5输出低电平,即点亮LED
GPIOE ->ODR   &= ~(1 << 5); //PB.5输出低电平,即点亮LED
for(i=0;i<1000000;i++);//延时


GPIOB ->ODR   |= 1 << 5;//PE.5输出高电平,即灭掉LED
GPIOE ->ODR   |= 1 << 5;//PB.5输出高电平,即灭掉LED
for(i=0;i<1000000;i++);//延时



}
}


//======================================================//
整个跑马灯的工程就只需这三个文件,就能简单实现跑马的功能,如果你想要延时的时间是规律的,那么你就要去使用定时器了。因为定时器定时的时间是准时的,软件延时第一消耗CPU的资源,然后时间也不够精确,所以一般在对时间要求没有很精确的要求是才会使用软件延时的做法。


//=======================================================================//
注释:1、如有错误,跪谢大神出来指错。
 2、如这篇文章对您有些帮助,转载请注明出处,谢谢!
//================================================================

关键字:STM32  跑马灯 引用地址:STM32跑马灯例程总结

上一篇:STM32F10X时钟系统学习笔记
下一篇:STM32蜂鸣器实例详解

推荐阅读最新更新时间:2024-03-16 15:39

STM32学习探究:流水灯的实现
流水灯的实现 这里我们使用 stm32mini 开发板实现外接流水灯,这里我采用了三个灯(说明问题就可以了)。外接的引脚分别为PA2,PB8,PC13三个引脚,在连接的时候,采用灯的正极接GPIO引脚,负极接GND(这是一种合理的方式)。 注意:虽然接VCC也可以发光,但是这样不是合理的连接方式,而且,发光的情况刚好与接GND的情况相反。 参考的相关资料如下: 时钟使能: 端口配置: 端口输出: 具体实现的代码如下: //led.h文件 #ifndef __LED_H #define __LED_H #include sys.h //LED端口定义 #define LED0 PAout(
[单片机]
<font color='red'>STM32</font>学习探究:流水灯的实现
STM32系列第3篇--GPIO初始化
使能和初始化IO口: GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOD,
[单片机]
STM32的ADC DMA USART综合学习
学习STM32的ADC转换,在开发板上写程序调试。 四个任务: 1.AD以中断方式(单次)采集一路 2.AD以中断方式连续采集四路 3. AD 以DMA方式采集一路,DMA深度为一级 4. AD 以DMA方式采集四路,每路DMA深度为28级,并滤波,说明滤波原理。 总结: 第一个任务 :ADC以中断方式采集一路ADC,通过配置ADC_InitStructure结构体中的ADC_ScanConvMode,它规定模数转换工作在扫描模式(多通道)还是单次模式(单通道), ADC_InitStructure.ADC_ScanConvMode=DISABLE,为单通道单次模式。 ADC_ContinuousConvMode,
[单片机]
STM32 JTAG引脚做普通I/O口用
1、开启AFIO时钟: RCC_APB2PeriphClockCmd (RCC_APB2Periph_AFIO, ENABLE) 2、改变指定管脚的映射GPIO_Remap_SWJ_Disable,SWJ完全禁用(JTAG+SW-DP): GPIO_PinRemapConfig (GPIO_Remap_SWJ_Disable, ENABLE) 3、改变指定管脚的映射GPIO_Remap_SWJ_JTAGDisable,JTAG-DP禁用+SW-DP 使能: GPIO_PinRemapConfig (GPIO_Remap_SWJ_JTAGDisable, ENABLE) 注意:注意顺序,一定要先使能复用时钟,再失能JATG。
[单片机]
STM32时钟设置
3.5的库中什么也不用做。已经在启动文件中设置好了时钟。 大家都知道在使用单片机时,时钟速度决定于外部晶振或内部RC振荡电路的频率,是不可以改变的。而ARM的出现打破了这一传统的法则,可以通过软件随意改变时钟速度。这一出现让我们的设计更加灵活,但是也给我们的设计增加了复杂性。为了让用户能够更简单的使用这一功能,STM32的库函数已经为我们设计的更加简单方便。 在比较靠前的版本中,我们需要向下面那样设置时钟: ErrorStatus HSEStartUpStatus; void RCC_Configuration(void) { RCC_DeInit(); // RCC system reset
[单片机]
STM32 jtag调试程序时程序跑飞
开发环境:keil MDK V5.10 操作系统:windows 7(32位) 目标硬件:STM32F103C8 问题描述:在使用jtag对某软件进行调试的时候,KEIL可以正常的进行软件下载,一旦使用F5全速运行时,立即发现程序跑飞了,暂停后汇编代码显示“MOVS R0 R0”。程序跑飞的时候可以看到目标设备程序执行过程正常(灯正常闪烁,串口调试信息正常输出)。 问题原因:芯片的JTAG引脚被复用,在程序初始化阶段将JTAG引脚remap为了普通的IO引脚导致。 PS:在使用JTAG进行程序调试的时候,如果程序中开了看门狗,调试程序进行了单步调试的情况也可能导致JTAG无法正常使用,因为目标设备的看门狗不能因为单步执行
[单片机]
【STM32+W5500】20,W5500作为Client客户端
与DNS失败一样,只需要把W5500的默认IP改成和路由器的IP一样就可以互联网通信了 实测收到邮件
[单片机]
【STM32+W5500】20,W5500作为Client客户端
STM32低功耗唤醒方式
MCU进入低功耗之后,以极低的功耗维持着系统“活着”,但是醒过来是需要一定条件的,比如定个“闹钟”,按键“按一下”等,目前常用的“正常的”唤醒方式有以下几种: 1、RTC定时唤醒; 2、外部中断唤醒(按键或者通讯唤醒); 3、特殊唤醒引脚唤醒(某些引脚具有专门的唤醒功能)。 下面,我们再来看一看如何通过RTC和外部中断唤醒MCU。 1、RTC定时唤醒 依然是从手册中我们可以看到,所有的RTC时间都可以把MCU从低功耗模式中唤醒: 介绍使用RTC的定时功能实现,定时1S唤醒一次,使用cubemx进行对RTC进行配置: 生成代码的时候,勾选这个选项,可以把不用的引脚配置为模拟输入模式,降低功耗: RTC的配置如图,使能RTC,
[单片机]
<font color='red'>STM32</font>低功耗唤醒方式
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved