jsp网站开发与数据库连接,网站名称怎么变更,长沙做网站大概多少钱,昆明企业为什么要做网站选用通用定时器TIM5的CH1。
PA0接一个按键#xff0c;默认接GND#xff0c;当按键按下时#xff0c;IO口被拉高#xff0c;此时#xff0c;可利用定时器的输入捕获功能#xff0c;测量按键按下的这段高电平的时间。 宏定义方便程序升级、移植#xff0c;举个例子#…选用通用定时器TIM5的CH1。
PA0接一个按键默认接GND当按键按下时IO口被拉高此时可利用定时器的输入捕获功能测量按键按下的这段高电平的时间。 宏定义方便程序升级、移植举个例子
输入捕获通道 GPIO 初始化里面有一个GENERAL_TIM_CH1_GPIO_CLK这个东西是个宏定义。使用不同GPIO的时候只需要修改头文件里面的宏定义不需要修改这个函数。
// TIM 输入捕获通道GPIO相关宏定义
#define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOAstatic void GENERAL_TIM_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 输入捕获通道 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin GENERAL_TIM_CH1_PIN;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING;GPIO_Init(GENERAL_TIM_CH1_PORT, GPIO_InitStructure);
}下面是宏定义。
#ifndef __BSP_GENERALTIME_H
#define __BSP_GENERALTIME_H#include stm32f10x.h/************通用定时器TIM参数定义只限TIM2、3、4、5************/
// 当使用不同的定时器的时候对应的GPIO是不一样的这点要注意
// 我们这里默认使用TIM5#define GENERAL_TIM TIM5
#define GENERAL_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define GENERAL_TIM_CLK RCC_APB1Periph_TIM5
#define GENERAL_TIM_PERIOD 0XFFFF
#define GENERAL_TIM_PSC (72-1)// TIM 输入捕获通道GPIO相关宏定义
#define GENERAL_TIM_CH1_GPIO_CLK RCC_APB2Periph_GPIOA
#define GENERAL_TIM_CH1_PORT GPIOA
#define GENERAL_TIM_CH1_PIN GPIO_Pin_0
#define GENERAL_TIM_CHANNEL_x TIM_Channel_1// 中断相关宏定义
#define GENERAL_TIM_IT_CCx TIM_IT_CC1
#define GENERAL_TIM_IRQ TIM5_IRQn
#define GENERAL_TIM_INT_FUN TIM5_IRQHandler// 获取捕获寄存器值函数宏定义
#define GENERAL_TIM_GetCapturex_FUN TIM_GetCapture1
// 捕获信号极性函数宏定义
#define GENERAL_TIM_OCxPolarityConfig_FUN TIM_OC1PolarityConfig// 测量的起始边沿
#define GENERAL_TIM_STRAT_ICPolarity TIM_ICPolarity_Rising
// 测量的结束边沿
#define GENERAL_TIM_END_ICPolarity TIM_ICPolarity_Falling// 定时器输入捕获用户自定义变量结构体声明
typedef struct
{ uint8_t Capture_FinishFlag; // 捕获结束标志位uint8_t Capture_StartFlag; // 捕获开始标志位uint16_t Capture_CcrValue; // 捕获寄存器的值uint16_t Capture_Period; // 自动重装载寄存器更新标志
}TIM_ICUserValueTypeDef;extern TIM_ICUserValueTypeDef TIM_ICUserValueStructure;/**************************函数声明********************************/
void GENERAL_TIM_Init(void);#endif /* __BSP_GENERALTIME_H */
下面GENERAL_TIM_Mode_Config是定时器模式配置。
里面初始化了两个结构体。
对于时基结构体
1.GENERAL_TIM_PERIOD配置ARR寄存器的值决定计数器一个周期的计数时间默认配置为0XFFFF(65535)即最大。 自动重装载寄存器ARR16位寄存器这里面装着计数器能计数的最大数值。当计数到这个值的时候如果使能了中断定时器就产生溢出中断。
CNT是16位的计数器只能往上计数最大计数值为65535。当计数达到自动重装载寄存器的时候产生更新事件并清零从头开始计数 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JOmOfWyS-1646185240167)(stm32 输入捕获 测量脉宽.assets/Snipaste_2022-02-27_10-49-11.png)]
时钟源定时器时钟TIMxCLK即内部时钟CK_INT经APB1预分频器分频提供。
APB1预分频系数等于1频率不变。
库函数中APB1预分频的系数是2即PCLK136M所以定时器时钟TIMxCLK36*272M。
计数器时钟CK_CNT
定时器时钟经过PSC预分频器后即CK_CNT用来驱动计数器计数。
PSC是16位的预分频器可以对定时器时钟TIMxCLK进行1~65536之间的任何一个数进行分频。CK_CNTTIMxCLK/(PSC1)。
2.GENERAL_TIM_PSC配置分频因子默认配置为72-1。可以计算出计数器的计数周期为(GENERAL_TIM_PSC1)/72M1us。 当捕获通道TIx上出现上升沿时发生第一次捕获。
计数器CNT的值被锁存到捕获寄存器CCR中进入捕获中断。
输入捕获能捕获的最小的时间为1us最长的时间为1us *(0Xffff1)65536us65.536ms。
超过这个计数周期的时候产生中断然后在中断里面做额外的处理。
需要记录好产生了多少次更新中断最后把更新时间加入脉宽时间里面。 GENERAL_TIM_NVIC_Config是中断优先级配置。只有一个中断源优先级可以随便配置。
#include bsp_GeneralTim.h// 定时器输入捕获用户自定义变量结构体定义
TIM_ICUserValueTypeDef TIM_ICUserValueStructure {0,0,0,0};// 中断优先级配置
static void GENERAL_TIM_NVIC_Config(void)
{NVIC_InitTypeDef NVIC_InitStructure; // 设置中断组为0NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); // 设置中断来源NVIC_InitStructure.NVIC_IRQChannel GENERAL_TIM_IRQ ; // 设置主优先级为 0NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 0; // 设置抢占优先级为3NVIC_InitStructure.NVIC_IRQChannelSubPriority 3; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE;NVIC_Init(NVIC_InitStructure);
}static void GENERAL_TIM_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 输入捕获通道 GPIO 初始化RCC_APB2PeriphClockCmd(GENERAL_TIM_CH1_GPIO_CLK, ENABLE);GPIO_InitStructure.GPIO_Pin GENERAL_TIM_CH1_PIN;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING;GPIO_Init(GENERAL_TIM_CH1_PORT, GPIO_InitStructure);
}///*
// * 注意TIM_TimeBaseInitTypeDef结构体里面有5个成员TIM6和TIM7的寄存器里面只有
// * TIM_Prescaler和TIM_Period所以使用TIM6和TIM7的时候只需初始化这两个成员即可
// * 另外三个成员是通用定时器和高级定时器才有.
// *-----------------------------------------------------------------------------
// *typedef struct
// *{ TIM_Prescaler 都有
// * TIM_CounterMode TIMx,x[6,7]没有其他都有
// * TIM_Period 都有
// * TIM_ClockDivision TIMx,x[6,7]没有其他都有
// * TIM_RepetitionCounter TIMx,x[1,8,15,16,17]才有
// *}TIM_TimeBaseInitTypeDef;
// *-----------------------------------------------------------------------------
// *//* ---------------- PWM信号 周期和占空比的计算--------------- */
// ARR 自动重装载寄存器的值
// CLK_cnt计数器的时钟等于 Fck_int / (psc1) 72M/(psc1)
// PWM 信号的周期 T ARR * (1/CLK_cnt) ARR*(PSC1) / 72M
// 占空比PCCR/(ARR1)static void GENERAL_TIM_Mode_Config(void)
{// 开启定时器时钟,即内部时钟CK_INT72MGENERAL_TIM_APBxClock_FUN(GENERAL_TIM_CLK,ENABLE);/*--------------------时基结构体初始化-------------------------*/ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 自动重装载寄存器的值累计TIM_Period1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_PeriodGENERAL_TIM_PERIOD; // 驱动CNT计数器的时钟 Fck_int/(psc1)TIM_TimeBaseStructure.TIM_Prescaler GENERAL_TIM_PSC; // 时钟分频因子 配置死区时间时需要用到TIM_TimeBaseStructure.TIM_ClockDivisionTIM_CKD_DIV1; // 计数器计数模式设置为向上计数TIM_TimeBaseStructure.TIM_CounterModeTIM_CounterMode_Up; // 重复计数器的值没用到不用管TIM_TimeBaseStructure.TIM_RepetitionCounter0; // 初始化定时器TIM_TimeBaseInit(GENERAL_TIM, TIM_TimeBaseStructure);/*--------------------输入捕获结构体初始化-------------------*/ TIM_ICInitTypeDef TIM_ICInitStructure;// 配置输入捕获的通道需要根据具体的GPIO来配置TIM_ICInitStructure.TIM_Channel GENERAL_TIM_CHANNEL_x;// 输入捕获信号的极性配置TIM_ICInitStructure.TIM_ICPolarity GENERAL_TIM_STRAT_ICPolarity;// 输入通道和捕获通道的映射关系有直连和非直连两种TIM_ICInitStructure.TIM_ICSelection TIM_ICSelection_DirectTI;// 输入的需要被捕获的信号的分频系数TIM_ICInitStructure.TIM_ICPrescaler TIM_ICPSC_DIV1;// 输入的需要被捕获的信号的滤波系数TIM_ICInitStructure.TIM_ICFilter 0;// 定时器输入捕获初始化TIM_ICInit(GENERAL_TIM, TIM_ICInitStructure);// 清除更新和捕获中断标志位TIM_ClearFlag(GENERAL_TIM, TIM_FLAG_Update|GENERAL_TIM_IT_CCx); // 开启更新和捕获中断 TIM_ITConfig (GENERAL_TIM, TIM_IT_Update | GENERAL_TIM_IT_CCx, ENABLE );// 使能计数器TIM_Cmd(GENERAL_TIM, ENABLE);
}void GENERAL_TIM_Init(void)
{GENERAL_TIM_GPIO_Config();GENERAL_TIM_NVIC_Config();GENERAL_TIM_Mode_Config();
}中断服务函数 输入捕获的起始边沿为GENERAL_TIM_STRAT_ICPolarity这是一个宏默认配置为上升沿。
// 测量的起始边沿
#define GENERAL_TIM_STRAT_ICPolarity TIM_ICPolarity_Rising按键默认接GND按键按下的时候被拉高这个时候这个由低到高的上升沿被捕获到这是第一次捕获。
此时把计数器清0开始计数同时把捕获边沿改成下降沿捕获。
第二次进入中断服务函数的时候说明捕获到下降沿这个时候表示脉宽捕获完毕。
读取捕获寄存器的值然后可以通过这个值算出脉宽的时间。
最后把捕获编译配置为上升沿为的是下一次捕获。
脉宽的时间超过了计数器的最大计数时间就会产生更新中断需要记录产生了多少次更新中断。
最后算脉宽的时间的时候加上更新的时间。
中断服务函数里面捕获结束标志位、捕获开始标志位、捕获寄存器的值、自动重装载更新标志在一个结构体里面定义。
// 定时器输入捕获用户自定义变量结构体声明
typedef struct
{ uint8_t Capture_FinishFlag; // 捕获结束标志位uint8_t Capture_StartFlag; // 捕获开始标志位uint16_t Capture_CcrValue; // 捕获寄存器的值uint16_t Capture_Period; // 自动重装载寄存器更新标志
}TIM_ICUserValueTypeDef;void GENERAL_TIM_INT_FUN(void)
{// 当要被捕获的信号的周期大于定时器的最长定时时定时器就会溢出产生更新中断// 这个时候我们需要把这个最长的定时周期加到捕获信号的时间里面去if ( TIM_GetITStatus ( GENERAL_TIM, TIM_IT_Update) ! RESET ) { TIM_ICUserValueStructure.Capture_Period ; TIM_ClearITPendingBit ( GENERAL_TIM, TIM_FLAG_Update ); }// 上升沿捕获中断if ( TIM_GetITStatus (GENERAL_TIM, GENERAL_TIM_IT_CCx ) ! RESET){// 第一次捕获if ( TIM_ICUserValueStructure.Capture_StartFlag 0 ){// 计数器清0TIM_SetCounter(GENERAL_TIM, 0 );// 自动重装载寄存器更新标志清0TIM_ICUserValueStructure.Capture_Period 0;// 存捕获比较寄存器的值的变量的值清0 TIM_ICUserValueStructure.Capture_CcrValue 0;// 当第一次捕获到上升沿之后就把捕获边沿配置为下降沿GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Falling);// 开始捕获标准置1 TIM_ICUserValueStructure.Capture_StartFlag 1; }// 下降沿捕获中断else // 第二次捕获{// 获取捕获比较寄存器的值这个值就是捕获到的高电平的时间的值TIM_ICUserValueStructure.Capture_CcrValue GENERAL_TIM_GetCapturex_FUN (GENERAL_TIM);// 当第二次捕获到下降沿之后就把捕获边沿配置为上升沿好开启新的一轮捕获GENERAL_TIM_OCxPolarityConfig_FUN(GENERAL_TIM, TIM_ICPolarity_Rising);// 开始捕获标志清0 TIM_ICUserValueStructure.Capture_StartFlag 0;// 捕获完成标志置1 TIM_ICUserValueStructure.Capture_FinishFlag 1; }TIM_ClearITPendingBit (GENERAL_TIM,GENERAL_TIM_IT_CCx); }
}main函数里面一些初始化在一个while循环中打印测量的脉宽时间。
计算的时候把周期GENERAL_TIMPERIOD和Capture_CcrValue的值都加1后再运算
#define GENERAL_TIM_PSC (72-1)
//CK_CNTTIMxCLK/(PSC1)
// TIM 计数器的驱动时钟定时器时钟经过PSC预分频器后即CK_CNT用来驱动计数器计数。uint32_t TIM_PscCLK 72000000 / (GENERAL_TIM_PSC1);// 自动重装载寄存器的值累计TIM_Period1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_PeriodGENERAL_TIM_PERIOD;
#define GENERAL_TIM_PERIOD 0XFFFFuint16_t Capture_CcrValue; // 捕获寄存器的值uint16_t Capture_Period; // 自动重装载寄存器更新标志
/*当要被捕获的信号的周期大于定时器的最长定时时定时器就会溢出产生更新中断
Capture_Period记录进入更新中断的次数*/下面这个计算高电平时间的计数器的值进入更新中断的次数*(自动重装载寄存器的值1)第二次捕获时捕获比较寄存器的值1。
// 计算高电平时间的计数器的值time TIM_ICUserValueStructure.Capture_Period * (GENERAL_TIM_PERIOD1) (TIM_ICUserValueStructure.Capture_CcrValue1);为什么都要加一呢是因为
计数器CNTCNT是16位的计数器只能往上计数最大计数值为65535。当计数达到自动重装载寄存器的时候产生更新事件并清零从头开始计数。
计数器是从0开始计数的0计数到65536就是65537个数了。
计算高电平脉宽时间TIM_PscCLK是计数频率倒数就是计一个数的周期。
计数器的计数周期 * 高电平时间的计数器的值(1/TIM_PscCLK) * timetime/TIM_PscCLK。
printf ( \r\n测得高电平脉宽时间%d.%d s\r\n,time/TIM_PscCLK,time%TIM_PscCLK );#include stm32f10x.h
#include bsp_led.h
#include bsp_usart.h
#include bsp_GeneralTim.h /*** brief 主函数* param 无 * retval 无*/
int main(void)
{uint32_t time;// TIM 计数器的驱动时钟uint32_t TIM_PscCLK 72000000 / (GENERAL_TIM_PSC1);/* 串口初始化 */USART_Config();/* 定时器初始化 */GENERAL_TIM_Init();printf ( \r\nSTM32 输入捕获实验\r\n );printf ( \r\n按下K1测试K1按下的时间\r\n );while ( 1 ){if(TIM_ICUserValueStructure.Capture_FinishFlag 1){// 计算高电平时间的计数器的值time TIM_ICUserValueStructure.Capture_Period * (GENERAL_TIM_PERIOD1) (TIM_ICUserValueStructure.Capture_CcrValue1);// 打印printf ( \r\n测得高电平脉宽时间%d.%d s\r\n,time/TIM_PscCLK,time%TIM_PscCLK );TIM_ICUserValueStructure.Capture_FinishFlag 0; } }
}