当前位置: 首页 > news >正文

小白跟做江科大32单片机之定时器

原理部分

1.

计数器每遇到一个上升沿就会计数值+1,。

72MHZ=72000000

72000000/65536/65536=0.01676380634307861328125=59.652323555555554  (s) 

2.

3.

计数时钟每来一个上升沿,计数值+1,自动运行。如果计数值与存储在自动重装载寄存器中的值相等,计数器清0,产生更新中断和更新事件,然后更新到NVIC,向上的那个表示中断,向下的表示更新事件。

这个主模式触发DAC的功能,就是直接通过更新事件直接映射到别的设备。

4.通用定时器

滤波信号之后会给触发控制器或者TRGI

外部时钟模式1输入:ETR,其他定时器,CH1引脚,CH1边沿引脚,CH2

5.主要看这个

6.

这个主要是由预分配缓冲器使得本次计数周期结束时,改变分频值不会受影响

7.RCC时钟树左边是系统时钟,右边是时钟频率

时钟树左边

时钟树右边

时钟树右边部分电路

这就是我们在程序中写RCC APB2/1Periphclockgmd作用的地方,打开时钟,就是在这个位置写1/让左边的时钟能够通过与门输出给外设


代码编写

实验一

1.根据江科大老师给的电路图进行连接

2.创建新项目

3.将显示屏相关代码复制到新项目中

3.思路

①写一个TIMER_init函数,其中包括

开启RCC时钟,

内部时钟模式,

配置时基单元

定时器中断控制

NVIC

配置运行控制

②在main函数中写一个定时器中断函数代码

4.编写TIMER.c代码

#include "stm32f10x.h"                  // Device header

void TIMER_Init()
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);    //开启GPIOB的时钟,通用定时器
    
    /*配置时钟源*/
    TIM_InternalClockConfig(TIM2);        //选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟
    /*时基单元初始化*/
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;                //定义结构体变量
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;        //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;    //计数器模式,选择向上计数
    TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;                //计数周期,即ARR的值
    TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;                //预分频器,即PSC的值
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);                //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元    
    
    /*中断输出配置*/
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);                        //清除定时器更新标志位
                                                                //TIM_TimeBaseInit函数末尾,手动产生了更新事件
                                                                //若不清除此标志位,则开启中断后,会立刻进入一次中断
                                                                //如果不介意此问题,则不清除此标志位也可
    
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);                    //开启TIM2的更新中断
    
    /*NVIC中断分组*/
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                //配置NVIC为分组2
                                                                //即抢占优先级范围:0~3,响应优先级范围:0~3
                                                                //此分组配置在整个工程中仅需调用一次
                                                                //若有多个中断,可以把此代码放在main函数内,while循环之前
                                                                //若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
    
    /*NVIC配置*/
    NVIC_InitTypeDef NVIC_InitStructure;                        //定义结构体变量
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;                //选择配置NVIC的TIM2线
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                //指定NVIC线路使能
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;    //指定NVIC线路的抢占优先级为2
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;            //指定NVIC线路的响应优先级为1
    NVIC_Init(&NVIC_InitStructure);                                //将结构体变量交给NVIC_Init,配置NVIC外设
    
    /*TIM使能*/
    TIM_Cmd(TIM2, ENABLE);            //使能TIM2,定时器开始运行
}

    
 

5.编写TIMER.h代码

#ifndef _TIMER__H
#define _TIMER__H

void TIMER_Init(void);


#endif

6.实验结果

实验二

1.接线

2.修改TIMER.c代码

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:定时中断初始化
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数配置为外部时钟,定时器相当于计数器
  */
void Timer_Init(void)
{
    /*开启时钟*/
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);            //开启TIM2的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);            //开启GPIOA的时钟
    
    /*GPIO初始化*/
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                        //将PA0引脚初始化为上拉输入
    
    /*外部时钟配置*/
    TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x0F);
                                                                //选择外部时钟模式2,时钟从TIM_ETR引脚输入
                                                                //注意TIM2的ETR引脚固定为PA0,无法随意更改
                                                                //最后一个滤波器参数加到最大0x0F,可滤除时钟信号抖动
    
    /*时基单元初始化*/
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;                //定义结构体变量
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;        //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;    //计数器模式,选择向上计数
    TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;                    //计数周期,即ARR的值
    TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;                //预分频器,即PSC的值
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);                //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元    
    
    /*中断输出配置*/
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);                        //清除定时器更新标志位
                                                                //TIM_TimeBaseInit函数末尾,手动产生了更新事件
                                                                //若不清除此标志位,则开启中断后,会立刻进入一次中断
                                                                //如果不介意此问题,则不清除此标志位也可
                                                                
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);                    //开启TIM2的更新中断
    
    /*NVIC中断分组*/
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                //配置NVIC为分组2
                                                                //即抢占优先级范围:0~3,响应优先级范围:0~3
                                                                //此分组配置在整个工程中仅需调用一次
                                                                //若有多个中断,可以把此代码放在main函数内,while循环之前
                                                                //若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
    
    /*NVIC配置*/
    NVIC_InitTypeDef NVIC_InitStructure;                        //定义结构体变量
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;                //选择配置NVIC的TIM2线
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                //指定NVIC线路使能
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;    //指定NVIC线路的抢占优先级为2
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;            //指定NVIC线路的响应优先级为1
    NVIC_Init(&NVIC_InitStructure);                                //将结构体变量交给NVIC_Init,配置NVIC外设
    
    /*TIM使能*/
    TIM_Cmd(TIM2, ENABLE);            //使能TIM2,定时器开始运行
}

/**
  * 函    数:返回定时器CNT的值
  * 参    数:无
  * 返 回 值:定时器CNT的值,范围:0~65535
  */
uint16_t Timer_GetCounter(void)
{
    return TIM_GetCounter(TIM2);    //返回定时器TIM2的CNT
}

3.修改TIMER.h代码

#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);
uint16_t Timer_GetCounter(void);

#endif
 

4.修改main.c代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"

uint16_t Num;            //定义在定时器中断里自增的变量

int main(void)
{
    /*模块初始化*/
    OLED_Init();        //OLED初始化
    Timer_Init();        //定时中断初始化
    
    /*显示静态字符串*/
    OLED_ShowString(1, 1, "Num:");            //1行1列显示字符串Num:
    OLED_ShowString(2, 1, "CNT:");            //2行1列显示字符串CNT:
    
    while (1)
    {
        OLED_ShowNum(1, 5, Num, 5);            //不断刷新显示Num变量
        OLED_ShowNum(2, 5, Timer_GetCounter(), 5);        //不断刷新显示CNT的值
    }
}

/**
  * 函    数:TIM2中断函数
  * 参    数:无
  * 返 回 值:无
  * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
  *           函数名为预留的指定名称,可以从启动文件复制
  *           请确保函数名正确,不能有任何差异,否则中断函数将不能进入
  */
void TIM2_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)        //判断是否是TIM2的更新事件触发的中断
    {
        Num ++;                                                //Num变量自增,用于测试定时中断
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);            //清除TIM2更新事件的中断标志位
                                                            //中断标志位必须清除
                                                            //否则中断将连续不断地触发,导致主程序卡死
    }
}
5.实验结果

定时器外部时钟试验结果

相关文章:

  • opencascade AIS_InteractiveContext源码学习5 immediate mode rendering 即时模式渲染
  • docker镜像基本操作
  • 学习面向对象前--Java基础练习题2
  • Linux安装Maven(详细教程手把手教会)
  • Java开发-面试题-0007-GPT和MBR的区别
  • 安装vue时候发现npm淘宝镜像不能使用,报出:npm.taobao.org和registry.npm.taobao.or
  • 华为HCIP Datacom H12-821 卷7
  • rockchip linux sdk指定编译配置文件
  • 动手学深度学习(Pytorch版)代码实践 -计算机视觉-37微调
  • MySQL 超出月份最大日期(工作总结)
  • “脏读”、“幻读”、“不可重复读”
  • Nuxt3用pm2启动报错[PM2][ERROR] File ecosystem.config.js malformated
  • 数据分析必备:一步步教你如何用matplotlib做数据可视化(10)
  • 【Redis】Redis内存使用优化方法
  • 浙大宁波理工学院2024年成人高等继续教育招生简章
  • Go 语言编译器的 //go: 详解
  • in typeof instanceof ===这些运算符有什么作用
  • IOS评论框不贴底(ios12新bug)
  • JavaScript的使用你知道几种?(上)
  • Lsb图片隐写
  • Mac转Windows的拯救指南
  • PAT A1092
  • Spring Cloud中负载均衡器概览
  • SSH 免密登录
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 聊聊redis的数据结构的应用
  • 那些被忽略的 JavaScript 数组方法细节
  • 盘点那些不知名却常用的 Git 操作
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 三栏布局总结
  • 写给高年级小学生看的《Bash 指南》
  • Hibernate主键生成策略及选择
  • zabbix3.2监控linux磁盘IO
  • 大数据全解:定义、价值及挑战
  • ​520就是要宠粉,你的心头书我买单
  • ​Benvista PhotoZoom Pro 9.0.4新功能介绍
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • #{}和${}的区别?
  • #stm32整理(一)flash读写
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • $.ajax,axios,fetch三种ajax请求的区别
  • (1)Jupyter Notebook 下载及安装
  • (2)空速传感器
  • (C11) 泛型表达式
  • (day18) leetcode 204.计数质数
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (附源码)php投票系统 毕业设计 121500
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (力扣)1314.矩阵区域和
  • (三)Kafka 监控之 Streams 监控(Streams Monitoring)和其他
  • (四)汇编语言——简单程序
  • (原)本想说脏话,奈何已放下
  • (原創) 如何使用ISO C++讀寫BMP圖檔? (C/C++) (Image Processing)