基于STM32之PWM控制舵机以及PWM控制呼吸灯

系列文章目录

利用PWM来实现对舵机的控制可以做一些小小的垃圾桶项目


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 系列文章目录
  • 前言
  • 一、了解定时器
  • 二、配置步骤
    • 1.通用定时器的配置
    • 2.用通用定时器来输出PWM
  • 总结


前言

对于PWM的学习可以用在许多地方:例如智能小车得到使用,智能开关盖垃圾桶的使用,可以加上蓝牙来控制舵机做一个简易的宿舍关灯神器。。。。。。


提示:以下是本篇文章正文内容,下面案例可供参考

一、定时器到底是何方神圣

示例:当你跑步的时候,你希望你可以在短短的12内跑完100米的距离,于是你拿出来秒表来

从0秒开始计时到12秒,这个过程就是定时器的作用。某一时刻开始计数,且计数到自己的预期值

就会产生一个中断事件,就是使对应的标志位置“1”,我们可以通过不断地对这个中断标志位。来判断计数是否完成。并且如果打开了中断功能,那么溢出时间地时候还会产生中断标志。

基于STM32之PWM控制舵机以及PWM控制呼吸灯_第1张图片

 

二.在32单片机的定时器(TIMX)分类

分别有1.高级定时器(TIM1~TIM8)2.通用定时器(TIM2~TIM5)3.基本定时器(TIM6~TIM7)

在我们常用地定时器一般是通用定时器,并且通用定时器在APB1外设总线上面(最大为36MHZ)

可以实现16位的向上,向下,向上/向下同时的计数,还可以进行输出比较,输入捕获。PWM单脉冲。

三.计数模式了解

了解向上计数的模式ARR代表的是自动从装载值(就是我们前面举例子的12秒)cnt(当前计数器的数值,就是当你跑步的时候突然间想知道时间过去了多少) CRRX(代表的是如果你跑的时间在9秒以内代表的是优秀,9秒以外代表的还可以。所以CRRX就是一个衡量水平的一个值)。具体的请仔细的结合下图理解。注意当计数器的值计数到自动重装载值得时候会有一个中断事件得产生

基于STM32之PWM控制舵机以及PWM控制呼吸灯_第2张图片基于STM32之PWM控制舵机以及PWM控制呼吸灯_第3张图片 基于STM32之PWM控制舵机以及PWM控制呼吸灯_第4张图片

 

 上图表示的就是为什么有前面举例的那些值,就是因为寄存器的存在

四.对于IO口的端口重映像功能

复用的意思就是二次使用,一个IO口不止有一个功能

基于STM32之PWM控制舵机以及PWM控制呼吸灯_第5张图片

 

 

五、使用步骤

1.PWM的定时器的配置

代码如下(示例):

#include "pwm.h"
#include "stm32f10x.h"
//对于pwm输出的配置
void pwm_Init(void){
    GPIO_InitTypeDef gpio_init_progrme;
	TIM_TimeBaseInitTypeDef tme_init_progrme;
	TIM_OCInitTypeDef pwm_init_progrme;
	
  
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
	
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 ,  ENABLE);
		RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE);
//因为使用的是端口的复用所以必须要开启复用时钟
  GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3 ,  ENABLE);
//并且由上面的图可以知道我们要使用的IO口为部分重印像
	
  gpio_init_progrme.GPIO_Mode=GPIO_Mode_AF_PP;
	gpio_init_progrme.GPIO_Pin=GPIO_Pin_5;
	gpio_init_progrme.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &gpio_init_progrme);
	


  tme_init_progrme.TIM_ClockDivision=TIM_CKD_DIV1;//一般不使用分频
	tme_init_progrme.TIM_CounterMode=TIM_CounterMode_Up;
	tme_init_progrme.TIM_Period=2000-1;//为自动重装载值ARR
	tme_init_progrme.TIM_Prescaler=360-1;//为预分频
  TIM_TimeBaseInit(TIM3, &tme_init_progrme );
		//接下来计算一下  因为APB1为36MHZ所以把他预分频为360
所以36M/360=1000000M,因为舵机的周期为20ms 所以 ARR/1000000=0.02.所以ARR=2000


	
	pwm_init_progrme.TIM_OutputState=TIM_OutputState_Enable;
	pwm_init_progrme.TIM_OCMode=TIM_OCMode_PWM1;
	pwm_init_progrme.TIM_OCPolarity=TIM_OCPolarity_Low;
   TIM_OC2Init(TIM3, &pwm_init_progrme);//PWM输出的定时器通道3
   TIM_OC2PreloadConfig( TIM3, TIM_OCPreload_Enable );
		  TIM_Cmd( TIM3, ENABLE);//开启定时器
	
	
}

2.超声波定时器的配置

代码如下(示例):

#include "HC-mode.h"
#include "stm32f10x.h"
#include "systick.h"
//为超声波的代码
uint16_t mscount =0;//
void HC_Init(void){
   GPIO_InitTypeDef GPIO_init_progrme;
   TIM_TimeBaseInitTypeDef TIM4_init_programe;
	 NVIC_InitTypeDef NVIC_init_programe;
	
	 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB,  ENABLE);//打开IO口的时钟
	 RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM4, ENABLE );//打开定时器的对应的时钟
	 NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);//因为要使用外部中断,所以必需要配置优先级组

    GPIO_init_progrme.GPIO_Mode=GPIO_Mode_Out_PP;
	  GPIO_init_progrme.GPIO_Pin=GPIO_Pin_11;//为tring的引脚
	  GPIO_init_progrme.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_init_progrme);
//对于结构体的配置,对应的寄存器的初始化
	  GPIO_init_progrme.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	  GPIO_init_progrme.GPIO_Pin=GPIO_Pin_10;
    GPIO_Init(GPIOB, &GPIO_init_progrme);
//为echo的引脚
    TIM4_init_programe.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM4_init_programe.TIM_CounterMode=TIM_CounterMode_Up;
	TIM4_init_programe.TIM_Period=1000-1;
   	TIM4_init_programe.TIM_Prescaler=72-1;
    TIM_TimeBaseInit(TIM4, &TIM4_init_programe);
	TIM_ITConfig(TIM4, TIM_IT_Update,  ENABLE);//对于PWM的输出,中间一个参数代表的是允许定时器可以不断的更新
    TIM_Cmd( TIM4, DISABLE);//对于定时器的使能
   NVIC_init_programe.NVIC_IRQChannel=TIM4_IRQn;
	 NVIC_init_programe.NVIC_IRQChannelSubPriority=1;
	 NVIC_init_programe.NVIC_IRQChannelPreemptionPriority=1;
	 NVIC_init_programe.NVIC_IRQChannelCmd=ENABLE;
   NVIC_Init(&NVIC_init_programe);//千万记住要使用外部中断就一定要配置中断优先级组
	 
}

void open_tim4(void){//打开定时器
      TIM_SetCounter( TIM4, 0);
	     mscount=0;
       TIM_Cmd( TIM4, ENABLE);

}

void close_tim4(void){//关闭定时器
	
    TIM_Cmd( TIM4, DISABLE);
 
}

void TIM4_IRQHandler(void){//对于定时器的中断

      if( TIM_GetITStatus( TIM4, TIM_IT_Update )!=RESET){
			    TIM_ClearITPendingBit(TIM4, TIM_IT_Update );
				mscount++;
			
			}
}

int GetEcho_time(void){
     uint16_t t=0;
	t =mscount*1000;
	   t += TIM_GetCounter(TIM4);
    TIM4->CNT=0;
	 dalay_ms(50);
	
	
	 return t;
}

float Getlength(void){
      int i=0;
	   uint16_t t=0;
	    float length=0;
	  float sum=0;
	  while(i!=5){
		  Tire_Send(1); 
			dalay_us(20);
		 Tire_Send(0); 
		while(Echo_time==0);
			
			open_tim4();
			i++;
		 while(Echo_time==1);
			
			close_tim4();
			t=GetEcho_time();
			length=((float)t/58.0);
			sum=sum+length;
		}
   length=sum/5.0;
  
		return length;
}



3。主函数
 

该处使用的url网络请求的数据。

extern int pwmval;
void dalay(uint16_t time){//延时函数
	
    uint16_t i=0;
	  while(time--){
	     i=12000;
		   while(i--);
	}
 

}
int main(){
	int pwmval;
  float   length;
	usart_init();
	pwm_Init();
	HC_Init();
	Shake_Init();
	exti_init();
   while(1){
		 pwmval=195;
	    length = Getlength();
	    printf("%.3f\r\n",length);//对获取的距离的精确
	   dalay_ms(500);

		 if(length<8){//超声波测距
		 for(pwmval=195;pwmval>=170;pwmval-=15)
		  TIM_SetCompare2 (TIM3, pwmval);//该函数是把当前值和CCRX进行比较
			 dalay_ms(1000);
			 
		 }
	 
		 else if(length>8){
		 		  TIM_SetCompare2 (TIM3, pwmval);
		 
		 }
		 
}
}
void EXTI1_IRQHandler(void)//外部中断,使用的是震动感应传感器来开盖
{	int pwmval;
	if(EXTI_GetITStatus( EXTI_Line1)  !=  RESET)//ÍⲿÖжÏÏß1£¬ÅжÏÊÇ·ñΪreset
	{
		 for(pwmval=195;pwmval>=170;pwmval-=15)
		  TIM_SetCompare2 (TIM3, pwmval);
			 dalay_ms(1000);
		
	
	
	}
       EXTI_ClearFlag(EXTI_Line1);//记住在任何时候都要清楚中断标志,否则后果自负


}


 


总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

你可能感兴趣的:(stm32)