STM32入门—HC-SR04/更新于2018/2/4

1、基本功能
HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测距精度可达高到3mm;模块包括超声波发射器、接收器与控制电路。
2、工作原理
(1).给超声波模块接入电源和地。
(2).给脉冲触发引脚(trig)输入一个长为20us的高电平方波 。
(3).输入方波后,模块会自动发射8个40KHz的声波,与此同时回波引脚(echo)端的电平会由0变为1;(此时应该启动定时器计时)
(4).当超声波返回被模块接收到时,回波引 脚端的电平会由1变为0;(此时应该停止定时器计数),定时器记下的这个时间即为超声波由发射到返回的总时长。 (5).根据声音在空气中的速度为344米/秒,即可计算出所测的距离。
(6).利用串口,将超声波测到的数据发送到电脑。
(7).利用串口发送阈值给单片机,当测到的距离小于阈值则报警 。

下面程序:
hcsr04.c文件

#include "hcsr04.h"  
#include "delay.h" 
#include "stm32f4xx.h" 
#include "led.h"

#define HCSR04_PORT     GPIOB  
#define HCSR04_CLK      RCC_APB2Periph_GPIOB  
#define HCSR04_TRIG     GPIO_Pin_5  
#define HCSR04_ECHO     GPIO_Pin_6

u16 msHcCount = 0;//ms¼ÆÊý

 void Hcsr04Init(void)
 {
     GPIO_InitTypeDef GPIO_InitStructure;

     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);

     GPIO_InitStructure.GPIO_Pin=HCSR04_TRIG; //·¢Ë͵çƽÒý½ÅTrig
     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //ÆÕͨÊä³öģʽ
     GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; //ÍÆÍìÊä³ö
     GPIO_Init(GPIOB,&GPIO_InitStructure);
     GPIO_ResetBits(HCSR04_PORT,HCSR04_TRIG);

     GPIO_InitStructure.GPIO_Pin=HCSR04_ECHO; //·¢Ë͵çƽÒý½ÅTrig
     GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN; //ÆÕͨÊäÈëģʽ
//   GPIO_InitStructure.GPIO_OType= 
   GPIO_Init(GPIOB,&GPIO_InitStructure);
     GPIO_ResetBits(HCSR04_PORT,HCSR04_ECHO);
 }

static void OpenTimerForHc() //´ò¿ª¶¨Ê±Æ÷
{  
        TIM_SetCounter(TIM3,0);//Çå³ý¼ÆÊý
        msHcCount = 0;  
        TIM_Cmd(TIM3, ENABLE);  //ʹÄÜTIMxÍâÉè  
}  

static void CloseTimerForHc() //¹Ø±Õ¶¨Ê±Æ÷
{  
        TIM_Cmd(TIM3, DISABLE); //ʹÄÜTIMxÍâÉè 
} 

u32 GetEchoTimer(void)  //»ñÈ¡¶¨Ê±Æ÷ʱ¼ä
{  
    u32 t = 0;  
    t = msHcCount*1000;//µÃµ½ms  
    t += TIM_GetCounter(TIM3);//µÃµ½us
        TIM3->CNT = 0;  //½«TIM3¼ÆÊý¼Ä´æÆ÷µÄ¼ÆÊýÖµÇåÁã  
                    delay_ms(50);  
    return t;  
}

float Hcsr04GetLength(void)  
{  
        u32 t = 0;  
        int i = 0;  
        float lengthTemp = 0;  
        float sum = 0;  
        while(i!=5)  
        {  
        TRIG_Send = 1; //·¢ËͿڸߵçƽÊä³ö 
        delay_us(20);                   
        TRIG_Send = 0;

        while(ECHO_Reci == 0); //µÈ´ý½ÓÊտڸߵçƽÊä³ö   
                OpenTimerForHc();  //´ò¿ª¶¨Ê±Æ÷
                i = i + 1;  

                while(ECHO_Reci == 1);  
                CloseTimerForHc();  //¹Ø±Õ¶¨Ê±Æ÷
                t = GetEchoTimer();   //»ñȡʱ¼ä£¬·Ö±æÂÊΪ1us

                lengthTemp = ((float)t*1.7f);//cm  
                sum = lengthTemp + sum ;            
        }  
        lengthTemp = sum/5.0f;  
        return lengthTemp;  
}


timer.c

#include "timer.h"
#include "led.h"


void TIM3_Int_Init(u16 arr,u16 psc) ͨÓö¨Ê±Æ÷3Öжϳõʼ»¯
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); ///ʹÄÜTIM3ʱÖÓ

    TIM_TimeBaseInitStructure.TIM_Period=arr; //ÉèÖÃ×Ô¶¯ÖØÔؼÆÊýÖÜÆÚ
    TIM_TimeBaseInitStructure.TIM_Prescaler=psc;//ÉèÖ÷ÖƵϵÊý
    TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//ÏòÉϼÆÊý
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;    //ÉèÖÃʱÖÓ·ÖƵÒò×Ó
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);  //¶¨Ê±Æ÷²ÎÊý³õʼ»¯

    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //ÔÊÐí¶¨Ê±Æ÷3¸üÐÂÖжÏ
    TIM_Cmd(TIM3,ENABLE);  //ʹÄܶ¨Ê±Æ÷3

  NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //¶¨Ê±Æ÷3ÖжÏ
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01;//ÇÀÕ¼ÓÅÏȼ¶1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //×ÓÓÅÏȼ¶3;
    NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  NVIC_Init(&NVIC_InitStructure);

}
//¶¨Ê±Æ÷3ÖжϷþÎñº¯Êý
void TIM3_IRQHandler (void)
{
  if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //Òç³öÖжÏ
  {
            LED1=!LED1;//DS1·­×ª
    }
  TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //Çå³ýÖжϱê־λ
}

usart.c

#include "sys.h"
#include "usart.h"  
//////////////////////////////////////////////////////////////////////////////////   
//Èç¹ûʹÓÃucos,Ôò°üÀ¨ÏÂÃæµÄÍ·Îļþ¼´¿É.
#if SYSTEM_SUPPORT_OS
#include "includes.h"                   //ucos ʹÓà   
#endif
//¼ÓÈëÒÔÏ´úÂë,Ö§³Öprintfº¯Êý,¶ø²»ÐèҪѡÔñuse MicroLIB    
#if 1
#pragma import(__use_no_semihosting)             
//±ê×¼¿âÐèÒªµÄÖ§³Öº¯Êý                 
struct __FILE 
{ 
    int handle; 
}; 

FILE __stdout;       
//¶¨Òå_sys_exit()ÒÔ±ÜÃâʹÓðëÖ÷»úģʽ    
void _sys_exit(int x) 
{ 
    x = x; 
} 
//Öض¨Òåfputcº¯Êý 
int fputc(int ch, FILE *f)
{   
    while((USART1->SR&0X40)==0);//Ñ­»··¢ËÍ,Ö±µ½·¢ËÍÍê±Ï   
    USART1->DR = (u8) ch;      
    return ch;
}
#endif

#if EN_USART1_RX   //Èç¹ûʹÄÜÁ˽ÓÊÕ
//´®¿Ú1ÖжϷþÎñ³ÌÐò
//×¢Òâ,¶ÁÈ¡USARTx->SRÄܱÜÃâĪÃûÆäÃîµÄ´íÎó       
u8 USART_RX_BUF[USART_REC_LEN];     //½ÓÊÕ»º³å,×î´óUSART_REC_LEN¸ö×Ö½Ú.
//½ÓÊÕ״̬
//bit15£¬   ½ÓÊÕÍê³É±êÖ¾
//bit14£¬   ½ÓÊÕµ½0x0d
//bit13~0£¬    ½ÓÊÕµ½µÄÓÐЧ×Ö½ÚÊýÄ¿
u16 USART_RX_STA=0;       //½ÓÊÕ״̬±ê¼Ç    

//³õʼ»¯IO ´®¿Ú1 
//bound:²¨ÌØÂÊ
void uart_init(u32 bound){
   //GPIO¶Ë¿ÚÉèÖÃ
  GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //ʹÄÜGPIOAʱÖÓ  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//ʹÄÜUSART1ʱÖÓ

    //´®¿Ú1¶ÔÓ¦Òý½Å¸´ÓÃÓ³Éä
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9¸´ÓÃΪUSART1    
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10¸´ÓÃΪUSART1  

    //USART1¶Ë¿ÚÅäÖÃ
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9ÓëGPIOA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//¸´Óù¦ÄÜ
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //ËÙ¶È50MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //ÍÆÍ츴ÓÃÊä³ö
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //ÉÏÀ­
    GPIO_Init(GPIOA,&GPIO_InitStructure); //³õʼ»¯PA9£¬PA10  

   //USART1 ³õʼ»¯ÉèÖÃ
    USART_InitStructure.USART_BaudRate = bound;//²¨ÌØÂÊÉèÖÃ
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//×Ö³¤Îª8λÊý¾Ý¸ñʽ
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//Ò»¸öֹͣλ
    USART_InitStructure.USART_Parity = USART_Parity_No;//ÎÞÆæżУÑéλ
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//ÎÞÓ²¼þÊý¾ÝÁ÷¿ØÖÆ
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //ÊÕ·¢Ä£Ê½
  USART_Init(USART1, &USART_InitStructure); //³õʼ»¯´®¿Ú1

  USART_Cmd(USART1, ENABLE);  //ʹÄÜ´®¿Ú1 

    //USART_ClearFlag(USART1, USART_FLAG_TC);

#if EN_USART1_RX    
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//¿ªÆôÏà¹ØÖжÏ

    //Usart1 NVIC ÅäÖÃ
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//´®¿Ú1ÖжÏͨµÀ
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//ÇÀÕ¼ÓÅÏȼ¶3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;       //×ÓÓÅÏȼ¶3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQͨµÀʹÄÜ
    NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷¡¢

#endif

}


void USART1_IRQHandler(void)                    //´®¿Ú1ÖжϷþÎñ³ÌÐò
{
    u8 Res;
#if SYSTEM_SUPPORT_OS       //Èç¹ûSYSTEM_SUPPORT_OSΪÕ棬ÔòÐèÒªÖ§³ÖOS.
    OSIntEnter();    
#endif
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //½ÓÊÕÖжÏ(½ÓÊÕµ½µÄÊý¾Ý±ØÐëÊÇ0x0d 0x0a½áβ)
    {
        Res =USART_ReceiveData(USART1);//(USART1->DR);  //¶ÁÈ¡½ÓÊÕµ½µÄÊý¾Ý

        if((USART_RX_STA&0x8000)==0)//½ÓÊÕδÍê³É
        {
            if(USART_RX_STA&0x4000)//½ÓÊÕµ½ÁË0x0d
            {
                if(Res!=0x0a)USART_RX_STA=0;//½ÓÊÕ´íÎó,ÖØпªÊ¼
                else USART_RX_STA|=0x8000;  //½ÓÊÕÍê³ÉÁË 
            }
            else //»¹Ã»ÊÕµ½0X0D
            {   
                if(Res==0x0d)USART_RX_STA|=0x4000;
                else
                {
                    USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
                    USART_RX_STA++;
                    if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//½ÓÊÕÊý¾Ý´íÎó,ÖØпªÊ¼½ÓÊÕ      
                }        
            }
        }            
  } 
#if SYSTEM_SUPPORT_OS   //Èç¹ûSYSTEM_SUPPORT_OSΪÕ棬ÔòÐèÒªÖ§³ÖOS.
    OSIntExit();                                             
#endif
} 
#endif  





main.c

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "beep.h"
#include "usart.h"
#include "key.h"
//#include "exti.h"
#include "timer.h"
#include "hcsr04.h" 



/*************³¬Éù²¨²â¾à*****************/
int main()  
{    
  float length=0;   //²âÁ¿µÄ³¤¶È
    u8 len;          //ÉèÖÃãÐֵʱ·¢ËÍÊý¾ÝµÄ³¤¶È
    u8 t,i,j;
    u16 times=0; 
    int table1[]={1,10,100,1000};
  long long s1=0;//ãÐÖµ    

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//ÉèÖÃϵͳÖжÏÓÅÏȼ¶·Ö×é2  

    delay_init(168);  //³õʼ»¯ÑÓʱº¯Êý
    LED_Init();             //³õʼ»¯LED¶Ë¿Ú  
    BEEP_Init();            //³õʼ»¯·äÃùÆ÷¶Ë¿Ú  
    uart_init(115200);
    printf("\r\n´®¿Ú³õʼ»¯³É¹¦£¡\r\n"); 
    Hcsr04Init();
    printf("\r\n³¬Éù²¨³õʼ»¯³É¹¦£¡\r\n");   
    TIM3_Int_Init(5000-1,8400-1);
  printf("\r\n¶¨Ê±Æ÷³õʼ»¯³É¹¦£¡\r\n");

while(1)
{       
    if(USART_RX_STA&0x8000)
    {                      
        len=USART_RX_STA&0x3fff;//µÃµ½´Ë´Î½ÓÊÕµ½µÄÊý¾Ý³¤¶È
        printf("\r\nÄúÉèÖõı¨¾¯ãÐֵΪ:\r\n");
        for(t=0;t<len;t++)
            {
                USART_SendData(USART1, USART_RX_BUF[t]);         //Ïò´®¿Ú1·¢ËÍÊý¾Ý
                while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//µÈ´ý·¢ËͽáÊø
            }
        printf("\r\n\r\n");//²åÈë»»ÐÐ
        USART_RX_STA=0;

        for(j=0;j<len;j++)    //½«×Ö·ûת»¯³ÉÊý×Ö
         {
                s1+=(USART_RX_BUF[len-1-j]-48)*table1[j];
         }
         t=s1;           //½«ãÐÖµ¸øt
         s1=0;   

        for(i=0;i<30;i++)   //²âÁ¿µÄ´ÎÊý
            {
            length = Hcsr04GetLength();  //²âÁ¿
            printf("²âµ½¾àÀëΪ:%.3f\n",length);

            if(length<t)   //±¨¾¯
                {
                    GPIO_SetBits(GPIOF,GPIO_Pin_8);   //BEEPÒý½ÅÀ­¸ß£¬ µÈͬBEEP=1;
                    delay_ms(300);                                      //ÑÓʱ300ms                         
                }
            else
                {
                 GPIO_ResetBits(GPIOF,GPIO_Pin_8);    //·äÃùÆ÷¶ÔÓ¦Òý½ÅGPIOF8À­µÍ                         
                }
            }   
    }

    else
    {
        times++;
        if(times%5000==0)
        {
            printf("\r\n³¬Éù²¨²â¾à\r\n");
        }
        if(times%200==0)printf("ÇëÊäÈëãÐÖµ8
}   

说明:这个程序,输入阈值之后才会开始测量,我设置的测量30次。可以根据自己需要,进行修改。
/*************更新于2018/1/30**********************/
STM32入门阶段,为期十天的超声波测距模块圆满完成了。从对STM32一无所知到现在略知一二我觉得收获还是很大的。
在我看来,开发STM32需要很规范很系统的框架,也就是说我们学习的时候就要条理清晰,慢慢形成网状的知识框架。比如说,很多源程序的一般步骤都很相似,一般来说第一步就是使能相应的时钟。
学习过程中最难的部分应该就是对原理的理解,比如0波特率,溢出时间的计算等。
一般遇到问题,我觉得先去数据手册或者中文手册比较有效,如果解决不了再去百度或者论坛。
在写程序的时候会遇到各种各样的问题,一般常见的有语法错误比较好查到并改正,但是如果在找使能时钟的函数,或者IO口用错时,很难查出错误,所以一定要细心。2灯的语句去逐步判断,把它放到不同的地方,来检测这个语句到底有没有执行,感觉还比较好用。
接下来我会继续学习新知识,并对之前的做补充更正。
/*************更新于2018/2/1*********************/
/**************欢迎指正*****************/

误差分析及精度调整

在超声波完成了基本的测距功能之后,通过串口打印出的数据可以看出,当超声波状态不稳定时,数据有较大的波动,而且有一些超出测量范围的数值。这就说明,测量的精度不够,我们可以通过两种办法解决此问题。其一:滤掉较大或较小的没用的数据,留下在测量范围内的数据。其二:加一些滤波,如平均值滤波卡尔曼滤波等。然后可以通过虚拟示波器将数据显示出来,来对比原始数据与滤波后的数据,最终选择效果最好的滤波。
/**************更新于2018/2/4**********************/
/**************欢迎指正*******************/

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值