赞
踩
使用正点原子stm32f103精英版
软件延时过程中,程序就进入延时函数中,无法执行其他程序
下图的72,是因为f103的主频是72MHz,这样调用延时肯定是不精准的
实时时钟就是 RTC
基本定时器的时钟来源只能是内部时钟
通过程序的方式无法直接访问影子寄存器,但可以通过写入arr自动重载寄存器,它再转移到影子寄存器生效,此时ARR寄存器就起到一个缓冲或缓存的作用
事件是默认产生;中断和DMA输出是默认不产生,但可以配置产生
ARPE位的作用:设置有缓冲作用后,ARR的值要等事件发生后写入影子寄存器;设置没有缓冲作用的话,ARR的值就马上转移到影子寄存器中生效
虽然最大总线的最大时钟频率是72、36MHz,但定时器的最大时钟频率不一定有这么大
可以看到例程中 APB2 预分频系数是1,所以最大还是72MHz
APB1 预分频系数是2,APB1时钟是从AHB 2分频过来的,所以APB1给到定时器的时钟要乘2,定时器时钟就也是72Mhz了
如一个例子,控制led亮1s,灭2s
(1)当没有缓冲时,假设先设置arr=99,1s后更新灭,然后重新写入arr=199灭2s,这其中写arr的值也需要时间
(2)而有缓冲时,假设先设置arr=99,1s后更新灭,然后在这1s内写入arr=199,此时因为有缓冲所以arr的值不会立即写入要等更新后写入,所以就节省了写入arr值的时间,减小了误差
ARR也是同理,寄存器最小值为0,我从0数到3,你不能说我就数了3个数吧,当然是3+1=4个数
基地址:
基本定时器技术模式固定递增,无分频因子
重复计数器寄存器只有高级定时器才有
自动重载预装载使能就是CR1寄存器的位7:APRE
基本定时器只有更新中断
更新中断产生的方式:
(1)定时器溢出时伴随更新时间和更新中断的产生
(2)通过软件设置UG位产生软件的更新时间从而产生更新中断
这里使用定时器溢出的方式
- #include "./BSP/TIMER/timer.h"
- #include "./BSP/LED/led.h"
-
- TIM_HandleTypeDef g_timx_handle;
-
- /* 定时器中断初始化函数 */
- void btim_timx_int_init(uint16_t arr, uint16_t psc)
- {
- g_timx_handle.Instance = TIM6;
- g_timx_handle.Init.Prescaler = psc;
- g_timx_handle.Init.Period = arr;
- HAL_TIM_Base_Init(&g_timx_handle);
-
- HAL_TIM_Base_Start_IT(&g_timx_handle);
-
- }
-
-
-
- /* 定时器基础MSP初始化函数 */
- void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
- {
- if(htim->Instance == TIM6)
- {
- __HAL_RCC_TIM6_CLK_ENABLE();
- HAL_NVIC_SetPriority(TIM6_IRQn, 2, 3);
- HAL_NVIC_EnableIRQ(TIM6_IRQn);
-
- }
-
- }
-
-
-
- /* 定时器6中断服务函数 */
- void TIM6_IRQHandler()
- {
- HAL_TIM_IRQHandler(&g_timx_handle);
- }
-
-
-
- /* 定时器溢出中断回调函数 */
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- {
- if(htim->Instance == TIM6) /* 判断是定时器6,否则多个定时器进来会混乱 */
- {
- LED0_TOGGLE();
-
- }
-
-
- }
-
通用定时器时钟来自RCC内部时钟,有4类:
(1)APB总线上的时钟
(2)ITR0-4内部触发输入时钟部分
(3)可以复用为ETR引脚的IO口
(4)定时器的通道1、通道2
如:
TI1_ED 来自通道1,双边沿
TI1FP1、TI2FP2来自通道1、2,单边沿
只有通用和高级定时器才可以参与
- #include "./BSP/TIMER/gtim.h"
-
- TIM_HandleTypeDef g_timx_pwm_chy_handle;
-
-
- /* 通用定时器PWM输出初始化函数 */
- void gtim_timx_pwm_chy_init(uint16_t arr, uint16_t psc)
- {
- TIM_OC_InitTypeDef timx_oc_pwm_chy;
-
- g_timx_pwm_chy_handle.Instance = TIM3;
- g_timx_pwm_chy_handle.Init.Prescaler = psc;
- g_timx_pwm_chy_handle.Init.Period = arr;
- g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式
- HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle);
-
- timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1;
- timx_oc_pwm_chy.Pulse = arr / 2; // 比较值,就是CCRx的值
- timx_oc_pwm_chy.OCPolarity = TIM_OCPOLARITY_LOW; // 输出极性为低,低电平有效
- HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy, TIM_CHANNEL_2);
-
- HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, TIM_CHANNEL_2);
-
-
- }
-
- /* 定时器输出PWM MSP初始化函数 */
- void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
- {
- if(htim->Instance == TIM3)
- {
- GPIO_InitTypeDef gpio_init_struct;
- __HAL_RCC_GPIOB_CLK_ENABLE(); /* LED0时钟使能 */
- __HAL_RCC_TIM3_CLK_ENABLE(); /* LED1时钟使能 */
-
- gpio_init_struct.Pin = GPIO_PIN_5; /* LED0引脚 */
- gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */
- gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
- HAL_GPIO_Init(GPIOB, &gpio_init_struct); /* 初始化LED0引脚 */
-
- /* 重映射 */
- __HAL_RCC_AFIO_CLK_ENABLE();
- __HAL_AFIO_REMAP_TIM3_PARTIAL();
-
- }
-
- }
-
-
-
- #include "./SYSTEM/sys/sys.h"
- #include "./SYSTEM/delay/delay.h"
- #include "./SYSTEM/usart/usart.h"
- #include "./BSP/LED/led.h"
- #include "./BSP/TIMER/gtim.h"
-
- extern TIM_HandleTypeDef g_timx_pwm_chy_handle;
-
- int main(void)
- {
- uint16_t ledpwm = 0;
- uint8_t dir = 1;
-
- HAL_Init(); /* 初始化HAL库 */
- sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72M */
- delay_init(72); /* 初始化延时函数 */
- led_init(); /* 初始化LED */
- usart_init(115200);
- gtim_timx_pwm_chy_init(499, 71); // 2KHz
-
-
-
- while(1)
- {
-
- delay_ms(10);
-
- if(dir) ledpwm++;
- else ledpwm--;
-
- if(ledpwm > 300) dir = 0;
- if(ledpwm == 0) dir = 1;
-
- __HAL_TIM_SET_COMPARE(&g_timx_pwm_chy_handle, TIM_CHANNEL_2, ledpwm);
- }
- }
-
只要 CC1S 不是00就是输入模式
CCR1读操作完成后,影子寄存器的值才会被转移到预装载寄存器中
t1 处产生一个捕获事件,将计数器的计数值转移到CCR1中 ,此时将计数器的值清零,将上升沿检测改为下降沿检测,
输入捕获分频系数:捕获几个上升沿触发
Polarity
Selection
Prescaler
Filter
72Mhz / 72 =1MHz 就是1us(1微秒)计数一次
- #include "./BSP/TIMER/gtim.h"
-
-
-
- TIM_HandleTypeDef g_timx_cap_chy_handle;
-
- void gtim_timx_cap_chy_init(uint16_t arr, uint16_t psc)
- {
- TIM_IC_InitTypeDef timx_ic_cap_chy = {0}; /* 初始化结构体变量建议给个初值0 */
-
- g_timx_cap_chy_handle.Instance = TIM5; /* 定时器5 */
- g_timx_cap_chy_handle.Init.Prescaler = psc; /* 定时器分频 */
- g_timx_cap_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 递增计数模式 */
- g_timx_cap_chy_handle.Init.Period = arr; /* 自动重装载值 */
- HAL_TIM_IC_Init(&g_timx_cap_chy_handle);
-
- timx_ic_cap_chy.ICPolarity = TIM_ICPOLARITY_RISING; /* 上升沿捕获 */
- timx_ic_cap_chy.ICSelection = TIM_ICSELECTION_DIRECTTI; /* 映射到TI1 */
- timx_ic_cap_chy.ICPrescaler = TIM_ICPSC_DIV1; /* 配置输入分频 */
- timx_ic_cap_chy.ICFilter = 0; /* 配置输入滤波器 */
- HAL_TIM_IC_ConfigChannel(&g_timx_cap_chy_handle, &timx_ic_cap_chy, TIM_CHANNEL_1);
-
- __HAL_TIM_ENABLE_IT(&g_timx_cap_chy_handle, TIM_IT_UPDATE); /* 使能更新中断 */
- HAL_TIM_IC_Start_IT(&g_timx_cap_chy_handle, TIM_CHANNEL_1); /* 开始捕获TIM5的通道1,捕获中断使能 */
-
- }
-
-
- void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
- {
- if(htim->Instance == TIM5)
- {
- GPIO_InitTypeDef gpio_init_struct;
- __HAL_RCC_TIM5_CLK_ENABLE();
- __HAL_RCC_GPIOA_CLK_ENABLE();
-
- gpio_init_struct.Pin = GPIO_PIN_0;
- gpio_init_struct.Mode = GPIO_MODE_AF_PP; // 复用功能是可以读取io的电平情况的,输出也能读值
- gpio_init_struct.Pull = GPIO_PULLDOWN;
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(GPIOA, &gpio_init_struct);
-
- HAL_NVIC_SetPriority(TIM5_IRQn, 1, 3);
- HAL_NVIC_EnableIRQ(TIM5_IRQn);
-
- }
- }
-
- /* 输入捕获状态(g_timxchy_cap_sta)
- * [7] :0,没有成功的捕获;1,成功捕获1次
- * [6] :0,还没捕获到高电平;1,已经捕获到高电平
- * [5:0]:捕获高电平后溢出的次数,最多溢出63次,所以最长捕获值 = 63*65536 + 65535 = 4194303
- * 注意:为了通用,我们默认ARR和CCRy都是16位寄存器,对于32位的定时器(如TIM5),也只按16位计算
- * F1系列定时器都是16位,把g_timxchy_cap_sta定义为uint16_t,还可以测的时间更长
- * 按1us的计数频率,最长溢时间为:4194303 us,约4.19s
- *
- * 说明一下:正常32位的定时器来说,1us计数器加1,溢出时间为4294秒,2^32 = 4294967296
- *
- */
- uint8_t g_timxchy_cap_sta = 0; /* 输入捕获状态 */
- uint16_t g_timxchy_cap_val = 0; /* 输入捕获值 */
-
- /* 定时器5中断服务函数 */
- void TIM5_IRQHandler(void)
- {
- HAL_TIM_IRQHandler(&g_timx_cap_chy_handle);
- }
-
- /* 定时器输入捕获中断回调函数 */
- void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
- {
- if(htim->Instance == TIM5)
- {
- if((g_timxchy_cap_sta & 0x80) == 0) // 还没有成功捕获
- {
- if(g_timxchy_cap_sta & 0x40) // 捕获下降沿
- {
- g_timxchy_cap_sta |= 0x80; // 标记捕获到一次高电平
- g_timxchy_cap_val = HAL_TIM_ReadCapturedValue(&g_timx_cap_chy_handle, TIM_CHANNEL_1);
- TIM_RESET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1); // 清除原来的设置
- TIM_SET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);// 开启新一次捕获上升沿
- }
- else /* 还未开始,第一次捕获上升沿 */
- {
- g_timxchy_cap_sta = 0;
- g_timxchy_cap_val = 0;
- g_timxchy_cap_sta |= 0x40; // 标记捕获到了上升沿
- __HAL_TIM_DISABLE(&g_timx_cap_chy_handle); // 关闭定时器5
- __HAL_TIM_SET_COUNTER(&g_timx_cap_chy_handle, 0); // 定时器5计数器清零
- TIM_RESET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1);// 清除原来的设置
- TIM_SET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING); // 捕获下降沿
- __HAL_TIM_ENABLE(&g_timx_cap_chy_handle); // 使能定时器5
- }
- }
- }
- }
-
- /* 定时器更新中断回调函数 */
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- {
- if(htim->Instance == TIM5)
- {
- if((g_timxchy_cap_sta & 0x80) == 0) // 还没有成功捕获
- {
- if(g_timxchy_cap_sta & 0x40) // 捕获下降沿
- {
- if((g_timxchy_cap_sta & 0x3F) == 0x3F) /* 高电平太长了 */
- {
- TIM_RESET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1);// 清除原来的设置
- TIM_SET_CAPTUREPOLARITY(&g_timx_cap_chy_handle, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING); // 设置捕获上升沿
- g_timxchy_cap_sta |= 0X80;
- g_timxchy_cap_val = 0XFFFF;
- }
- else /* 累计定时器溢出次数 */
- {
- g_timxchy_cap_sta++;
- }
- }
- }
- }
-
- }
-
-
- #include "./SYSTEM/sys/sys.h"
- #include "./SYSTEM/delay/delay.h"
- #include "./SYSTEM/usart/usart.h"
- #include "./BSP/LED/led.h"
- #include "./BSP/TIMER/gtim.h"
-
- extern uint8_t g_timxchy_cap_sta; /* 输入捕获状态 */
- extern uint16_t g_timxchy_cap_val; /* 输入捕获值 */
-
- int main(void)
- {
- uint32_t temp = 0;
- uint8_t t = 0;
-
- HAL_Init(); /* 初始化HAL库 */
- sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72M */
- delay_init(72); /* 初始化延时函数 */
- led_init(); /* 初始化LED */
- usart_init(115200);
- gtim_timx_cap_chy_init(65535, 71);
-
- while(1)
- {
- if(g_timxchy_cap_sta & 0x80) // 还没有成功捕获
- {
- temp = g_timxchy_cap_sta & 0x3F;
- temp *= 65536; /* 溢出时间总和 */
- temp += g_timxchy_cap_val; /* 总的高电平时间 */
- printf("HIGH:%d us\r\n", temp);
- g_timxchy_cap_sta = 0; /* 开启下一次捕获 */
- }
-
- t++;
-
- if(t > 20) /* 200ms进入一次 */
- {
- t = 0;
- LED0_TOGGLE(); /* LED0闪烁,提是程序在运行 */
- }
- delay_ms(10);
- }
- }
-
4个时钟源:(1)内部时钟;(2)外部触发1:由CH1、CH2;(3)外部触发2:由IO的ETR;(4)内部触发输入:一般用于级联
SlaveMode:
(1)DISABLE:不使用从模式就是使用内部时钟
(2)RESET:复位
(3)GATED:门电路
(4)TRIGGER:触发模式
(5)EXTERNAL1:外部时钟模式1
触发源:
边沿检测器:
边沿检测器有2个, 上2个是上面的检测器,下3个是下面的检测器
BOTHEDGE用处暂不明
分频器:
外2会用到分频器,外1没用到
滤波器:
滤波器外1和外2都用到了,实验里没用
- #include "./BSP/TIMER/gtim.h"
-
- TIM_HandleTypeDef g_timx_cap_chy_handle;
-
- void gtim_timx_cap_chy_init(uint16_t arr, uint16_t psc)
- {
- TIM_SlaveConfigTypeDef tim_slave_config = {0};
-
- g_timx_cap_chy_handle.Instance = TIM2; /* 定时器5 */
- g_timx_cap_chy_handle.Init.Prescaler = psc; /* 定时器分频 */
- g_timx_cap_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 递增计数模式 */
- g_timx_cap_chy_handle.Init.Period = arr; /* 自动重装载值 */
- HAL_TIM_IC_Init(&g_timx_cap_chy_handle);
-
- tim_slave_config.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
- tim_slave_config.InputTrigger = TIM_TS_TI1FP1;
- tim_slave_config.TriggerPolarity = TIM_TRIGGERPOLARITY_RISING;
- tim_slave_config.TriggerFilter = 0;
- HAL_TIM_SlaveConfigSynchro(&g_timx_cap_chy_handle, &tim_slave_config);
-
- HAL_TIM_IC_Start(&g_timx_cap_chy_handle, TIM_CHANNEL_1);
-
- }
-
- void HAL_TIM_IC_MspInit(TIM_HandleTypeDef *htim)
- {
- if(htim->Instance == TIM2)
- {
- GPIO_InitTypeDef gpio_init_struct;
- __HAL_RCC_TIM2_CLK_ENABLE();
- __HAL_RCC_GPIOA_CLK_ENABLE();
-
- gpio_init_struct.Pin = GPIO_PIN_0;
- gpio_init_struct.Mode = GPIO_MODE_AF_PP; // 复用功能是可以读取io的电平情况的,输出也能读值
- gpio_init_struct.Pull = GPIO_PULLDOWN;
- gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; // 输入可以不设置速度
- HAL_GPIO_Init(GPIOA, &gpio_init_struct);
-
- }
- }
- #include "./SYSTEM/sys/sys.h"
- #include "./SYSTEM/delay/delay.h"
- #include "./SYSTEM/usart/usart.h"
- #include "./BSP/LED/led.h"
- #include "./BSP/TIMER/gtim.h"
- #include "./BSP/KEY/key.h"
-
- extern TIM_HandleTypeDef g_timx_cap_chy_handle;
-
- int main(void)
- {
- uint16_t curcnt;
- uint16_t oldcnt;
- uint8_t key;
- uint8_t t = 0;
-
- HAL_Init(); /* 初始化HAL库 */
- sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72M */
- delay_init(72); /* 初始化延时函数 */
- led_init(); /* 初始化LED */
- usart_init(115200);
- gtim_timx_cap_chy_init(65535, 0);
- key_init();
-
- while(1)
- {
- key = key_scan(0);
- if(key == KEY0_PRES)
- {
- __HAL_TIM_SET_COUNTER(&g_timx_cap_chy_handle, 0);
- }
-
- curcnt = __HAL_TIM_GET_COUNTER(&g_timx_cap_chy_handle);
- if(oldcnt != curcnt)
- {
- oldcnt = curcnt;
- printf("CNT:%d\r\n", oldcnt);
- }
- t ++;
-
- if(t > 20)
- {
- t = 0;
- LED0_TOGGLE();
- }
- delay_ms(10);
- }
- }
-
此时定时器计数cnt == arr 的时候会溢出,因为设置了 arr = 65535,所以最大计数值即最大捕获数量就是 65535,如果要增大计数量,可以添加定时器更新中断
重复计数器,对REP寄存器写一个值,每次溢出就减1,指导减为0后,就产生更新事件
通道1、2、3都有CHxN就是互补通道
再同步就是软件手动产生更新事件后,RCR寄存器的值会再缓冲到它的影子寄存器中,影子寄存器就被重置了
p105 5:43
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。