STC8H系列—16.GPIO方式驱动HC-SR04超声波模块教程
一、概述:
超声波模块HC-SR04使用Arduino驱动的例程比较多,驱动起来也是比较的简单,自然不在本文的讨论的范围。本文在C51内核的高性能芯片STC8H系列的平台上驱动HC-SR04超声波模块,驱动方式有三种,传统的方式采用GPIO方式,第二种为串口方式,第三种为I2C方式,由于硬件的限制本文使用传统的GPIO方式驱动模块【可以在模块背面R4、R5两个电阻位分别安装一个10K的电阻即可实现方式二与方式三的驱动,驱动方法不在本文的探讨范围】。
如下的例程实现超声波模块超声波束的发射与采集,通过回声来确定探测距离,然后单片机将返回的数据量化、计算,然后将距离数据显示在OLED屏上。
超声波模块的驱动方法,单片机向TR端发射一个10us的脉冲信号,当模块接收到触发信号后,模块开始工作,模块向被测物体发射一束超声波信号,声波信号的返回时间与距离成正比,模块自波束发射完成起向单片机输出一个高电平脉冲,当模块接收到波束信号高电平脉冲信号结束。当单片机INTO接收到上升沿时,定时器(12T)开始计时【每一个计数脉冲用时1us】,当下降沿到达时,定时器结束计时,然后将计时时间转换成距离。
二、知识链接:
1、工作时序:
单片机P20端口给模块Trig脚一个大于 10uS的高电平脉冲;模块的Echo给单片机INTO端(P32),会给出一个与距离等比的高电平脉冲信号,可根据脉宽时间“T”【注:定时器输出值为us,必须换成s】算出【C=340m/s】:
距离=T*C/2
2、引脚介绍:
3、模式转换:
三、实验平台搭建:
1、MCU:STC-打狗棒系列核心实验板 V2.3
2、实验板平台:德飞莱LY-51s
3、显示:SSD1306 0.96寸白色OLED屏(4脚IIC接口)
4、硬件连接表:
0.96寸4脚OLED接线图硬I2C接线表
SDL---------->P24
CLK---------->P25
VCC---------->+5V
GND---------->GND
超声波模块HC-SR04接线图
VCC---------->+5V
Trig---------->P20(触发信号)
Echo---------->P32(接收信号)
四、测试源代码:
#include <STC8H.h>
#include <stdio.h>
#include "intrins.h"
#include "oledfont.h"
#define uint8_t unsigned char
#define u8 unsigned char
#define u16 unsigned int
#define uint32_t unsigned long
#define SIZE 16
#define XLevelL 0x00
#define XLevelH 0x10
#define Max_Column 128
#define Max_Row 64
#define Brightness 0xFF
#define X_WIDTH 128
#define Y_WIDTH 64
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
unsigned int a0=0;//测量的距离值
void init_IO();//初始化IO
//超声波
void init_Ultra();
void start_Ultra();
void Delay10us(); //@12.000MHz
void Delay1ms(unsigned char x); //@12.000MHz
//硬件IIC
void init_IIC();//初始化硬IIC
void IIC_wait();//执行等待
void IIC_SendData(unsigned char dat);//发送数据
void IIC_RevAck();//接收ACK信号
void IIC_STOP();//停止信号
//OLED控制用函数
void OLED_Init(void);
void OLED_WR_Byte(unsigned char dat,unsigned char cmd);
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr);
void OLED_ShowString(uint8_t x,uint8_t y, uint8_t *p);
void OLED_Set_Pos(unsigned char x, unsigned char y);
void OLED_Clear(void);
void main()
{
uint8_t oledBuf[16];
P_SW2 |= 0x80; //扩展寄存器XFR访问使能
init_IO(); //初始化IO
init_IIC();//初始化硬IIC
OLED_Init();//初始化OLED
init_Ultra();
OLED_ShowString(0,0,"Ultrasonic Test");
OLED_ShowString(0,4,"by lizhipeng!");
OLED_ShowString(0,6," 2023/08/18");
sprintf((char *)oledBuf ,"Length:%d mm",a0);//格式化输出
OLED_ShowString(0,2,oledBuf);
while(1)
{
start_Ultra();//开始测距
//清空显示
sprintf((char *)oledBuf ,"Length: ");//格式化输出
OLED_ShowString(0,2,oledBuf);
//显示数值
Delay1ms(10);
sprintf((char *)oledBuf ,"Length:%d mm",a0);//格式化输出
OLED_ShowString(0,2,oledBuf);
}
}
void init_IO()
{
RSTCFG=0x50; //开启RST键进入ISP模式
P0M1 = 0x00; P0M0 = 0x00; //设置P0口为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置P1口为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置P3口为准双向口
}
/***************************超声波部分**********************************/
//初始化超声波
void init_Ultra()
{
//开启INT0中断
IT0=0;//INT0边缘触发
IE0=0;//清空标志位
EX0=1;//开启INT0中断
EA=1;//开总中断
PX0=1;//PX0提高INT0的优先级
IPH|=0x01;//设置PX0H=1
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式模式一16位不重装
TL0 = 0x00; //设置定时初始值
TH0 = 0x00; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 0; //定时器0开始计时
ET0=0;//不中断只计时
P20=0;
}
//开始测距
void start_Ultra()
{
unsigned int temp=0;
//产生10us脉冲
P20=1;
Delay10us();
P20=0;
Delay1ms(200);
//读取高电平的值
temp=TH0;
temp=temp<<8;
temp+=TL0;
//计算距离,单位为mm
a0=temp*34;
a0=a0/200;
}
//INT0中断接收
void INT0_isr() interrupt 0//INT0中断入口
{
if(P32==1)//上升沿
{
TL0 = 0x00; //设置定时初始值
TH0 = 0x00; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
else//下降沿
{
TR0=0; //停止计时
}
IE0=0;//清空中断标志位
}
void Delay10us() //@12.000MHz
{
unsigned char i;
i = 38;
while (--i);
}
void Delay1ms(unsigned char x) //@12.000MHz
{
unsigned char i, j;
while(x--)
{
i = 16;
j = 147;
do
{
while (--j);
} while (--i);
}
}
/***************OLED函数部分已省略*************/
Naiva: 这个互补输出可以关闭吗?比如我只想要P1.0 / PWM1P输出 pwm方波;但是P1.1/PWM1N 还可以用作其他用途。
WY14792849080: 那个怎么写入 16 位数据啊 没看懂😭
shy746522: 博主你好,请问有头文件程序吗
午后来杯java: 如果用arduino编程该怎么做呢
菲子叭叭: 想问一下为什么除了读取flash ID 以外的数据都是0x00