目录
- 一、项目准备
- 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; // 最大速度50MHzGPIO_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; // 自动重装载寄存器参数ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 0; // 预分频器寄存器参数PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; // 重复计数器寄存器参数:仅供高级计数器使用// 初始化时基单元TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);// 重置标志位:初始化参数时会产生更新中断TIM_ClearFlag(TIM2, TIM_IT_Update);// 使能更新中断TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);// 配置中断优先级:分组2NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 配置NVIC参数NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; // 中断请求通道:TIM2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 中断请求通道状态:使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 抢占优先级:2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 响应优先级:1// 初始化嵌套中断向量控制器NVIC_Init(&NVIC_InitStructure);// 启动定时器TIM2TIM_Cmd(TIM2, ENABLE);
}
Timer.h
#ifndef __TIMER_H
#define __TIMER_Hvoid 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); // 重置标志位}
}