蓝桥杯学习笔记 单片机CT107D 利用PCA模块实现超声波测距

一.前言

最近在琢磨开发板上的超声波模块,一般的方法是发出超声波后开启一个计时器,等待接收端口(P1^1)变为低电平或者触发计时器溢出中断后计算数据计算或是其他操作,但这么做有个问题,就是在等待接收端口回应的时候用的是while循环,这一段时间内无法进行其他操作,所以在距离较长的时候会出现一些问题(如数码管亮度减少),同时为了数据的准确,不能再while中加入数码管扫描的操作

附:之前使用的代码

void Measure_Distance()
{
	unsigned int time;
	TMOD&=0xf0;
	TH0=0;
	TL0=0;
	SendWave();
	TR0=1;
	while(RX==1&&TF0==0);//问题就出现这里
	TR0=0;
	if(TF0==0)
	{
		time=TH0<<8|TL0;
		distance=time*0.017;
	}
	if(TF0==1)
	{
		TF0=0;
		distance=255;
	}
}

前几天查阅资料发现,15系列单片机有一个叫PCA的东西,其中一个模块正好再P1^1端口处,所以可以考虑利用PCA中断实现超声波测距

二.PCA介绍

手册上是这么介绍的

没错,这个PCA是可以用作定时器的,所以再CT107D上我们就有了四个定时器(定时器0,1,2,PCA),但在这里我们用他的外部脉冲捕捉(即捕获模式)那手册上说明可以用于PWM输出,那么是否可以在比赛使用呢,我觉得是可以,但由于端口是固定的,局限性很大(见下图)

1.PCA寄存器介绍(部分)

CMOD寄存器 

一般设为0x01(12分频,开启计数溢出中断)

CCON寄存器:主要用于中断的设置,以及计时器的启动

 初始化时全部置0即可

CCAPMx寄存器(由于CCAPM0连接了P1^1端口,所以以CCAPM0举例)

由于接收到信号时RX位下降沿,所以CAPN0设为1,同时需要开启捕获标志CCF0

2.捕获模式介绍

总结一下流程:在配置好寄存器后,打开计数标志位,在PCA捕获到信号后,计数器中CH,CL中的值会给到CCAPnH和CCAPnL中 ,通过读取这两个寄存器的值便可得到时间.

附:在PCA中,计时器溢出标志位和PCA模块标志位都会触发中断,在中断函数中注意判断是谁触发的中断并执行相应的操作.

三.示例代码

由于距离计算需要一点时间,所以我在定时器1中设置每隔大概125ms执行一次数据计算

#include <STC15F2K60S2.H>
#include "intrins.h"
sbit TX=P1^0;
sbit RX=P1^1;
code unsigned char SMG_Nodot[] =
{
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
bit PCA_Flag;
unsigned int PCA_times;//时间读取
unsigned char Distance;//距离
unsigned int count=0;//计数器计数
void Measure_Distance();
void Delay12us()		//@12.000MHz用于发送40khz的脉冲
{
	unsigned char i;

	_nop_();
	_nop_();
	i = 33;
	while (--i);
}
void Delay_SMG(unsigned int t)
{
	while(t--);
}
void SelectHC573(unsigned char channel,unsigned char dat)
{
	P0=dat;
	switch(channel)
	{
		case 4:
			P2=(P2&0x1f)|0x80;
		break;
		case 5:
			P2=(P2&0x1f)|0xa0;
		break;
		case 6:
			P2=(P2&0x1f)|0xc0;
		break;
		case 7:
			P2=(P2&0x1f)|0xe0;
		break;
		case 0:
			P2=(P2&0x1f)|0x00;
		break;
	}
	P2=(P2&0x1f)|0x00;
}
void Display_SMG(unsigned char pos,unsigned char dat)
{
	SelectHC573(6,0x01<<(pos-1));
	SelectHC573(7,dat);
	Delay_SMG(500);
	SelectHC573(6,0x01<<(pos-1));
	SelectHC573(7,0xff);
}
void Display_Dynamic()
{
	Display_SMG(6,SMG_Nodot[Distance/100]);
	Display_SMG(7,SMG_Nodot[Distance%100/10]);
	Display_SMG(8,SMG_Nodot[Distance%10]);
}
void Timer1_Init()
{
	TH1=(65535-1000)/256;
	TL1=(65535-1000)%256;
	TMOD=0x16;	
	TR1=1;
	PT1=1;
	ET1=1;
	EA=1;
}
void Timer1_Service() interrupt 3//每隔一定时间触发一次中断
{
	TH1=(65535-1000)/256;
	TL1=(65535-1000)%256;
	count++;
	if(count==125)
	{
		Measure_Distance();
		count=0;
	}
}
void PCA_Init()//PCA初始化
{
	CMOD=0x01;
	CCAPM0=0x11;
	CCON=0x00;
}
void PCA_Service() interrupt 7
{
	CR=0;
	if(CCF0==1)//由模块标志位触发的中断,说明数据有效
	{
		CCF0=0;
		PCA_times=(CCAP0H<<8)|CCAP0L;//读取时间
		PCA_Flag=1;
	}
	if(CF==1)//计时器溢出中断,说明数据无效
	{
		CF=0;
		PCA_Flag=0;
	}
}
void Send_Wave()//发送40khz脉冲
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		TX=1;
		Delay12us();
		TX=0;
		Delay12us();
	}
}
void Measure_Distance()//距离计算
{
	Send_Wave();
	CH=0;
	CL=0;
	CCF0=0;
	CF=0;
	CR=1;
	if(PCA_Flag==1)
	{
		Distance=PCA_times*0.017;
	}
	if(PCA_Flag==0)
	{
		Distance=255;
	}
}
void Sys_Init()
{
	SelectHC573(4,0xff);
	SelectHC573(5,0x00);
	PCA_Init();
	Timer0_Init();
}
void main()
{
	Sys_Init();
	while(1)
	{
		Display_Dynamic();
	}
}

  • 23
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值