文章目录
TIM定时器与中断
参考视频
/*定时器配置,先不用*/
void My_Timer1_Init(void)
{
//1.初始化时钟配置
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
//2.初始化时基单元,调用的时内部时钟,定时器上电后默认使用内部时钟,不写也是调用内部时钟,可以不写,但是调用外部时钟必须写
TIM_InternalClockConfig(TIM2);
//3.配置时基单元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;//1分频
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
/*时基单元里每个关键寄存器的参数,没有CNT计数器的参数可以用setCounter和getCounter函数操作计数器
计数器溢出频率:CK_CNT_OV=CK_CNT/(ARR+1)=CK_PSC/(PSC+1)/(ARR+1)
定时频率=72M/(PSC+1)/(ARR+1)
72MHZ=72,000,000HZ,下设置的时1HZ*/
TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1; 周期,ARR重装器的值,取值范围:0~65535
TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1; PSC预分频器的值,取值范围:0~65535
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //重复计数器的值,高级定时器才有,不用时直接给0
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
//中断,我这里又RTOS所以注释了
//TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//开启更新中断与NVIC的通路
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组2
//NVIC_InitTypeDef NVIC_InitStruct;
//NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
//NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
//NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;//抢占优先级
//NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;//响应优先级
//NVIC_Init(&NVIC_InitStruct);
//启动定时器
TIM_Cmd(TIM2,ENABLE);
}
/*定时中断而言,中断函数就是为别的文件服务的,所以可以在想用的文件里调用*/
//void TIM2_IRQHandler(void){
//if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET){
//中断内容
//清除标志位
//TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
//}
//}
TIM输出比较(占空比信号概念)
参考视频
| 模式 |
描述 |
| 冻结 |
CNT=CCR时,REF保持原状态 |
| 匹配时置有效电平 |
CNT=CCR时,REF置有效电平(高电平) |
| 匹配时置无效电平 |
CNT=CCR时,REF置无效电平(低电平) |
| 匹配时电平翻转 |
CNT=CCR时,REF电平翻转 |
| 强制为无效电平 |
CMT与CCR无效,REF强制为无效电平 |
| 强制为有效电平 |
CMT与CCR无效,REF强制为有效电平 |
| PWM模式1 |
向上计数:CNT<CCR时,REF置有效电平,CNT>=CCR时,REF置无效电平 |
| PWM模式1 |
向下计数:CNT>CCR时,REF置无效电平,CNT<=CCR时,REF置有效电平 |
| PWM模式2 |
向上计数:CNT<CCR时,REF置无效电平,CNT>=CCR时,REF置有效电平 |
| PWM模式2 |
向下计数:CNT>CCR时,REF置有效电平,CNT<=CCR时,REF置无效电平 |
/*
比较器
当CNT>CCR和CNT<CCR时输出TIM_OC1就会对应的置1置0
每个高级定时器和通用定时器都拥有4个输出比较通道;并且高级定时器的三个通道额外拥有死区生成和互补输出的功能
输出比较模式
| 模式 | 描述 |
|----------------|---------------------------------------------------------|
| 冻结 |CNT=CCR时,REF保持原状态 |
|匹配时置有效电平|CNT=CCR时,REF置有效电平(高电平) |
|匹配时置无效电平|CNT=CCR时,REF置无效电平(低电平) |
| 匹配时电平翻转 |CNT=CCR时,REF电平翻转 |
| 强制为无效电平 |CMT与CCR无效,REF强制为无效电平 |
| 强制为有效电平 |CMT与CCR无效,REF强制为有效电平 |
|----------------|---------------------------------------------------------|
| PWM |向上计数:CNT<CCR时,REF置有效电平,CNT>=CCR时,REF置无效电平|
| 模式1 |向下计数:CNT>CCR时,REF置无效电平,CNT<=CCR时,REF置有效电平|
|----------------|---------------------------------------------------------|
| PWM |向上计数:CNT<CCR时,REF置无效电平,CNT>=CCR时,REF置有效电平|
| 模式2 |向下计数:CNT>CCR时,REF置有效电平,CNT<=CCR时,REF置无效电平|
|----------------|---------------------------------------------------------|
冻结模式:正在输出PWM波想要暂停,可以使用这个模式.设置后高低电平维持为暂停时刻的状态
匹配时置有效电平(置高电平),匹配时置无效电平(置低电平),匹配时电平翻转:都是高级定时器里的说法.是和关断、刹车这些功能配合表述的.
强制为无效电平,强制为有效电平:与冻结模式差不多.
PWM模式1和PWM模式2:它们可以输出频率和占空比都可调的PWM波形
PWM基本结构
时基单元:->PSC预分频器->CNT计数器->ARR自动重装器
^ ^
| |
运行控制 v
输出比较单元(*4):CRR捕获/比较器->CNT<CCR时,REF置有效电平 -REF->极性->GPIO
CNT>=CCR时,REF置无效电平 -REF->选择->GPIO
PWM频率: Freq=CK_PSC/(PSC+1)/(ARR+1)
PWM占空比: Duty=CCR/(ARR+1)
PWM分辨率: Reso= 1/(ARR+1)
*/
PWM(占空比信号代码)
参考视频
void My_TIM2_Init(void)
{
My_TIM2_Init_GPIO();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;//1分频
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
/*时基单元里每个关键寄存器的参数,没有CNT计数器的参数可以用setCounter和getCounter函数操作计数器
计数器溢出频率:CK_CNT_OV=CK_CNT/(ARR+1)=CK_PSC/(PSC+1)/(ARR+1)
定时频率=72M/(PSC+1)/(ARR+1)
72MHZ=72,000,000HZ,下设置的时1HZ*/
TIM_TimeBaseInitStruct.TIM_Period = 100 - 1; //周期,ARR重装器的值,取值范围:0~65535
TIM_TimeBaseInitStruct.TIM_Prescaler = 720 - 1; //PSC预分频器的值,取值范围:0~65535
TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //重复计数器的值,高级定时器才有,不用时直接给0
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
//启动定时器
TIM_Cmd(TIM2,ENABLE);
//初始化输出比较单元
//PA0->OC1输出通道(OC1)
/*对结构体而言现在它时局部变量,如果不给它的成员赋初始值,它成员的值是不确定的,可能会导致比如高级定时器做通用定时器输出PWM时,
TIM2改成TIM1这样结构体原来用不到的成员现在用到了,而那些成员没给赋值,那就会导致高级定时器输出PWM出现一些奇怪的问题
为了避免程序中出现不确定因素,有没有用到都把结构体的值全部配置一下,之后在修改个别的值*/
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);//给结构体赋初始值
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;//设置输出比较模式
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;//设置输出比较的极性
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;//设置输出使能
TIM_OCInitStruct.TIM_Pulse = 50;//设置CCR
TIM_OC1Init(TIM2,&TIM_OCInitStruct);
}
呼吸灯
uint8_t i;
void PWM_Task(void *param){
My_TIM2_Init();
while(1){
for(i=0;i<=100;i++){
//单独修改CCR寄存器值
TIM_SetCompare1(TIM2,i);
vTaskDelay(10);
}
for(i=0;i<=100;i++){
TIM_SetCompare1(TIM2,100-i);
vTaskDelay(10);
}
}
}