stm32f103c8t6学习 输入捕获测pwm频率(计频法)

main.c

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "pwm.h"
#include "beamsensor.h"
#include "timer.h"

uint16_t time;
uint16_t number;
uint16_t count;

int main(void)
{
	OLED_Init();//初始化外设
	pwm_init();
	beamsensor_init();
	timer_init();
	
	OLED_ShowString(1,1,"freq:00000Hz");
	OLED_ShowString(2,1,"count:00000");
	OLED_ShowString(3,1,"time:00000");
	
	pwm_setprescaler(720-1);//freq=72m/(psc+1)/(100-1+1)
	pwm_setcompare(50);
	while(1)//死循环
	{
		OLED_ShowNum(1,6,number,5);
		OLED_ShowNum(2,7,count_get(),5);//uint_16最大65,535
		OLED_ShowNum(3,6,time,5);
	}
}
void TIM3_IRQHandler(void)//tim3中断函数 在startup文件中查找
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)//检查tim2跟新中断标志位
	{
		number=count_get();
		count=0;
		time++;
		TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//中断函数执行结束后清零中断标志位
	}
}


完善pwm模块

pwm.c

#include "stm32f10x.h"                  // Device header

void pwm_init(void)//开启外设时钟→配置时基单元→配置输出比较单元→配置gpio口→运行控制启动计数器
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//通用计时器tim2是apb1总线的外设,故开启apb1的rcc时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启gpio_a时钟
	/*引脚重映射
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);//启用部分重映射1(pa0→pa15;pa1→pb3)
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//解除JTAG的赋用,可使pa15、pb3、pb4做普通gpio使用
	*/
	GPIO_InitTypeDef GPIO_InitStruct;//定义结构体 初始化gpio中一参数
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出 引脚控制来自片上外设,pwm通过引脚输出
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;//使用gpio_a0 tim2引脚查看引脚配置图
	//GPIO_InitStruct.GPIO_Pin=GPIO_Pin_15;//引脚重映射至pa15 
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);//初始化gpio
	
	//配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//定义结构体 初始化时基单元中一参数
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//滤波器采样频率 选用一分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
	TIM_TimeBaseInitStruct.TIM_Period=100-1;//周期 arr
	TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//预分频器 psc
	//定时频率=72m/(psc+1)/(arr+1)定时一秒即一赫兹=72m/10000/7200
	//注:psc和arr取值范围[0~65535]
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//重复计数器 高级定时器中用
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化
	
	//配置输出比较单元
	TIM_OCInitTypeDef TIM_OCInitStruct;//定义结构体 初始化输出比较单元中一参数
	TIM_OCStructInit(&TIM_OCInitStruct);//所有结构体变量赋初始值
	//之后,根据使用的定时器类型针对部分变量进行修改(通用计时器tim2只需用到结构体的部分参数,其余参数在高级定时器中使用)
	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=0 ;//设置ccr
	//频率=72m/(psc+1)/(arr+1) 占空比=ccr/(arr+1) 分辨率=1/(arr+1)
	TIM_OC1Init(TIM2, &TIM_OCInitStruct);
	
	TIM_Cmd(TIM2, ENABLE);//启动定时器
}
void pwm_setcompare(uint16_t Compare1)//修改占空比
{
	TIM_SetCompare1(TIM2, Compare1);
}
void pwm_setprescaler(uint16_t Prescaler)//修改psc以改变频率且不改变占空比
{
	TIM_PrescalerConfig(TIM2, Prescaler, TIM_PSCReloadMode_Immediate);//写入立即生效 TIM_PSCReloadMode_Update更新事件生效
	
}

pwm.h

#ifndef __pwm_h 
#define __pwm_h 

void pwm_init(void);
void pwm_setcompare(uint16_t Compare1);
void pwm_setprescaler(uint16_t Prescaler);

#endif

改写beamsensor.c用于计频

#include "stm32f10x.h"                  // Device header

extern uint16_t count;//跨文件申明变量

void beamsensor_init(void)//初始外设 配置中断:rcc时钟→gpio中断响应→afio中断引脚选择→exti边缘检测及控制→nvic优先级选择→信号进入cpu
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启gpio_b时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启afio时钟
	
	GPIO_InitTypeDef GPIO_InitStruct;//定义结构体 初始化gpio中一参数
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;//上拉输入
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;//使用gpio_b12
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct);//初始化gpio
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource12);//配置afio中断引脚为gpio_b12
	
	//配置exti
	EXTI_InitTypeDef EXTI_InitStruct;//定义结构体 初始化exti中一参数
	EXTI_InitStruct.EXTI_Line=EXTI_Line12;//使用gpio_b12所在的第12号线路
	EXTI_InitStruct.EXTI_LineCmd=ENABLE;
	EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;//中断模式
	EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
	EXTI_Init(&EXTI_InitStruct);
	
	//配置nvic
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置优先级分组
    NVIC_InitTypeDef NVIC_InitStruct;//定义结构体 初始化nvic中一参数
	NVIC_InitStruct.NVIC_IRQChannel=EXTI15_10_IRQn;//exti10~15
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;//响应优先级
	NVIC_Init(&NVIC_InitStruct);//初始化
}
void EXTI15_10_IRQHandler(void)//各个通道中断函数名都是固定的,在startup文件中查找
{
	if(EXTI_GetITStatus(EXTI_Line12)==SET)//判断中断标志位是否是EXTI_Line12
	{
		if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_12)==0)//下降沿触发→低电平
		{
			count ++;//中断自加
			EXTI_ClearITPendingBit(EXTI_Line12);//中断函数执行结束后清零中断标志位
		}
	}
}
uint16_t count_get(void)
{
	return count;
}

beamsensor.h

#ifndef __beamsensor_h 
#define __beamsensor_h 

void beamsensor_init(void);
//void EXTI15_10_IRQHandler(void) 中断函数不需要声明,中断函数自动执行
uint16_t count_get(void);

#endif

timer.c改用tim3定时一秒中断

#include "stm32f10x.h"
//extern uint16_t number;//跨文件申明变量

void timer_init(void)//初始化定时器 rcc开启时钟→选择时基单元时钟源→配置时基单元→配置输出中断控制→配置nvic打开定时器中断的通道,并分配优先级→使能运行控制
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//通用计时器tim3是apb1总线的外设,故开启apb1的rcc时钟
	
	TIM_InternalClockConfig(TIM3);//选择内部时钟 定时器上电后默认选择,不写该行代码也行
	
	//配置时基单元
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//定义结构体 初始化时基单元中一参数
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//滤波器采样频率 选用一分频
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//向上计数模式
	TIM_TimeBaseInitStruct.TIM_Period=10000-1;//周期 arr
	TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;//预分频器 psc
	//定时频率=72m/(psc+1)/(arr+1)定时一秒即一赫兹=72m/10000/7200
	//注:psc和arr取值范围[0~65535]
	TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//重复计数器 高级定时器中用
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);//初始化
	
	TIM_ClearFlag(TIM3,TIM_IT_Update);//手动清除时基单元初始化带来的中断标志位 避免刚初始化完就立马进中断
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//使能跟新中断
	
	//配置nvic
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置优先级分组
    NVIC_InitTypeDef NVIC_InitStruct;//定义结构体 初始化nvic中一参数 结构体变量可重复使用
	NVIC_InitStruct.NVIC_IRQChannel=TIM3_IRQn;//tim3在nvic中的通道
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;//响应优先级
	NVIC_Init(&NVIC_InitStruct);//初始化
	
	TIM_Cmd(TIM3, ENABLE);//启动定时器
}
/*中断函数样例 可于主函数中直接使用,也可跨文件申明变量直接调用
void TIM3_IRQHandler(void)//tim2中断函数 在startup文件中查找
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)//检查tim3跟新中断标志位
	{
		number++;
		TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//中断函数执行结束后清零中断标志位
	}
}
*/

timer.h

#ifndef __TIMER_H
#define __TIMER_H

void timer_init(void);

#endif

OLED模块前有介绍

运行效果

计频法测pwm频率

修改pwm_setprescaler()参数以改变pwm频率

  • 8
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值