目录
- 一、项目准备
- 1. 工程模板
- 2. 器件接线
- 二、外部时钟
- 1. 端口复用
- 2. 流程示意
- 三、定时器模块
- Timer.c
- Timer.h
- 四、遮光计数
一、项目准备
1. 工程模板
本篇项目所用模板包含以下模块,声明函数见头文件,模块添加和函数功能详见往期记录。
2. 器件接线
主装置:ST-Link
仿真器,STM32
系统板,MB102
面包板,OLED
显示屏(接线详见往期记录)
除了A15
,B3
,B4
是JLINK
的调试端口,其他端口可随意使用。器件接线如下:
器件 | 端口/电源 |
---|---|
3.3/VCC | + |
GND | - |
OLED-SCL | B8 |
OLED-SDA | B9 |
Sensor-DO | A0 |
增设模块:对射式红外传感器(A0
端口)
二、外部时钟
1. 端口复用
将多个功能赋予一个输入输出端口(I/O
),并且不同的功能可以通过设置工作模式来切换,称为端口复用。若一个GPIO
同时被外置外设和内置内设使用,就称为复用。
2. 流程示意
因为选择对射式红外传感器输出时钟信号,所以需要配置GPIO
端口;使用外部时钟ETR
给定时器供能,选择外部时钟模式2
,初始化时基单元和NVIC
,最后启动定时器即可。
其中,具有TIM2
定时器的外部时钟源模式的复用功能的GPIO
为A0
,所以将传感器接入PA0
引脚;由于是外部触发中断,手动产生的时钟信号频率较低,可以关闭预分频器(PSC = 0
),也可以适当降低重装载目标值(ARR = 10-1
),但需要启用滤波器消除抖动。
如此,每次触发外部中断,计数器的值(CNT
)就会加1
,累计十次触发更新中断。
三、定时器模块
Timer.c
#include "stm32f10x.h"
void Timer_Init(void)
{
// 开启外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // TIM2定时器
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIOA端口
// 使用外部时钟模式二:(外部触发)关闭预分频器,极性为正向(上升沿有效),指定采样频率和采样点数
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);
// 配置端口参数
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入模式:默认高电平
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 最大速度50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 13号引脚
// 初始化PA0端口
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置时基单元参数
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 滤波器采样频率:1分频
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数器模式:向上计数
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1; // 自动重装载寄存器参数ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 0; // 预分频器寄存器参数PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; // 重复计数器寄存器参数:仅供高级计数器使用
// 初始化时基单元
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
// 重置标志位:初始化参数时会产生更新中断
TIM_ClearFlag(TIM2, TIM_IT_Update);
// 使能更新中断
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
// 配置中断优先级:分组2
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置NVIC参数
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; // 中断请求通道:TIM2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 中断请求通道状态:使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 抢占优先级:2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 响应优先级:1
// 初始化嵌套中断向量控制器
NVIC_Init(&NVIC_InitStructure);
// 启动定时器TIM2
TIM_Cmd(TIM2, ENABLE);
}
Timer.h
#ifndef __TIMER_H
#define __TIMER_H
void Timer_Init(void);
#endif
四、遮光计数
#include "stm32f10x.h" // 器件模块
#include "OLED.h" // OLED模块
#include "Timer.h" // 定时器模块
uint16_t Num; // 数值
int main(void)
{
// 初始化
OLED_Init();
Timer_Init();
// 显示计数
OLED_ShowString(1, 1, "Num:");
OLED_ShowString(2, 1, "CNT:");
while(1)
{
OLED_ShowNum(1, 5, Num, 5);
OLED_ShowNum(2, 5, TIM_GetCounter(TIM2), 5);
}
}
// TIM2中断请求通道控制
void TIM2_IRQHandler(void)
{
// 检查TIM2中断线请求状态寄存器的标志位
if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) // 更新中断触发
{
Num ++; // 计数
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 重置标志位
}
}