STM32 外部时钟脉冲计数实验
前言
最近在学正点原子的HAL库视频,通用定时器脉冲计数功能的实现,以前都习惯用标准库了,所以现在尝试参考HAL库的原理用标准库的思想来实现这个功能。
1、实验原理
本实验使用外部时钟模式1,外部输入引脚作为定时器的时钟来源。
使用开发板的 WK_UP 按键按下产生高电平脉冲作为定时器的计数器时钟来源,计数器工作在递增计数模式,那么每来一个上升沿信号,计数器就加一。即每按下一次按键产生一次高电平脉冲,计数器加一,一直计数到ARR的值溢出从新计数。
2、开发板原理图
2、定时器工作原理框图
外部时钟源信号通过通道 1 输入后,TI1 分别要经过滤波器、边沿检测器后来到 TI1FP1,被触发输入选择器选择为触发源,接着来到从模式控制器,从模式选择为外部时钟模式 1,这时候外部时钟源信号就会到达时基单元的预分频器,最后,经过分频后就可作为计数器的计数时钟了。外部时钟源信号的边沿计数个数会保存到计数器寄存器中,需要时直接读取 CNT 的值即可。
2、主要源码
示例代码如下:
void tim2_Init(u8 arr)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0};
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /* 使能TIM2时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* 使能GPIOA时钟 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; /* PA0 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; /* 下拉输入 */
GPIO_Init(GPIOA, &GPIO_InitStructure); /* 初始化GPIOA */
GPIO_ResetBits(GPIOA, GPIO_Pin_0); /* IO初始化为低电平 */
TIM_TimeBaseStructure.TIM_Period = arr; /* 设置重装载值 */
TIM_TimeBaseStructure.TIM_Prescaler = 0; /* 预分频器为0 */
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; /* 不分频 */
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;/* 向上计数模式 */
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); /* 初始化TIM2时基单元 */
TIM_ITRxExternalClockConfig(TIM2, TIM_TS_ETRF); /* 配置定时器2外部触发 */
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);/* 外部时钟模式2的配置 */
TIM_Cmd(TIM2, ENABLE); /* 使能定时器2 */
}
相关成员解析:
成员 | 说明 |
---|---|
TIM_ExtTRGPSC_OFF | TIM ETRP 关闭预分频 |
TIM_TS_ETRF | TIM 外部触发输入 |
TIM_ExtTRGPolarity_Inverted | TIM 外部触发极性翻转:低电平或下降沿有效 |
TIM_ExtTRGPolarity_NonInverted | TIM 外部触发极性非翻转:高电平或上升沿有效 |
int main(void)
{
u8 key ,count;
u8 oldcnt = 0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为 115200
LED_Init(); //初始化与LED连接的硬件接口
KEY_Init();
tim2_Init(10);//计数值为10次
while(1)
{
key = KEY_Scan(0);
if(key == KEY1_PRES)
{
TIM_SetCounter(TIM2, 0);//清空计数值
}
count = TIM_GetCounter(TIM2);//获取计数值
if(oldcnt != count)
{
oldcnt = count;
printf("CNT:%d\r\n", oldcnt);
}
}
}
理想的实验结果:
不理想的实验结果:
3、总结
通用定时器的频率计数学习起来还是比较好理解的,只要把定时器的工作模式和工作原理框图弄明白就比较好理解了。
测试时有时候结果很不理想,数值跳的很明显,不确定是不是按键抖动引起的,还是我程序设计逻辑上不够严谨导致的。