实验目的:
本实验的主要目的是探究LED流水灯的控制方式,了解单片机的内部资源和外设库的使用方法。通过实验,希望能够达到以下目标:
掌握基于标准外设库的LED流水灯程序设计方法;
学会利用单片机内部资源进行LED流水灯的控制;
掌握电路的基本连接方式,学会根据原理图进行硬件搭建;
分析实验结果,理解电路连接和程序执行的效果。
实验原理:
LED流水灯的控制原理可以通过单片机外设库和内部资源来实现。外设库提供了对单片机I/O口的操作函数,如延时、计数器、中断等。内部资源包括存储器、定时器、串口等,可以用来存储程序代码、控制LED灯珠的亮灭时间以及实现通信等功能。电路连接方面,需要将LED灯珠的正极连接到单片机I/O口,负极接地,同时串联适当的电阻以保护LED灯珠。
实验任务
以 STM32最小系统核心板(STM32F103C8T6)+面板板+3只_(或更多)红绿蓝LED 搭建电路,使用GPIOA7,GPIOB9,GPIOC15,这3个端口控制LED灯,轮流闪烁,间隔时长1秒。
1)写出工程项目创建文件夹、添加STM32标准外设库文件(.c,.h)的详细过程;
2)LED灯的亮/灭周期是通过软件循环延时完成的,其准确周期大致是多少呢?
在没有示波器条件下,可以使用Keil的软件仿真逻辑分析仪功能观察管脚的时序波形,更方便动态跟踪调试和定位代码故障点。 请用此功能观察GPIO端口的输出波形,并分析时序状态正确与否、高低电平转换周期(LED闪烁周期)实际为多少。
实验步骤
在Keil中新建工程,在一个空文件夹中创建工程,选择STM32F103C8系列单片机。
创建完成后可见看见LED文件夹下自动生成的文件
打开keil5
点击project ,new project
选择刚才新建的文件夹
再新建文件夹,用来存放本次工程
2-1 STM32工程模版
给工程文件起名
可以起具体的名字,方便识别
这里取名project
取器件型号选STM32F103C8T6
工程建好,开始填充文件
启动文件位置在arm文件中
固件库\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm\
返回工程模版文件夹,为了美观简化,新建Start文件夹
复制粘贴
stm32f10x.h
外设寄存器描述文件
system_stm32f10x.c/ system_stm32f10x.h
配置时钟
Stm32主频72mhz
文件地址
固件库\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\stm32f10x.h"
复制到新建的Start文件夹
因为内外核描述文件分开
然后添加内核寄存器描述文件
core_cm3.c/ core_cm3.h
文件地址
固件库\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\CoreSupport\core_cm3.c"
复制到Start文件夹下
回到keil,将刚才复制的文件添加到工程里来
单击Source Group 1
再单击一下,改个名字
改为Start
右键单击他,选择添加已存在文件到组里
测试是否可用
返回工程文件夹
新建User
在keil重复添加组的操作
然后右键User,Add New item
选c文件,叫main,文件路径更改到User
#include "stm32f10x.h" // Device header
int main(void)
{
while(1)
{
}
}
以上,完成了寄存器模式的使用基础。
接下来,开始添加库
打开工程文件夹,新建Library
内核库函数源文件src
其他inc
固件库\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\
复制到Library
回到keil,重复添加组操作
可ctrl+a全选
添加完后,不能直接使用,再添加文件
固件库\STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template\
添加到User下
回到keil,添加进组
还需要宏定义
从#include "stm32f10x.h"中选中stm32f10x.h,跳转
条件编译
#ifdef USE_STDPERIPH_DRIVER
#include “stm32f10x_conf.h”
#endif
复制
USE_STDPERIPH_DRIVER
打开工程选项即魔术棒,c/++,Defin 栏
粘贴USE_STDPERIPH_DRIVER
调试,点击魔术棒,选择Debug,点击选择你使用的工具
然后点击Setting
在flash Download,勾选Reset and Run
连接系统版后下载。
实验结果:
测试代码如下
#include "stm32f10x.h" // Device header
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// GPIO_SetBits(GPIOC, GPIO_Pin_13);
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
while (1)
{
}
}
实验任务
用标准外设库方式使用某个端口GPIOA7,B9,C15端口管脚控制几个LED灯,轮流闪烁,间隔时长1秒
实现代码
Main.c`#include <stdint.h>
#include <stm32f10x.h>
#include <Delay.h>
int main(void) {
// 1. 初始化GPIOA、GPIOB和GPIOC的相关寄存器,配置为输出模式
// 使能GPIOA、GPIOB和GPIOC的时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN;
// 配置GPIOA的Pin7为推挽输出模式
GPIOA->CRL &= ~(GPIO_CRL_CNF7 | GPIO_CRL_MODE7);
GPIOA->CRL |= GPIO_CRL_MODE7;
// 配置GPIOB的Pin9为推挽输出模式
GPIOB->CRH &= ~(GPIO_CRH_CNF9 | GPIO_CRH_MODE9);
GPIOB->CRH |= GPIO_CRH_MODE9;
// 配置GPIOC的Pin15为推挽输出模式
GPIOC->CRH &= ~(GPIO_CRH_CNF15 | GPIO_CRH_MODE15);
GPIOC->CRH |= GPIO_CRH_MODE15;
// 2. 循环中轮流点亮其中一个LED灯,并延时1秒
while (1) {
// 点亮GPIOA的Pin7灯
GPIOA->BSRR = GPIO_BSRR_BS7;
// 关闭GPIOB的Pin9和GPIOC的Pin13灯
GPIOB->BRR = GPIO_BRR_BR9;
GPIOC->BRR = GPIO_BRR_BR15;
Delay_ms(1000); // 延时1秒
// 点亮GPIOB的Pin9灯
GPIOB->BSRR = GPIO_BSRR_BS9;
// 关闭GPIOA的Pin7和GPIOC的Pin15灯
GPIOA->BRR = GPIO_BRR_BR7;
GPIOC->BRR = GPIO_BRR_BR15;
Delay_ms(1000); // 延时1秒
// 点亮GPIOC的Pin15灯
GPIOC->BSRR = GPIO_BSRR_BS15;
// 关闭GPIOA的Pin7和GPIOB的Pin9灯
GPIOA->BRR = GPIO_BRR_BR7;
GPIOB->BRR = GPIO_BRR_BR9;
Delay_ms(1000); // 延时1秒
}
return 0;
}`
还需要添加
Delay.c
#include "stm32f10x.h" // Device header
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// GPIO_SetBits(GPIOC, GPIO_Pin_13);
GPIO_ResetBits(GPIOC, GPIO_Pin_13);
while (1)
{
}
}
Delay.h
#ifndef __DELAY_H
#define __DELAY_H
void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);
#endif
在没有示波器条件下,可以使用Keil的软件仿真逻辑分析仪功能观察管脚的时序波形,更方便动态跟踪调试和定位代码故障点。 请用此功能观察GPIO端口的输出波形,并分析时序状态正确与否、高低电平转换周期(LED闪烁周期)实际为多少。
首先,设置options for target:
①Target页的设置:
图1:options for target ->Target
Target界面中,选择跟正确的晶振大小,我使用的是8MHz的外部晶振。这个选项在软件仿真中起到很 重要的作用,如果选择错误,那么波形一定是错误的,因为时间不准确。此前,我增加默认为72MHz, 结果波形与预料的不一致,原本是1s翻转一次的波形,显示出来的周期比预想的长得多。不过这个参数 只是在软件仿真中起作用,当程序在硬件中运行并没有影响。
②Debug页的设置:
图2:options for target -> Debug
首先应该选择Use Simulator,其次是Run to main()选项打钩,然后分别修改上图中的 3 、4、5 、6, 注意, 3和5在STM32的单片机中应该都是固定的,但是4和6是跟你所采用的具体某一款单片机是对应
的。 4和6应该是图1中STMicroelectronics 保持一致。
按照以上步骤设置后点击OK,完成设置。
2、点击Debug,进入调试界面,选择逻辑分析仪,选择要观察的引脚,选择的两个引脚分别是PA7,PB9,就要在文中打出PORTA.7 ,PORTB.9。
3、运行程序,观察波形,把光标移动到逻辑分析仪显示波形的区域,上下滚动滑轮,就可以放大和缩小波形。注意,波形出现需要时间,请耐心等待。
由图中可
18.00863
22.99279
软件延时一秒约为
0.003168
实验总结:
通过使用STM32最小系统核心板和3个LED灯,利用GPIOA7、GPIOB9和GPIOC15控制LED灯的轮流闪烁,间隔时长为1秒。LED灯的亮/灭周期是通过软件循环延时函数Delay_ms(1000)来实现的。
在实验过程中,使用了Keil的软件仿真逻辑分析仪功能观察了波形,并测试了准确周期。经过测量,从18.00863秒开始经过5秒延时后到达22.99279秒。
通过这次实验,我不仅学习了如何搭建电路并控制LED灯的闪烁,还了解了软件循环延时函数的应用和Keil的仿真功能的使用方法。这些知识将有助于我在以后的嵌入式系统开发中更好地理解和应用。