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频率