输入捕获
这个时序图为什么 我要这么圈呢 因为输入捕获 并不是一个 io 就可以实现的
它用分割线 分成了两半。 而它必须 要有两个 io 才可以 一端输出 之后
一端捕获数据 这样才叫输入捕获的过程
定时器只要有io有对应的 定时器通道 我们就可以设置为输入捕获 或者输出比较
这样我们用起来就很方便。
输出比较回顾
@接上一篇的输出比较 我们简单回顾一下其中的知识点
占空比 就是 一个周期内高电平持续的时间和周期时间的比值 即 高电平时间:一周期时间
ARR可以改变占空比的比值。
代码设计
1)PA1 作为 输出比较 的io PA7 作为 输入捕获的 IO
灵活运用定时器通道 并且定时器都是独立存在的 不用考虑他们冲突的问题
3)代码
GPIOA7.c
GPIO_InitTypeDef GPIO_Initstruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_Initstruct.GPIO_Pin=GPIO_Pin_7;
GPIO_Initstruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Initstruct.GPIO_Mode =GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_Initstruct);
配置为输入 选择 浮空输入就行
NVIC.c
NVIC_InitTypeDef NVIC_Initstruct;
NVIC_Initstruct.NVIC_IRQChannel =TIM3_IRQn;
NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_Initstruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Initstruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_Initstruct);
因为要计算捕获数据 所以要不断产生溢出 时间 产生溢出时间 就要配置中断 配置中断 必要
中断优先级
TIM3.c
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitstruct;
TIM_TimeBaseInitstruct.TIM_Period=65535;
TIM_TimeBaseInitstruct.TIM_Prescaler=0;
TIM_TimeBaseInitstruct.TIM_CounterMode =TIM_CounterMode_Up;
TIM_TimeBaseInitstruct.TIM_ClockDivision =TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitstruct);
定时器配置 这里的ARR 必须为最大 预分频只要取到合适的 起到倍频就行了 即要大于1
因为我们的分频只要不为 0 得到(0+1) 那么他可以 倍频 在定时器二我会说取 65535的原因
你们可以先记下来 等会在回头看看
TIM3Capture.c
TIM_ICInitTypeDef TIM_ICInitstruct;
TIM_ICInitstruct.TIM_ICSelection =TIM_ICSelection_DirectTI; //寄存器映射到 外设
TIM_ICInitstruct.TIM_ICPrescaler =TIM_ICPSC_DIV1;//预分频系数为 1
TIM_ICInitstruct.TIM_ICPolarity =TIM_ICPolarity_Rising;//高电平
TIM_ICInitstruct.TIM_Channel =TIM_Channel_2;
TIM_ICInitstruct.TIM_ICFilter =0X00;//一周期更新一次
TIM_ICInit(TIM3,&TIM_ICInitstruct);
TIM_PWMIConfig(TIM3,&TIM_ICInitstruct);//配置为输入模式 (重点 )
其中要点
寄存器映射 :寄存器是特殊的存储器 ,给寄存器地址命名的过程就是 寄存器映射
简单的说 它存放的就是ARR的值
PWM IN.C(重点看 )
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
GPIOA7_IN();//1 初始化io
NVICstruct();// 2 中断
TIM_DeInit(TIM3); //复位
TIM3_BaseInit();//4 //定时器 配置
TIM3_CaptureInit();//5 //输入配置
TIM_SelectInputTrigger(TIM3,TIM_TS_TI2FP2);//输入触发源 通道二
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);//捕获 上升沿 配置为复位模式
TIM_ITConfig(TIM3,TIM_IT_CC2,ENABLE);
TIM_Cmd(TIM3,ENABLE);
输入捕获 为复位模式 (重要)
输入捕获的全过程
捕获的是占空比 占空比就是高电平
输入的基本流程 1 io ----2 中断 -----3 复位 (在检查一次中断有无出错)----4 定时
---5转为输入模式-----选择输入触发源 -------设置捕获上升沿-----更新中断源-----使能定时器
OUTput.c
void TIM2_PwmOutPut(unsigned int peroid,unsigned int TIM2Plshu)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitstruct;
TIM_OCInitTypeDef TIM_OCInitstruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_TimeBaseInitstruct.TIM_Period=peroid;//ARR 设置为变量
TIM_TimeBaseInitstruct.TIM_Prescaler=0; //不分频
TIM_TimeBaseInitstruct.TIM_CounterMode =TIM_CounterMode_Up;
TIM_TimeBaseInitstruct.TIM_ClockDivision =TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitstruct);
TIM_PrescalerConfig(TIM2,35,TIM_PSCReloadMode_Immediate); (重点)
//设置定时器的arr 在定时器工作时 的值为 35
//这样就可以算出他在工作时的频率了
36/(35+1)*(0+1)=1M
TIM_OCInitstruct.TIM_OCMode =TIM_OCMode_PWM2;
TIM_OCInitstruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitstruct.TIM_OCPolarity =TIM_OCPolarity_Low;
TIM_OCInitstruct.TIM_Pulse=TIM2Plshu;
TIM_OC2Init(TIM2,&TIM_OCInitstruct);
TIM_CtrlPWMOutputs(TIM2,ENABLE); (重点)配置为输出模式
TIM_Cmd(TIM2,ENABLE);
}
注意输出模式的函数名字
注意输出模式的函数 TIM_CtrlPWMOutputs(TIM2,ENABLE);
解答 TIM3遗漏的问题
TIM3 为什么 设为 65535
/*******************************
根据上面算出了 TIM2的频率(往下看 )
//设置定时器的arr 在定时器工作时 的值为 35
//这样就可以算出他在工作时的频率了
36/(35+1)*(0+1)=1M
**************************/
通过TIM2的计算得出 最大频率为1m 对应的计数值也应该是最大了
那么在TIM3身上 设定的 65535 得到的频率也应该是 1M 那么就是 捕获速度设为最大了
提高效率
中断函数
void TIM3_IRQHandler(void)
{
TIM_ClearITPendingBit(TIM3,TIM_IT_CC2);//清除标志位
GPOA7_CCR2=TIM3->CCR2;
if(GPOA7_CCR2!=0){
Workhanlder=(TIM3->CCR1*100)/GPOA7_CCR2;
PWM_HZ=SystemCoreClock/GPOA7_CCR2;
}else {
Workhanlder=0;
PWM_HZ=0;
}
}
GPOA7_CCR2=TIM3->CCR2; 计算周期占空比
Workhanlder=(TIM3->CCR1*100)/GPOA7_CCR2;
(TIM3->CCR1*100) 相当于一个100倍的长度 100不是固定的 这里只是为一个合适的取值
为了给输出比较的初始化取值方便 继续往下看。
这样就得出了 设定的高电平的周期长度 注意是高电平信号周期长度 最后除以 CCR2
得到的是 占空比的工作周期次数
注意字母写法
TIMX->CCRX:寄存器的写法: 指的是 比较值 比较值用于确定占空比
main.c
#include "stm32f10x.h"
#include "funcofig.h"
#include "tim.h"
#include "lcd.h"
#include "systick.h"
#include "key.h"
#define PWM_x(X,B) (B+1)*X/100 //X为占空比
extern unsigned int PWM_HZ;
extern unsigned int Workhanlder;
unsigned char x1=10,y1=1;
unsigned char keyflag=2;
unsigned char keyreturns;
unsigned char show_lcd=2;
unsigned char key_pwm;
char PWM_IN_buff[128];
char PWM_OUT_buff[128];
char CCR2_IN_buff[128];
char CCR2_OUT_buff[128];
void ALLInit(void)
{
SysTickInit(); //1ms中断一次
STM3210B_LCD_Init();
key_init();//按键
PWM_INConfig();//输入模式配置(重要)
GPIOA1_OUT();//输出函数调用
LCD_Clear(White); //清屏为白色
LCD_SetBackColor(Red);
LCD_SetTextColor(Black); //字体为 蓝色
show_lcd=2;
lcd_xianshi();
TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1);//往下看 有你想知道的答案
}
//
void lcd_xianshi(void)
{
if(show_lcd==2)
{
LCD_SetBackColor(White);//背景为白色
LCD_SetTextColor(Blue); //字体为 蓝色
sprintf((unsigned char *)PWM_OUT_buff,"PWM_OUT2:%dKHZ ",y1);
LCD_DisplayStringLine(Line3,PWM_OUT_buff);
sprintf((unsigned char *)PWM_IN_buff,"PWM_IN2:%dHZ ",PWM_HZ/2);
LCD_DisplayStringLine(Line4,PWM_IN_buff);
sprintf((unsigned char *)CCR2_OUT_buff,"CCR2_OUT:%d ",x1);
LCD_DisplayStringLine(Line5,CCR2_OUT_buff);
sprintf((unsigned char *)CCR2_IN_buff,"CCR2_IN:%d ",Workhanlder);
LCD_DisplayStringLine(Line6,CCR2_IN_buff);
LCD_DisplayChar(Line5,319-16*12,'%');
LCD_DisplayChar(Line6,319-16*12,'%');
//
}
}
void PWM_Capture_OUT(void)
{
key_pwm=key_Scan();//按键函数
switch(key_pwm){
case 'B':
Delay_Ms(100);
if(show_lcd==2){//事件2 (为复位事件)
show_lcd=2; //标记事件2
lcd_xianshi();
if(x1==100){ //加到100%
x1=10; //加到100% 就回到10%
} else
{
x1+=10;//每次加 10%
}
if(y1==7) TIM2_PwmOutPut(286-1,PWM_x(x1,286-1)+1);
else TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1);
}break;
case 'C':
Delay_Ms(100); //消抖
if(show_lcd==2){//事件2
show_lcd=2; //标记事件2
lcd_xianshi();
if(y1==10){ //加10khz
y1=0; //回到0khz
}
else
{
y1+=1;//每次加1khz
}
if(y1==7) TIM2_PwmOutPut(286-1,PWM_x(x1,286-1)+1);
else TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1);
}
break;
}
}
***核心部分
#define PWM_x(X,B) (B+1)*X/100 //X为占空比
B相当于是占空比的次数 简单理解就行了
根据这段代码反推出初始化的赋值
下面的多看几次 (工程最核心部分)
unsigned char x1=10,y1=1;
TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1);
我们这里的两千并不是随意写的 根据 #define PWM_x(X,B) (B+1)*X/100 对应
TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1); 结合中断函数来看
Workhanlder=(TIM3->CCR1*100)/GPOA7_CCR2; 因为这里乘了100 原本为1m的计算频率现在就为
10 000 00/100 =10000了 又因为占空比为 ( #define PWM_x(X,B) (B+1)*X/100 )
这样对应了初始化函数部分形参 得到占空比为(0+1)*10/100=10% //X为占空比
所以 计算频率又为 10000 *10%=1000 hz 因为是输出 比较 和输入捕获 所以要乘2
所以初始化频率为2000HZ
可能出现的问题
if(y1==7) TIM2_PwmOutPut(286-1,PWM_x(x1,286-1)+1);
else TIM2_PwmOutPut(2000/y1-1,PWM_x(x1,2000/y1-1)+1);
286可以根据情况来改 286相当于是某个时间点定时器固定的值
如果还是出错 可以把y1的值 改为 11
知识点比较多 大家要稳住
key.c
#include "stm32f10x.h"
#include "key.h"
void key_init(void)
{
GPIO_InitTypeDef GPIO_Initstruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
GPIO_Initstruct.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2;
GPIO_Initstruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Initstruct.GPIO_Mode =GPIO_Mode_IPU;
GPIO_Init(GPIOB,&GPIO_Initstruct);
GPIO_Initstruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_8;
GPIO_Init(GPIOA,&GPIO_Initstruct);
}
unsigned char key_Scan(void)
{
static unsigned char key_res=0;
switch(key_res){
case 0:if((A0==GPIO_RESET)||(A8==GPIO_RESET)||(B1==GPIO_RESET)||(B2==GPIO_RESET)){
key_res=1;
}break;
case 1:if((A0==GPIO_RESET)||(A8==GPIO_RESET)||(B1==GPIO_RESET)||(B2==GPIO_RESET)){
key_res=2;
if(A0==GPIO_RESET) {return 'A';}
if(A8==GPIO_RESET) {return 'B';}
if(B1==GPIO_RESET) {return 'C';}
if(B2==GPIO_RESET) {return 'D';}
}break;
case 2:if((A0!=GPIO_RESET)&&(A8!=GPIO_RESET)&&(B1!=GPIO_RESET)&&(B2!=GPIO_RESET)){
key_res=0;
}break;
}
return 88;
}
main.c
#include "stm32f10x.h"
#include "systick.h"
#include "lcd.h"
#include "tim.h"
#include "key.h"
#include "funcofig.h"
int main(void)
{
ALLInit(); ///用到的所有初始化
while(1)
{
PWM_Capture_OUT();//捕获占空比
}
}
提及的要点多看几次 很重要