基本定时器
一、实验目的
1.cubemx工程配置,
2定时器用户代码实现
二、实验内容
利用基本定时完成1s延时,并打印相关内容的输出
三、实验原理及说明
STM32F1 的通用定时器是一个通过可编程预分频器(PSC)驱动的 16 位自动装载计数器(CNT)构成。STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32 的每个通用定时器都是完全独立的,没有互相共享的任何资源。
STM3F1 的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5)定时器功能包括:
1)16 位向上、向下、向上/向下自动装载计数器(TIMx_CNT)。
2)16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~65535 之间的任意数值。
3)4 个独立通道(TIMx_CH1~4),这些通道可以用来作为:
A.输入捕获
B.输出比较
C.PWM 生成(边缘或中间对齐模式)
D.单脉冲模式输出
4)可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外一个定时器)的同步电路。
5)如下事件发生时产生中断/DMA:
A.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
C.输入捕获
D.输出比较
E.支持针对定位的增量(正交)编码器和霍尔传感器电路
F.触发输入作为外部时钟或者按周期的电流管理
四、实验设备
一套STM32实验设备、头歌实践教学平台。
五、实验步骤
1.1 双击打开软件 stm32cubemx。

1.2 开始创建工程,本次实训采用的开发板MCU型号为STM32F103C8T6,所以直接根据MCU配置工程,打开软件后选择 access to mcu selector。

1.3 搜索芯片STM32F103C8T6,并选择芯片型号 STM32F103C8T6 ,并点击“start project”创建工程。

1.4 芯片选择完成后,进入配置界面,配置分为如下几类:
a) System Core 用于配置MCU核心功能,如时钟,中断,调试接口等;
b) Analog 用于配置MCU的ADC功能;
c) Timers 用于配置MCU的定时器;
d) Connectivity 用于配置MCU外设接口,如SPI,USART,CAN等;
e) Computing 用于配置MCU的CRC校验
f) Middleware 用于配置MCU的中间件,如文件系统,实时操作系统等; 学院可以根据实际需要,选择相应的功能配置,过程如下: 展开“system core”标签,找到“SYS"选项,在右边选择如图所示配置调试接口为JTAG 5脚接口,如果是其他接口,按照需要选择,配置完成后,右边的MCU预览图相应管脚会显示为绿色。

1.5 切换到”RCC“标签,配置系统时钟,本实验用到的开发板主时钟使用8MHz晶振,备份域时钟使用32.768kHz时钟,分别接在MCU的相应引脚上,所以在配置的时候HSE(高速外部时钟)选择使用外部晶振(crystal),LSE(低速外部时钟)选择使用外部晶振(crystal),具体如图所示。

1.6 切换到“Connectivity”标签,在实验过程中需要使用串口打印信息,所以需要配置串口功能,此处选择USART1,配置为异步通信,其他参数(奇偶校验,波特率等)使用默认即可,按照如图所示配置“USART1”。

到此,MCU核心功能的相关配置完成,接下来配置用户代码部分。
用户代码目前用到的主要是针对基本输入输出端口的配置,主要如下:
a) GPIO_Input 配置为输入端口,同时可选择上拉或者下拉,用于获取IO电平
b) GPIO_Output 配置为输出端口,同时可选择上拉或者下拉,用于输出高低电平
c) GPIO_Analog 配置为模拟功能,主要用于ADC采集使用
d) GPIO_EXIT 配置为外部中断模式,同时可选择上拉或者下拉
1.7 鼠标定位到右侧MCU引脚图,选择PB12和PB13引脚,单击相应引脚,开发板的按键连接到此IO引脚,故将其配置成输入,同时使用中断方法检测按键,故需要使能外部中断,为了同时检测上升沿与下降沿,需要选择GPIO mode为“Rising/Falling Edge”,具体如图所示配置:

1.8 切换到“System Core”的“GPIO”标签,找到刚才配置的GPIO引脚PB12,按如图所示配置名称和引脚,名称输入“KEY2”,相当于在生成的工程项目中为此IO口添加宏定义,便于程序阅读和维护。

按照同样的方法配置PB13引脚,最后如图所示

以上为按键部分的配置,接下来添加LED部分的配置,LED输出电平控制LED的亮灭,所以需要配置为输出模式,同时从原理图知道,每个LED都自带上拉电阻,所以不需要再使用内部上拉或者下拉,为了同时能输出高低电平,需要配置为推挽输出,即“push pull”,为了保证默认状态下LED为熄灭状态,设置“GPIO Output level”为“High",具体如图所示:
以下为定时器配置

定时器模式配置部分说明,如下所示:
Slave Mode:用于使能主从模式,本次不需要
Triger Source:用于设置触发源,本次不需要
Clock Source:用于设置定时器时钟源,此处设置为内部时钟源
Channel1~4:用于设置定时器捕获与输出通道,本次不需要
Combined Channels:设置混合功能,如互补PWM输出
定时器参数设置说明,如下所示:
Prescaler (PSC - 16 bits value):设置时钟分频
Counter Mode:设置计数模式(向上,向下,中间)
Counter Period:定时周期
Internal Clock division:设置内部时钟分频
Auto-Reload:自动重装载使能设置
后面为定时器触发相关设置,本次用不到;
1.9 切换到“System Core”的“NVIC”标签,由于需要使用外部中断,所以要使能中断,并配置中断优先级,中断优先级使用默认就可以,找到外部中断,并使能,其他中断相关配置可以先不用理会,后续使用到了会详细说明,同时使能定时器TIM2中断,配置如图所示

1.10 切换到 “Clock configuration”,结合HSE(高速外部时钟)和LSE(低速外部时钟),设置MCU系统时钟为72MHz,GPIO时钟使用APB2的时钟,时钟部分将在后续章节讲解,目前按如下配置。

以上为用户代码部分的配置,由于本次实验只用到了GPIO口相关的操作,所以只需要配置GPIO口相关的部分,以下为串口相关的配置。
本课程所有的实验据使用stm32cubeIDE编译,由于该集成开发环境不带有串口输出功能,所以为了实现串口输出,需要将串口重映射到之前配置的“USART1”,以下为串口重映射相关的操作,具体会在串口相关章节讲解。
1.11 配置工程并生成代码,输入工程名称“project",具体如图所示。

切换到”code generator“标签,按如图所示生成代码。

1.12 打开STM32CubeIDE,打开之前生成的工程。
点击”File--> open project from file system......”。

1.13 找到生成文件的文件夹,并打开

1.14 按下右边的标签“MX",即可显示项目文件。

1.15 为项目添加一个C语言源文件,命名为“retarget.c”,如图所示

在文件中添加如下代码:
#include "retarget.h"
#include <_ansi.h>
#include <_syslist.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/times.h>
#include "retarget.h"
#include <stdint.h>
//#include "usart.h"
#if !defined(OS_USE_SEMIHOSTING)
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
UART_HandleTypeDef *gHuart;
void RetargetInit(UART_HandleTypeDef *huart)
{
gHuart = huart;
/* Disable I/O buffering for STDOUT stream, so that
* chars are sent out as soon as they are printed. */
setvbuf(stdout, NULL, _IONBF, 0);
}
int _isatty(int fd)
{
if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
return 1;
errno = EBADF;
return 0;
}
int _write(int fd, char *ptr, int len)
{
HAL_StatusTypeDef hstatus;
if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
{
hstatus = HAL_UART_Transmit(gHuart, (uint8_t *) ptr, len, HAL_MAX_DELAY);
if (hstatus == HAL_OK)
return len;
else
return EIO;
}
errno = EBADF;
return -1;
}
int _close(int fd)
{
if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
return 0;
errno = EBADF;
return -1;
}
int _lseek(int fd, int ptr, int dir)
{
(void) fd;
(void) ptr;
(void) dir;
errno = EBADF;
return -1;
}
int _read(int fd, char *ptr, int len)
{
HAL_StatusTypeDef hstatus;
if (fd == STDIN_FILENO)
{
hstatus = HAL_UART_Receive(gHuart, (uint8_t *) ptr, 1, HAL_MAX_DELAY);
if (hstatus == HAL_OK)
return 1;
else
return EIO;
}
errno = EBADF;
return -1;
}
int _fstat(int fd, struct stat *st)
{
if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
{
st->st_mode = S_IFCHR;
return 0;
}
errno = EBADF;
return 0;
}
#endif //#if !defined(OS_USE_SEMIHOSTING)
1.16 为项目添加一个C语言头文件,命名为“retarget.h”,如图所示

添加头文件代码如下:
#ifndef FIRMWARE_RETARGET_H
#define FIRMWARE_RETARGET_H
#ifndef _RETARGET_H__
#define _RETARGET_H__
#include "stm32f1xx_hal.h"
#include <sys/stat.h>
#include <stdio.h>
void RetargetInit(UART_HandleTypeDef *huart);
int _isatty(int fd);
int _write(int fd, char *ptr, int len);
int _close(int fd);
int _lseek(int fd, int ptr, int dir);
int _read(int fd, char *ptr, int len);
int _fstat(int fd, struct stat *st);
#endif //#ifndef _RETARGET_H__
#endif //FIRMWARE_RETARGET_H
1.17 打开项目文件Core->Src->syscalls.c,为避免重定义,将以下几行注释:

1.18 打开项目文件Core->Src->main.c ,在如下位置添加一行代码实现串口重映射初始化,如图所示:

以上是为了打印调试信息添加的串口重映射配置,下面开始实现任务代码部分
1.19 打开项目文件Core->Src->tim.c,在如下位置添加代码,如图所示:


打开项目文件Core->Src->main.c,在如下位置添加代码,如图所示:

1.20 编译项目,并将生成的hex文件下载到开发板,观察现象。
任务代码
需要准时定时1s需要配置下面的的两个空的参数

测试说明
定时器设定定时时间为1s,1s时间到了之后就会打印 timer 1s elapsed