智能小车5-测速显示小车

测速模块

对射式测速模块:有遮挡的时候会输出高电平;没遮挡的时候会输出低电平根据之前小车安装的测速片,结合这个测速模块,通过计算高低电平变化的频率,就可以计算出速度!

 测速的具体计算:

综上所述,目的就是根据高低电平来计算出速度:

轮子走一圈,经过一个周长, C = 2x3.14x 半径 = 3.14 x 直径( 6.5cm
对应的码盘也转了一圈,码盘有 20 个格子,每经过一个格子,会遮挡(高电平)和不遮挡(低电平), 那么一个脉冲就是走了 3.14 * 6.5 cm /20 = 1.0205CM ,定时器可以设计成一秒,统计脉冲数,一个脉冲就是1cm。
假设一秒有 80 脉冲,那么就是 80cm/s

模块组装

将模块粘在测速轮的两边,将VCC和GND接到单片机引出的面包板的正负极,并将OUT口接到P2.1 (后改为P3.2,见之后的说明)

 代码实现:

speed.c:

#include "reg52.h"
#include "UART.h"
 
sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册
 
sbit speedOUT = P2^1;
int cnt_timer = 0;
int cnt_pulse = 0;
int speed = 0;
 
void Timer0Init(void)		
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x00;		//设置定时初值
	TH0 = 0x4C;		//设置定时初值 //50ms
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	ET0 = 1;
	EA = 1;   //打开中断!
}
 
//timer0的中断处理程序 //中断程序一般写在main函数的后面 //定时器0溢出时将触发这个中断函数
void speed_inter() interrupt 1 
{
	cnt_timer++;
	TL0 = 0x00;		//设置定时初值
	TH0 = 0x4C;		//设置定时初值 //50ms
	
 
	if(cnt_timer == 20){//经过(20*50毫秒 =)1秒
		cnt_timer = 0;
		speed = cnt_pulse;
		Send_string("speed = ");
		
		if((speed/10) == 0){//说明speed是个位数
			Send_byte(speed + 0x30);
		}else{//说明speed是两位数
			Send_byte(speed/10%10 + 0x30);//“速度的十位”显示字符型数字
			Send_byte(speed/1%10 + 0x30);//“速度的个位”显示字符型数字
		}
		
		Send_string("cm/s\r\n");
		cnt_pulse = 0;
	}
	
}
 
void pulse_detect()
{
	while(speedOUT == 1);//等待OUT变成低电平,即等待一次不遮挡
	while(speedOUT == 0);//等待OUT变成高电平,即等待一次遮挡
	cnt_pulse++; //此时经过一个脉冲
	
}

uart.c:

#include "reg52.h"
#include <motor.h>
#include <string.h>

#define SIZE 12

sbit D5 = P3^7;
sfr AUXR =  0x8E;
char buffer[SIZE];

/*
void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	AUXR &= 0xBF;		//定时器时钟12T模式
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;			//设置定时初始值
	TH1 = 0xFD;			//设置定时重载值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
}
*/

void UartInit()		//9600bps@11.0592MHz
{
	SCON = 0x50;  //配置串口工作方式1,REN使能接收
	
	//配置定时器1,工作方式为8位自动重载
	TMOD &= 0x0f;//定时器1工作方式位8位自动重装
	TMOD |= 0x20;
	
	TH1 = 0xFD; 
	TL1 = 0xFD; //9600波特率的初值
	
	TR1 = 1;//启动定时器
	ES  = 1;//开启串口中断
	EA  = 1;//开启总中断
	
	
}


void Send_byte(char data_msg)
{
	SBUF = data_msg;
	while(TI == 0);//在请求中断时,TI= 1,既!TI=0,等待数据的发送完成;响应中断结束后TI = 0,既!TI = 1,将TI清零
	TI = 0;

}

void Send_string(char* str)
{
	while(*str != '\0')
	{
		Send_byte(*str);
		str++;
	}
}


//TI 发送请求中断标志位,是指单片机向电脑发送
//RI 接收请求中断标志位,是指单片机接收电脑的消息


main.c

#include "reg52.h"
#include <delay.h>
#include <motor.h>
#include <uart.h>
#include <speed.h>

sbit led2 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口


void main()
{
	Timer0Init();
	UartInit();
	while(1)
		{
			Motor_front();
			pulse_detect();
		}

} 

实现效果

由于使用了串口来不断发送速度信息,因此可以使用串口软件上接收:

一些问题

以上代码虽然可以实现期望的效果,但是也有一些问题,就是由于“paulse_detect"函数使用了两个while(),会导致一旦调用了这个函数,那么除了中断之外的方法都无法让程序执行其他功能了,在这个单纯实现测速的代码中这样做没有问题,但是如果想要在测速的基础上再实现一些其他的功能,那“paulse_detect"函数的写法就不利于功能的扩展了....

解决办法就是将测速传感器的脉冲检测的OUT口也配置成一个中断,即使用P3.2口的外部中断(但是P3.2之前用于给电机供电,所以别忘记还需要修改一下电机部分的sbit定义!!),这样既可以保留测速的功能,也不会影响main函数之后可能进行的其他操作。

同时需要注意,配置外部中断时,应该配置成下降沿触发而不是低电平触发:

由参考手册得知

IT0 = 1,配置外部中断0下降沿触发中断 

同时,对于speed的显示,刚刚对于每一位的提取再转化为字符的行为很麻烦,可以使用sprintf(speed_real,"speed: %d cm/s\r\n",speed); 来直接构建字符串,但是记得提前定义一个char speed_real[24],并添加stdio.h的库!

接下来看看修改后的代码:

motor.c中的新定义:
sbit RightconlA = P3^6;   //B-1A
sbit RightconlB = P3^3;   //B-1B

sbit LeftconlA = P3^4;    //A-1A
sbit LeftconlB = P3^5;    //A-1B
speed.c:
#include "reg52.h"
#include "UART.h"
#include "stdio.h"
 
sfr AUXR = 0x8E; //配置了这句话,才可以在UART的初始化里写AUXR寄存器,原因见STC89系列的手册
 
int cnt_timer = 0;//定时器统计计数
int cnt_pulse = 0;//统计格子,脉冲次数
int speed = 0;//速度
int flag;


 
void Timer0Init()		
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x00;		//设置定时初值
	TH0 = 0x4C;		//设置定时初值 //50ms
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	ET0 = 1;
	EA = 1;   //打开中断!
}

void EX0_Init() //外部中断0
{
	EX0 = 1; //打开外部中断
	//EA = 1 //总中断(不过在串口初始化相关已经打开了总中断,所以可以在这里省略)
	//因为测速模块的原理是“有遮挡,输出高电平;无遮挡,输出低电平”,而我们要在检测到有间隙的时候触发中断,既在有遮挡变换到无遮挡(高电平变到低电平)的瞬间检测
	//既下降沿触发
	IT0 = 1;//外部中断下降沿触发
}
 
//timer0的中断处理程序 //中断程序一般写在main函数的后面 //定时器0溢出时将触发这个中断函数
void speed_inter() interrupt 1 
{
	cnt_timer++;
	TL0 = 0x00;		//设置定时初值
	TH0 = 0x4C;		//设置定时初值 //50ms
	
 
	if(cnt_timer == 20){//经过(20*50毫秒 =)1秒
		flag = 1;
		cnt_timer = 0;//当20次表示1s,重新让cnt_timer从0开始,计算下一次的1s
		//计算小车的速度,也就是拿到cnt_pulse的值
		speed = cnt_pulse;
	
		cnt_pulse = 0;//1秒后拿到cnt_pulse个格子,就能算出这1s的速度,格子清零
	}
	
}

void pulse_Inter() interrupt 0 //外部中断0,即P3.2口变低电平时会自动触发这个中断处理程序,即触发一次不遮挡就会进入中断
{
	cnt_pulse++; //此时经过一个脉冲
}
UART.c:
#include "reg52.h"
#include <motor.h>
#include <string.h>

#define SIZE 12

sbit D5 = P3^7;
sfr AUXR =  0x8E;
char buffer[SIZE];

/*
void UartInit(void)		//9600bps@11.0592MHz
{
	PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	AUXR &= 0xBF;		//定时器时钟12T模式
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xFD;			//设置定时初始值
	TH1 = 0xFD;			//设置定时重载值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
}
*/

void UartInit()		//9600bps@11.0592MHz
{
	AUXR = 0x01;
	SCON = 0x50;  //配置串口工作方式1,REN使能接收
	
	//配置定时器1,工作方式为8位自动重载
	TMOD &= 0x0f;//定时器1工作方式位8位自动重装
	TMOD |= 0x20;
	
	TH1 = 0xFD; 
	TL1 = 0xFD; //9600波特率的初值
	
	TR1 = 1;//启动定时器
	ES  = 1;//开启串口中断
	EA  = 1;//开启总中断
	
	
}


void Send_byte(char data_msg)
{
	SBUF = data_msg;
	while(TI == 0);//在请求中断时,TI= 1,既!TI=0,等待数据的发送完成;响应中断结束后TI = 0,既!TI = 1,将TI清零
	TI = 0;

}

void Send_string(char* str)
{
	while(*str != '\0')
	{
		Send_byte(*str);
		str++;
	}
}


//TI 发送请求中断标志位,是指单片机向电脑发送
//RI 接收请求中断标志位,是指单片机接收电脑的消息


//M1前进     M2后退       M3左    M4右  
void Uart_Handler() interrupt 4
{
	static int i = 0;//静态变量,被初始化一次
	char temp;

	if(RI == 1)//中断处理函数中,对于接收中断的响应
	{
		RI = 0;//清除接收中断标志位
		temp = SBUF;
		
		if(temp == 'M')
			{
			i = 0;			
			}
		
		buffer[i++] = temp;
		
		
		if(buffer[0] == 'M')
			{
			switch(buffer[1])
				{
				case '1':
					D5 = 0;
					Motor_front();
					break;
				case '2':Motor_back();
					break;
				case '3':Motor_Left();
					break;
				case '4':Motor_Right();
					break;
				default:
					Motor_Stop();
					break;
				}
				
			}
			if(i == 12)
			{
				memset(buffer,'\0',SIZE);
				i =0;
			}
	
	}
	if(TI)
	{
		
	}
}
main.c:
#include "reg52.h"
#include <delay.h>
#include <motor.h>
#include <uart.h>
#include <speed.h>
#include "stdio.h"

sbit speedOUT = P3^2;//外部中断0
sbit led2 = P3^6;//根据原理图(电路图),设备变量led2指向P3组IO口的第6口
extern int flag;
char speed_real[24];//主程序发送速度数据的字符串缓冲区
extern int speed;//速度

void main()
{
	Timer0Init();
	UartInit();
	EX0_Init();
	
	while(1)
		{
			if(flag)
			{
				sprintf(speed_real,"speed: %d cm/s\r\n",speed); //构建字符串
				Send_string(speed_real);
				flag = 0;
			}

		}

} 

  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值