赞
踩
视频地址:1.基于STM32的超声波雷达-演示_哔哩哔哩_bilibili
备注:文档最后有所有文件的网盘地址
全部必要硬件(左到右):
其他扩展硬件
外设 | 型号 | 备注 |
stm32主控芯片 | stm32c8t6 | |
超声波传感器 | hc-sr04 | |
舵机 | sg90 | |
lcd显示屏 | ST7735S 1.8寸 128*160tft lcd | |
舵机的控制信号为周期是20ms 的脉宽调制(PWM)信号,其中脉冲宽度从0.5ms-2.5ms,相对应舵盘的位置为0—180度,呈线性变化。也就是说,给它提供一定的脉宽,它的输出轴就会保持在一个相对应的角度上,无论外界转矩怎样改变,直到给它提供一个另外宽度的脉冲信号,它才会改变输出角度到新的对应的位置上。舵机内部有一个基准电路,产生周期20ms,宽度1.5ms的基准信号,有一个比较器,将外加信号与基准信号相比较,判断出方向和大小,从而产生电机的转动信号。
舵机内部控制电路板接受来自信号线相应的PWM控制信号,进而控制电机转动,电机带动一系列齿轮组,减速后传动至输出舵盘。舵机的输出轴和位置反馈电位计是相连的,舵盘转动的同时,带动位置反馈电位计,电位计将输出一个电压信号到控制电路板,进行反馈,然后控制电路板根据所在位置决定电机的转动方向和速度,从而达到目标停止。
GND :地线。
+5V :舵机电源,接5V,(3.3V也可正常工作)。
PWM:舵机控制引脚。
引脚一般可以根据线的颜色区分:棕色GND、红色VCC、黄色PWM
引脚连接关系:(PA1:定时器2的通道2)
核心代码:全部代码见文件夹工程
- // 产生周期为20ms(50HZ),高电平宽度为0.5ms~2.5ms(占空比范围)
- // ARR , PSC 可是多个值,
- // ARR = 20000-1 PSC = 72-1;取这个值方便计算而已,其他值也可以
- // 舵机电平要求0.5ms~2.5ms 既占空比:0.5ms/20ms = ccr/20000 ~ 2.5ms/20ms = ccr/20000
- // ccr 500 ~ 2500
- void pwm_init(void)
- {
- //1、打开时钟(TIM,GPIO)
- //2、配置GPIO为复用推挽输出
- //3、选择时钟源
- //4、配置时基单元
- //5、配置输出比较单元
- //6、运行控制(启动定时器)
-
- //1、打开时钟
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // TIM2在APB1总线
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIOA在APB2总线
-
- //2、配置GPIO为复用推挽输出
- GPIO_InitTypeDef gpioInit;
- gpioInit.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出(控制权给片上外设(定时器))
- gpioInit.GPIO_Pin = GPIO_Pin_1;
- gpioInit.GPIO_Speed = GPIO_Speed_50MHz; //一般设置50MHZ即可
- GPIO_Init(GPIOA, &gpioInit);
-
- //3、选择内部时钟
- TIM_InternalClockConfig(TIM2);
-
- //4、配置时基单元
- TIM_TimeBaseInitTypeDef timeInit;
- timeInit.TIM_ClockDivision = TIM_CKD_DIV1; // 外部时钟滤波单元的分频系数,没用,随便配置一个
- timeInit.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
- timeInit.TIM_Period = 20000 - 1; // 重装值
- timeInit.TIM_Prescaler = 72-1; // 分频值
- timeInit.TIM_RepetitionCounter = 0; // 重复计数器(高级定时器才有)
- TIM_TimeBaseInit(TIM2, &timeInit);
-
- //5、配置输出比较单元
- TIM_OCInitTypeDef ocInit;
- TIM_OCStructInit(&ocInit); // 结构体初始化(没引用的成员赋默认值)
- ocInit.TIM_OCMode = TIM_OCMode_PWM1; // 设置输出模式PWM1模式(先高电平,后低电平)
- ocInit.TIM_OCPolarity = TIM_OCPolarity_High; // 设置输出比较的极性不翻转
- ocInit.TIM_OutputState = TIM_OutputState_Enable; // 设置输出使能
- ocInit.TIM_Pulse = 0; // 设置ccr的值(用于调节占空比)
- TIM_OC2Init(TIM2, &ocInit); // 设置通道2输出PWM
-
- //6、运行控制(启动定时器)
- TIM_Cmd(TIM2, ENABLE);
- }
-
- /**
- * @brief 设置pwm的占空比
- *
- * @param ccr 根据舵机要求计算:取500-2500
- */
- void pwm_setCCR(uint16_t ccr)
- {
- TIM_SetCompare2(TIM2, ccr); // 修改通道2ccr的值,实现修改占空比
- }
-
- /**
- * @brief 根据角度旋转舵机
- * ccr取值500~2500 角度0~180
- * 500~2500范围是2000; 0~180范围是180
- * 等比例缩放 ccr/2000 = angle / 180
- * ccr = angle / 180 *2000
- * ccr是从500开始,所以还要再偏移500
- * ccr = angle / 180 *2000 + 500
- * @param angle 旋转角度
- *
- */
- void servo_setAngle(float angle)
- {
- uint16_t ccr;
- ccr = angle / 180 *2000 + 500;
- pwm_setCCR(ccr);
- }

最终效果图
HC-SR04超声波距离传感器的核心是两个超声波传感器。一个用作发射器,将电信号转换为40 KHz超声波脉冲。接收器监听发射的脉冲。如果接收到它们,它将产生一个输出脉冲,其宽度可用于确定脉冲传播的距离。
该传感器体积小,易于在任何机器人项目中使用,并提供2厘米至400厘米(约1英寸至13英尺)之间出色的非接触范围检测,精度为3mm,工作电压为5伏。
以下是完整的规格:
描述 | 参数 |
Operating Voltage工作电压 | 直流3.3V---5V |
Operating Current工作电流 | 15毫安 |
Operating Frequency运行频率 | 40K赫兹 |
Max Range最大范围 | 4m |
Min Range最小范围 | 2厘米 |
Ranging Accuracy测距精度 | 3毫米 |
Measuring Angle测量角度 | 15度 |
Trigger Input Signal触发输入信号 | 10µS TTL脉冲 |
Dimension尺寸 | 45 x 20 x 15毫米 |
VCC :HC-SR04超声波距离传感器电源引脚,接5V。
Trig :(Trigger) 引脚用于触发超声波脉冲。
Echo :回声当接收到反射信号时,引脚产生一个脉冲。脉冲长度与检测发射信号所需时间成正比。
GND :地线。
只要提供一个 10uS以上脉冲触发信号,该模块内部将发出8个 40kHz周期电平并检测回波。一旦检测到有回波信号则输出回响信号。回响信号的脉冲宽度与所测的距离成正比。 由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。
公式: uS/58=厘米或者uS/148=英寸; 或是: 距离=高电平时间*声速( 340M/S) /2;
建议测量周期为 60ms以上, 以防止发射信号对回响信号的影响
stm32和超声波传感器引脚连接关系:(PB6为定时器4通道1)
stm32和OLED显示屏引脚连接关系:(OLED调试超声波传感器需要用到)
核心代码:全部代码见文件夹工程
- //返回超声波毫米值
- uint32_t hcsr04_getValueMm(void)
- {
- uint32_t dist, distMm;
- static uint64_t timeEnd;
-
- //触发超声波测量
- GPIO_WriteBit(GPIOB,TRIG_PIN,Bit_SET); //Trig输出高电平
- delay_us(15); //保持15微秒生效
- GPIO_WriteBit(GPIOB,TRIG_PIN,Bit_RESET); //Trig输出低电平
-
- while((GPIO_ReadInputDataBit(GPIOB,ECHO_PIN) == 0)); //等待低电平结束,开始测量
- g_time = 0; //计时清零
- while(GPIO_ReadInputDataBit(GPIOB,ECHO_PIN) == 1); //等待高电平结束,测量结束
- timeEnd = g_time;
-
- if(timeEnd/100 < 38) //判断是否小于38毫秒,大于38毫秒的就是超时,直接跳到下面返回0
- {
- dist=(timeEnd*346) / 2; //计算距离,25°C空气中的音速为346m/s
- distMm=dist/100; //timeEnd单位是10微秒,得出单位为毫米的距离结果,还得除以100
- }else
- {
- distMm=0;
- }
-
- return distMm;
- }
-
- //中断服务函数,回波计时,每10微秒g_time加1
- void TIM4_IRQHandler(void)
- {
- if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET) //获取TIM2定时器的更新中断标志位
- {
- g_time++;
- TIM_ClearITPendingBit(TIM4, TIM_IT_Update); //清除更新中断标志位
- }
- }
-
- //定时器4初始化
- //定时10us,提供超声波测量时间
- //定时器4中断服务函数再drv_sr04.c
- void time4_init(void)
- {
- //1、RCC开启时钟
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
-
- //2、选择时基单元的时钟源
- TIM_InternalClockConfig(TIM4); //选择内部时钟(不写也行,默认就是内部时钟)
-
- //3、配置时基单元
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
- TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //外部时钟滤波单元的分频系数,没用,随便配置一个就行
- TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
- //频率 = CK_PSC / (PSC + 1) / (ARR + 1) CK_PSC=72MHZ
- //时间=1/频率 72MHZ/72/10 ===》 10us
- TIM_TimeBaseInitStruct.TIM_Prescaler = 72-1; //分频值
- TIM_TimeBaseInitStruct.TIM_Period = 10-1; //周期,ARR自动重装器的值
- TIM_TimeBaseInitStruct.TIM_RepetitionCounter =0; //重复计数器的值,高级定时器才有,给0就行
- TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStruct);
- //TIM_TimeBaseInit设置自动更新会进一次中断,这边清除中断解决刚上电就会进一次中断的问题
- TIM_ClearFlag(TIM4,TIM_FLAG_Update);
-
-
- //4、配置中断输出控制
- TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);//更新中断到NVIC使能
-
- //5、配置NVIC
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //选择优先级分组2
-
- NVIC_InitTypeDef NVIC_InitStruct;
- NVIC_InitStruct.NVIC_IRQChannel = TIM4_IRQn;
- NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
- NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
- NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
- NVIC_Init(&NVIC_InitStruct);
-
- //6、配置运行控制
- TIM_Cmd(TIM4, ENABLE); //启动定时器3
- }

最终效果图
该显示屏是一块以ST7735S驱动的1.8英寸采用SPI通信的TFT全彩屏,分辨率是128*128,这里采用RGB565 16bit的色块编译模式(RGB565即高五位为Red,第五位为Blue,中间六位为Green,共16位)。本文仅设计该屏幕的简单应用,不对底层原理进行深究。
引脚 | Parameter |
GND | 接地 |
VCC | 3.3V-5V电源接入 |
SCL | SPI总线时钟信号 |
SDA | SPI总线写数据信号 |
RES | 液晶屏复位信号,低电平复位 |
DC | 液晶屏寄存器/数据选择信号,高电平:寄存器,低电平:数据 |
CS | 液晶屏片选信号,低电平使能 |
BL | 背光控制,高电平点亮,如无需控制则接3.3V常亮 |
屏幕的参数配置的大体流程如下:
显示屏的显示原理就是在屏幕上打点,显示中文,英文,图片本质都是在对应的位置,将这些点事先找出来就是取模;中文,英文,图片都要先取模才能显示。
英文取模
附:ASCII码完整表:注第一个字符为空格,不要遗漏
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
4.设置如下,然后点击确定。
> 点阵要选择的数要大于字符所占字节数,例如8x16的字符所占字节为 8x16/2=16,所以这里点阵选大于16就行
8x16字模在例程font.h中已经取好 如下所示
中文取模
8x16字模在例程font.h中已经取好 如下所示
注:每个字的字模前需要添加这个汉字,并用双引号括起来然后加上逗号!
图片取模
引脚连接关系
LCD初始化代码:全部代码见文件夹工程
- // lcd1.8寸 128*160 初始化函数
- void lcd_init(void)
- {
- lcd_gpio_init();
- spi_init();
-
- lcd_set_rest(); // lcd复位
-
- lcd_wr_bl(1); // 打开背光
- delay_ms(100);
-
- //************* Start Initial Sequence **********//
- lcd_wr_regist(0x11); //Sleep out
- delay_ms(120); //Delay 120ms
- //------------------------------------ST7735S Frame Rate-----------------------------------------//
- lcd_wr_regist(0xB1);
- lcd_wr_data(0x05); lcd_wr_data(0x3C); lcd_wr_data(0x3C);
-
- lcd_wr_regist(0xB2);
- lcd_wr_data(0x05); lcd_wr_data(0x3C); lcd_wr_data(0x3C);
-
- lcd_wr_regist(0xB3);
- lcd_wr_data(0x05); lcd_wr_data(0x3C); lcd_wr_data(0x3C);
- lcd_wr_data(0x05); lcd_wr_data(0x3C); lcd_wr_data(0x3C);
-
- //------------------------------------End ST7735S Frame Rate---------------------------------//
- lcd_wr_regist(0xB4); //Dot inversion
- lcd_wr_data(0x03);
-
- //------------------------------------ST7735S Power Sequence---------------------------------//
- lcd_wr_regist(0xC0);
- lcd_wr_data(0x28); lcd_wr_data(0x08); lcd_wr_data(0x04);
-
- lcd_wr_regist(0xC1);
- lcd_wr_data(0XC0);
-
- lcd_wr_regist(0xC2);
- lcd_wr_data(0x0D); lcd_wr_data(0x00);
-
- lcd_wr_regist(0xC3);
- lcd_wr_data(0x8D); lcd_wr_data(0x2A);
-
- lcd_wr_regist(0xC4);
- lcd_wr_data(0x8D); lcd_wr_data(0xEE);
-
- //---------------------------------End ST7735S Power Sequence-------------------------------------//
- lcd_wr_regist(0xC5); //VCOM
- lcd_wr_data(0x1A);
-
- lcd_wr_regist(0x36); //MX, MY, RGB mode
- if(USE_HORIZONTAL==0)lcd_wr_data(0x00);
- else if(USE_HORIZONTAL==1)lcd_wr_data(0xC0);
- else if(USE_HORIZONTAL==2)lcd_wr_data(0x70);
- else lcd_wr_data(0xA0);
-
- //------------------------------------ST7735S Gamma Sequence---------------------------------//
- lcd_wr_regist(0xE0);
- lcd_wr_data(0x04); lcd_wr_data(0x22); lcd_wr_data(0x07);
- lcd_wr_data(0x0A); lcd_wr_data(0x2E); lcd_wr_data(0x30);
- lcd_wr_data(0x25); lcd_wr_data(0x2A); lcd_wr_data(0x28);
- lcd_wr_data(0x26); lcd_wr_data(0x2E); lcd_wr_data(0x3A);
- lcd_wr_data(0x00); lcd_wr_data(0x01); lcd_wr_data(0x03);
- lcd_wr_data(0x13);
-
- lcd_wr_regist(0xE1);
- lcd_wr_data(0x04); lcd_wr_data(0x16); lcd_wr_data(0x06);
- lcd_wr_data(0x0D); lcd_wr_data(0x2D); lcd_wr_data(0x26);
- lcd_wr_data(0x23); lcd_wr_data(0x27); lcd_wr_data(0x27);
- lcd_wr_data(0x25); lcd_wr_data(0x2D); lcd_wr_data(0x3B);
- lcd_wr_data(0x00); lcd_wr_data(0x01); lcd_wr_data(0x04);
- lcd_wr_data(0x13);
- //------------------------------------End ST7735S Gamma Sequence-----------------------------//
-
- lcd_wr_regist(0x3A); //65k mode
- lcd_wr_data(0x05);
- lcd_wr_regist(0x29); //Display on
- }

测试代码效果
使用TFT显示屏的驱动,在屏幕上画出雷达GUI图像
绘制雷达图像代码
- // 根据角度和长度,绘制从圆心开始的斜线
- void radar_line(double k,int r)
- {
- int16_t x,y;
-
- x=80+r*(double)cos(k/180*3.1415926);
- y=108-r*(double)sin(k/180*3.1415926);
-
- lcd_simple_line(80,108,x,y,GREEN);
-
- }
- //雷达图像
- void radar_picture(void)
- {
- lcd_draw_chinese(80,0,GREEN,BLACK,16, 0,"超声波雷达");
-
- //画圆:(圆心坐标,半径,颜色)
- lcd_simple_circle(80,108,76,GREEN);
- lcd_simple_circle(80,108,57,GREEN);
- lcd_simple_circle(80,108,38,GREEN);
- lcd_simple_circle(80,108,19,GREEN);
-
- lcd_simple_fill(0, 108, 160, 20, BLACK); //去掉园的下半部分
-
- //画斜线:(角度,长度)
- radar_line(30,85);
- radar_line(60,85);
- radar_line(90,85);
- radar_line(120,85);
- radar_line(150,85);
- lcd_simple_line(0,108,160,108,GREEN);
-
- //数据信息
- lcd_draw_integer(0, 46, GREEN, BLACK, 16, 0, 3, 150); // 150°数值
- lcd_draw_integer(38, 22, GREEN, BLACK, 16, 0, 3, 120); // 120°数值
- lcd_draw_integer(83, 20, GREEN, BLACK, 16, 0, 2, 90); // 90°数值
- lcd_draw_integer(124, 32, GREEN, BLACK, 16, 0, 2, 60); // 60°数值
- lcd_draw_integer(140, 49, GREEN, BLACK, 16, 0, 2, 30); // 30°数值
-
- lcd_draw_chinese(21, 44, GREEN, BLACK, 16, 0, "°"); // 150°符号
- lcd_draw_chinese(59, 19, GREEN, BLACK, 16, 0, "°"); // 120°符号
- lcd_draw_chinese(97, 18, GREEN, BLACK, 16, 0, "°"); // 90°符号
- lcd_draw_chinese(137, 30, GREEN, BLACK, 16, 0, "°"); // 60°符号
- lcd_draw_chinese(152, 45, GREEN, BLACK, 16, 0, "°"); // 30°符号
-
- lcd_simple_hz(0, 0, GREEN, "角度");
- lcd_simple_char(4,0,GREEN, ':');
- lcd_simple_hz(4,0,GREEN ,"°"); //显示°
-
- lcd_simple_hz(0, 7, GREEN, "距离");
- lcd_simple_char(4, 7, GREEN, ':');
- lcd_simple_str(9,7,GREEN,"mm");
- }

根据超声波传感器返回的距离值,根据屏幕尺寸等比例缩放,在屏幕上打印对应的点,下面是关键逻辑代码
- while (1)
- {
- for (uint8_t i = 30; i <= 150; i++) // 舵机旋转
- {
- distMm = hcsr04_getValueMm(); // 获取超声波数据
- uint16_t lcdMm = distMm/6; // 等比例缩小,便于显示在屏幕上
- if(distMm <= 500)
- {
- lcd_simple_int(5,7, BLACK, 4, oldMn); // 覆盖上次距离信息
- lcd_simple_int(5,7, GREEN, 4, distMm); // 显示新的距离信息
- oldMn = distMm;
-
- radar_redPoint(i, lcdMm); // 屏幕上打点
- }
- // lcd_draw_integer(3,114,3,GREEN,BLACK,16,0,distanceMm);
- servo_setAngle(i);
- lcd_simple_int(5,0, BLACK, 3, i-1); // 覆盖上次距离信息
- lcd_simple_int(5,0, GREEN, 3, i); // 显示新的距离信息
- delay_ms(20);
-
- }
- lcd_simple_int(5,0, BLACK, 3, 150); // 覆盖上次内容
-
- for (uint8_t i = 30; i <= 150; i++) // 舵机往回旋转
- {
- distMm = hcsr04_getValueMm(); // 获取超声波数据
- uint16_t lcdMm = distMm/6; // 等比例缩小,便于显示在屏幕上
- if(distMm <= 500)
- {
- radar_redPoint(180-i, lcdMm);
- lcd_simple_int(5,7, BLACK, 4, oldMn); // 覆盖上次内容
- lcd_simple_int(5,7, GREEN, 4, distMm); // 显示新的内容
- oldMn = distMm;
- }
- servo_setAngle(180 - i);
-
- lcd_simple_int(5,0, BLACK, 3, 180-i+1); // 覆盖上次内容
- lcd_simple_int(5,0, GREEN, 3, 180-i); // 显示新的内容
-
- delay_ms(20);
-
- }
- lcd_simple_int(5,0, GREEN, 3, 30); // 显示新的内容
-
- }

链接:https://pan.baidu.com/s/11KXIBepREsnWUQEn3BvVLg
提取码:8oai
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。