wenbo2005.online

学习记录 / STM32

超声波+OLED

STM322025-05-21
1,开启一个定时器,选择输入捕获,并开启中断,命名为ECHO;(36-1 -> 65535)//===============注意定时器挂在哪个APB总线上//====该方法不准

2,选择一个输出引脚,并命名为TRIG,默认低电平;

3,开启I2C1,;(可以开一个串口打印)

4,引入头文件:    #include "OLED.h"
        #include "stdio.h"
        #include "string.h"

(需要添加OLED文件)

5,全局变量:

uint8_t IS_FIRST_CAPTURED=0;//标识位
uint32_t IC_Val1=0;
uint32_t IC_Val2=0;
uint32_t NUM1=0;//计算数据1,未转化
uint16_t NUM2=0;//计算数据2,已转化

6,声明自定义函数:

uint16_t HCSR04_Read(void);//声明自定义函数
void delay_ms(uint16_t time);//===================================

7,初始化准备:

    OLED_Init();
    OLED_Clear();
    HAL_TIM_Base_Start(&htim3);//使能定时器
    HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);//使能定时器的输入捕获中断=======================================这里开了定时器3的通道1
    char a[]="Hello World";
    char b[]="distance:";
    char c[]="cm";

8,循环外,只运行一次:

OLED_ShowString(4,1,b);//=================================位置自取
OLED_ShowString(4,13,c);

9,主函数内容:

    OLED_ShowString(1,3,a);
    OLED_ShowNum(4,10,HCSR04_Read(),3);

/*printf("Distance: %d cm\r\n",HCSR04_Read());
HAL_Delay(500);*///====================================================串口打印

10,自定义函数:

int fputc(int ch,FILE*f)//串口输出函数,printf函数
{
    HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,100);
    return ch;
}

//==============================================================================以下为超声波运行程序,根据开启的通道不同可更改
void delay_us(uint16_t time)
{
    __HAL_TIM_SET_COUNTER(&htim3,0);//计时器置零
    while(__HAL_TIM_GET_COUNTER(&htim3)<time);//获得计数值,并比较
}

void delay_ms(uint16_t time)
{
    __HAL_TIM_SET_COUNTER(&htim3,0);//计时器置零
    while(__HAL_TIM_GET_COUNTER(&htim3)<time);//获得计数值,并比较
}

uint16_t HCSR04_Read(void)//超声波读取函数
{
    HAL_GPIO_WritePin(TRIG_GPIO_Port,TRIG_Pin,GPIO_PIN_RESET);//先拉低电平
    delay_us(5);
    HAL_GPIO_WritePin(TRIG_GPIO_Port,TRIG_Pin,GPIO_PIN_SET);//发送测距信号的高平信号
    delay_us(20);
    HAL_GPIO_WritePin(TRIG_GPIO_Port,TRIG_Pin,GPIO_PIN_RESET);//再次拉低
    __HAL_TIM_ENABLE_IT(&htim3,TIM_IT_CC1);
    HAL_Delay(500);
    return NUM2;
}

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)//判断定时器的通道1
    {
        if(IS_FIRST_CAPTURED==0)//判断是否为第一次,防溢出;设标志位
        {
            IS_FIRST_CAPTURED=1;//不是的第一次捕获,将它置1
        IC_Val1=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);//记录返回值,并赋值于IC_Val1
        __HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);//上升变下降沿
        }
    else if(IS_FIRST_CAPTURED==1)
    {
        IS_FIRST_CAPTURED=0;
        IC_Val2=HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1);//用IC_Val2记录这个值
        __HAL_TIM_SET_COUNTER(htim,0);//计时器清零

        if(IC_Val1<IC_Val2)//判断是否溢出
        {
            NUM1=IC_Val2-IC_Val1;//没有溢出,赋值NUM1
        }
        else if(IC_Val1>IC_Val2)
        {
            NUM1=0xffff-IC_Val1+IC_Val2;//已经溢出,最大值65536
        }
            NUM2=NUM1*0.017;//标准大气压,15度;mm换算为cm;      NUM2=NUM1*340/2/10000  减轻CPU压力
            __HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);//变上升沿
            __HAL_TIM_DISABLE_IT(&htim3,TIM_IT_CC1);
     }
   }
}

//=====================================================24/3/15优化代码

1,配置,IC直接与间接捕获

2,工程代码:

uint32_t read_time=0;
uint16_t HCSR04_Read()//超声波读取函数
{
    HAL_GPIO_WritePin(TRIG_GPIO_Port,TRIG_Pin,GPIO_PIN_RESET);//先拉低电平
    delay_us(5);
    HAL_GPIO_WritePin(TRIG_GPIO_Port,TRIG_Pin,GPIO_PIN_SET);//发送测距信号的高平信号
    delay_us(20);
    HAL_GPIO_WritePin(TRIG_GPIO_Port,TRIG_Pin,GPIO_PIN_RESET);//再次拉低
    __HAL_TIM_ENABLE_IT(&htim2,TIM_IT_CC1);

    if(uwTick-read_time<100) return 0;
    read_time=uwTick;

    return distance;
}

uint32_t run_time=0;
void Tx_proc()//========================================调用即可
{
    if(uwTick-run_time<100) return;
    run_time=uwTick;

    if(HCSR04_Read()!=0)
    printf("Distance: %d cm\r\n",distance);
}

void delay_us(uint16_t time)
{
    __HAL_TIM_SET_COUNTER(&htim2,0);//计时器置零
    while(__HAL_TIM_GET_COUNTER(&htim2)<time);//获得计数值,并比较
}

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance==TIM2)
    {
        if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)
        {
            ic1_val=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);
            ic2_val=HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_2);
            if(ic2_val>=ic1_val)
            {
                distance=(ic2_val-ic1_val)*0.017;
            }
            else
            {
                distance=0xffff-ic1_val+ic2_val;
            }
            HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1);
            HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);
        }
    }
}

struct __FILE
{
  int handle;
};
FILE __stdout;
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,50);
  return ch;
}

//=========================================================================新方法

1,开启一个定时器直接输入捕获通道即可,并使能,//===========================注意是36-1或72-1

2,开启一个输出通道,并命名为TRIG;

#include "stdio.h"

uint8_t  TIM4CH1_CAPTURE_STA=0;                            //输入捕获状态  
uint16_t TIM4CH1_CAPTURE_VAL;                            //输入捕获值(TIM2是16位)

float len = 0;
uint32_t time= 0;

HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_1);   //开启TIM2的捕获通道2,并且开启捕获中断
HAL_TIM_ENABLE_IT(&htim4,TIM_IT_UPDATE);   //使能更新中断

 while (1)
  {
      CHL_capture();
      if(TIM4CH1_CAPTURE_STA & 0x80)    //成功捕获一个脉宽
      {
            time = TIM4CH1_CAPTURE_STA & 0x3F;    //获取溢出次数
            time *= 65536;        //获得溢出的时间值
            time += TIM4CH1_CAPTURE_VAL;    //加上最后一次取得的值
            len = time * 342.62*100/2000000;
            TIM4CH1_CAPTURE_STA = 0;
      }
      printf("%.1fcm\r\n",len);
          HAL_Delay(400);
  }

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)//更新中断(溢出)发生时执行
{
    if((TIM4CH1_CAPTURE_STA&0X80) ==0)        //还未捕获成功
    {
        if(TIM4CH1_CAPTURE_STA&0X40)        //捕获到一个下降沿
        {
            if((TIM4CH1_CAPTURE_STA&0X3F)==0X3F)    //高电平时间太长了
            {
                TIM4CH1_CAPTURE_STA |= 0X80;    //标记成功捕获一次
                TIM4CH1_CAPTURE_VAL = 0XFFFF;    //
            }

            else
                TIM4CH1_CAPTURE_STA++;            //否则标记溢出数加一
        }
    }
}

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//捕获中断发生时执行
{
    if((TIM4CH1_CAPTURE_STA&0x80)==0)    //还未捕获成功
    {
        if(TIM4CH1_CAPTURE_STA&0x40)    //成功捕获到一个下降沿
        {
            TIM4CH1_CAPTURE_STA |= 0X80;    //标记成功,捕获到一次高电平完成
            TIM4CH1_CAPTURE_VAL  = HAL_TIM_ReadCapturedValue(&htim4, TIM_CHANNEL_1);    //获取当前捕获值
            TIM_RESET_CAPTUREPOLARITY(&htim4, TIM_CHANNEL_1);            //清除原来设置
            TIM_SET_CAPTUREPOLARITY(&htim4, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);    //捕获到下降沿后,将捕获复位到捕获上升沿
        }

        else                            //捕获到一个上升沿
        {
            TIM4CH1_CAPTURE_STA = 0;
            TIM4CH1_CAPTURE_VAL = 0;
            TIM4CH1_CAPTURE_STA |= 0x40;    //第六位标记为捕获到上升沿
            __HAL_TIM_DISABLE(&htim4);        //关闭定时器
            __HAL_TIM_SET_COUNTER(&htim4, 0);    //定时器初始值设置为0
            TIM_RESET_CAPTUREPOLARITY(&htim4, TIM_CHANNEL_1);
            TIM_SET_CAPTUREPOLARITY(&htim4, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);    //捕获到上升沿之后,将捕获设置为下降沿
            __HAL_TIM_ENABLE(&htim4);
        }

    }
    HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_1);
}
void CHL_capture(void)
{
    uint32_t i;

    HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
    for(i=0;i<72*40;i++)
        __NOP();
    HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
}

struct __FILE
{
  int handle;
};
FILE __stdout;
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,50);
  return ch;
}