《STM32开发指南》第六章 跑马灯实验
- 格式:pdf
- 大小:870.35 KB
- 文档页数:10
跑马灯实验1 实验目的(1) 了解通用IO口的输出类型和初始化过程,学会对GPIO库函数的使用;(2) 掌握基本IO口的使用;(3) 利用GPIO函数和延时函数实现对LED灯的交替闪烁,实现类似跑马灯的效果。
2 实验任务(1) 编写程序,实现对LED1~LED8的轮流点亮;(2) 仿真调试,调整延时时间,利用仿真示波器观察延时时间长短;(3) 下载程序,观察跑马灯运行状况。
3 实验说明本实验将要实现的是控制实训平台上的8个LED灯实现一个类似跑马灯的效果,LED通过控制IO口的高低电平工作,因此实验的关键在于如何控制STM32的IO口输出。
4预习要求(1) 初始化IO口包括哪些基础设置。
(2)GPIO的输入输出模式。
5 实验步骤(1) 在实训平台上将IO口与LED(LED1~LED8)连接;(2) 复制工程模板文件夹,新建led.c和led.h文件,并将新建文件加入工程中;(3) 编写led.h文件,声明void LED_Init(void)初始化函数,宏定义LED1~LED8;(4) 编写led.c文件,建立void LED_Init(void)初始化函数,实现对LED灯用到的IO端口的配置,配置为推挽输出,速度为50MHZ;(5) 编写main()函数,实现对LED1~LED8的轮流点亮;(6) 软件仿真,调整延时时间,利用仿真示波器观察延时时间长短;(7) 下载程序,观察跑马灯的运行状况。
硬件设计本实验用到的硬件只有LED(LED1 ~ LED8)。
电路实训平台上默认是未连接好的,所以在硬件上需要根据自己的需要将其与MCU进行连接。
注意:LED的硬件为共阳极连接,需将IO口连接端置为低电平才能点亮。
LED模块原理图如4.1所示:图4.1 LED模块原理图软件设计(1) 新建文件,命名为跑马灯实验。
复制粘贴之前的Template工程。
图4.2 跑马灯实验文件(2) 新建LED文件。
在跑马灯实验文件夹下面新建一个HARDWARE的文件夹,用来存储与硬件相关的代码,然后在HARDWARE文件夹下新建一个LED 文件夹,用来存放与LED相关的代码,如图4.3所示。
6.1 STM32 IO简介本章将要实现的是控制ALIENTEK战舰STM32开发板上的两个LED实现一个类似跑马灯的效果,该实验的关键在于如何控制STM32的IO口输出。
了解了STM32的IO口如何输出的,就可以实现跑马灯了。
通过这一章的学习,你将初步掌握STM32基本IO口的使用,而这是迈向STM32的第一步。
这一章节因为是第一个实验章节,所以我们在这一章将讲解一些知识为后面的实验做铺垫。
为了小节标号与后面实验章节一样,这里我们不另起一节来讲。
在讲解STM32的GPIO之前,首先打开我们光盘的第一个固件库版本实验工程跑马灯实验工程(光盘目录为:“4,程序源码\标准例程-V3.5库函数版本\实验1跑马灯/USER/LED.Uv2”),可以看到我们的实验工程目录:图6.1.1 跑马灯实验目录结构接下来我们逐一讲解一下我们的工程目录下面的组以及重要文件。
①组FWLib下面存放的是ST官方提供的固件库函数,里面的函数我们可以根据需要添加和删除,但是一定要注意在头文件stm32f10x_conf.h文件中注释掉删除的源文件对应的头文件,这里面的文件内容用户不需要修改。
②组CORE下面存放的是固件库必须的核心文件和启动文件。
这里面的文件用户不需要修改。
③组SYSTEM是ALIENTEK提供的共用代码,这些代码的作用和讲解在第五章都有讲解,大家可以翻过去看下。
④组HARDWARE下面存放的是每个实验的外设驱动代码,他的实现是通过调用FWLib下面的固件库文件实现的,比如led.c里面调用stm32f10x_gpio.c里面的函数对led进行初始化,这里面的函数是讲解的重点。
后面的实验中可以看到会引入多个源文件。
⑤组USER下面存放的主要是用户代码。
但是system_stm32f10x.c文件用户不需要修改,同时stm32f10x_it.c里面存放的是中断服务函数,这两个文件的作用在3.1节有讲解,大家可以翻过去看看。
6.1 STM32IO简介本章将要实现的是控制A LIENT EK战舰S TM32开发板上的两个LED实现一个类似跑马灯的效果,该实验的关键在于如何控制STM32的IO口输出。
了解了STM32的IO口如何输出的,就可以实现跑马灯了。
通过这一章的学习,你将初步掌握S TM32基本IO口的使用,而这是迈向S TM32的第一步。
这一章节因为是第一个实验章节,所以我们在这一章将讲解一些知识为后面的实验做铺垫。
为了小节标号与后面实验章节一样,这里我们不另起一节来讲。
在讲解STM32的GP IO之前,首先打开我们光盘的第一个固件库版本实验工程跑马灯实验工程(光盘目录为:“4,程序源码\标准例程-V3.5库函数版本\实验1跑马灯/U SER/LED.Uv2”),可以看到我们的实验工程目录:图6.1.1 跑马灯实验目录结构接下来我们逐一讲解一下我们的工程目录下面的组以及重要文件。
①组FWLib下面存放的是ST官方提供的固件库函数,里面的函数我们可以根据需要添加和删除,但是一定要注意在头文件s tm32f10x_conf.h文件中注释掉删除的源文件对应的头文件,这里面的文件内容用户不需要修改。
②组CORE下面存放的是固件库必须的核心文件和启动文件。
这里面的文件用户不需要修改。
③组SYSTEM是ALI ENTEK提供的共用代码,这些代码的作用和讲解在第五章都有讲解,大家可以翻过去看下。
④组HARDWARE下面存放的是每个实验的外设驱动代码,他的实现是通过调用FWLib下面的固件库文件实现的,比如led.c里面调用s tm32f10x_g pio.c里面的函数对led进行初始化,这里面的函数是讲解的重点。
后面的实验中可以看到会引入多个源文件。
可编辑修改精选全文完整版实验一跑马灯实验一、实验内容1、基本的流水灯根据图1电路,编写一段程序,使8个发光二极管D1、D2、D3、D4、D5、D6、D7、D8顺序(正序)点亮:先点亮D1,再点亮D2、D3……D8、D1……,循环点亮。
每点亮一个LED,采用软件延时一段时间。
2、简单键控的流水灯不按键,按正序点亮流水灯;按下K1不松手,按倒序点亮流水灯,即先点亮D8,再顺序点亮D7、D6……D1、D8……。
松手后,又按正序点亮流水灯。
3、键控的流水灯上电,不点亮LED,按一下K1键,按正序点亮流水灯。
按一下K2键,按倒序点亮流水灯,按一下K3键,全部关闭LED。
二、实验方案1、总体方案设计考虑到K4键未被使用,所以将实验内容中的三项合并到一个主函数中:K4键代替实验内容第二项中的K1键;单片机一开机即执行实验内容第一项;K1、K2、K3键实现实验内容第三项。
所用硬件:AT89C52、BUTTON、LED-BLUE、电源输入:P2.0-K1;P2.1-K2;P2.2-K3;P2.3-K4。
低电平有效输出:P0.0~P0.7-D0~D7。
LED组连线采用共阳极,低电平有效软件设计:软件延时采用延时函数delay(t),可调整延迟时间:void delay(uint t){uint i;while(t--)for(i=0;i<1000;i++){if(P2!=oldK&&P2!=K[0])break;//按下了其他键退出循环}}由于涉及到按键变化所以要设置一个变量oldK保留按键键值,要在延时程序中检测是否按键,当按键后立即设置oldK的值。
按键判断采用在while循环中利用条件语句判断P2的值然后执行该键对应的代码段,达到相应的响应。
为了让K4键的效果优化,即状态变化从当前已亮灯开始顺序点亮或逆序点亮,利用全局变量n来记录灯号,利用算法即可实现。
主要算法:1、全局变量的定义:uchar D[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0X7f};//单个LED亮uchar AllOff=0xff;//LED全灭uchar AllOn=0x00;//LED全亮uchar K[]={0xff,0xfe,0xfd,0xfb,0xf7};//按键开关uchar oldK;//记录已按键int n;2、顺序、逆序点亮流水灯:void forward(){for(n=0;n<=7;n++){out=D[n];delay(15);if(P2!=oldK&&P2!=K[0])break;}out=AllOff;}void backward(){for(n=7;n>=0;n--){out=D[n];delay(15);if(P2!=oldK&&P2!=K[0])break;}out=AllOff;}3、实验内容第二项流水灯灯亮顺序变换:void hold(){n=8;while(1){if(P2==K[4]){//一直按着K4键,逆序点亮跑马灯oldK=K[4];if(n==-1)n=7; //D0灯亮后点亮D7while(n>=0){out=D[n];n--;if(delay4(15))break;}}if(P2==K[0]){//未按下K4键,一直正序点亮跑马灯oldK=K[0];if(n==8)n=0;//D7灯亮后点亮D0while(n<=7){out=D[n];n++;if(delay4(15))break;}}if(P2!=K[4]&&P2!=K[0]){//按下了其他键,退出hold函数break;}}}4、对应实验内容第一项,开机顺序点亮流水灯:while(1){//开机即正序点亮流水灯forward();if(P2!=K[0]){break;}}2、实验原理图图2-1 实验原理图3、程序流程图图2-2 程序流程图三、源程序#include"reg51.h"#define uchar unsigned char#define uint unsigned int#define out P0uchar D[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0X7f};//单个LED亮uchar AllOff=0xff;//LED全灭uchar AllOn=0x00;//LED全亮uchar K[]={0xff,0xfe,0xfd,0xfb,0xf7};//按键开关uchar oldK;//记录已按键int n;//记录当前亮的灯号void delay(uint t){uint i;while(t--)for(i=0;i<1000;i++){if(P2!=oldK&&P2!=K[0])break;//按下了其他键退出循环}}void delay10ms(){uint i;for(i=0;i<10000;i++);}void forward(){for(n=0;n<=7;n++){out=D[n];delay(15);if(P2!=oldK&&P2!=K[0])break;}out=AllOff;}void backward(){for(n=7;n>=0;n--){out=D[n];delay(15);if(P2!=oldK&&P2!=K[0])break;}out=AllOff;}int delay4(uint t){uint i;while(t--)for(i=0;i<1000;i++){if(P2!=oldK){ //按键变化退出循环return 1;}}return 0;}void hold(){n=8;while(1){if(P2==K[4]){//一直按着K4键,逆序点亮跑马灯oldK=K[4];if(n==-1)n=7; //D0灯亮后点亮D7while(n>=0){n--;if(delay4(15))break;}}if(P2==K[0]){//未按下K4键,一直正序点亮跑马灯oldK=K[0];if(n==8)n=0;//D7灯亮后点亮D0while(n<=7){out=D[n];n++;if(delay4(15))break;}}if(P2!=K[4]&&P2!=K[0]){//按下了其他键,退出hold函数break;}}}void main(){oldK=K[0];while(1){//开机即正序点亮流水灯forward();if(P2!=K[0]){break;}}while(1){out=AllOff;if((P2&0x0f)!=0x0f){//检测有键按下delay10ms();//延时10ms再去检测//P2.0_K1键按下正序点亮流水灯if(P2==K[1]){oldK=K[1];while(1){forward();if(P2!=K[1]&&P2!=K[0]){//按下了其他键,退出break;}}}//P2.1_K2键按下逆序点亮流水灯if(P2==K[2]){while(1){backward();if(P2!=K[2]&&P2!=K[0]){//按下了其他键,退出break;}}}//P2.2_K3键按下关闭全部LEDif(P2==K[3]){oldK=K[3];out=AllOff;}//P2.3_K4键按下长按逆序点亮流水灯,不按正序点亮流水灯,直到其他键按下停止if(P2==K[4]){hold();}}}}四、实验结果1、基本的流水灯:开机后即重复顺序点亮流水灯,等待其他按键。
微控制器综合设计与实训实验名称:实验三跑马灯实验实验三:跑马灯实验1 实训任务(1) 编写程序,实现对LED1~LED8的轮流点亮;(2) 仿真调试,调整延时时间,利用仿真示波器观察延时时间长短;(3) 下载程序,观察跑马灯运行状况。
1.1 实验说明本实验将要实现的是控制实训平台上的8个LED灯实现一个类似跑马灯的效果,LED通过控制IO口的高低电平工作,因此实验的关键在于如何控制STM32的IO口输出。
1.2 实验步骤(1) 在实训平台上将IO口与LED(LED1~LED8)连接;(2) 复制工程模板文件夹,新建led.c和led.h文件,并将新建文件加入工程中;(3) 编写led.h文件,声明void LED_Init(void)初始化函数,宏定义LED1~LED8;(4) 编写led.c文件,建立void LED_Init(void)初始化函数,实现对LED灯用到的IO端口的配置,配置为推挽输出,速度为50MHZ;(5) 编写main()函数,实现对LED1~LED8的轮流点亮;(6) 软件仿真,调整延时时间,利用仿真示波器观察延时时间长短;(7) 下载程序,观察跑马灯的运行状况。
2 程序设计2.1 通过数组实现流水灯:2.2 通过宏定义实现流水灯:2.3 通过函数实现流水灯:2.4 通过SYSTICK中断实现流水灯:3硬件原理图设计4 总结通过数组实现流水灯:通过宏定义实现流水灯:通过函数实现流水灯:通过SYSTICK中断实现流水灯:实验心得:本次实验通过四种方法来实现流水灯,分别是通过数组实现流水灯,通过宏定义实现流水灯,通过函数实现流水灯,通过SYSTICK中断实现流水灯。
让我体会到单片机代码的多样性及强大的拓展功能。
MCU通过控制IO口的高低电平来直接控制LED的亮灭,所以本实验的关键是如何控制STM32的IO口输出,来达到我们想要的效果。
就比如灯光秀。
第六章跑马灯实验STM32最简单的外设莫过于IO口的高低电平控制了,本章将通过一个经典的跑马灯程序,带大家开启STM32之旅,通过本章的学习,你将了解到STM32的IO口作为输出使用的方法。
在本章中,我们将通过代码控制ALIENTEK战舰STM32开发板上的两个LED:DS0和DS1交替闪烁,实现类似跑马灯的效果。
本章分为如下四个小节:6.1,STM32 IO口简介6.2,硬件设计6.3,软件设计6.4,仿真与下载6.1 STM32 IO简介本章将要实现的是控制ALIENTEK战舰STM32开发板上的两个LED实现一个类似跑马灯的效果,该实验的关键在于如何控制STM32的IO口输出。
了解了STM32的IO口如何输出的,就可以实现跑马灯了。
通过这一章的学习,你将初步掌握STM32基本IO口的使用,而这是迈向STM32的第一步。
STM32的IO口可以由软件配置成如下8种模式:1、输入浮空2、输入上拉3、输入下拉4、模拟输入5、开漏输出6、推挽输出7、推挽式复用功能8、开漏复用功能每个IO口可以自由编程,但IO口寄存器必须要按32位字被访问。
STM32的很多IO口都是5V兼容的,这些IO口在与5V电平的外设连接的时候很有优势,具体哪些IO口是5V兼容的,可以从该芯片的数据手册管脚描述章节查到(I/O Level标FT的就是5V电平兼容的)。
STM32的每个IO端口都有7个寄存器来控制。
他们分别是:配置模式的2个32位的端口配置寄存器CRL和CRH;2个32位的数据寄存器IDR和ODR;1个32位的置位/复位寄存器BSRR;一个16位的复位寄存器BRR;1个32位的锁存寄存器LCKR;这里我们仅介绍常用的几个寄存器,我们常用的IO端口寄存器只有4个:CRL、CRH、IDR、ODR。
CRL和CRH控制着每个IO口的模式及输出速率。
STM32的IO口位配置表如表6.1.1所示:表6.1.1 STM32的IO口位配置表STM32输出模式配置如表6.1.2所示:表6.1.2 STM32输出模式配置表接下来我们看看端口低配置寄存器CRL的描述,如图6.1.1所示:图6.1.1 端口低配置寄存器CRL各位描述该寄存器的复位值为0X4444 4444,从图6.1.1可以看到,复位值其实就是配置端口为浮空输入模式。
从上图还可以得出:STM32的CRL控制着每组IO端口(A~G)的低8位的模式。
每个IO端口的位占用CRL的4个位,高两位为CNF,低两位为MODE。
这里我们可以记住几个常用的配置,比如0X0表示模拟输入模式(ADC用)、0X3表示推挽输出模式(做输出口用,50M速率)、0X8表示上/下拉输入模式(做输入口用)、0XB表示复用输出(使用IO口的第二功能,50M速率)。
CRH的作用和CRL完全一样,只是CRL控制的是低8位输出口,而CRH控制的是高8位输出口。
这里我们对CRH就不做详细介绍了。
给个实例,比如我们要设置PORTC的11位为上拉输入,12位为推挽输出。
代码如下:GPIOC->CRH&=0XFFF00FFF;//清掉这2个位原来的设置,同时也不影响其他位的设置GPIOC->CRH|=0X00038000; //PC11输入,PC12输出GPIOC->ODR=1<<11; //PC11上拉通过这3句话的配置,我们就设置了PC11为上拉输入,PC12为推挽输出。
IDR是一个端口输入数据寄存器,只用了低16位。
该寄存器为只读寄存器,并且只能以16位的形式读出。
该寄存器各位的描述如图6.1.2所示:图6.1.2 端口输入数据寄存器IDR各位描述要想知道某个IO口的状态,你只要读这个寄存器,再看某个位的状态就可以了。
使用起来是比较简单的。
ODR是一个端口输出数据寄存器,也只用了低16位。
该寄存器为可读写,从该寄存器读出来的数据可以用于判断当前IO口的输出状态。
而向该寄存器写数据,则可以控制某个IO口的输出电平。
该寄存器的各位描述如图6.1.3所示:图6.1.3 端口输出数据寄存器ODR各位描述了解了这几个寄存器,我们就可以开始跑马灯实验的真正设计了。
关于IO口更详细的介绍,请参考《STM32参考手册》第105页8.1节。
在此,我们可以总结一下,对于学过A VR的人来说,我们都知道A VR的IO口由3个寄存器控制:DDR、PORT、PIN。
这里我们可以拿STM32的IO控制寄存器和A VR的来个类比:1、STM32的CRL和CRH就相当于AVR的DDR寄存器,用来控制IO口的方向,只不过STM32的CRL和CRH功能更强大一点罢了。
2、STM32的ODR就相当于A VR的PORT,都是用来控制IO口的输出电平或者上下拉电阻的。
3、STM32的IDR就相当于A VR的PIN,都是用来存储IO口当前的输入状态(高低电平)的。
除此之外,STM32还有BSRR、BRR、LCKR等几个寄存器用于控制IO口,这点是A VR 所没有的。
6.2 硬件设计本章用到的硬件只有LED(DS0和DS1)。
其电路在ALIENTEK战舰STM32开发板上默认是已经连接好了的。
DS0接PB5,DS1接PE5。
所以在硬件上不需要动任何东西。
其连接原理图如图6.2.1下:图6.2.1 LED与STM32连接原理图6.3 软件设计首先,找到之前3.2节新建的TEST工程,在该文件夹下面新建一个HARDWARE的文件夹,用来存储以后与硬件相关的代码。
然后在HARDW ARE文件夹下新建一个LED文件夹,用来存放与LED相关的代码。
如图6.3.1所示:图6.3.1 新建HARDW ARE文件夹然后我们打开USER文件夹下的TEST.Uv2工程,按按钮新建一个文件,然后保存在HARDW ARE->LED文件夹下面,保存为led.c。
在该文件中输入如下代码:#include "led.h"//初始化PB5和PE5为输出口.并使能这两个口的时钟//LED IO初始化void LED_Init(void){RCC->APB2ENR|=1<<3; //使能PORTB时钟RCC->APB2ENR|=1<<6; //使能PORTE时钟GPIOB->CRL&=0XFF0FFFFF;GPIOB->CRL|=0X00300000;//PB.5 推挽输出GPIOB->ODR|=1<<5; //PB.5 输出高GPIOE->CRL&=0XFF0FFFFF;GPIOE->CRL|=0X00300000;//PE.5推挽输出GPIOE->ODR|=1<<5; //PE.5输出高}该代码里面就包含了一个函数void LED_Init(void),该函数的功能就是用来实现配置PB5和PE5为推挽输出。
这里需要注意的是:在配置STM32外设的时候,任何时候都要先使能该外设的时钟!APB2ENR是APB2总线上的外设时钟使能寄存器,其各位的描述如图6.3.2所示:图6.3.2 寄存器APB2ENR各位描述我们要使能的PORTB和PORTE的时钟使能位,分别在bit3和bit6,只要将这两位置1就可以使能PORTA和PORTD的时钟了。
该寄存器还包括了很多其他外设的时钟使能。
大家在以后会慢慢使用到的。
关于这个寄存器的详细说明在《STM32参考手册》的第70页。
在设置完时钟之后就是配置完时钟之后,LED_Init配置了PB5和PE5的模式为推挽输出,并且默认输出1。
这样就完成了对这两个IO口的初始化。
保存led.c代码,然后我们按同样的方法,新建一个led.h文件,也保存在LED文件夹下面。
在led.h中输入如下代码:#ifndef __LED_H#define __LED_H#include "sys.h"//LED端口定义#define LED0 PBout(5)// DS0#define LED1 PEout(5)// DS1void LED_Init(void);//初始化#endif这段代码里面最关键就是2个宏定义:#define LED0 PBout(5)// DS0#define LED1 PEout(5)// DS1这里使用的是位带操作来实现操作某个IO口的1个位的,关于位带操作前面已经有介绍,这里不再多说。
需要说明的是,这里可以使用另外一种操作方式实现。
如下:#define LED0 (1<<5) //led0 PB5#define LED1 (1<<5) //led1 PE5#define LED0_SET(x) GPIOB->ODR=(GPIOB->ODR&~LED0)|(x ? LED0:0)#define LED1_SET(x) GPIOE->ODR=(GPIOE->ODR&~LED1)|(x ? LED1:0)后者通过LED0_SET(0)和LED0_SET(1)来控制PB5的输出0和1。
而前者的类似操作为:LED0=0和LED0=1。
显然前者简单很多,从而可以看出位带操作带来的好处。
以后像这样的IO口操作,我们都使用位带操作来实现,而不使用第二种方法。
将led.h也保存一下。
接着,我们在Manage Components管理里面新建一个HARDWARE 的组,并把led.c加入到这个组里面,如图6.3.3所示:图6.3.3 给工程新增HARDW ARE组单击OK,回到工程,然后你会发现在Project Workspace里面多了一个HARDW ARE的组,在改组下面有一个led.c的文件。
如图6.3.4所示:图6.3.4新增HARDW ARE组然后用之前介绍的方法(在3.2节介绍的)将led.h头文件的路径加入到工程里面。
回到主界面,在main函数里面编写如下代码:#include "sys.h"#include "usart.h"#include "delay.h"#include "led.h"//ALIENTEK战舰STM32开发板实验1//跑马灯实验int main(void){Stm32_Clock_Init(9);//系统时钟设置delay_init(72); //延时初始化LED_Init(); //初始化与LED连接的硬件接口while(1){LED0=0;LED1=1;delay_ms(300);LED0=1;LED1=0;delay_ms(300);}}代码包含了#include "led.h"这句,使得LED0、LED1、LED_Init等能在main函数里被调用。