基于STC8G/H单片机HCSR04超声波模块测距,并通过串口字符串打印(RC频率12MHZ)​

137 阅读6分钟

基于STC8G/H单片机HCSR04超声波模块测距,并通过串口字符串打印(RC频率12MHZ)​

当下载完程序后,就可以在串口中看到超声波测试的距离距离。非常棒!!!!

STC8单片机简介:

STC8G/H系列是宏晶科技推出的高性能8位单片机,基于增强型8051内核,主频可达35MHz,单周期指令执行效率高。该系列集成丰富外设,如12位ADC、PWM、SPI、I2C、UART等,适用于工业控制、智能家居、消费电子等领域。STC8G/H支持宽电压工作(2.0V-5.5V),内置高精度RC振荡器,部分型号提供硬件USB接口。存储资源灵活,Flash容量从8KB到64KB可选,SRAM最高4KB,部分型号支持EEPROM。抗干扰能力强,符合工业级温度范围(-40℃~85℃)。

HCSR04模块简介:

HCSR04是一款常见的超声波测距模块,通过发射和接收超声波信号计算物体距离。其测量范围通常为2cm至400cm,精度可达3mm,工作电压为5V,

HCSR04引脚定义:

序号针脚名称功能描述
1VCC模块供电正极,典型工作电压(3.3~5)VDC。
2Trig触发端。
3Echo接收端,当接收到反射信号时,引脚产生一个脉冲。脉冲的长度与检测发射信号所需的时间成正比。
4GND模块供电负极。

HCSR04工作原理:

a28bcbb8dca84bcd8ed4bae999287533.png 首先,先要发送一个触发信号(Trig端口)至少为10us。当有信号回来时信号输入口会有一个高电频的跳变,使用单片机内部定时器来计时看高电频持续时间有多长,用这个就能算出距离。

超声波距离计算公式:

distance = (float)time * 0.017;(单位cm) 这个乘法操作是在依据超声波传播的时间来计算距离。超声波在空气中的传播速度大约是 340m/s,也就是 34000cm/s。
因为超声波从发射到遇到障碍物再反射回来,所经过的路程是实际距离的两倍,所以计算实际距离时需要除以 2。
1 个机器周期的时间是 1/12000000 秒(假定单片机晶振频率为 12MHz),那么距离计算公式为 distance = (34000 * time * (1/12000000)) / 2,经过化简后得到 distance = time * 0.017这里的 0.017 就是经过化简后的系

电路连接 :

捕.PNG 上面电路非常简单,接了一个二极管和一个超声波探头。比起STC89C52单片机,STC8无需外部复位电路,和外部晶振,也无需上拉电阻,可以直接使用dip封装的芯片。

完整代码:

#include <stc8.h>
#include <stdio.h>

// 类型定义
#define uchar unsigned char
#define uint unsigned int

// 引脚定义
sbit Trig = P3^5;  // 超声波触发引脚
sbit Echo = P3^4;  // 超声波接收引脚
sbit LED = P1^2;   // 状态指示LED

// 全局变量
uint g_distance_cm;     // 距离(厘米)
uint g_distance_mm;     // 距离(毫米)
uint distance_array[6]; // 存储6次测量结果
#define DISTANCE_THRESHOLD 100  // 距离阈值(毫米)

// 函数声明
void Delay10ms(unsigned int c);
void Delay10us(unsigned int c);
void Uart1_Init(void);
void UART1_Send(unsigned char dat);
void UART1_SendString(char *str);
void main_Init();
void GetDistanceInMM();
uint GetDistanceSixTimesAndCalculateAverage();

// 延时10ms函数
void Delay10ms(unsigned int c) {
    unsigned char i, j, k;
    for (k = c; k > 0; k--) {
        
        i = 156;
        j = 213;
        do {
            while (--j);
        } while (--i);
    }
}

// 延时10us函数
void Delay10us(unsigned int c) {
    unsigned char i, k;
    for (k = c; k > 0; k--) {
        i = 38;
        while (--i);
    }
}

// 串口1初始化(9600bps@12MHz)
void Uart1_Init(void) {
    SCON = 0x50;    // 8位数据,可变波特率
    AUXR |= 0x40;   // 定时器时钟1T模式
    AUXR &= 0xFE;   // 串口1选择定时器1为波特率发生器
    TMOD &= 0x0F;   // 设置定时器1为模式1
    TL1 = 0xC7;     // 设置定时初始值
    TH1 = 0xFE;     // 设置定时初始值
    ET1 = 0;        // 禁止定时器1中断
    TR1 = 1;        // 启动定时器1
}

// 串口发送一个字符
void UART1_Send(unsigned char dat) {
    SBUF = dat;             // 将数据写入串口发送缓冲区
    while (!TI);            // 等待发送完成
    TI = 0;                 // 清除发送完成标志
}

// 串口发送字符串
void UART1_SendString(char *str) {
    while (*str) {          // 遍历字符串直到结束符
        UART1_Send(*str++); // 发送当前字符并指向下一个
    }
}

// 主初始化函数
void main_Init() {
    P1M0 = 0x00; P1M1 = 0x00; // 设置P1口为准双向口
    P3M0 &= ~0x30; P3M1 &= ~0x30;  // 设置P3.4和P3.5为准双向口

    Uart1_Init(); // 初始化串口
}

// 超声波测距函数(单位:毫米)
void GetDistanceInMM() {
    unsigned int time;

    // 触发超声波模块
    Trig = 0;
    Delay10us(1);
    Trig = 1;
    Delay10us(2);
    Trig = 0;

    // 等待回声信号
    while (!Echo);
    TR0 = 1;        // 启动定时器0
    while (Echo);
    TR0 = 0;        // 停止定时器0

    // 计算时间(单位:机器周期)
    time = TH0 * 256 + TL0;
    TH0 = 0;        // 重置定时器0
    TL0 = 0;

    // 计算距离(单位:毫米)
    // 距离 = 时间 × 声速(340m/s) ÷ 2 = time × 17 / 1000 (cm) × 10 = time × 17 / 100 (mm)
    g_distance_mm = (uint)time * 17 / 100;
    g_distance_cm = g_distance_mm / 10; // 转换为厘米
}

// 进行6次测量并计算平均值
uint GetDistanceSixTimesAndCalculateAverage() {
    uint i;
    uint sum = 0;
    
    for (i = 0; i < 6; i++) {
        GetDistanceInMM();           // 执行单次测量
        distance_array[i] = g_distance_cm; // 保存测量结果
        sum += g_distance_cm;        // 累加测量值
        Delay10ms(100);              // 间隔1秒
    }
    
    return sum / 6;                  // 返回平均值
}

void main() {
    char str[30];
    uint average_distance;

    main_Init();     // 初始化系统
    Trig = 0;        // 初始状态下关闭超声波触发

    TMOD &= 0xF0;    // 配置定时器0为模式1
    TMOD |= 0x01;
    TH0 = 0;
    TL0 = 0;

    while (1) {
        // 执行6次测量并计算平均值
        average_distance = GetDistanceSixTimesAndCalculateAverage();
        
        // 发送平均值到串口
        sprintf(str, "Average Distance: %u cm\r\n", average_distance);
        UART1_SendString(str);

        // 根据平均值控制LED
        if (average_distance * 10 < DISTANCE_THRESHOLD) {
            LED = 0;  // 距离小于阈值,点亮LED
            sprintf(str, "Warning: Distance is less than %u mm!\r\n", DISTANCE_THRESHOLD);
            UART1_SendString(str);
        } else {
            LED = 1;  // 距离大于阈值,熄灭LED
        }

        Delay10ms(1000); // 每10秒测量一次
    }
}

P1M0 = 0x00; P1M1 = 0x00; // 设置P1口为准双向口
P3M0 &= ~0x30; P3M1 &= ~0x30;  // 设置P3.4和P3.5为准双向口

为端口模式定义,在STC89c52单片机是不需要定义的,只有P0口为开漏输出,其他口都是准双向口。但STC8有多种端口模式可以选,所以需要定义端口模式(直接在stc-isp软件中I/O口配置工具,选择端口和模式就会生成c代码)。

程序下载

打开stc-isp软件,根据自己的芯片选择型号,选择串口。特别注意:IRC频率选择12MHZ,如果选择别的,串口字符串接收的时候就会乱码。串口接收时 要在接收缓冲区中勾选文本模式,波特率设置为9600。如果发现还是乱码,选择更多设置将接收数据的编码方式选择ansi。 ​

​实验现象

把程序下载完后,按照上面设置,就能看到测量的距离。