基本外设配置
外设配置、定时器、编码器模式、速度读取、pwm,exti
基本外设的程序配置
创建.c文件和.h文件,头文件中注意 #ifndef _xxx
#def _xxx
#endif
配置编码器模式
编码器1——PA0/PA1—TIM2
编码器2——PB6/PB7—TIM4
#标准库 编码器的配置
//摘自B站天下行走
void Encoder_TIM2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_ICInitTypeDef TIM_ICInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;//初始化GPIO--PA0、PA1
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0 |GPIO_Pin_1;
GPIO_Init(GPIOA,&GPIO_InitStruct);
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);//初始化定时器。
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=65535;
TIM_TimeBaseInitStruct.TIM_Prescaler=0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
TIM_EncoderInterfaceConfig(TIM2,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//配置编码器模式
TIM_ICStructInit(&TIM_ICInitStruct);//初始化输入捕获
TIM_ICInitStruct.TIM_ICFilter=10;
TIM_ICInit(TIM2,&TIM_ICInitStruct);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//配置溢出更新中断标志位
TIM_SetCounter(TIM2,0);//清零定时器计数值
TIM_Cmd(TIM2,ENABLE);//开启定时器
}
1、PA0和PA1浮空输入,开启时钟
2、定时器初始化,TIM2
定时器详解
(定时器:
通用定时器的基本工作原理: 首先,定时器时钟信号送入16位可编程预分配器(Prescaler),该预分配器系数为0~65535之间的任意数值。预分配器溢出后,会向16位的主计数器(Counter Period)发出一个脉冲信号。 预分频器,本质上是一个加法计数器,预分频系数实际上就是加计数的溢出值。
定时器发生中断时间的计算方法: 定时时间 = (Prescaler+1 ) X (Counter Period+1) X 1/ 定时器时钟频率 时钟信号1KHz,Prescaler为9,Counter Period为999,定时时间? (感觉定时器一般需要用到中断,这是要使能中断,然后在回调函数里写中断程序。在main函数里要开启定时器。)
高级定时器timer1,timer8以及通用定时器timer9,timer10,timer11的时钟来源是APB2Z总线
通用定时器timer2~timer5, 通用定时器timer12-14以及基本定时器timer6-timer7时钟来源是APB1总线
定时器就是每隔多少时间单片机做一件事,具体多少时间需要我们自己来设定,譬如间隔1ms,也就是1000HZ,时钟来源的频率/(ARR+1)/(PSC+1)
#例子 (hal库)
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2) //处理TIM2间隔定时中断 判断传过来的定时器实例是不是TIM2
{
AL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
}
if(htim->Instance == TIM3) //处理TIM3间隔定时中断
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
}
}
/* USER CODE END 0 */
//main函数里
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2); //启动定时器TIM2
HAL_TIM_Base_Start_IT(&htim3); //启动定时器TIM3
/* USER CODE END 2 */
高级控制定时器(TIM1与TIM8)
通用定时器(TIM2~TIM5)
基本定时器(TIM6与TIM7) 我参考的 这个知乎大佬
#这些配置可以在cubemx里完成,也更简单一些:
slave mode:总共有5中,Disable、外部时钟模式1,复位模式,门级驱动模式,触发模式
还有那个trigger也不懂,一般就选disable吧,希望懂的大佬可以指点一下
具体模式用法及概念我也不懂QAQ
cubemx中定时器配置
编码器模式
标准库这样
TIM_ICStructInit(&TIM_ICInitStruct);//初始化输入捕获
TIM_ICInitStruct.TIM_ICFilter=10;
cubemx这样
input filter 滤波器一般在0-15之间,我选的10(别人的经验值),可以不分频,编码器1是在PA0和PA1上,选择通道1和通道2
在初始化中添加打开定时器的encoder模式: HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL);
使用函数__HAL_TIM_GET_COUNTER(&htim2)可以实时获取计数值
__HAL_TIM_SET_COUNTER()设置计数器数值
续:其实编码器也就那么回事,跟gpio差不多的,配置相应的参数,调用相应的函数。具体的:(标准库)
TIM_EncoderInterfaceConfig(TIM2,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);//配置编码器模式
用TIM2,TIM_EncoderMode参数是模式,是单相计数(只能反映速度)还是两相计数(速度和方向)
TIM_IC1Polarity和TIM_IC2Polarity参数就是通道1、2的捕捉极性。
Countingon TI1 only:TI2为高时(第一行):TI1上升沿则向下计数,下降沿则向上计数。
Countingon TI1 and TI2:一个周期完成4次跳变。精度提高
这个编码器配置完成后就可以用相关函数算出速度了
速度读取
int Read_Speed(int TIMx)
{
int value_1;
switch(TIMx)
{
case 2:value_1=(short)TIM_GetCounter(TIM2);TIM_SetCounter(TIM2,0);break;//IF是定时器2,1.采集编码器的计数值并保存。2.将定时器的计数值清零。
case 4:value_1=(short)TIM_GetCounter(TIM4);TIM_SetCounter(TIM4,0);break;
default:value_1=0;
}
return value_1;
}
PWM
void PWM_Init_TIM1(u16 Psc,u16 Per)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1 | RCC_APB2Periph_AFIO,ENABLE);//开启时钟
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;//初始化GPIO--PA8、PA11为复用推挽输出
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8 |GPIO_Pin_11;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);//初始化定时器。
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=Per;
TIM_TimeBaseInitStruct.TIM_Prescaler=Psc;
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);/*【2】*///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;
TIM_OC1Init(TIM1,&TIM_OCInitStruct);
TIM_OC4Init(TIM1,&TIM_OCInitStruct);
TIM_CtrlPWMOutputs(TIM1,ENABLE);//高级定时器专属--MOE主输出使能
TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);/*【3】*///ENABLE//OC1预装载寄存器使能
TIM_OC4PreloadConfig(TIM1,TIM_OCPreload_Enable);//ENABLE//OC4预装载寄存器使能
TIM_ARRPreloadConfig(TIM1,ENABLE);//TIM1在ARR上预装载寄存器使能
TIM_Cmd(TIM1,ENABLE);//开定时器。
}
用cubemx使用pwm代码
时钟为72MHZ,PSC设置为71,一个周期时间:72/72x1000=1ms,
1MHZ的频率时间为1us
然后需要这两个函数:
HAL_TIM_Base_Start_IT(&htim3); //启动定时器 HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3); //开启PWM
重写回调函数,(这里是一个呼吸灯的例子,a为crr的值)
int a=0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim3)
{
a++;
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_3,a);
if(a>=999) a=0;
}
}
EXIT
void MPU6050_EXTI_Init(void)
{
EXTI_InitTypeDef EXTI_InitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);//开启时钟
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;/**【1】**///GPIO_Mode_AF_PP
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;//PB5配置为上拉输入
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5);//
EXTI_InitStruct.EXTI_Line=EXTI_Line5;
EXTI_InitStruct.EXTI_LineCmd=ENABLE;
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStruct);
}
“本站所有文章均为原创,欢迎转载,请注明文章出处:一只菜鸡儿。(https://blog.csdn.net/Linuxzbc/article/details/108207512)百度和各类采集站皆不可信,搜索请谨慎鉴别。技术类文章一般都有时效性,本人习惯不定期对自己的博文进行修正和更新,因此请访问出处以查看本文的最新版本。”