高级会员

- 积分
- 748
- 金钱
- 748
- 注册时间
- 2015-9-17
- 在线时间
- 60 小时
|
最近才开始学习stm32,遇到了很多问题,今天分享一下成果 。
功能: 1、利用定时器2通道2输出pwm(0~256)
2、利用串口1改变其占空比,并显示出理论正确值
3、利用定时器3通道2捕获pwm,并在中断中显示实际测试值
4、计算中模拟了一个16位捕获状态计数寄存器最高位为高电平状态标置位,次高位为“溢出计数器”溢出位,余下的14位低位用来计数
我用的是战舰开发版,实验中把PA1和PA7相连。
主函数
#include "stm32f10x.h"
#include "time.h"
#include "BEEP.h"
#include "LED.h"
#include "usart.h"
#include "delay.h"
u16 current_count=0;//当前计数值(不论是否计数溢出)
u32 calculate_time=0;//计算高电平时间
u16 capture_state_count=0;//16位模拟寄存器(捕获状态计数寄存器)
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
LED_Init();
beep_Init();//占用GPIOB管脚设置,外设若改变且在beep前使用初始化函数,beep不响
delay_init();
uart_init(19200);//可以通过串口一改变pwm的占空比输出
PWM_Init(256-1,71,50);
//TIM_Init(6000,7199);
Capture_Init(100-1,71);
beep=1;//初始化完毕提示
delay_ms(100);
beep=0;
while(1)
{
led1=0;
delay_ms(500);
led1=1;
delay_ms(500);
}
}
定时器相关函数文件
#include "time.h"
#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
#include "usart.h"
extern u16 capture_state_count;//16位模拟寄存器(捕获状态计数寄存器)
extern u16 current_count;//当前计数值(不论是否计数溢出)
extern u32 calculate_time;//计算高电平时间
/*定时器配置*/
//定时器2
void TIM_Init(u16 TIME_reload,u16 prescaler) //参数1是重装载值(u16),参数2是与分频系数(u16) Tout(溢出时间)=(reload+1)(prescaler+1)/Tclk (Tclk是配置时钟频率,一般为phb1X2的时钟72M)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructre;
NVIC_InitTypeDef NVIC_InitStructre;
/*1、初始化定时器时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
/*2、初始化定时器时基函数*/
TIM_DeInit(TIM2);
TIM_TimeBaseInitStructre.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructre.TIM_Period=TIME_reload;
TIM_TimeBaseInitStructre.TIM_Prescaler=prescaler;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructre);
/*3、打开中断并选择中断源*/
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
NVIC_InitStructre.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructre.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructre.NVIC_IRQChannelSubPriority=3;
NVIC_InitStructre.NVIC_IRQChannelPreemptionPriority=3;
NVIC_Init(&NVIC_InitStructre);
/*4、打开定时器*/
TIM_Cmd(TIM2,ENABLE);
}
/*pwm配置*/
void PWM_Init(u16 time_reload,u16 TIM_Prescaler,u16 pluse_reload)//1、时基单元重装载值2、时基单元预分频系数3、输出比较器装载值
{
/*定时器2通道2*/
//定义结构体变量
GPIO_InitTypeDef GPIO_InitStructre;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructre;
TIM_OCInitTypeDef TIM_OCInitStructre;
/*1、配置时钟,输出管脚时钟、定时器外设时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
/*2、管脚配置*/
GPIO_InitStructre.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructre.GPIO_Pin=GPIO_Pin_1;
GPIO_InitStructre.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructre);
/*3、定时器时基单元配置*/
TIM_TimeBaseInitStructre.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructre.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructre.TIM_Period=time_reload;
TIM_TimeBaseInitStructre.TIM_Prescaler=TIM_Prescaler;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructre);
/*4、定时器输出比较单元配置*/
TIM_OCInitStructre.TIM_OCMode=TIM_OCMode_PWM2;
TIM_OCInitStructre.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStructre.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStructre.TIM_Pulse=pluse_reload;
TIM_OC2Init(TIM2,&TIM_OCInitStructre);
/*5、定时器重装值、比较寄存值允许位打开*/
TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable);//允许改变通道2的输出比较寄存器预存值(调节占空比)
TIM_ARRPreloadConfig(TIM2,ENABLE); //允许改变定时器的重装载值的预存值(调节周期)
/*6、定时器打开使能*/
TIM_Cmd(TIM2,ENABLE);
}
/*捕获配置*/
void Capture_Init(u16 time_reload,u16 TIM_Prescaler)
{
/*定时器3通道2*/
GPIO_InitTypeDef GPIO_InitStructre;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructre;
TIM_ICInitTypeDef TIM_ICInitStructre;
NVIC_InitTypeDef NVIC_InitStructre;
/*1、打开外设时钟及输入管脚时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
/*2、配置输入管脚*/
GPIO_InitStructre.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructre.GPIO_Pin=GPIO_Pin_7;
GPIO_InitStructre.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructre);
/*3、配置时基单元*/
TIM_TimeBaseInitStructre.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructre.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructre.TIM_Period=time_reload;
TIM_TimeBaseInitStructre.TIM_Prescaler=TIM_Prescaler;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructre);
/*4、配置输入捕获单元*/
TIM_ICInitStructre.TIM_Channel=TIM_Channel_2;
TIM_ICInitStructre.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM_ICInitStructre.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM_ICInitStructre.TIM_ICFilter=0x00;
TIM_ICInitStructre.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3,&TIM_ICInitStructre);
/*5、打开并配置通道2的输入捕获中断*/
TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_CC2,ENABLE);//开启更新中断,用于检测电平时间较长,计数器已经重装载的情况
NVIC_InitStructre.NVIC_IRQChannel=TIM3_IRQn;
NVIC_InitStructre.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructre.NVIC_IRQChannelSubPriority=3;
NVIC_InitStructre.NVIC_IRQChannelPreemptionPriority=2;
NVIC_Init(&NVIC_InitStructre);
/*6、打开定时器3*/
TIM_Cmd(TIM3,ENABLE);
TIM_ClearITPendingBit(TIM3, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
}
/*中断服务函数计算高电平时间,其中定义了u16 capture_state_count来模拟一个寄存器,运用位操作来主动捕获*/
void TIM3_IRQHandler(void)
{
if(TIM_GetITStatus(TIM3, TIM_IT_Update)!= RESET)//计数器跟新溢出
{
if(capture_state_count&0x8000)//检测出是在高电平期间溢出,记录溢出次数
capture_state_count++;
if(capture_state_count&0x4000)//“溢出次数“计数器也溢出,提示打印,并清空模拟寄存器
{
printf("溢出错误!!!\n");
capture_state_count=0;
}
}
if(TIM_GetITStatus(TIM3,TIM_IT_CC2)!= RESET)//检测出跳变
{
if(capture_state_count&0x8000)//前一个状态是高电平,现在已跳变为低电平
{
current_count=TIM_GetCapture2(TIM3);//获取当前计数器值
TIM_OC2PolarityConfig(TIM3,TIM_ICPolarity_Rising);//为检测下一个高电平做准备
calculate_time=((capture_state_count&0x3fff)*100)+current_count; //计算高电平占用时间,单位微秒
printf("高电平实际占用时间:%d us\n",calculate_time);//显示
delay_ms(500);
capture_state_count=0;//捕获状态计数寄存器清零,为下次检测做准备
}
else //前一个状态是低电平,现在已跳变为高电平
{
TIM_SetCounter(TIM3,0);//清零,以进入高电平为起点,便于计算
capture_state_count|=0x8000;//置15位为1,标记现在已经处于高电平阶段
TIM_OC2PolarityConfig(TIM3,TIM_OCPolarity_Low);////为检测下一个低电平做准备
}
}
TIM_ClearITPendingBit(TIM3, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位
}
第一次发贴,有什么问题请大家指出来
|
|