基于51单片机的红外摇头小风扇

实验准备

本实验基于51单片机控制小风扇,在软件keil5上编写程序。需要使用到的元件有51单片机直流电机舵机红外遥控器杜邦线蜂鸣器数码管。需要完成NEC红外遥控器解码、舵机转动控制、电机转速控制、蜂鸣器发声四部分程序的编写,最后将这四部分合并再将相应元件组装,完成一个基于51单片机的红外摇头小风扇的设计。同时能够在数码管显示直流电机转速的档位,一个有0~10这一个档位,0就是停止,10最大。

硬件原理及实现

舵机控制

原理

舵机是由直流电机、减速齿轮组、传感器和控制电路组成的一套自动控制系统。通过发送信号,指定输出轴旋转角度。舵机的控制一般需要一个20ms左右的时基脉冲,该脉冲的高电平部分一般为0.5ms-2.5ms范围内的角度控制脉冲部分,总间隔为2ms。以180度角度伺服为例,那么对应的控制关系是这样的:0.5ms--------------0度; 1.0ms------------45度;1.5ms------------90度;2.0ms-----------135度; 2.5ms-----------180度。舵机上有三根线,红黄褐三种颜色,褐色线为舵机信号线,通过给信息线提供不同的电信号来控制舵机转过不同的角度。
舵机的PWM信号频率改变一定要有延时,要给舵机足够的时间转到指定的角度后才能改变PWM频率。

程序设计

使用51单片机的定时器2控制中断

#include<STC15F2K60S2.h>
int flag=0;
sbit pwm1=P1^1;
sbit key1=P3^2;//开关1引脚
unsigned int value[]={6,11,16,21,16,11};//误差原因,6-0°,11-45°,16-90°,21-135°,26-180°
unsigned int percent = 0;//0.1ms次数标识
int k=0,count=0;
void Timer0Initial()
{
	T2L = 0xAE;		
	T2H = 0xFB;
} //定时0.1ms,11.0592MHz,0.01%的误差
 
void initial_Timer()
{
	
		   
	
	AUXR |= 0x04;	//设置1T模式
		
	Timer0Initial();	
	
	AUXR |= 0x10;//定时器2开始计时
	IE2 |=0x04;	//允许定时器2中断
	EA = 1;	//打开总中断
}
 
void delay(unsigned int x)
{
	unsigned int i,j;
	for(i = 0;i< x; ++i)
		for(j = 120; j >0 ; --j)
			;
}//延时函数,1ms

void keyscan()//按键扫描函数
{
	if(key1 == 0)
	{
		delay(3);//按键消抖,延时消抖
		if(key1 == 0)
		{
			
			while(!key1);//按键放开
			
			flag=!flag;
		}
		
	}
 
	
}
 
void initial()
{
	key1 = 1;
	
	
	initial_Timer();
}//初始化

void Timer0() interrupt 12 //定时器2
{
	if(flag==1){//若打开开关
		percent += 1;//设置周期
		if(percent == 200)
		{
			count++;
			percent = 0;
			pwm1 = 1;
		}//产生低电平,当达到20ms时,进入下个周期,重新产生蹈叩缙?
		if(percent == value[k])
		{
			
			pwm1 = 0;
		}//产生高电平,当时间达到时,变为低电平
		if(count==20){
			count=0;
			k++;
			if(k==6)k=0;
		}//,13ms/60°,延时,给舵机时间转动到指定的角度
	}
	Timer0Initial();
 
}

void main()
{
	initial();
	while(1)
	{
		keyscan();
		delay(10);
	}
}

直流电机转速控制

原理

在PWM驱动控制的调整系统中,按一个固定的频率来接通和断开电源,并且根据需要改变一个周期内“接通”和“断开”时间的长短。通过改变直流电机电枢上电压的“占空比”来达到改变平均电压大小的目的,从而来控制电动机的转速。
如图1所示:
图1 PWM信号的占空比
图1 PWM信号的占空比

设电机始终接通电源时,电机转速最大为Vmax,设占空比为D= t1 / T,则电机的平均速度为Va = Vmax * D,其中Va指的是电机的平均速度;Vmax 是指电机在全通电时的最大速度;D = t1 / T是指占空比。由上面的公式可见,当我们改变占空比D=t1/T时,就可以得到不同的电机平均速度Vd,从而达到调速的目的。严格来说,平均速度Vd与占空比D并非严格的线性关系,但是在一般的应用中,我们可以将其近似的看成是线性关系。所以,我们通过改变高电平持续的时间来进行直流电机调速。

程序设计

使用51单片机的定时器0来控制中断

#include<STC15F2K60S2.h>
sbit Key1=P3 ^ 2; //风扇减速
sbit Key2=P3 ^ 3; //风扇加速
sbit Key3=P1 ^ 7; //风扇停止或者开始
sbit pwm1=P4^1;
sbit pwm2=P4^2;
bit fflag=0;//风扇转动标志位
int speed = 50,count = 0;
/****************延时处理**********************/
void Delay( unsigned int xms )
{
    unsigned char i;
    for( ; xms > 0; xms-- )
        for( i = 114; i > 0; i-- )
        {
            ;
        }
}
/****************初始化**********************/
void init(){
	P4M0=0x06;
	P4M1=0x00;//设置P4.1,P4.2为推挽输出
	pwm1=0;
	pwm2=0;
	AUXR |= 0x80;	//定时器时钟1T模式
	TMOD = 0x01; //设置定时器模式,16位自动重装载
	TL0 = (65536-1000)%256;		
	TH0 = (65536-1000)/256;	
	TF0=0;
	TR0=1;//定时器0开始计时
	ET0=1;//打开定时器0中断
	EA=1;//打开总中断
}
/************按键处理函数***************/
void keys(){
	if(Key3==0){
		Delay(10);
		if(Key3==0){
			
			fflag=~fflag;
		}
		while(!Key3);
	}
	if(Key1==0){
		Delay(10);
		if(Key1==0){
			
			speed-=5;
			if(speed<=0) speed=0;
		}
		while(!Key1);
	}
	if(Key2==0){
		Delay(10);
		if(Key2==0){
			
			speed+=5;
			if(speed>=100)speed=100;
		}
		while(!Key2);
	}
}
/***********中断处理函数**********/
void timer0()interrupt 1
{
	TR0 = 0;
	TL0 = (65536-1000)%256;		
	TH0 = (65536-1000)/256;	
	TR0 = 1;
	if(fflag==1){
		count++;
		if(count>100){
			count=0;
		
		}
		if(count<=speed){
				pwm1=1;
		}
		else pwm1=0;
	}
}
void main()
{
	init();
	while(1){
		keys();
	}
}

NEC红外解码

原理

NEC 协议使用38 kHz 载波频率,其数据格式包括了引导码、用户码、用户码(或者用户码反码)、按键键码和键码反码,最后一个停止位。停止位主要起隔离作用,一般不进行判断。其中数据编码总共是 4 个字节 32 位,如图 2 所示。第一个字节是用户码,第二个字节可能也是用户码,或者是用户码的反码,具体由生产商决定,第三个字节就是当前按键的键数据码,而第四个字节是键数据码的反码,可用于对数据的纠错。
在这里插入图片描述
图 2 NEC 协议数据格式

• 引导码:9ms 的载波+4.5ms 的空闲。
• 比特值“0”:560us 的载波+560us 的空闲。
• 比特值“1”:560us 的载波+1.68ms 的空闲。

在这里插入图片描述
如上图所示,当一体化接收头收到38kHz红外信号时,载波为低电平,空闲为高电平

NEC红外遥控器键值码如下图所示:
在这里插入图片描述

程序设计

使用51单片机的使用定时器1控制中断

#include<STC15F2K60S2.h>
#define uchar unsigned char
#define uint unsigned int
sbit led_sel=P2^3;
sbit IRIN=P3^6;
uchar irtime = 0;
uchar startflag = 0;	// 起始标志位
uchar ir_rc_ok = 0;		// 红外高/低电平时间接收完成标志
uchar bitnum = 0;
uchar ir_change_ok = 0;		// 转码完成标志
 
uchar irdata[33];		// 电平时间数组
uchar ircode[4]={0,0,0,0};	// 遥控解码数组
/********* 延时函数 **********/
void delayms(uint xms)
{
	uint i,j;
	for(i=xms;i>0;i--)
		for(j=110;j>0;j--);
}	  
/********** 系统初始化 ********/
void sysinit()
{
	// 初始化定时器
	TMOD |= 0x20;	// 设置定时器1位工作方式2 (0~255)
	TH1 = 0x00;		// 赋初值
	TL1 = 0x00;   256*(1/12m)*12=0.256ms
	TR1 = 1;	// 启动定时器1
	ET1 = 1;	// 使能定时器1
 
	// 初始化外部中断2
	INT_CLKO |= 0x10;//开INT2;
	EA = 1;		// 开总中断
}


/********* LED灯初始化 **********/
void IOinit(){
	P0M0=0xff;
	P0M1=0x00;
	P2M1=0x00;
	P2M0=0x08;
	led_sel=1;
	P0=0x00;
}
/************ 转换编码 *************/
void changecode()
{
	uchar k = 1;
	uchar i,j;
	uchar value;
	if(ir_rc_ok ==1)		// 如果ir接受完成就进行转码
	{
		for(i=0;i<4;i++)	// 获得前导码后的4个
		{
			for(j=0;j<8;j++)//8位
			{
				value = value>>1;	// 
				if(irdata[k]>6&&irdata[k]<10)		// 判断数据是否为" 1 "
				{
					value |= 0x80;
				}
				k++;
			}
			ircode[i] = value;		// 存储 
		}
		if(ircode[2]==~ircode[3]){
			ir_change_ok = 1;		// 编码转换完成标志
			ir_rc_ok = 0;		// ir接收标志复位	
		}
	}
}
/********* 定时器1中断服务函数 ***********/
void t0()interrupt 3
{
	irtime++;
}
/********* INT2处理函数 ***********/
void exint1() interrupt 10
{
	if(startflag)	
	{
		if(irtime>32&&irtime<63) 		// 检测前导码
		{
			bitnum=0;			
		}			
		
		irdata[bitnum]=irtime;		// 从前导码开始接收数据
		irtime=0;
		bitnum++;
		
		if(bitnum==33)		// 前导码+4字节数据,共33比特 
		{
			bitnum=0;
			ir_rc_ok = 1;
		}		
 
	}
	else
	{
		startflag = 1;
		irtime = 0;
	}
}
void main()
{
	IOinit();
	sysinit();		// 初始化
	while(1)
	{
		changecode();	// 解码
		if(ir_change_ok == 1) {
			P0=ircode[2];
			ir_change_ok =0;
		}
	}
}

蜂鸣器短暂发声

原理

无源蜂鸣器只需改变Beep端口的电平,产生一个周期性的方波即可使蜂鸣器发生声音,不同的频率发出的声音不同。其中,ULN2003是一个功放,用于放大电流。电阻R14和电容C21是用来保护电路的。若人为将Beep端口的电平一直置为高电平,在没有保护电路的情况下,容易烧毁电路,但即使有保护电路也应该注意不要将Beep端口长时间置于高电平,这对器件也是有一定损害的。
在这里插入图片描述

程序设计

#include <STC15F2K60S2.H>
#define uint  unsigned int
#define uchar unsigned char

/*---------引脚别名定义---------*/
sbit sbtBeep = P3 ^ 4;                  //蜂鸣器引脚
sbit sbtKey1 = P3 ^ 2;                  //按键1引脚
/*---------初始化函数--------*/
void init()
{
    P3M1 = 0x00;
    P3M0 = 0x10;                  //设置P3^4为推挽模式
    P0 = 0x00;                    //关闭P0端口
    sbtBeep = 0;                  //蜂鸣器引脚置0,以保护蜂鸣器
}
uint xb=0;
/*---------延时子函数--------*/
void delay( uint xms )
{
    uchar i;
    for( ; xms > 0; xms-- )
        for( i = 114; i > 0; i-- )
        {
            ;
        }
}
/*---------蜂鸣器发声函数--------*/
void beeps(){
	for(xb=0;xb<255;xb++){
		sbtBeep=1;
		delay(10);
		sbtBeep=0;
		delay(10);
	}
}
/*---------主函数--------*/
void main()
{
    init();
    while( 1 )
    {
        if( sbtKey1 == 0 )
        {
            delay( 10 );                     //延时消抖
            if( sbtKey1 == 0 )
            {
                while( !sbtKey1 );       //松手后才响
                beeps();
            }
        }
    }
}

红外摇头小风扇程序

github代码链接

实物效果图

在这里插入图片描述
在这里插入图片描述

实验心得

舵机和直流电机都是通过PWM信号控制,舵机利用PWM信号转动到指定的角度,而直流电机利用PWM信号进行调速。舵机的PWM信号频率改变一定要有延时,要给舵机足够的时间转到指定的角度后才能改变PWM频率。在程序运行时,各个定时器,各部分中断都是独立运行的,互不干扰,红外遥控解码就是利用中断INT2和定时器同时独立运行实现解码。蜂鸣器因为只要短暂发声,所以不需要使用定时器来定时,利用循环,循环次数增多,一次循环实现beep信号的一个周期性变化,这样就能完成短暂发声。在实验过程中,我发现当LED灯数码管同时亮时,LED灯的亮度要比只有LED灯亮时要暗,所以我要LED灯交替到数码管亮时的延迟增加,这样就能让LED灯数码管同时亮时LED灯更亮。原理是通过增加LED灯交替到数码管亮时的延迟,改变脉冲的高电平的时间,即LED的导通时间,这样改变了接入到LED灯周期信号的占空比,就改变了LED灯的亮度

  • 13
    点赞
  • 126
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例 基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例 基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例 基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机嵌入式开发,应用案例
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值