其它文章链接,独家吐血整理
(实验3)单片机,STM32F4学习笔记,代码讲解【按键输入实验】【正点原子】【原创】
(实验4)单片机,STM32F4学习笔记,代码讲解【串口实验】【正点原子】【原创】
(实验5)单片机,STM32F4学习笔记,代码讲解【外部中断实验】【正点原子】【原创】
(实验6,实验7)单片机,STM32F4学习笔记,代码讲解【看门狗实验】【正点原子】【原创】
(实验8)单片机,STM32F4学习笔记,代码讲解【定时器实验】【正点原子】【原创】
(实验9)单片机,STM32F4学习笔记,代码讲解【PWM输出实验】【正点原子】【原创】
(实验10)单片机,STM32F4学习笔记,代码讲解【输入捕获实验】【正点原子】【原创】
(实验11)单片机,STM32F4学习笔记,代码讲解【电容触摸按键实验】【正点原子】【原创】
(实验12)单片机,STM32F4学习笔记,代码讲解【OLED显示实验】【正点原子】【原创】
(实验13)单片机,STM32F4学习笔记,代码讲解【TFTLCD彩屏显示实验】【正点原子】【原创】
(实验15)单片机,STM32F4学习笔记,代码讲解【RTC实时时钟实验】【正点原子】【原创】
(实验17)单片机,STM32F4学习笔记,代码讲解【待机唤醒实验】【正点原子】【原创】
(实验23)单片机,STM32F4学习笔记,代码讲解【DMA实验】【正点原子】【原创】
(实验25)单片机,STM32F4学习笔记,代码讲解【SPI实验】【正点原子】【原创】
(实验34)单片机,STM32F4学习笔记,代码讲解【FLASH模拟EEPROM实验】【正点原子】【原创】
(实验36)单片机,STM32F4学习笔记,代码讲解【外部SRAM实验】【正点原子】【原创】
(实验37)单片机,STM32F4学习笔记,代码讲解【内存管理实验】【正点原子】【原创】
(实验38)单片机,STM32F4学习笔记,代码讲解【SD卡实验】【正点原子】【原创】
(实验39)单片机,STM32F4学习笔记,代码讲解【FATFS实验】【正点原子】【原创】
(实验46)单片机,STM32F4学习笔记,代码讲解【FPU测试实验】【正点原子】【原创】
(实验47)单片机,STM32F4学习笔记,代码讲解【DSP-FFT测试实验】【正点原子】【原创】
(实验50)单片机,STM32F4学习笔记,代码讲解【串口IAP实验】【正点原子】【原创】
(实验50)单片机,STM32F4学习笔记,代码讲解【串口IAP实验-RTC时钟实验】【正点原子】【原创】
(实验55)单片机,STM32F4学习笔记,代码讲解【网络通信实验】【正点原子】【原创】
实验现象
本实验利用TIM5_CH1来做输入捕获,我们将捕获PA0上的高电平脉宽,并将脉宽时间通过串口打印出来,大家可以通过按WK_UP按键,模拟输入高电平。同时,本实验将保留上一个实验的PWM输出,DS0还是会由暗–>亮的循环变化,大家可以通过杜邦线连接PA0和PF9,来观测PWM输出的高电平时间。
作者注:这里,DS0不是像前面那个,暗渐渐亮渐渐暗渐渐亮,而是暗渐渐亮瞬间暗再渐渐亮循环
主程序
extern u8 TIM5CH1_CAPTURE_STA; //输入捕获状态
extern u32 TIM5CH1_CAPTURE_VAL; //输入捕获值
int main(void)
{
long long temp=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200);//初始化串口波特率为115200
TIM14_PWM_Init(500-1,84-1); //84M/84=1Mhz的计数频率计数到500,PWM频率为1M/500=2Khz
TIM5_CH1_Cap_Init(0XFFFFFFFF,84-1); //以1Mhz的频率计数,记满一次0xFFFFFFFF是4294秒,这几乎不可能,太长了吧
while(1)
{
delay_ms(10);
TIM_SetCompare1(TIM14,TIM_GetCapture1(TIM14)+1);
if(TIM_GetCapture1(TIM14)==300)TIM_SetCompare1(TIM14,0);
if(TIM5CH1_CAPTURE_STA&0X80) //成功捕获到了一次高电平 1000 0000
{
temp=TIM5CH1_CAPTURE_STA&0X3F; //0011 1111 最大是0x3F*4294秒,这特么也太长太长了吧,这上面没溢出一次,TIM5CH1_CAPTURE_STA低6位会加1一次
temp*=0XFFFFFFFF; //溢出时间总和
temp+=TIM5CH1_CAPTURE_VAL; //得到总的高电平时间
printf("HIGH:%lld us\r\n",temp); //打印总的高点平时间
TIM5CH1_CAPTURE_STA=0; //开启下一次捕获
}
}
}
定时器5输入捕获初始化程序
TIM_ICInitTypeDef TIM5_ICInitStructure;
//定时器5通道1输入捕获配置
//arr:自动重装值(TIM2,TIM5是32位的!!)
//psc:时钟预分频数
void TIM5_CH1_Cap_Init(u32 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //TIM5时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0
GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5); //PA0复用位定时器5
TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
//初始化TIM5输入捕获参数
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断
TIM_Cmd(TIM5,ENABLE ); //使能定时器5
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
}
定时器5中断程序
//捕获状态
//[7]:0,没有成功的捕获;1,成功捕获到一次.
//[6]:0,还没捕获到低电平;1,已经捕获到低电平了.
//[5:0]:捕获低电平后溢出的次数(对于32位定时器来说,1us计数器加1,溢出时间:4294秒)
u8 TIM5CH1_CAPTURE_STA=0; //输入捕获状态
u32 TIM5CH1_CAPTURE_VAL; //输入捕获值(TIM2/TIM5是32位)
//定时器5中断服务程序
void TIM5_IRQHandler(void)
{
//if((TIM5CH1_CAPTURE_STA&0X80)==0)只判断第7位
//if(TIM5CH1_CAPTURE_STA&0X40)只判断第6位
//if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)只判断0-5位是否全为1
//TIM5CH1_CAPTURE_STA|=0X80;第7位置为1,0-6位保持原样
//TIM5CH1_CAPTURE_STA|=0X40;第6位置为1,0-5,7位保持原样
//现在我所有都明白了,就是将一个8位变量间接当做寄存器使用,很巧妙,首先定时器5初始化时就默认设置好上升沿触发了
//然后定时器5中断里面第一个if判断是定时器计数中断,第二个if判断是捕获器中断,先说第一个,当定时器计数溢出4294秒
//此时若捕获到高电平说明还没遇到下降沿也就是还处于高电平,于是TIM5CH1_CAPTURE_STA++;每加一次代表4294秒
//if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)只判断0-5位是否全为1,这一句代表高电平太长了这不可能但也加进去了4294*0x3F秒
//然后第二个if中,发生捕获那么一定是上升沿捕获(初始化设置好的),那么此时进入else清空计数,设置下降沿,同时第6位置1
//于是再进入捕获中断,判断第6位是否是1,如果是那么第7位置1,然后定时器计数中断再判断第17位是否为1,那么这就标记好了
//就这么简单,哈哈哈
if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获 1000 0000
{
if(TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)//溢出
{
if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
{
TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获了一次
TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;
}else TIM5CH1_CAPTURE_STA++;
}
}
if(TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
{
if(TIM5CH1_CAPTURE_STA&0X40) //捕获到一个下降沿
{
TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次高电平脉宽
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);//获取当前的捕获值.
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
}else //还未开始,第一次捕获上升沿
{
TIM5CH1_CAPTURE_STA=0; //清空
TIM5CH1_CAPTURE_VAL=0;
TIM5CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿
TIM_Cmd(TIM5,DISABLE ); //关闭定时器5
TIM_SetCounter(TIM5,0);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获
TIM_Cmd(TIM5,ENABLE ); //使能定时器5
}
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
}
代码讲解
//输入捕获实验很简单=测量高电平脉冲的持续时间=据此可计算脉冲宽度或者测量频率(私以为不就是频率计嘛)
//原理很简单,就是先将定时器设置成向上捕获状态,当高电平来临时,触发后得到当前CNT值=定时器计数值,然后再清0
//于是此时定时立即设置成向下捕获模式,当下降沿来临时说明高电平持续时间结束了,于是得到当前CNT计数值
//可是向上与向下之间肯定会有N次计数溢出,这没事,所以总CNT计数值=CCRx2(向下捕获的CNT)+N*ARR(溢出计数值)
//于是下面就好做了,利用定时器计数频率,计数这些个数字得到的时间即可
//除了TIM6和TIM7,其它定时器都有输入捕获功能,这个程序代码呢,就是使用TIM5来进行输入捕获前面的TIM14输出的PWM波
//哈哈,活学活用
//在定时器输入捕获时,上升沿或者下降沿触发捕获时,还可以设置触发中断/DMA等
//输入/比较模式寄存器中,TIMx_CCMR1和TIMx_CCMR2两个寄存器,前者输入捕获通道12,后者是34
//这和前面PWM输出实验中所说,也是两个寄存器,一个控制12路·,一个控制34路类似,在这里TIM5用TIMx_CCMR1低8位0-7
//进行输入捕获通道1,这低8位中,四位用来设置滤波器,2位设置预分频,2位设置通道方向
//此程序中,TIM5通道1中,预分频设置00=一次边沿触发一次捕获,滤波器设置0000=不滤波(提高响应速度),CC1设置01=IC1映射到TI1上
//作者说,IC1与TI1不明白的,可看中文参考手册,淦,CC1设置01=IC1=对应于TIMx_CH1
//输入捕获的自动重装载值和计数频率=前面说过的定时器设置方式=一样的
//这一块的具体思路,我大概明白了,程序没有百分百弄明白,就是把这个TIM5CH1_CAPTURE_STA,8位数据=一个字节间接当做寄存器使用了
//这和那个串口打印一摸一样的道理,总之就是很精彩,8位最高位用来表示成功捕获到一次表示,6位用来做设置下降沿捕获标志位
//而剩下的6位全部用来存储溢出的次数,你想想本来溢出一次就是4294秒,没溢出一次这六位数据加1,所以足够了
注:这里,DS0不是像前面那个,暗渐渐亮渐渐暗渐渐亮,而是暗渐渐亮瞬间暗再渐渐亮循环