嵌入式系统及应用实验报告

实验1、流水灯

一、实验目的

        熟悉keil开发环境和实验板的使用,了解并熟悉实验板上单片机I/O口和LED灯的电路结构,掌握STM32单片机I/O口编程方法,掌握顺序控制程序的简单编程。

二、实验内容

1、实验原理

        I/O口是单片机与外界联系的通道,它可对各类外部信号(模拟量、开关量、频率信号)进行检测、判断和处理,并可控制各类外部设备。单片机通过I/O与外部世界互相感知。

        图示电路中,有L0~L7共八个发光二极管,当引脚LED_SEL输入为1,对于A~H引脚,只要输入为1,则点亮相连接的发光二极管。

        A~H引脚连接STM32F108VB芯片的PE8~PE15,程序初始化时,对其进行初始设置。引脚LED_SEL为1时,发光二极管才工作,否则右边的数码管工作。

        注意,LED_SEL连接于PB3,该引脚具有复用功能,在默认状态下,该引脚的IO不可用,需对AFIO_MAPR寄存器进行设置,设置其为IO可用。

2、实验步骤

(1)创建keil项目

        启动keil,选择Project | new uvision Project,输入项目名称“led”,系统自动追加后缀为“.uvproj”。选择存储的文件夹为d:\xxx\led(建议所有文件名都使用英文字母开头),选择芯片为STMicroelectronics公司的STM32F103VB。

(2)编写文件代码

        点击“File | new…”,生成一个空白文件,选择“File | save”保存为d:\xxx\led\led.c。后面所有的.c文件都如此操作。这是一个存储与硬件相关函数的文件,其中包含了二极管与数码管的初始化和实现;再用同样方法建立与led.c相关的led.h、delay.c、led.c、sys.c以及相应的.h文件;最后建立main.c并保存。

(3)将文件载入工程

        按“+”展开project窗口中的Target,出现Source Group,在右键弹出的菜单中选择“Add Files to Group ‘Source Group’”,控制文件对话框进入d:\xxx\led,选择stm32f10x.s,将stm32f10x.s这个启动文件以及led.c、delay.c、sys.c、usart.c、main.c依次加入到项目中去。

(4)编译调试

        单击按钮栏“Build”或“Rebuild”,对整个工程进行编译连接,观察文件夹下增加了哪些文件;如果出现了错误,则在下方的Command窗口中按照错误信息进行分析;之后可在按钮栏“Start/Stop debug session”进行调试。

(5)烧录运行

        启动MCUISP并连接STM32单片机,数据线分别连接STM32单片机上的COM口和计算机上的USB口,先搜索串口并选择对应的COM口,再选择“联机下载时的程序文件”为对应项目生成的.hex文件,最后点击“开始编程”,并先后快速且连续地按下“RESET”按键和“ISP”按键。

(6)记录实验结果并分析

        观察烧录启动后实验板上的现象并记录。

三、实验结果与分析

1、实验结果

        观察到实验板上L0、L1、L2、L3、L4、L5、L6、L7发光二极管从右至左依次点亮,间隔300ms。当L0、L1、L2、L3、L4、L5、L6、L7发光二极管全部点亮后,L0、L1、L2、L3、L4、L5、L6、L7发光二极管同时熄灭,间隔300ms后,L0、L1、L2、L3、L4、L5、L6、L7发光二极管再次从右至左依次点亮。如此反复循环。

2、实验分析

(1)引入头文件
#include "sys.h"
#include "delay.h"
#include "led.h"

        这里引入了三个头文件:

① sys.h头文件包含了STM32单片机的一些基本宏定义;

② delay.h头文件包含了延时函数的定义;

③ led.h头文件包含了LED灯控制的函数定义。

(2)系统初始化
Stm32_Clock_Init( 6 );
delay_init( 72 );
LED_Init();

        这里进行了系统初始化,包括时钟初始化、延时函数初始化和LED灯初始化。

(3)GPIO 初始化
GPIOE->ODR &= ~(0xff<<8);
LED_SEL = 1;

        这里使用了STM32单片机中的GPIOE引脚来控制LED灯的亮灭,通过设置ODR寄存器的值来实现。LED_SEL是一个宏定义,用于选择需要控制的LED灯。

(4)流水灯控制
light = 0x01;
while( 1 )
{
    GPIOE->ODR |= (light<<8);
    delay_ms( 300 );
    light = light<<1;
    if( light==0x00 )
    {
        GPIOE->ODR &= ~(0xff<<8);
        delay_ms( 300 );
        light = 0x01;
    }     
}

        这里使用了while(1)循环来不断重复控制LED灯的亮灭,实现流水灯的效果。首先将light 变量赋值为0x01,然后在循环中不断左移,即将灯光从右往左移动。当light变量左移8次(即灯光移到最左边)时,将ODR寄存器的值清零,然后重新将light变量赋值为0x01,即将灯光从左往右移动。

实验2、8位数码管动态扫描

一、实验目的

        了解8位数码管动态显示原理;掌握stm32f10x扩展端口的方法。

二、实验内容

1、实验原理

        数码管中的A~G、DP段分别连接到电路图中的A~G、H线上,当某段上有一定的电压差值时,便会点亮该段。当E3输入为1,也就是LED_SEL输入为0时,根据SEL0~SEL2的值确定选中的数码管,即位选,再根据A~H引脚的高低电平,点亮对应段,即段选。

2、实验步骤

(1)创建keil项目

        启动keil,选择Project | new uvision Project,输入项目名称“led”,系统自动追加后缀为“.uvproj”。选择存储的文件夹为d:\xxx\led(建议所有文件名都使用英文字母开头),选择芯片为STMicroelectronics公司的STM32F103VB。

(2)编写文件代码

        点击“File | new…”,生成一个空白文件,选择“File | save”保存为d:\xxx\led\led.c。后面所有的.c文件都如此操作。这是一个存储与硬件相关函数的文件,其中包含了二极管与数码管的初始化和实现;再用同样方法建立与led.c相关的led.h、delay.c、led.c、sys.c以及相应的.h文件;最后建立main.c并保存。

(3)将文件载入工程

        按“+”展开project窗口中的Target,出现Source Group,在右键弹出的菜单中选择“Add Files to Group ‘Source Group’”,控制文件对话框进入d:\xxx\led,选择stm32f10x.s,将stm32f10x.s这个启动文件以及led.c、delay.c、sys.c、usart.c、main.c依次加入到项目中去。

(4)编译调试

        单击按钮栏“Build”或“Rebuild”,对整个工程进行编译连接,观察文件夹下增加了哪些文件;如果出现了错误,则在下方的Command窗口中按照错误信息进行分析;之后可在按钮栏“Start/Stop debug session”进行调试。

(5)烧录运行

        启动MCUISP并连接STM32单片机,数据线分别连接STM32单片机上的COM口和计算机上的USB口,先搜索串口并选择对应的COM口,再选择“联机下载时的程序文件”为对应项目生成的.hex文件,最后点击“开始编程”,并先后快速且连续地按下“RESET”按键和“ISP”按键。

(6)记录实验结果并分析

        观察烧录启动后实验板上的现象并记录。

(7)修改晶振频率

        修改晶振频率,重新编译连接后再次进行观察,对两次结果加以比较,并分析由此产生的视觉效果差异。

三、实验结果与分析

1、实验结果

观察到实验板上8个数码管从左至右依次显示对应的数字,且每一个数码显示的数字在1-9之间循环。

修改晶振频率,可以通过加快扫描频率,达到一定的扫描频率时,八位数码管看上去像是在同时显示。

2、实验分析

(1)引入头文件
#include "sys.h"
#include "delay.h"
#include "led.h"

        这里引入了三个头文件:

① sys.h头文件包含了STM32单片机的一些基本宏定义;

② delay.h头文件包含了延时函数的定义;

③ led.h头文件包含了LED灯控制的函数定义。

(2)系统初始化
Stm32_Clock_Init( 6 );
delay_init( 72 );
LED_Init();
LED_SEL = 0;

        这里进行了系统初始化,包括时钟初始化、延时函数初始化和LED数码管初始化。并选择需要控制的LED数码管。

(3)数码管显示
SetLed(0, show_w1%10);
delay_ms(100);
SetLed(1, show_w2%10);
delay_ms(100);
SetLed(2, show_w3%10);
delay_ms(100);
SetLed(3, show_w4%10);
delay_ms(100);
SetLed(4, show_w5%10);
delay_ms(100);
SetLed(5, show_w6%10);
delay_ms(100);
SetLed(6, show_w7%10);
delay_ms(100);
SetLed(7, show_w8%10);
delay_ms(100);

        这里使用了SetLed()函数来将计数值显示在LED数码管上。show_w1到show_w8是计数器的计数值,%10是为了保证只显示个位数。delay_ms()函数用于控制每个数码管的显示时间间隔。

(4)计数器递增
show_w1++;
show_w2++;
show_w3++;
show_w4++;
show_w5++;
show_w6++;
show_w7++;
show_w8++;

        这里将计数器的计数值逐个递增,当达到最大值时会重新从0开始计数。

实验3、按键输入

一、实验目的

        通过本实验了解STM32F103RB硬件结构,掌握各引脚功能和接线;了解GPIO各寄存器的功能与应用,加深对按键输入检测过程的理解。

二、实验内容

1、实验原理

        本实验电路与原理与“8位数码管动态扫描”实验相同。

2、实验步骤

(1)建立Key工程,芯片选用STM32103RB,其他设置与前几个实验保持一致。拷贝参考程序清单中的代码,编译后形成可执行文件;

(2)编译链接成功后,上载到实验板,用不同的速率敲击或长按键盘按键,或者同时按下多个按键,观察LED的反转速度有什么变化;

(3)结合按键接收原理,分析上述过程;

(4)仔细阅读程序,不断修改延迟参数,找出最合适的参数设置。

三、实验结果与分析

1、实验结果

(1)敲击速率较快

        LED的反转速度变得更快;

(2)敲击速率较慢

        LED的反转速度变得更慢;

(3)长按键盘按键

        LED只会在按键松开时反转一次,不会反复反转;

(4)同时按下多个按键

        只有其中一个按键对应控制的LED反转,而其他LED不反转。

2、实验分析

        按键接收原理是通过扫描检测按键的状态来实现的。在STM32单片机中,通过轮询检测按键的状态,当按键被按下时会改变对应的IO口电平状态,从而触发中断或返回按键编号,实现按键的检测和操作。

        在实现按键控制LED灯的过程中,程序不断地扫描按键的状态,当检测到按键被按下时,程序通过按键编号来控制对应的LED灯反转。如果敲击速率较快,则按键状态会更快地改变,程序会更快地检测到按键的变化,从而更快地反转LED。如果敲击速率较慢,则程序需要等待一定的时间才能检测到按键的变化,从而反转LED的速度会变慢。

        当按键被长按时,按键的状态不会发生变化,因此只会在按键松开时触发一次LED反转。同时按下多个按键时,程序只会检测到其中一个按键的状态变化,从而只会控制对应的LED反转,而不会对其他LED产生影响。

(1)引入头文件
#include "sys.h"
#include "delay.h" 
#include "led.h"
#include "key.h"

这里引入了四个头文件:

① sys.h头文件包含了STM32单片机的一些基本宏定义;

② delay.h头文件包含了延时函数的定义;

③ led.h头文件包含了LED灯控制的函数定义;

④ key.h头文件包含了按键控制的函数定义。

(2)系统初始化
Stm32_Clock_Init(9);
delay_init(72);
LED_Init();
KEY_Init();

        这里进行了系统初始化,包括时钟初始化、延时函数初始化、LED 灯初始化和按键初始化。

(3)按键控制 LED 灯
t=KEY_Scan();
if(t)
{         
    switch(t)
    {     
        case 1:
            LED0=!LED0;
            break;
        case 2:
            LED3=!LED3;
            break;
        case 3:    
            LED7=!LED7;
            break;
    }
}

        这里使用 KEY_Scan() 函数来检测按键是否被按下,并返回按键编号。如果有按键被按下,则根据不同的按键编号控制不同的 LED 灯亮灭。LED0、LED3、LED7 分别对应不同的 LED 灯,!LEDx 表示将 LED 灯的状态取反。

(4)延时函数
else delay_ms(10);

        如果没有按键被按下,则进行 10ms 的延时。

实验4、定时器-数字钟

一、实验目的

        熟悉STM32的定时器和GPIO模块,了解定时器和GPIO的工作原理和使用方法;掌握使用定时器模块和GPIO模块实现数字时钟的方法;了解数字时钟的基本原理和设计思路。

二、实验内容

1、实验原理

        利用STM32的定时器模块来生成时钟信号,然后通过控制GPIO模块的输出来显示时间。

2、实验步骤

(1)使用STM32的定时器模块,设置定时器的时钟源、预分频器、计数器周期等参数,从而生成一个稳定的时钟信号。

(2)使用STM32的GPIO模块,将数码管的控制引脚设置为输出模式,从而能够控制数码管的亮灭。

(3)在定时器每次计数完成后,产生一个定时器中断,中断处理函数中更新时间的变量,并将时间数据转换为数码管的显示格式。

(4)使用STM32的NVIC模块,配置定时器中断的优先级和使能中断。

(5)在主函数中启动定时器,使其开始计数,并等待定时器中断的触发。

(6)在定时器中断处理函数中,根据时间变量的更新,将时间数据转换为数码管的显示格式,并将数据输出到数码管的控制引脚上,实现数字时钟的功能。

三、实验结果与分析

1、实验结果

下载程序后,8位数码管初始化为00-00-00,分别表示时-分-秒。由定时器计时,每过1秒,“秒”的显示值加1。当“秒”的显示值加到59后,再过1s,其值变为00。同时,“分”的值加1。当“分”的值加到59,再过1分钟,“分”的值变为00。同时“时”的值加1。当“时”的值为23,再过1小时后,“时”的值变为00。

2、实验分析

(1)引入头文件
#include "timer.h"

        代码中只引入了 timer.h 头文件,该头文件包含了定时器模块的函数定义。

(2)系统初始化
Stm32_Clock_Init( 6 );
delay_init( 72 );
TimerxInit( 9999,7199 );
LED_Init();
LED_SEL = 0;

        这里进行了系统初始化,包括时钟初始化、延时函数初始化、定时器初始化、LED初始化。

(3)数字时钟的实时显示
while(1)
{
    SetLed(0, hour/10);
    delay_ms(1);
    SetLed(1, hour%10);
    delay_ms(1);
    SetLed(2, 10);
    delay_ms(1);
    SetLed(3, minute/10);
    delay_ms(1);
    SetLed(4, minute%10);
    delay_ms(1);
    SetLed(5, 10);
    delay_ms(1);
    SetLed(6, second/10);
    delay_ms(1);
    SetLed(7, second%10);
    delay_ms(1);
}
① 显示小时数

        调用 SetLed() 函数将小时数的十位数转换为数码管的显示格式,并输出到第一个数码管的控制引脚上;再将小时数的个位数转换为数码管的显示格式,并输出到第二个数码管的控制引脚上。

② 显示冒号

        调用 SetLed() 函数将冒号的显示格式输出到第三个数码管的控制引脚上。

③ 显示分钟数

        调用 SetLed() 函数将分钟数的十位数转换为数码管的显示格式,并输出到第四个数码管的控制引脚上;再将分钟数的个位数转换为数码管的显示格式,并输出到第五个数码管的控制引脚上。

④ 显示冒号

        调用 SetLed() 函数将冒号的显示格式输出到第六个数码管的控制引脚上。

⑤ 显示秒数

        调用 SetLed() 函数将秒数的十位数转换为数码管的显示格式,并输出到第七个数码管的控制引脚上;再将秒数的个位数转换为数码管的显示格式,并输出到第八个数码管的控制引脚上。

⑥ 等待 1ms

        调用 delay_ms() 函数实现 1ms 的延时,以便下一次的数码管显示。

实验5、RTC实时时钟

一、实验目的

        熟悉STM32的RTC模块,了解RTC的工作原理和使用方法;掌握使用RTC模块实现实时时钟的方法;了解实时时钟的基本原理和设计思路;学习如何使用STM32的外设库函数编写实时时钟程序。

二、实验内容

1、实验原理

        RTC(Real-Time Clock)实时时钟是一种能够提供精确时间信息的电子设备,通常用于计算机、移动设备、汽车电子等需要实时时间显示和计时的场合。RTC实时时钟通常由时钟芯片、晶振、电池等组成,其工作原理如下:

(1)RTC实时时钟的核心是时钟芯片,通常由数字时钟芯片、温补晶振、时钟计数器等组成。

(2)晶振是时钟芯片的重要组成部分,用于提供时钟信号。晶振的频率越高,时钟精度越高。

(3)RTC实时时钟通常需要使用电池来提供备用电源,以便在断电或者掉电的情况下仍然能够维持时钟计时的准确性。

(4)时钟计数器是时钟芯片的另一个重要组成部分,用于记录时间信息。时钟计数器通常由秒计数器、分计数器、小时计数器、日历计数器等组成。

2、实验步骤

(1)连接电路

        将RTC实时时钟模块与数字电路实验板连接。通常需要连接VCC、GND、SCL、SDA等引脚,连接方式可以参考RTC实时时钟模块的说明书。

(2)编写程序

        使用开发工具,编写程序实现RTC实时时钟的功能,如显示当前时间、设置时间等。程序可以使用相应的库函数,也可以手动编写程序实现。

(3)烧录程序

        将编写好的程序烧录到STM32开发板中,以便实现RTC实时时钟的功能。

(4)测试程序

        测试程序是否能够正常工作,如能够正确显示当前时间、能够设置时间等。如果出现问题,需要检查硬件连接或者程序代码,进行相应的修正。

(5)调试电路

        如果RTC实时时钟模块不能正常工作,需要检查电路连接是否正确,电源是否稳定等。可以通过示波器等工具进行调试,以便找出问题所在。

(6)优化程序

        根据实际需要,可以对程序进行优化,如加入闹钟功能、加入自动校时功能等,以提高RTC实时时钟的使用价值。

三、实验结果与分析

1、实验结果

        程序下载后,有以下两种情况:

(1)芯片第一次初始化RTC,则程序将写入HEX生成的时间信息到芯片RTC时钟中,然后读出时钟信息。通过数码管显示。

(2)芯片不是第一次初始化RTC,则程序将读取RTC对应寄存器的值,以时间信息显示在数码管上。

        如果开发板上有放入3V的小电池,则即使掉电,RTC时钟依然在走。程序刚下载,数码管显示的数据为时-分-秒。K1键,则显示年月日,左边四位为年份,最右边两位为日期。其它两位为月份。K2键,数码管继续显示时-分-秒。

2、实验分析

(1)引入头文件
#include "sys.h"
#include "led.h"
#include "key.h"
#include "delay.h"
#include "rtc.h"
#include "usart.h"

        这里引入了六个头文件: sys.h、delay.h、led.h、key.h、rtc.h 和 usart.h。

(2)定义常量
const u8 *COMPILED_DATE=__DATE__;
const u8 *COMPILED_TIME=__TIME__;
const u8* Week[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

        COMPILED_DATE 和 COMPILED_TIME 分别表示代码编译的日期和时间,Week 数组表示周几的字符串。

(3)系统初始化
u8 key = 0;
Stm32_Clock_Init( 6 );
delay_init( 72 );
LED_Init();
LED_SEL = 0;
KeyInit();
RtcInit();

        包括时钟初始化、延时函数初始化、LED 灯初始化、按键初始化和 RTC 模块初始化。

(4)进入主循环并进行按键检测
while(1)
{
    key = KeyScan()
    SetLed(0,timer.hour/10);
    delay_ms(1);
    SetLed(1,timer.hour%10);
    delay_ms(1);
    SetLed(2,10);
    delay_ms(1);
    SetLed(3,timer.minute/10);
    delay_ms(1);
    SetLed(4,timer.minute%10);
    delay_ms(1);
    SetLed(5,10);
    delay_ms(1);
    SetLed(6,timer.sec/10);
    delay_ms(1);
    SetLed(7,timer.sec%10);
    delay_ms(1);
    if( key==1 )
    {
        while( key==1||key==0 )
        {
            SetLed(0,timer.year/1000);
            delay_ms(1);
            SetLed(1,timer.year%1000/100);
            delay_ms(1);
            SetLed(2,timer.year%100/10);
            delay_ms(1);
            SetLed(3,timer.year%10);
            delay_ms(1);
            SetLed(4,timer.month/10);
            delay_ms(1);
            SetLed(5,timer.month%10);
            delay_ms(1);
            SetLed(6,timer.date/10);
            delay_ms(1);
            SetLed(7,timer.date%10);
            delay_ms(1);
            key = KeyScan();
        }
    }
}

        不断读取 RTC 模块中的时间,并将其显示在数码管上。如果检测到按键按下,则进入设置日期和时间的模式,将当前的日期和时间显示在数码管上,并等待用户输入。如果检测到按键松开,则退出设置日期和时间的模式,并将设置好的日期和时间保存到 RTC 模块中。

实验6、定时器中断

一、实验目的

        初步掌握中断编程的一般原理与基本方法;掌握定时器寄存器状态配置;进一步理解STM32系列处理器的定时器资源与设置。

二、实验内容

1、实验原理

        STM32的通用定时器是一个通过可编程预分频器(PSC)驱动的16位自动装载计数器(CNT)构成。STM32的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和PWM)等。 使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32的每个通用定时器都是完全独立的,没有互相共享的任何资源。

        STM3的通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:

(1)16位向上、向下、向上/向下自动装载计数器(TIMx_CNT);

(2)16位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率分频系数为1~65535之间的任意数值;

(3)4个独立通道(TIMx_CH1~4),这些通道可以用来作为:

① 输入捕获;

② 输出比较;

③ PWM生成(边缘或中间对齐模式);

④ 单脉冲模式输出。

(4)可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用1个定时器控制另外一个定时器)的同步电路。

(5)如下事件发生时产生中断/DMA:

① 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发);

② 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数);

③ 输入捕获;

④ 输出比较;

⑤ 支持针对定位的增量(正交)编码器和霍尔传感器电路;

⑥ 触发输入作为外部时钟或者按周期的电流管理。

2、实验步骤

        创建项目至烧录运行与前几个实验操作一致,观察实验现象并记录。

三、实验结果与分析

1、实验结果

        TIM3的定时器中断控制L1的翻转,L0的翻转提示程序正在运行。

2、实验分析

(1)timer.c
① 引入头文件
#include "timer.h"
#include "led.h"

        这里头文件引入了 timer.h 和 led.h 两个头文件,其中 timer.h 头文件包含了定时器的函数定义,led.h 头文件包含了 LED 灯控制的函数定义。

② 定时器中断处理函数
void TIM3_IRQHandler(void)
{                  
    if(TIM3->SR&0X0001)
    {
        LED1=!LED1;                             
    }      
    TIM3->SR&=~(1<<0);    
}

        这里定义了定时器 TIM3 的中断处理函数 TIM3_IRQHandler。当定时器计数器计数达到设定的值时,会触发定时器中断,执行中断处理函数。在中断处理函数中,首先判断定时器中断是否为更新中断(UIF),如果是,则将 LED1 状态取反,从而实现 LED 灯闪烁的效果。然后清除定时器中断标志位,以便下次中断的触发。

③ 定时器初始化函数
void Timerx_Init(u16 arr,u16 psc)
{
    RCC->APB1ENR|=1<<1;
    TIM3->ARR=arr;
    TIM3->PSC=psc;
    TIM3->DIER|=1<<0;
    TIM3->DIER|=1<<6;
    TIM3->CR1|=0x01;
    MY_NVIC_Init(1,3,TIM3_IRQChannel,2);     
}

        这里定义了定时器初始化函数Timerx_Init,用来初始化STM32单片机的定时器TIM3。函数接受两个参数,分别是计数器的自动重装值和预分频器的分频值。首先使能定时器TIM3的时钟,然后设置计数器的自动重装值和预分频器的分频值。设置后,使能定时器更新中断和定时器溢出中断,启动定时器计数,并开启相应NVIC中断。这里设置定时器的中断优先级为2。

(2)main.c
① 引入头文件
#include "sys.h"
#include "usart.h"  
#include "delay.h" 
#include "led.h"
#include "key.h"
#include "exti.h"
#include "wdg.h"
#include "timer.h"

        这里引入了八个头文件:

(i)sys.h头文件包含了STM32单片机的一些基本宏定义;

(ii)usart.h头文件包含了串口通信的函数定义;

(iii)delay.h头文件包含了延时函数的定义;

(iv)led.h头文件包含了LED灯控制的函数定义;

(v)key.h头文件包含了按键控制的函数定义;

(vi)exti.h头文件包含了外部中断的函数定义;

(vii)wdg.h头文件包含了看门狗定时器的函数定义;

(viii)timer.h头文件包含了定时器的函数定义。

② 系统初始化
Stm32_Clock_Init(9);
delay_init(72);
uart_init(72,9600);
LED_Init();
Timerx_Init(5000,7199);

        这里进行了系统初始化,包括时钟初始化、延时函数初始化、串口通信初始化、LED 灯初始化和定时器初始化。其中,Stm32_Clock_Init() 函数用来初始化系统时钟,把系统时钟设置为 72MHz;delay_init() 函数用来初始化延时函数;uart_init() 函数用来初始化串口通信,设置波特率为 9600bps;LED_Init() 函数用来初始化 LED 灯控制的 IO 口;Timerx_Init() 函数用来初始化定时器,设置定时器的计数器和分频器的初值,这里设置定时器的时钟为 72MHz,计数器初值为 5000,分频器初值为 7199。

③ 主函数
while(1)
{
    LED0=!LED0;
    delay_ms(200);     
}

        这里进入了主函数,程序会不断地循环执行。在循环中,先将 LED0 状态取反,从而实现 LED 灯闪烁的效果。然后调用 delay_ms() 函数,延时 200ms,控制 LED 灯的亮灭时间,从而实现 LED 灯闪烁的频率。

实验7、学号移位显示

一、实验目的

        了解8位数码管动态显示原理;掌握stm32f10x扩展端口的方法;掌握控制循环移位的方法。

二、实验内容

1、实验原理

        嵌入式 STM32 学号移位显示实验的原理是利用STM32微控制器的GPIO口控制LED灯的亮灭来显示学号。具体步骤如下:

(1)将学号转换成二进制数

        在计算机中,数字一般以二进制数的形式存储和处理。因此,需要将学号转换成二进制数,以便在STM32微控制器中进行处理和显示。将学号2005010106转换成二进制数:0010 0000 0000 0101 0000 0001 0000 0001 0000 0110。

(2)将二进制数分组

        由于STM32微控制器的GPIO口数量有限,需要将二进制数分成若干组,每组包含8位二进制数。例如,将上述学号分为以下几组:0010 0000、0000 0101、0000 0001、0000 0001和0000 0110。

(3)将二进制数写入GPIO口

        将每组二进制数写入到STM32微控制器的GPIO口中,其中每一位二进制数对应一个LED灯的亮灭。例如第一组二进制数0010 0000中的第一位对应第一个LED灯,第二位对应第二个LED灯,以此类推。在STM32微控制器中,每个GPIO口都有一个编号,例如PB0表示第0个GPIO口,PB1表示第1个GPIO口,以此类推。因此,可以通过设置每个GPIO口的电平来控制每个LED灯的亮灭。

(4)实现学号的移位显示

        将每组二进制数依次写入GPIO口中,通过控制每个GPIO口的电平来控制每个LED灯的亮灭,从而实现学号的移位显示。例如,先将第一组二进制数0010 0000写入PA0PA7的GPIO口中,控制PA5为高电平,其他GPIO口为低电平,从而点亮第6个LED灯;然后将第二组二进制数0000 0101写入PA8PA15的GPIO口中,控制PA8、PA10、PA12、PA13、PA14为高电平,其他GPIO口为低电平,从而点亮第9、11、13、14、15个LED灯;依此类推,直到将所有组的二进制数都写入GPIO口中,同时为为学号预留等长度的不可见字符(0xff),完成学号的移位显示。

        需要注意的是,STM32微控制器的GPIO口需要进行初始化配置,包括设置输入输出模式、上拉下拉电阻、时钟等等。同时,由于每个GPIO口只能控制一个LED灯的亮灭,因此需要根据需要选择合适的GPIO口进行连接,以便实现学号的移位显示。

2、实验步骤        

        创建项目至烧录运行与前几个实验操作一致,观察实验现象并记录。

三、实验结果与分析

1、实验结果

学号的首个数字2从数码管右端先显示,并依次左移显示出剩下的学号,直到学号全部显示并情全部退出,往复循环。

2、实验分析

(1)引用头文件
#include "sys.h"
#include "delay.h"
#include "led.h"

        该部分引用了系统初始化、延时和LED控制相关的头文件。

(2)定义常量和变量
#define uchar unsigned char
int sel_led[8]={0,1,2,3,4,5,6,7};
int num[18]={9,9,9,9,9,9,9,9,2,0,0,5,0,1,0,1,0,6};
int i,j,k;

        该部分定义了常量和变量,其中sel_led数组表示LED的选择,num数组表示学号的每一位数字,初始值为9999999920010106。i、j、k为循环计数器。

(3)系统初始化
Stm32_Clock_Init(6);
delay_init(72);
LED_Init();
LED_SEL = 0;

        该部分对系统进行初始化,包括设置系统时钟、延时初始化和LED初始化。

(4)主程序循环
while (1) {
    for (i = 0, j = 0; j < 1000; i++, j++) {
        if (num[j % 8] == 9) {
            LedValue(0x00);
        } else {
            SetLed(sel_led[i % 8], num[j % 8]);
        }
        delay_ms(1);
    }
    num[18] = num[0];
    for (k = 0; k < 18; k++) {
        num[k] = num[k + 1];
    }
}

        该部分是主程序循环,分为两个部分:

① for循环:循环1000次,每次循环控制LED显示一个数字,控制的方式是将数字转换为二进制数,然后将每一位二进制数对应的LED灯点亮或熄灭。如果当前数字为9,则将所有LED灯熄灭。

② 数组移位:将num数组的第一个元素赋值给num数组的最后一个元素,然后将num数组中每个元素的值向前移一位,以实现学号的移位显示。

        需要注意的是,该代码中的LED控制函数SetLed和LedValue并未给出,需要根据具体的硬件电路进行实现。同时,为了实现学号的移位显示,需要将num数组的长度设置为18,其中前8个元素存放学号的后8位数字,后10个元素存放学号的前10位数字。

实验8、自由落体

一、实验目的

        熟悉keil开发环境和实验板的使用,了解并熟悉实验板上单片机I/O口和LED灯的电路结构,掌握STM32单片机I/O口编程方法,掌握顺序控制程序的简单编程,并完成自由落体运动的运动推导。

二、实验内容

1、实验原理

        I/O口是单片机与外界联系的通道,它可对各类外部信号(模拟量、开关量、频率信号)进行检测、判断和处理,并可控制各类外部设备。单片机通过I/O与外部世界互相感知。

        STM32学习板中,有L0~L7共八个发光二极管,当引脚LED_SEL输入为1,对于A~H引脚,只要输入为1,则点亮相连接的发光二极管。

        A~H引脚连接STM32F108VB芯片的PE8~PE15,程序初始化时,对其进行初始设置。引脚LED_SEL为1时,发光二极管才工作,否则右边的数码管工作。

        注意,LED_SEL连接于PB3,该引脚具有复用功能,在默认状态下,该引脚的IO不可用,需对AFIO_MAPR寄存器进行设置,设置其为IO可用。

2、实验步骤

        创建项目至烧录运行与前几个实验操作一致,观察实验现象并记录,下面给出计算距离的公式推导:

        由牛顿第二定律,物体所受合力等于物体的质量乘以加速度,即

F=ma

        在自由落体的情况下,物体所受合力只有重力,因此有

F=mg

        其中m为物体的质量,g为重力加速度。由于自由落体起始时速度为零,因此可以使用初速度为0的匀加速直线运动公式

s=\frac{1}{2}at^{2}

        计算自由落体的距离s,其中t为下落的时间。联立牛顿第二定律和匀加速直线运动公式

s=\frac{1}{2}gt^{2}

        其中g为重力加速度,t为下落的时间。

三、实验结果与分析

1、实验结果

假定小球的初始位置在L0,并按照公式计算从L0到L7以自由落体状态“下落”,然后在从L7到L0回弹,直至速度为0,如此往复。

2、实验分析

(1)引用头文件和定义变量
#include "sys.h"
#include "delay.h"
#include "led.h"
u8 light;

        该部分引用了系统初始化、延时和LED控制相关的头文件,并定义了一个变量light,用于存储LED灯的状态。

(2)系统初始化
Stm32_Clock_Init(6);
delay_init(72);
LED_Init();
GPIOE->ODR &= ~(0xff << 8);
LED_SEL = 1;

        该部分对系统进行初始化,包括设置系统时钟、延时初始化和LED初始化。同时,将GPIOE的ODR寄存器的8~15位清零,即将LED灯全部关闭。LED_SEL的值为1,表示选择两个LED灯进行移位。

③ 灯的移位
light = 0x80;
while( 1 ){
    while( 1 )
    {
        GPIOE->ODR |= (light<<8);
        delay_ms( 447 ); 
        light = light>>1;
        GPIOE->ODR &= ~(0xff<<8);

        GPIOE->ODR |= (light<<8);
        delay_ms( 185 );
        light = light>>1;
        GPIOE->ODR &= ~(0xff<<8);
  
        GPIOE->ODR |= (light<<8);
        delay_ms( 142 );
        light = light>>1;
        GPIOE->ODR &= ~(0xff<<8);

        GPIOE->ODR |= (light<<8);
        delay_ms( 120 );
        light = light>>1;
        GPIOE->ODR &= ~(0xff<<8);
  
        GPIOE->ODR |= (light<<8);
        delay_ms( 106 );
        light = light>>1;
        GPIOE->ODR &= ~(0xff<<8);
  
        GPIOE->ODR |= (light<<8);
        delay_ms( 94 );
        light = light>>1
        GPIOE->ODR &= ~(0xff<<8);
  
        GPIOE->ODR |= (light<<8);
        delay_ms( 91 );
        light = light>>1;
        GPIOE->ODR &= ~(0xff<<8);
        if( light==0x01 )
        {
            GPIOE->ODR |= (light<<8);
            delay_ms( 90 );
            light = light>>1;
            GPIOE->ODR &= ~(0xff<<8);
            delay_ms( 1 );
            light = 0x01;
            break;
        }     
    }
    while( 1 )
    {
        GPIOE->ODR |= (light<<8);
        delay_ms( 90 );
        light = light<<1;
        GPIOE->ODR &= ~(0xff<<8);
   
        GPIOE->ODR |= (light<<8);
        delay_ms( 91 );
        light = light<<1;
        GPIOE->ODR &= ~(0xff<<8);
  
        GPIOE->ODR |= (light<<8);
        delay_ms( 94 );
        light = light<<1;
        GPIOE->ODR &= ~(0xff<<8);
  
        GPIOE->ODR |= (light<<8);
        delay_ms( 106 );
        light = light<<1;
        GPIOE->ODR &= ~(0xff<<8);
  
        GPIOE->ODR |= (light<<8);
        delay_ms( 120 );
        light = light<<1;
        GPIOE->ODR &= ~(0xff<<8);
  
        GPIOE->ODR |= (light<<8);
        delay_ms( 142 );
        light = light<<1;
        GPIOE->ODR &= ~(0xff<<8);

        GPIOE->ODR |= (light<<8);
        delay_ms( 185 );
        light = light<<1;
        GPIOE->ODR &= ~(0xff<<8);
        break;
    }
}

        该部分是主程序循环,分为两个部分:

第一个while循环:控制LED灯从左往右移位,每次移位一个位置,延时时间逐渐减小。

第二个while循环:控制LED灯从右往左移位,每次移位一个位置,延时时间逐渐增加。

        需要注意的是,该代码中的LED控制函数SetLed和LedValue并未给出,需要根据具体的硬件电路进行实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有为肥宅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值