本文描述用新定义51单片机(RD8G37)+超声波一体测距传感器实现简单的测距测速仪。
测距仪演示效果
新定义RD8G37Q48RJ开发板
超声波测距模块:
8位并口屏
1、main.c
cpp
unsigned short timeConsuming=0;
unsigned int oldDistance;
void rectClearScreen(void);
void updateDisplay(void)
{
unsigned int d[2];
float v,dis;
char buf[8]={0};
memset(buf, '0', 8);
Measure_Distance(d);
dis=((float)d[0])/1000;
sprintf(buf,"%0.f2d",dis); // 获取当前秒
buf[4]='\0';
if(d[0]<500){
//rectClearScreen();
GUI_WriteASCII_BIG(6,60,buf,VGA_YELLOW,VGA_RED);
}
else GUI_WriteASCII_BIG(6,60,buf,VGA_WHITE,VGA_BLACK);
if(oldDistance>d[0])
v=((float)(oldDistance-d[0]))/d[1];
else v=(d[0]-oldDistance)/d[1];
sprintf(buf,"%0.2f",v); // 获取当前秒
buf[4]='\0';
GUI_WriteASCII(150,60,buf,VGA_Mint,VGA_BLACK);
oldDistance=d[0];
}
void rectClearScreen(void)
{
uint8_t i;
setColor(VGA_RED);
for(i=0;i<30;i+=3)
{
drawRect(i+6,i*176/220+60,214-i,110-i*176/220);
}
}
void draw_interface(void)
{
setColor(VGA_BLACK);
clrScr(VGA_BLACK);
setColor(VGA_Orange_Red);
fillRect(5,5,105,83);
setColor(VGA_Golden);
fillRect(115,5,215,83);
setColor(VGA_Medium_Blue);
fillRect(5,93,105,171);
setColor(VGA_Mint);
fillRect(115,93,215,171);
GUI_Write32CnChar(10,10,"测距测速仪",VGA_Orange_Red,VGA_BLACK);
GUI_Write32CnChar(118,113,"新定义",VGA_WHITE,VGA_Dark_Green);
GUI_WriteASCII(20,145,"RD8G37Q48RJ",VGA_Dark_Mineral_Blue,VGA_BLACK);
setColor(VGA_BLACK);
fillRect(5,53,215,111);
GUI_Write32CnChar(102,72,"米",VGA_WHITE,VGA_BLACK);
GUI_WriteASCII(150,60,"1.1",VGA_Mint,VGA_BLACK);
GUI_WriteASCII(165,82,"m/s",VGA_WHITE,VGA_BLACK);
setColor(0XC618);
drawRoundRect(0,0,219,175);
}
void main(void)
{
/*<Generated by EasyCodeCube begin>*/
/*<UserCodeStart>*//*<SinOne-Tag><36>*/
IcResourceInit();
InitLCD();
setColor(VGA_BLACK);
draw_interface();
/*<UserCodeEnd>*//*<SinOne-Tag><36>*/
/*<UserCodeStart>*//*<SinOne-Tag><4>*/
/*****MainLoop*****/
while(1)
{
/*<UserCodeStart>*//*<SinOne-Tag><14>*/
/***User program***/
updateDisplay();
Delay(50000);
/*<UserCodeEnd>*//*<SinOne-Tag><14>*/
/*<Begin-Inserted by EasyCodeCube for Condition>*/
}
/*<UserCodeEnd>*//*<SinOne-Tag><4>*/
/*<Generated by EasyCodeCube end>*/
}
2、传感器驱动
HC_SR04.c
cpp
#include "SC_Init.h"
#include "HC_SR04.h"
extern unsigned int time;
void Delay_us(unsigned short time)
{
do
{
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
}while(--time);
}
void HC_GPIO_Init(void)
{
ResetTrig(); //Trig拉低,为输出脉冲触发信号做准备
}
void Measure_Distance(unsigned int* distance) //测距
{
//unsigned int distance[2]=0;
SetTrig(); //10us的脉冲触发信号
Delay_us(10);
ResetTrig();
while(HC_ECHO==0); //等待Echo输出高电平
time=0; //开始记录回波信号脉宽
while(HC_ECHO==1); //等待Echo输出低电平
distance[0]=time*1.7;//根据声速和时间计算距离,即distance=time*340/2/100
distance[1]=time;
/*
关于分辨力(mm):
定时器每次对time加1是10us,10us=0.01ms,340m/s=340mm/ms
计算距离时,最小分辨力为:0.01(ms) * 340(mm/ms) / 2 = 1.7(mm)
小于模块标准精度3mm,故测距结果十分精准
*/
return ; //返回距离,单位mm
}
HC_SR04.h
cpp
#ifndef _HC_SR04_H_
#define _HC_SR04_H_
#define HC_TRIG P21
#define HC_ECHO P20
#define SetTrig() HC_TRIG=1
#define ResetTrig() HC_TRIG=0
//#define ReadEcho() GPIO_ReadPin(CW_GPIOB,GPIO_PIN_9)
void HC_GPIO_Init(void);
void Measure_Distance(unsigned int* distance);
#endif
3、初始化和中断
SC_Init.c,
初始化8位并口屏GPIO,TIMER0。
TIMER0设置为10us中断一次,做为距离传感器的测量时间最小单位。
cpp
void SC_Init(void)
{
//Forbid editing areas before the following label !!!
SC_GPIO_Init();
SC_OPTION_Init();
SC_TIM0_Init();
/*write initial function here*/
EA = 1;
}
/*****************************************************
*函数名称: SC_GPIO_Init
*函数功能: GPIO初始化函数
*入口参数:void
*出口参数:void
*****************************************************/
void SC_GPIO_Init(void)
{
//Forbid editing areas before the following label !!!
GPIO_Init(GPIO3, GPIO_PIN_6,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO3, GPIO_PIN_5,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO3, GPIO_PIN_4,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO3, GPIO_PIN_3,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO3, GPIO_PIN_2,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO3, GPIO_PIN_1,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO3, GPIO_PIN_0,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO1, GPIO_PIN_0,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO2, GPIO_PIN_0,GPIO_MODE_IN_HI);
GPIO_Init(GPIO2, GPIO_PIN_1,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO0, GPIO_PIN_4,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO0, GPIO_PIN_5,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO0, GPIO_PIN_6,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO5, GPIO_PIN_1,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO5, GPIO_PIN_5,GPIO_MODE_OUT_PP);
GPIO_Init(GPIO4, GPIO_PIN_7,GPIO_MODE_OUT_PP);
/*GPIO_Init write here*/
}
/*****************************************************
*函数名称: SC_TIM0_Init
*函数功能: TIMER0初始化函数
*入口参数:void
*出口参数:void
*****************************************************/
void SC_TIM0_Init(void)
{
//Forbid editing areas before the following label !!!
TIM0_TimeBaseInit(TIM0_PRESSEL_FSYS_D12,TIM0_MODE_TIMER);
TIM0_WorkModeConfig(TIM0_WORK_MODE2,229, 0);
TIM0_ITConfig(ENABLE,LOW);
TIM0_Cmd(ENABLE);
/*TIM0_Init write here*/
}
SC_it.c
TIMER0中断,每次中断计数加1。
cpp
void Timer0Interrupt() interrupt 1
{
/*TIM0_it write here begin*/
//Forbid editing areas between the labels !!!
/*TIM0_it write here*/
/*<Generated by EasyCodeCube begin>*/
/*<UserCodeStart>*//*<SinOne-Tag><55>*/
//Timer0Interrupt
{
/*<UserCodeStart>*//*<SinOne-Tag><15>*/
/***User program***/
time++;
/*<UserCodeEnd>*//*<SinOne-Tag><15>*/
/*<Begin-Inserted by EasyCodeCube for Condition>*/
}
/*<UserCodeEnd>*//*<SinOne-Tag><55>*/
/*<Generated by EasyCodeCube end>*/
/*Timer0Interrupt Flag Clear begin*/
//Forbid editing areas between the labels !!!
/*Timer0Interrupt Flag Clear end*/
}
总结
1、程序中用了TIMER0,主要是TIMER0可以做到us级,可以使测距更准确。
2、HC_SR04传感器的算法是通用的。
3、RD8G37Q48是QFN封装,PCB封装引脚延长到3mm,可以用烙铁焊接。
4、HC_SR04传感器不能测太远距离,室内3米以内应该没问题。
5、所用屏幕为ST7775,220*176分辨率,8位并口屏。
6、工程的建立用的是EasyCodeCube.exe,主要实现了gpio和timer初始化。程序编写和下载用的是keil。