舵机、震动传感器、超声波使用代码

震动传感器

void SHAKE_Init(void)
{
  	GPIO_InitTypeDef  shake_init;   //GPIO_InitTypeDef½á¹¹ÌåÔÚGPIO.h
   //ʹÄÜAPB2µÄʱÖÓ GPIOA
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);	//rcc.hÖÐ
	
//½á¹¹ÌåÅäÖà 
shake_init.GPIO_Mode =   GPIO_Mode_IPD;//ÏÂÀ­/ÉÏÀ­¶¼¿ÉÒÔ£¬Ö»Êdzõʼ»¯Á˵çƽ£¬×îÖÕÒÔIOÒý½ÅΪÖ÷
shake_init.GPIO_Pin  =   GPIO_Pin_4;
shake_init.GPIO_Speed=   GPIO_Speed_10MHz;	
 GPIO_Init(GPIOB,&shake_init);
}

舵机

舵机PWM引脚不是随便选着的,根据下面的选择,选择引脚后定时器也是需要根据表里的去配置

void motor_config(void)
{
   GPIO_InitTypeDef         GPIO_Motorinit;//GPIO结构体
	 TIM_TimeBaseInitTypeDef  TIM_Motorinit;//通用定时器结构体
	 TIM_OCInitTypeDef        TIMPWM_Motorinit;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);  //定时器
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);  //引脚复用
	
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); //部分重映射
	
	GPIO_Motorinit.GPIO_Mode= GPIO_Mode_AF_PP;//复用推挽输出
	GPIO_Motorinit.GPIO_Pin=  GPIO_Pin_5;// 
	GPIO_Motorinit.GPIO_Speed=GPIO_Speed_50MHz; 
  GPIO_Init(GPIOB, &GPIO_Motorinit);
	
	TIM_Motorinit.TIM_ClockDivision= TIM_CKD_DIV1;       / /设置时钟分割为不分频
	TIM_Motorinit.TIM_CounterMode=   TIM_CounterMode_Up; //TIM 向上计数
	TIM_Motorinit.TIM_Period=        200-1;           // ARR
	TIM_Motorinit.TIM_Prescaler=   7200-1;            //PSC
    TIM_TimeBaseInit(TIM3,&TIM_Motorinit);

	TIMPWM_Motorinit.TIM_OCMode=      TIM_OCMode_PWM1 ;    // 定时器模式  
	TIMPWM_Motorinit.TIM_OutputState= TIM_OutputState_Enable; / 比较输出使能
	TIMPWM_Motorinit.TIM_OCPolarity=  TIM_OCPolarity_Low ;  // 有效输出极性    
	TIM_OC2Init(TIM3,&TIMPWM_Motorinit);  // 初始化定时器三通道二
	TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);  通道二预装载值
	TIM_Cmd(TIM3,ENABLE);//ʹÄÜ
	
}

HC_SR04超声波模块

1.定义GPIO引脚一个发送引脚,一个接收引脚

void HC_SR04Config(void)
{
    GPIO_InitTypeDef GPIO_hcsr04init;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 
	
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	//Trig PB11   发送
    GPIO_hcsr04init.GPIO_Mode=  GPIO_Mode_Out_PP;   // 推挽输出
	GPIO_hcsr04init.GPIO_Pin= GPIO_Pin_11;
	GPIO_hcsr04init.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,  &GPIO_hcsr04init);
	
		//ECHO PB10   接收
    GPIO_hcsr04init.GPIO_Mode=  GPIO_Mode_IN_FLOATING;   // 浮空输入检查高电平
	GPIO_hcsr04init.GPIO_Pin= GPIO_Pin_10;
	GPIO_Init(GPIOB,  &GPIO_hcsr04init);
}

2.定时器配置,配置微秒定时器

    TIM_TimeBaseInitTypeDef TIM_hcsr04init; 
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);


    TIM_Motorinit.TIM_ClockDivision= TIM_CKD_DIV1;       / /设置时钟分割为不分频
	TIM_Motorinit.TIM_CounterMode=   TIM_CounterMode_Up; //TIM 向上计数
	TIM_Motorinit.TIM_Period=        200-1;           // ARR
	TIM_Motorinit.TIM_Prescaler=   7200-1;            //PSC
    TIM_TimeBaseInit(TIM3,&TIM_Motorinit);
	TIM_Cmd(TIM4,DISABLE);//先关闭,检查高低电平时再打开
	TIM_ITConfig(TIM4,TIM_IT_Update, ENABLE);  // 定时器中断,允许溢出更新

3.配置中断,配置再内核里,在misc.c的misc.h中找结构体

	NVIC_InitTypeDef NVIC_hcsr04init;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);





	NVIC_hcsr04init.NVIC_IRQChannel=TIM4_IRQn  ;          //  通道,使用定时器4的,因为定时器 
                                                        配置的时候就是用定时器,在stm32f10x.h 
                                                        中找TIM4_IRQn  
    //需要定义优先级分组misc.h中找NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	NVIC_hcsr04init.NVIC_IRQChannelPreemptionPriority= 0 ;  // 抢占优先级  misc.c中
	NVIC_hcsr04init.NVIC_IRQChannelSubPriority= 0;          // 子优先级
	NVIC_hcsr04init.NVIC_IRQChannelCmd=  ENABLE;         //使能
	NVIC_Init(&NVIC_hcsr04init);//结构体初始化

完整代码

#include "HC_SR04.h"
#include "stm32f10x.h"
 
void HC_SR04Config(void)
{
    GPIO_InitTypeDef GPIO_hcsr04init;
    TIM_TimeBaseInitTypeDef TIM_hcsr04init;    
	NVIC_InitTypeDef NVIC_hcsr04init;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
	
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	//Trig PB11  ·¢Ë͵çƽ
    GPIO_hcsr04init.GPIO_Mode=  GPIO_Mode_Out_PP;    
	GPIO_hcsr04init.GPIO_Pin= GPIO_Pin_11;
	GPIO_hcsr04init.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,  &GPIO_hcsr04init);
	
		//ECHO PB10  ½ÓÊÕµçƽ²»ÐèÅäÖÃËÙ¶È
    GPIO_hcsr04init.GPIO_Mode=  GPIO_Mode_IN_FLOATING;   
	GPIO_hcsr04init.GPIO_Pin= GPIO_Pin_10;
	GPIO_Init(GPIOB,  &GPIO_hcsr04init);
	
	//¶¨Ê±Æ÷4
	TIM_hcsr04init.TIM_ClockDivision=TIM_CKD_DIV1 ;          
	TIM_hcsr04init.TIM_CounterMode  =TIM_CounterMode_Up;     
	TIM_hcsr04init.TIM_Period       =1000-1;                
	TIM_hcsr04init.TIM_Prescaler    =72-1;                   
 
    TIM_TimeBaseInit(TIM4,&TIM_hcsr04init);
	TIM_ITConfig(TIM4,TIM_IT_Update, ENABLE);  //¶¨Ê±Æ÷ÖÐ¶Ï   ÔÊÐíÒç³ö¸üÐÂ
	TIM_Cmd(TIM4,DISABLE);//¼ì²é¸ßµÍµçƽÔÙ´ò¿ª
	
	//ÖжÏ
	NVIC_hcsr04init.NVIC_IRQChannel=TIM4_IRQn  ;                
                                                              
	NVIC_hcsr04init.NVIC_IRQChannelPreemptionPriority= 0 ;  
	NVIC_hcsr04init.NVIC_IRQChannelSubPriority= 0;          
	NVIC_hcsr04init.NVIC_IRQChannelCmd=  ENABLE;
	NVIC_Init(&NVIC_hcsr04init);
}

4.开启定时器,上三步的时候已经开启了

5.Trig引脚

在.h中宏定义


#define ECHO_Reci  GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10)//读取PB10引脚高低电平,也就是下面定义的发送出的10us电平


//通过这个宏定义去发送10us以上高电平
#define TRIG_Send(a) if(a) \
							        GPIO_SetBits(GPIOB, GPIO_Pin_11); \
                     else \
							      	GPIO_ResetBits(GPIOB, GPIO_Pin_11);\

\:换行,告诉编译器连接下一行的作用

6.等待Ec引脚输入高电平开始,定时器打开——开启计数器计数

定义一个定时器开打函数

//打开定时器4
extern uint16_t mscount =0;
void Open_tim4(void)
{
  TIM_SetCounter(TIM4,0);   //开打之后开始计数
  mscount =0;//mscount用于计算五次取平均值减少误差
  TIM_Cmd(TIM4,ENABLE);//打开定时器

}

7.等待Ec引脚输入高电平结束,定时器关闭——停止计数器计数

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

需要已给中断服务函数

TIM4_IRQHandler()在startup_stm32f10x_hd.s中

void TIM4_IRQHandler(void)
{
   if( TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET)       // 检查是否发生中断,TIM_GetITStatus                            
                                                            在tim.h里
	 {
	  TIM_ClearITPendingBit(TIM4, TIM_IT_Update);     // 清除中断标志
	  mscount++;//计数加一(一共计数五次)	 
	 }
}

8.通过计数器的值计算超声波测量距离

  //获取定时器计数值
int GetEcho_time(void)
{
    uint32_t t=0;
	t=mscount*1000;//固定搭配
    t+=TIM_GetCounter(TIM4);    //获取定时器计数值
    TIM4->CNT =0;//定时器计数值清零
  	delay_xms(50);
	
	return t;
}

//获取超声波测距距离
float Getlength(void)   //在循环中调用,不断获取距离
{
    int i=0;
	uint32_t t=0;
	float length=0;
	float sum=0;

	while(i!=5)//计算五次取平均值
  {
		TRIG_Send(1);   // .h宏定义里PB11发出高电平 
	    delay_us(20);   //高电平持续20us,超声波配置要求
        TRIG_Send(0);   //.h宏定义里PB11发出低电平 
		
		while( ECHO_Reci == 0);  // ECHO_Reci宏定义:检测PB11接收的是高电平还是低电平,只有是高 
                                 电平才继续往下执行代码,不然继续等待接收到高电平
	    Open_tim4();   //定义的定时器计数函数
	    i=i+1;         //打开一次计数一次

		while(ECHO_Reci==1);

	    Close_tim4();//关闭定时器计数
	    t=GetEcho_time();//关闭定时器计数之后取获取计数值

        length=((float)t/58.0);//测距距离

	    sum=sum+length;//五次的总和距离
   }
	length=sum/5.0;//平均距离

	return length;	
}

距离计算的总思路:为了减小误差我们取五次值计算平均值 。在主循环中不断执行距离获取函数Get length(),在这个函数中发送20us以上高电平,这次引脚检测到高电平,定时器计数函数打开,开始计数。计数次数i+1。当20us高电平过去了,引脚检测到低电平,关闭定时器计数,然后获取定时器计数的值 (cnt),

cnt的计算就是mscount*1000+TIM_GetCounter()。mscount每次发生中断加一

测距长度就l=t/58.0(固定公式)

然后五次l相加除以5,就是最后测距距离