2019-01-19 21:54:06 lin5103151 阅读数 8502
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3992 人正在学习 去看看 朱有鹏

1.功能介绍
智能台灯可分成自动和手动两种模式。在自动模式下,台灯能根据环境光的亮暗与人是否被台灯所检测到(人是否在)来自动开启台灯。当人被微机检测到,环境光又达到某个程度的时候(可以设定与调节),台灯就会开启。如果环境光没有达到这个程度,台灯不会开启。当人没有被微机检测到,无论多暗,台灯也不会开。  手动模式是为了不习惯使用自动模式的人或是台灯中的微机出故障等紧急情况时用的。在手动模式下,智能台灯和普通台灯是一样使用的。
主要功能 :
(1)亮度不够且有人靠近时台灯自动亮;
(2)靠的太近会提醒坐姿不正(蜂鸣器)
(3)附近无人时台灯自动熄灭(30秒) 时间可调
(4)根据环境亮度调节等亮度
(5)可手动调节台灯亮度
(6)设定学习时间

2.硬件设计
(1)总体硬件设计
整体硬件电路是以AT89C52单片机为控制核心,主要由热释电红外传感器,光敏电阻信号处理电路,提醒电路,灯光控制电路,故障报警电路等组成。单片机可将热释电红外传感器检测到的人体辐射红外信号及光强信号的模拟量转换成数字量。
在这里插入图片描述

(1)LED驱动电路
在这里插入图片描述
LED驱动电路采用3路串联、每路4颗的LED灯,使用三极管S8050来控制LED灯的亮灭。在软件上采用PWM控制方式,以此达到控制LED灯的亮度。
(2)光敏感应电路
在这里插入图片描述
对于台灯亮度的感应采用了光敏电阻,利用光敏电阻的阻值随着亮度的改变而改变,电阻值的改变会改变光敏电阻上的电压值。这时,通过AD转换器采集电压,转换成相应的光强数据传输给单片机。
在这里插入图片描述
(3)人体感应电路
人体感应电路采用了HC-SR501基于红外线技术的数字传感器。当传感器感应到人体时,传感器IO引脚输出高电平;当无人体时,传感器输出低电平。
在这里插入图片描述
(4)红外接近传感器
红外接近传感器采用了E18- D80NK数字型传感器,检测到目标是低电平输出,正常状态是高电平输出;此传感器的功能为检测用户是否坐于台灯前。
在这里插入图片描述
3.软件设计
(1)数码管驱动程序

#define DUAN P0				  //数码管段位
sbit W0=P2^7;		//数码管位端
sbit W1=P2^6;
sbit W2=P2^5;
sbit W3=P2^4;

/**********************************************************************
* 名称 : display();
* 功能 : 数码管显示
* 输入 : 无
* 输出 : 无
***********************************************************************/	  
void display()
{
	if(flag_set==0)			   //正常模式下
	{
		DUAN=tab[min/10];	   //送入段码,秒数高位
		W0=0;				   //打开位地址
		delay(1);			   //小延时
		W0=1;				   //关闭位地址
		DUAN=tab_dian[min%10]; //送入段码,秒数低位
		W1=0;
		delay(1);
		W1=1;
		DUAN=tab[sec/10];	   //送入段码,分钟数高位
		W2=0;
		delay(1);
		W2=1;
		DUAN=tab[sec%10];	   //送入段码,分钟数高位
		W3=0;
		delay(1);
		W3=1;
	}
	else if(flag_set==1)	   //设置模式下闪烁相应位
	{
		if(ss==1)			   //闪烁标志  ss=1 正常显示
		{
			DUAN=~tab[min/10];
			W0=0;
			delay(1);
			W0=1;
			DUAN=~tab_dian[min%10];
			W1=0;
			delay(1);
			W1=1;
		}
		else				   //闪烁标志  ss=0 熄灭相应位 达到闪烁效果	 ss在定时器里500ms取反一次
		{
			DUAN=~tab[10];	   //
			W0=0;
			delay(1);
			W0=1;
			DUAN=~tab_dian[10];
			W1=0;
			delay(1);
			W1=1;
		}
		DUAN=~tab[sec/10];
		W2=0;
		delay(1);
		W2=1;
		DUAN=~tab[sec%10];
		W3=0;
		delay(1);
		W3=1;
	}
	else
	{
		
		DUAN=~tab[min/10];
		W0=0;
		delay(1);
		W0=1;
		DUAN=~tab_dian[min%10];
		W1=0;
		delay(1);
		W1=1;
		if(ss==1)
		{
			DUAN=~tab[sec/10];
			W2=0;
			delay(1);
			W2=1;
			DUAN=~tab[sec%10];
			W3=0;
			delay(1);
			W3=1;
		}
		else
		{
			DUAN=~tab[10];
			W2=0;
			delay(1);
			W2=1;
			DUAN=~tab[10];
			W3=0;
			delay(1);
			W3=1;
		}
	}
}

(2)按键驱动程序

sbit change= P2^3;	//自动模式切换按键
sbit set = P2^2;	//设置按键
sbit add = P2^1;	//加按键
sbit sub = P2^0;	//减按键

/**********************************************************************
* 名称 : KEY();
* 功能 : 按键控制
* 输入 : 无
* 输出 : 无
***********************************************************************/
void KEY()
{
	uint lum_mean,lum_all;
	uchar b,c;
	if(change==0)				  //自动切换按键按下
	{
		delay(10);				  //去抖
		if(change==0)			  //再次判断按键按下
		{
			buzz=0;				  //蜂鸣器鸣响
			flag_auto=!flag_auto; //自动模式标志位取反
			if(flag_auto==1)	  //当切换到手动模式时  首先将LED发光比例PWM设置在50%
			scale=20;
			
		}
		while(!change) display();buzz=1; //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
	}
	if(jiejin==0&&flag_jiejin==1) //接近传感器检测到障碍时  开启报警
	{
		buzz=0;
		flag_jiejin=0;
	}
	if(jiejin!=flag_jiejin)	      //接近传感器检测不到障碍时  关闭报警
	{
		buzz=1;
		flag_jiejin=1;
	}
	if(set==0)				      //设置键按下时
	{
		delay(10);
		if(set==0)
		{
			buzz=0;
			flag_set++;			  //设置变量++
			if(flag_set==3)		  //加到3时回复回正常模式
			flag_set=0;
			flag_bs=0;			  //按下设置 关闭报警
			
		}
		while(!set) display(); buzz=1;//等待按键释放  松开按键后关闭蜂鸣器、刷新显示
	}
	if(flag_set==1)					  //加键按键只有在设置状态(flag_set!=0)时按下才有效	  调分
	{								 
		if(add==0)					  //加按键按下时
		{
			delay(10);				  //消抖
			if(add==0)
			{
				buzz=0;				  //蜂鸣器响
				min++;				  //分++
				if(min>=60)
				min=0;
				
			}
			while(!add) display(); buzz=1;	 //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
		if(sub==0)					  //减按键按下时
		{
			delay(10);				  //消抖
			if(sub==0)
			{
				buzz=0;				  //蜂鸣器响
				min--;				  //分--
				if(min>0)
				min=59;
				
			}
			while(!sub) display(); buzz=1;	 //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
	}
	if(flag_set==2)					//调秒
	{								
		if(add==0)					//加键按下
		{						
			delay(10);				//消抖
			if(add==0)
			{
				buzz=0;				//蜂鸣器响
				sec++;				//秒++
				if(sec>=60)
				sec=0;
				
			}
			while(!add) display(); buzz=1;	  //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
		if(sub==0)					 //减键按下
		{
			delay(10);
			if(sub==0)				 //消抖
			{
				buzz=0;				 //蜂鸣器响
				sec--;				 //秒--
				if(sec<0)
				sec=59;
				
			}
			while(!sub) display();	buzz=1;	  //等待按键释放  松开按键后关闭蜂鸣器、刷新显示
		}
		while(!sub);
	}
		
	if(flag_auto==0)					//自动模式
	{
		if(flag_rsd==1)					//且有人在范围内时	环境发光强度控制灯光变化
		{
			for(b=0;b<49;b++) 			//将空数组tt[]内数值整体左移一位
			{
				tt[b]=tt[b+1];			//将后一数值放到前一位置
			}
			tt[49]=ADC0809();			//将读出的ad0809数值放入tt[49]
			for(c=0;c<50;c++)			//将tt[]内数值相加
			{
				lum_all=lum_all+tt[c];
			}
			lum_mean=lum_all/50;		//将总数/50取出平均值
//			lum_all=0;					//将总数清零
				
			if(lum_mean<=30) scale=1;			   //判断取出平均值大小  小于30  发光强度0%
			else if(lum_mean>=150) scale=41;	   //大于150  发光强度100%
			else scale=((lum_mean-30)/3)+1;		   //其他值时将其计算得到发光强度 (计算目的是为了得到一个1-41之间的数值 控制灯光变化)
		}
		else
		scale=1;					 //没有人在范围内时 将灯光亮度调至0%
	}
	else						  	 //手动模式下
	{
		if(flag_set==0)				 //正常模式下
		{
			if(add==0)				 //加键按下
			{
				delay(10);
				if(add==0)
				{
				//	buzz=0;           //蜂鸣器响
					scale++;		  //灯光比例++
					if(scale>=41)
					scale=41;
					display();
				}
			//	while(!add) display();	buzz=1;
			}
			if(sub==0)				  //减键按下时
			{
				delay(10);
				if(sub==0)
				{
				//	buzz=0;			   //蜂鸣器响
					scale--;		   //灯光比例--
					if(scale>1)
					scale=1;
					display();
				}
		//		while(!sub) display(); buzz=1;
			}
		}
	}
}

(3)ADC控制程序

#define Data_ADC0809 P1
//ADC0809 控制引脚定义
sbit ST=P3^1;
sbit EOC=P3^2;
sbit OE=P3^3;

extern uchar ADC0809();	   //函数声明
/**********************************************************************
* 名称 : ADC0809();
* 功能 : ADC0809把模拟量转化为八位数字量
* 输入 : 无
* 输出 : 无
***********************************************************************/
uchar ADC0809()
{
	uchar temp_=0x00;	
	OE=0;		 //初始化高阻态	   转化初始化   低电平,禁止输出允许
	ST=0;
	ST=1;		 //上升沿 清零    
	ST=0;		 //下降沿 开始转换
	while(EOC==0);	    //外部中断 等待AD转换结束	EOC为1时AD转换结束跳出
	OE=1;			  	//高电平,输出允许
	temp_=Data_ADC0809;	//读取转换的AD值
	OE=0;				//低电平,禁止输出允许
	return temp_;		//返回ADC读取值
}

(4)LED亮度控制程序

//管脚声明
sbit LED = P3^4;	//PWM输出
sbit change= P2^3;	//自动模式切换按键
sbit rsd = P3^6;    //热释电
sbit jiejin=P3^5;   //接近开关
sbit buzz=P3^7;     //蜂鸣器报警电路
/**********************************************************************
* 名称 : init();
* 功能 : 初始化定时器
* 输入 : 无
* 输出 : 无
***********************************************************************/
void init()
{
	TMOD=0x11;	   //工作方式1
	TH1=0x3c;
	TL1=0xb0;	   //T1赋初值50ms
	TH0=0xff;
	TL0=0xe7;	   //T0赋初值25us	  
	ET0=1;
	ET1=1;		   //打开中断允许开关
	EA=1;		   //中断总开关
	TR0=1;		   //开定时器0 开关
	TR1=0;		   //关定时器0 开关
}

/**********************************************************************
* 名称 : void time0() interrupt 1
* 功能 : 定时器T0 中断服务函数:PWM脉冲发生函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void time0() interrupt 1
{
	uchar n;
	TH0=0xff;
	TL0=0xe7;		 //重新赋初值
	n++;			 //每25us  n++
	if(n>scale)		 //n<设置比例时,打开灯
	{
		LED=1;
	}
	else if(n<=scale)//n大于等于设置比例时 关闭灯
	{
		LED=0;
	}
	if(n==40)		 //n==40  :25us*40=1ms   1kHZ
	{
		n=0;		 //n=0
	}
	else ;	
}

/**********************************************************************
* 名称 : void time1() interrupt 3
* 功能 : 定时器T1 中断服务函数:计时和闪烁控制	  红外热释
* 输入 : 无
* 输出 : 无
***********************************************************************/
void time1() interrupt 3
{
	uchar m;
	TH1=0x3c;
	TL1=0xb0;		 //重新赋初值
	m++;			 //50ms  m++
	if((m==10||m==20)&&flag_set!=0)	  //每过500ms  并且 在设置状态时 
	{
		ss=!ss;						  //闪烁变量取反
	}
	if(m==20)						  //到达1s时
	{
		m=0;						  //m=0
		if(rsd==0)					  //热释电无信号时
		rsd_sec++;					  //热释电计时秒++
		if(rsd_sec<=30&&rsd==1)		  //热释电计时秒小于等于30 并且 热释电有信号时
		{
			rsd_sec=0;				  //将热释电秒清零
			flag_rsd=1;				  //标志位置1 控制AD0809采集数值 调节灯光亮度
		}
		else if(rsd_sec>30&&rsd==0)	  //热释电计时秒大于30 并且 热释电无信号时
		{
			flag_rsd=0;				  //标志位置0 停止ad0809转换 关闭灯光
			rsd_sec=0;				  //热释电计时秒清零
		}
		if(flag_set==0&&flag_bs==0&&((min+sec)!=0))		 //正常模式下&&未报警&&定时时间不为零时
		{
			sec--;
			if(sec<0)									 //定时秒--  小于0时
			{
				sec=59;									 //复位到59秒
				min--;									 //分--
			}
			if(min<=0&&sec==0)							 //分和秒都减到零时
			{
				min=0;
				flag_bs=1;
				buzz=0;									 //蜂鸣器报警提示时间到
			}
		}
//		else buzz=1;	
	}	
}

(5)主函数


/**********************************************************************
* 名称 : main();
* 功能 : 主函数
* 输入 : 无
* 输出 : 无
***********************************************************************/
void main()
{
	init();		  //调用初始化函数
	flag_auto=1;  //初始化手动模式
	rsd=0;		  //热释电引脚置低(有信号时时高电平)
	delay(500);	  //延时500ms后开机

	while(1)	  //大循环
	{
		KEY();		 //调用按键函数
		display();	 //调用显示函数
	}
}

源码+AD电路图 下载:关注公众号,首页回复“智能台灯”获取资料
在这里插入图片描述

2016-05-26 22:11:09 sunzhaojie613 阅读数 22101
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3992 人正在学习 去看看 朱有鹏

    用自己的手机控制自己的台灯,是不是想想就挺有趣的! 以后就可以在床上,用手机来控制台灯的开关,是不是很酷!博主以前也有过这种想法,然后就尝试做了一下。为了让有和我一样想法的同学少走点弯路,就写了这篇博客,与诸君共勉。大笑


国际惯例先上效果图



    先讲一下整体思路哈!手机肯定不能直接控制台灯的,需要一个中间物来协调,在这里我用的是51单片机(如果大家不知道也没关系,下面我还会说的)。接下来就是具体怎么控制的,其实原理挺简单的。1.手机通过蓝牙来与单片机通信,因而单片机需要外接一个蓝牙模块(我用的是hc-05  主从一体 蓝牙模块)。大家千万不要被外接给吓到了,外接模块一点都不难的,就只要去淘宝卖相应的模块然后用杜邦线(不知道的可以把它当做导线来理解)和51单片机连起来就好了。到这里手机已经可以和51单片机通信了,也就是说手机可以给单片机发送“开灯”和“关灯”的消息了。2.接下来就要解决当51单片机接收到”开灯“和”关灯“的消息后,该怎么控制台灯实际的开关?这个时候我们就需要一个继电器(也是单片机的外接模块),关于继电器我们可以看下面的图片。继电器一共有三个输出端口(常开端 公共端 常闭端)。事先申明,我们可以通过单片机控制继电器的公共端是和常开端

                                          




连通,还是和常闭端连通。现在我们只需要剪断台灯的一根电线,将电线的两头分别和继电器的常开端和公共端连接起来即可。通过单片机控制继电器的公共端和常开端连接时台灯打开,反之台灯关闭。大致原理就是这样,我们来梳理一下整个流程。首先手机通过蓝牙和单片机的蓝牙模块建立通信,当手机发送一个打开台灯信号时,单片机收到相应的信号并控制继电器的公共端指向常开端,台灯亮起。  




  next~就是具体实现了。一共分为两大部分,分别是Android端和单片机端,先从Android端开始说起。


   一.Android端:

   Android端其实就是一个简单的蓝牙通信,Android端只需要通过蓝牙向单片机的蓝牙模块发送开关对应的消息即可(我是用0xff表示打开台灯,0x00关闭台灯)。先来看看工程的总体结构以及软件界面。


                              


  其中BluetoothTool类是一个蓝牙工具类,里面有关于蓝牙的连接以及发送接收数据功能。IUpdateUI是一个接口,用来在 BlurtoothTool中更新主界面的设备列表以及log。MainAty就是主界面的Activity。activity_main.xml和layout_lv_devices_item.xml不用多说了吧,就是一些界面有关的。关于Android端的解析以贴代码为主,因为代码中我都有详细的解释,比较重要的我会在博客中用文字再次解释的。

 

1.MainAty:


获取蓝牙适配器,可以通过蓝牙适配器获取蓝牙设备的信息。

/**
 * 获得默认的蓝牙适配器
 */
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();


如果手机没打开蓝牙,则界面跳转到打开蓝牙界面。

@Override
protected void onStart() {
    super.onStart();

    /** 判断蓝牙是否可用,不可用时请求打开*/
    if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
        Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivity(intent);
    }
}


  通过蓝牙适配器获取之前匹配过的蓝牙设备信息(如单片机的蓝牙设备),所以第一次使用的时候,先用手机自带的蓝牙匹配成功一次哈!蓝牙设备中一个比较重要的信息就是设备地址-如98:D3:33:80:83:05就是一个蓝牙设备地址,唯一标示。

/** 获取以前匹配过的蓝牙设备*/
        Set<BluetoothDevice> devices = null;
        if (mBluetoothAdapter != null)
            devices = mBluetoothAdapter.getBondedDevices();
        else
            Toast.makeText(MainAty.this, "该设备不支持蓝牙功能 ", Toast.LENGTH_SHORT).show();

        if (devices != null && devices.size() > 0) {
            data.clear();
            for (BluetoothDevice device : devices) {
                HashMap<String, Object> map = new HashMap<>();
                map.put("lv_left_icon", R.drawable.lv_left_icon);
                map.put("lv_address", device.getAddress());
                map.put("lv_right_icon", R.drawable.lv_right_white);
                data.add(map);
            }
        } else {
            HashMap<String, Object> map = new HashMap<>();
            map.put("lv_left_icon", R.drawable.lv_left_icon);
            map.put("lv_address", "没有已经匹配的设备");
            map.put("lv_right_icon", R.drawable.lv_right_white);
            data.add(map);
            mTextView.append("没有已经匹配的设备" + "\r\n");
        }

        simpleAdapter.notifyDataSetChanged();

 连接指定的蓝牙:通过调用BluetoothTool连接蓝牙,我们传入了设备的地址"(String) data.get(0).get("lv_address")"以及连接类型 BluetoothTool.ServiceOrClient.CLIENT(这里我们是以客户端的形式连接,也就是单片机的蓝牙当作客户端 )。之后设置了BluetoothTool的更新UI接口,并在MainAty中具体实现。
builder.setPositiveButton("连接", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
        mBluetoothTool = new BluetoothTool((String) data.get(0).get("lv_address"),
                BluetoothTool.ServiceOrClient.CLIENT);
        mBluetoothTool.SetOnIUpdateUI(new IUpdateUI() {
            @Override
            public void updateListViewDevices() {
                for (int i = 0; i < data.size(); i++) {
                    if (i == index) {
                        data.get(i).put("lv_right_icon", R.drawable.checked);
                        continue;
                    }
                    data.get(i).put("lv_right_icon", R.drawable.lv_right_white);
                }

                simpleAdapter.notifyDataSetChanged();
            }

            @Override
            public void updateLog(String msg) {
                mTextView.append("\r\n" + msg);
            }
        });

    }


});


  可以看到打开台灯按钮的点击事件,只是调用了BluetoothTool的发送功能向单片机蓝牙发送了一个ff消息(具体发送时将ff转化成16进制0xff,因而在单片机端我们会收到一个0xff的数据)。关闭事件同上。

@Override
public void onClick(View view) {
    int id = view.getId();

    switch (id) {
        case R.id.id_btn_open:
            if (mBluetoothTool != null) {
                mBluetoothTool.sendData("ff");
            } else
                Toast.makeText(MainAty.this, "蓝牙未连接...", Toast.LENGTH_SHORT).show();
            break;
        case R.id.id_btn_close:
            if (mBluetoothTool != null) {
                mBluetoothTool.sendData("00");
            } else
                Toast.makeText(MainAty.this, "蓝牙未连接...", Toast.LENGTH_SHORT).show();
            break;
        default:
            break;
    }
}



2.BluetoothTool


传入的蓝牙设备地址(一般是单片机端蓝牙的地址)
/**
 * 蓝牙设备地址
 */
private String mBluetoothAddress = null;


通过传入的蓝牙地址获取相应的蓝牙设备。

/**
 * 蓝牙设备
 */
private BluetoothDevice mDevice = null;

mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(mBluetoothAddress);


这里我们都是以客户端的形式连接的。(也就是单片机上的蓝牙是客户端)。

/**
 * 枚举 表示是客户端还是服务端
 */
public static enum ServiceOrClient {
    NONE, SERVICE, CLIENT
}
private ServiceOrClient mServiceOrClient = ServiceOrClient.NONE;


Handler 用来更新UI

private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_UPDATE_LISTVIEW:
                if (iUpdateUI != null)
                    iUpdateUI.updateListViewDevices();
                break;
            case MSG_UPDATE_LOG:
                if(iUpdateUI!=null)
                iUpdateUI.updateLog(msg.obj + "");
                break;
        }
    }
};


单片机的蓝牙与手机端的蓝牙通信的socket,说明一下蓝牙通信其实也是基于socket通信的。

/**
 * 蓝牙客户端socket
 */
private BluetoothSocket mClientSocket = null;


以客户端身份连接的线程,我们来看看具体实现。

/**
 * 客户端线程
 */
private ClientThread mClientThread = null;


  通过蓝牙设备获取相应的socket,之后单片机的蓝牙和手机的蓝牙通信都是通过这个socket。其中在蓝牙中,每个服务和服务属性都唯一地由"全球唯一标识符" (UUID)来校验。而且这个UUID的值必须是00001101-0000-1000-8000-00805F9B34FB,这个是android的API上面说明的,用于普通蓝牙适配器和android手机蓝牙模块连接的。获取之后通过socket的connect进行连接,连接成功之后开启读取数据的线程。

/**
 * 客户端线程
 */
private class ClientThread extends Thread {
    @Override
    public void run() {
        super.run();
        try {
            /** 客户端通过服务端的UUID与之连接*/
            mClientSocket = mDevice.createRfcommSocketToServiceRecord(
                    UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));

            Message msg = Message.obtain(null, MSG_UPDATE_LOG);
            msg.obj = "正在连接。。。";
            mHandler.sendMessage(msg);

            /** 连接*/
            mClientSocket.connect();


            msg = Message.obtain(null, MSG_UPDATE_LOG);
            msg.obj = "连接成功";
            mHandler.sendMessage(msg);


            msg = Message.obtain(null, MSG_UPDATE_LISTVIEW);
            mHandler.sendMessage(msg);

            /** 接收数据*/
            mReadThread = new ReadThread();
            mReadThread.start();

        } catch (IOException e) {
            e.printStackTrace();

            Message msg = Message.obtain(null, MSG_UPDATE_LOG);
            msg.obj = "连接失败";
            mHandler.sendMessage(msg);
        }
    }
}


  可以看到线程一直在查看有没有数据,如果有的话就接受,并根据接收到的数据进行相应的显示。有一点要先说一下,就是如果手机成功发送了一个开灯命令给单片机,单片机收到之后成功控制继电器将台灯打开之后,单片机会回发一个消息0xff给手机。因此手机端只要收到0xff这个消息,就知道台灯打开成功了手机就可以显示台灯成功开启。

/**
 * 读取数据线程
 */
private class ReadThread extends Thread {
    @Override
    public void run() {
        super.run();

        byte[] buffer = new byte[1024];
        int bytes;
        InputStream in = null;

        try {
            in = mClientSocket.getInputStream();

            while (true) {
                if ((bytes = in.read(buffer)) > 0) {
                    byte[] buf_data = new byte[bytes];
                    for (int i = 0; i < bytes; i++) {
                        buf_data[i] = buffer[i];


                        int j = buffer[i];
                        j = buffer[i] & 0xff;
                        String str = Integer.toHexString(j);
                        if ("ff".equals(str)) {
                            Message msg = Message.obtain(null, MSG_UPDATE_LOG);
                            msg.obj = "台灯打开";
                            mHandler.sendMessage(msg);
                        } else if ("0".equals(str)) {//注意不能用00,因为0x00实际的值是0

                            Message msg = Message.obtain(null, MSG_UPDATE_LOG);
                            msg.obj = "台灯关闭";
                            mHandler.sendMessage(msg);
                        } else {
                           Message msg = Message.obtain(null, MSG_UPDATE_LOG);
                            msg.obj = "err...";
                            mHandler.sendMessage(msg);
                        }

                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();

            Message msg = Message.obtain(null, MSG_UPDATE_LOG);
            msg.obj = "连接数据失败";
            mHandler.sendMessage(msg);
        } finally {
            if (in != null)
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

    }
}


向单片机发送数据,通过socket获取相应的输出流,然后将要发送的字符串转化成16进制发送。

/**
 * 发送数据
 *
 * @param str
 */
public void sendData(String str) {
    if (mClientSocket == null) {
        Log.d(TAG, "sendData: 没有连接。。。");

        Message msg = Message.obtain(null, MSG_UPDATE_LOG);
        msg.obj = "没有连接";
        mHandler.sendMessage(msg);
        return;
    }

    OutputStream out = null;
    try {
        out = mClientSocket.getOutputStream();
        out.write(getHexBytes(str));
    } catch (IOException e) {
        e.printStackTrace();
        Message msg = Message.obtain(null, MSG_UPDATE_LOG);
        msg.obj = "发送失败";
        mHandler.sendMessage(msg);

    }
}


连接蓝牙,就是启动客户端连接线程。

/**
 * 连接蓝牙
 */
private void connect() {
    if (mIsConnected == true) {
        Log.d(TAG, "connect: 已经连接");
        Message msg = Message.obtain(null, MSG_UPDATE_LOG);
        msg.obj = "已经连接";
        mHandler.sendMessage(msg);
        return;
    }

    /** 客户端*/
    if (mServiceOrClient == ServiceOrClient.CLIENT) {
        if (!mBluetoothAddress.equals("null")) {

            mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(mBluetoothAddress);

            mClientThread = new ClientThread();
            mClientThread.start();
            mIsConnected = true;
        } else Log.d(TAG, "connect: address is null");
    }

}



Android端项目github地址:https://github.com/973927190/TableLamp



二.单片机端:


说具体实现之前,先要说一下用到的设备。


1.51单片机开发板 附上博主买的地址

 https://item.taobao.com/item.htm?spm=a1z09.2.0.0.TjO3yS&id=10613893319&_u=t1kstub999f8 

2.杜邦线(公对母,母对母,公对公) 附上博主买的地址

https://detail.tmall.com/item.htm?id=41254478179&spm=a1z09.2.0.0.TjO3yS&_u=t1kstub97e0c&sku_properties=122216547:20213

3.继电器(1路继电器模块带光耦隔离 支持高低电平触发 5V 一路) 我的台灯是usb接口的电压挺小的,大家也用这种台灯做这个吧。附上博主买的地址

https://detail.tmall.com/item.htm?id=41231430731&spm=a1z09.2.0.0.TjO3yS&_u=t1kstub9bd31

4.蓝牙模块(HC-05 主从机一体蓝牙模块 无线蓝牙串口透传模块 无线模块)  附上博主买的地址

https://detail.tmall.com/item.htm?spm=a220m.1000858.1000725.1.couEso&id=41281471872&areaId=330100&cat_id=2&rn=c5c64203413d531f3954899ca97dfd00&user_id=2207691322&is_b=1


哈哈 先给大家看一看单片机方面的代码 大家看了之后肯定就会有动力写了!

#include <reg52.h>
unsigned char flage,temp;
sbit p33=P3^3;//单片机P3.3口

void main()
{
	TMOD=0x20;//设置定时器1为工作方式2
    // 波特率=9600时定时初值为FDH
	TH1=0xfd;//装载TH1
	TL1=0xfd;//装载TL1
	TR1=1;//启动T1(定时器1),开始计数
	REN=1;//允许串行接收
	//SM0=0 SM1=1 为工作方式2
	SM0=0;
	SM1=1;
	EA=1;//开启总中断
	ES=1;//允许串口产生中断
	
	while(1)
	{
		if(flage==1)
		{
			ES=0;//不允许串口产生中断 保证此次操作安全
		    flage=0;
			SBUF=temp;//发送数据
			while(!TI);
			TI=0;//取消此次中断申请
			ES=1;//允许串口产生中断
		}
	}
}

void interrupt4() interrupt 4//4号中断 处理函数
{
	RI=0;//取消此次中断申请
	if(SBUF==0xff)//开灯
		p33=1;//单片机P33口置为高电平
	else if(SBUF==0x00)//关闭
		p33=0;//单片机P33口置为低电平	
	temp=SBUF;
	flage=1;
}

是不是看起来感觉挺少挺简单的,没错这就是单片机方面的所有代码。个人感觉单片机方面代码其实问题不是很大的,主要是硬件方面的问题,所以代码先放一放,我们先来说说具体器件的问题。



1.51单片机

   图一是单片机开发板,其中开发板中间那个长方形就是51单片机,图二就是单个的51单片机,图三是51单片机的引脚图。引脚就是单片机裸露在外面的银色导体,引脚可以输出高电压(等价于逻辑“1”)也可以输出低电压(等价于逻辑“0”)。补充一下电平信号的概念,TTL电平信号被利用的最多是因为通常数据表示采用二进制规定,+5V等价于逻辑“1”,0V等价于逻辑“0”,这被称做TTL(晶体管-晶体管逻辑电平)信号系统,这是计算机处理器控制的设备内部各部分之间通信的标准技术。个人认为单片机最重要的一个特性就是我们可以往单片机中写入自己的程序(C++/C/汇编  这个过程也叫做烧写程序),通过自己的程序控制单片机各个引脚的输出电压,然后在通过引脚的输出电压来控制相应的外接模块。外接模块就是将单片机的引脚和模块的引脚连接起来,单片机引脚的输出电压当做模块引脚的输入电压。如果之前没有接触过单片机开发的,博主强烈建议去看看“郭天祥十天学会单片机的视频教程”。如果你去淘宝买了单片机开发板到时会有一张光盘里面有很多的资料 教学视频 开发工具 以及配套开发板的结构图,郭天祥十天学会单片机的视频教程光盘里也有的。博主我将单片机有关的资料全部打包上传了 http://pan.baidu.com/s/1hrYwv1U


           

                              图一                                                                                         图二                                                                             图三

 2.HC-05主从一体蓝牙模块 

    HC-05主从一体蓝牙模块一共有6个引脚,我们只需要关注VCC,GND,TXD,RXD 这四个引脚。VCC:电源端,接单片机的VCC(高电平)。GND:接地端,接接单片机的GND端(低电平)。TXD:发送端,一般表示为自己的发送端,正常通信必须接另一个设备的RXD(我的单片机P30口是RX端)。RXD:接收端,一般表示为自己的接收端,正常通信必须接另一个设备的TXD(我的单片机P31口是TX端)led指示蓝牙连接状态,快闪表示没有蓝牙连接,慢闪表示进入AT模式,双闪表示蓝牙已连接并打开了端口。注意! 不要将电源接到信号脚上,会直接烧坏。有可能你们的单片机RXD端,TXD端和我的不一样,这个就要去看光盘里的开发板结构图了,里面有画出来的。这里我想提醒一下大家,单片机烧写程序也是通过RXD端和TXD端。所以在烧写的时候要确保RXD端和TXD端没有外接其他模块,如果你接了蓝牙就会烧写失败。

  蓝牙模块的编程本质上就是串口编程,串口编程大家可以去看看郭天祥十天学会单片机的视频教程”里面有相应的教学。在这里我稍微解释一下波特率,波特率,可以通俗的理解为一个设备在一秒钟内发送(或接收)了多少码元的数据。为了在彼此之间通讯,蓝牙收发端必须使用相同的波特率进行操作。如果将接收波特率设置为高于发送方的波特率,则接收数据时会出现错误。   hc-05可以用指令调节波特率,我们就用默认的9600bps。。在单片机代码中,我们要通过设置单片机的计数器将将单片机的波特率也调成9600,同时打开中断开关,这部分的代码如下。


	TMOD=0x20;//设置定时器1为工作方式2
    // 波特率=9600时定时初值为FDH
	TH1=0xfd;//装载TH1
	TL1=0xfd;//装载TL1
	TR1=1;//启动T1(定时器1),开始计数
	REN=1;//允许串行接收
	//SM0=0 SM1=1 为工作方式2
	SM0=0;
	SM1=1;
	EA=1;//开启总中断
	ES=1;//允许串口产生中断


    蓝牙模块收到数据会触发4号中断,程序进入4号中断处理函数。我们只要重写中断函数如下。51单片机有两个物理上独立的接收 发送缓冲器SBUF,它们占用同一地址99H。 在中断处理函数中通SBUF存储着蓝牙模块接收到的数据。将其和我们自己定义的‘开’和‘关’进行比较,如果接收到的数据是0xff就将pP33口置为高电平(打开台灯),反之接收到的数据是0x00就将pP33口置为低电平(关闭台灯)。单片机的P33口又和继电器的控制端口连接(这个我们之后会具体分析的)。

void interrupt4() interrupt 4//4号中断 处理函数
{
	RI=0;//取消此次中断申请
	if(SBUF==0xff)//开灯
		p33=1;//单片机P33口置为高电平
	else if(SBUF==0x00)//关闭
		p33=0;//单片机P33口置为低电平	
	temp=SBUF;
	flage=1;
}


  在中断函数中,处理完所有操作之后都会将flage置为1。在main函数中有一个无限循环,其中如果flage=1的话 就通过SBUF发送数据给手机端的蓝牙。发送的temp就是收到之前接收到的数据,还记得在之前分析Android端BluetoothTool的接收函数的时候,有说到如果手机成功发送了一个开灯命令给单片机,单片机收到之后成功控制继电器将台灯打开之后,单片机会回发一个消息0xff给手机。因此手机端只要收到0xff这个消息,就知道台灯打开成功了。具体发送过程就是在下面的代码中完成的,至于代码中ES TI这些都是和串口编程有关的,个人建议去看看视频教学比较好。

while(1)
	{
		if(flage==1)
		{
			ES=0;//不允许串口产生中断 保证此次操作安全
		    flage=0;
			SBUF=temp;//发送数据
			while(!TI);
			TI=0;//取消此次中断申请
			ES=1;//允许串口产生中断
		}
	}


3.继电器(1路继电器模块带光耦隔离 支持高低电平触发 5V 一路) 


    继电器模块接口有1、DC+:接电源正极(电压按继电器要求,有5V.9V.12V和24V选择)2、DC-:接电源负极3、IN:可以高或低电平控制继电器吸合。 IN端是用来控制继电器公共端是和常闭端连接还是和常开端连接用的,如果IN端是高电平那么继电器的公共端就和常闭端连接,反之公共端和常开端连接。我是将IN端和单片机的P33口连接,通过改变单片机P33端上的电平,从而改变继电器IN端的电平,达到控制继电器开合的效果。这里非常有必要说明一点,就是继电器的IN端和单片机的哪个口连的问题。不是所有的端口都可以连得,要接有上拉电阻的端口才可以,因为如果没有接上拉电阻的端口就算在代码中将该端口置为1,实际中该端口电压达不到高电压,只有接有外接电阻端口的电压才能达到高电压。至于怎么判断单片机端口是不是有接外接电阻有两种方法,一看单片机(开发板)的结构图找到接有外接电阻的端口,二是自己一个一个试过去。如代码所示,打开台灯的时候将P33口置为1(1是高电平 0是低电平)。

   继电器输出端:1、NO:  继电器常开接口,继电器吸合前悬空,吸合后与COM短接 2、COM:继电器公用接口 3、NC:  继电器常闭接口,继电器吸合前与COM短接,吸合后悬空

	if(SBUF==0xff)//开灯
		p33=1;//单片机P33口置为高电平
	else if(SBUF==0x00)//关闭
		p33=0;//单片机P33口置为低电平


4.台灯

   台灯方面主要就是将台灯的一根导线(零线或者火线)弄断,然后两端分别继电器的NO(继电器常开接口) COM(继电器公用接口)连接就好。这里要注意,台灯要是那种USB接口的,USB接口的有降压器会将220V降下来的。千万不要用那种不是USB的,那种电压太高太危险了,而且继电器也承受不了这么大的电压,要买相应的继电器。 切记!


5.单片机代码 

#include <reg52.h>
unsigned char flage,temp;
sbit p33=P3^3;//单片机P3.3口

void main()
{
	TMOD=0x20;//设置定时器1为工作方式2
    // 波特率=9600时定时初值为FDH
	TH1=0xfd;//装载TH1
	TL1=0xfd;//装载TL1
	TR1=1;//启动T1(定时器1),开始计数
	REN=1;//允许串行接收
	//SM0=0 SM1=1 为工作方式2
	SM0=0;
	SM1=1;
	EA=1;//开启总中断
	ES=1;//允许串口产生中断
	
	while(1)
	{
		if(flage==1)
		{
			ES=0;//不允许串口产生中断 保证此次操作安全
		    flage=0;
			SBUF=temp;//发送数据
			while(!TI);
			TI=0;//取消此次中断申请
			ES=1;//允许串口产生中断
		}
	}
}

void interrupt4() interrupt 4//4号中断 处理函数
{
	RI=0;//取消此次中断申请
	if(SBUF==0xff)//开灯
		p33=1;//单片机P33口置为高电平
	else if(SBUF==0x00)//关闭
		p33=0;//单片机P33口置为低电平	
	temp=SBUF;
	flage=1;
}






到这里手机控制台灯的开关有关内容都已经介绍完毕,大家不妨自己动手做一个,挺有趣的。

Android端项目github地址:https://github.com/973927190/TableLamp


单片机端项目:http://pan.baidu.com/s/1i4P87dj

单片机有关的资料: http://pan.baidu.com/s/1hrYwv1U

如果手机控制台灯开关的做出来了,大家也可以做做手机控制台灯暗亮的,可以用电阻来做的哈,





2013-06-15 11:47:00 lxk7280 阅读数 6030
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3992 人正在学习 去看看 朱有鹏

名称:智能家居

转载请注明出处,http://blog.csdn.net/lxk7280

QQ 416815882

 

很久没写博文了,今天决定用一上午记录曾经用51单片机做的一个智能家居并作为自己第一个比赛的作品。

 

有以下几个主要部分:

1.现室外光照在一定范围内控制窗帘的自动打开与关闭,可以让上班族无需为每天拉、关窗帘而烦扰。

2.根据外界环境湿度来控制晾衣架的伸缩,在室外湿度比较大的时候为避免衣服受潮自动把晾衣架缩回来,反之正常湿度则可以伸出去让衣服更好的晾晒。

3.室内出现燃气泄漏时可以自动关闭燃气阀门并给户主手机发出报警信号,并自动打开风机排除险情。

这几个部分相结合,从而成为一个较完整的智能家居系统,实现家居的智能化和自动化。当然该系统同时还存在很多尚待改进的地方。

 

 

摘要以及材料:以STC89C51单片机为控制核心,通过光敏传感器,烟雾传感器MQ-2,温湿度传感器DHT11,继电器,NRF24L01等设计的控制电路,实现

直流电机带动风扇转动(与烟雾传感器),步进电机带动窗帘开闭(与光敏传感器有关),步进电机控制衣架伸缩(与温湿度传感器有关)。

 

下面以简洁的语言介绍三个传感器模块:

        烟雾传感器模块:能检测到烟雾,可用香烟或者燃烧的纸等测试。若有烟雾 DOUT口会输出高电压(约为5V),平时会输出低电压(约为0V),因此可用51单片机的IO口直接检测是否有烟雾。

        光敏传感器模块:同理,可检测到光,若光强高于一定程度,DOUT口会输出高电压(5V),在此不再赘述。

        温湿度传感器模块:此模块难于上面两个模块。需要在软件上写出相应程序,之后可用(串口调试助手)检测会对外输出五个数据,其中有温度的两个数据(整数部分和小数部分)和湿度(整数部分和小数部分)和一个检验位。(在本智能家居中,通过一个无线NRF24L01模拟室外湿度的检测并返回的控制中心室内的51单片机,再与和单片机有线连接的温湿度传感器测得的数据进行比较)

      总之,这三个模块是很简单的。因为对外只需要三个连接线,两个为正负供电,一个为数据线。除了温湿度传感器需要用软件调试之外其余的都可很轻易检测并实现相应的反应动作。

    

关键核心:

        通过STC89C51单片机的IO口不断的检测各个传感器的反馈信号,采集信号,并与预定值进行比较,并做出相应反应。如,利用P2的低五位对温湿度传感器,光敏传感器等进行数据采集和电压采集,对采集到的数据进行分析和过滤从而得到环境的温度,对采集到的电压进行比较,由此判断是否有光、光强是否达到一定值或是否有烟雾危险等等。用P1 P3的低四位控制两个步进电机。用继电器控制直流电机。

 

附照:

  1.烟雾传感器

2.光敏传感器

3.温湿度传感器

4.继电器

5.无线模块

 

部分程序:

步进电机运转部分:

void  motor_ffw1()

 { 

   unsigned char i;

   unsigned int  j;

   for (j=0; j<12; j++)         //转1*n圈 

    {

      for (i=0; i<8; i++)       //一个周期转30度

        {

          if(Q==1) P1 = FFW[i]&0x1f;  //取数据

     if(Q==2) P1 = FFZ[i]&0x1f;

          delay_two(5);                   //调节转速

        }

     } 

 }

温湿度传感器读取数据部分:

   RH();    //室内

   shinei_temp=U8T_data_H;

   shinei_RH=U8RH_data_H;

   RH2(); //室外

   shiwai_temp=U8T_data_H;

   shiwai_RH=U8RH_data_H;

   //串口显示程序 

   if(shinei_RH>shiwai_RH&&vis_run2==0)

   {

    if(vis_run2==0)

    run2(1);//电机2正转 把衣架伸出去

vis_run2=1;

   

   }

   if(shinei_RH<=shiwai_RH)

   {

if(vis_run2==1)

         run2(2);//电机2 反转 把衣架缩回来

    vis_run2=0;

   }

烟雾检测部分:

void check_smog()      //检测烟雾

{

if(com_yanwu==0 /*烟雾被检测*/&&vis_send_smog==0/*且未发送*/)

{

 vis_send_smog=1;

 fengji_run=0;

}

if(com_yanwu==1)

{

fengji_run=1;

vis_send_smog=0;

}

}

 

 

 

完整程序(分为室内室外两个部分):

     

 

   1.室内部分(一个c文件,两个h文件):

#include <reg51.h>
#include <intrins.h>
#include "LQ12864.h"
typedef unsigned char uchar;
typedef unsigned char uint;
//****************************************IO端口定义***************************************
sbit CE     =P2^0;
sbit CSN     =P2^1;
sbit  SCK     =P2^2;
sbit MOSI =P2^3;
sbit  MISO =P2^4;
sbit IRQ  =P2^5;
//***********************************Buf数组*******************************************

uchar TxBuf[32]= 0X00;

//*********************************************NRF24L01*************************************
#define TX_ADR_WIDTH    5    // 5 uints TX address width
#define RX_ADR_WIDTH    5    // 5 uints RX address width
#define TX_PLOAD_WIDTH  32   // 20 uints TX payload
#define RX_PLOAD_WIDTH  32   // 20 uints TX payload
uint const TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x11}; //本地地址
uint const RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x10}; //接收地址
//***************************************NRF24L01寄存器指令*******************************************************
#define READ_REG        0x00   // 读寄存器指令
#define WRITE_REG       0x20  // 写寄存器指令
#define RD_RX_PLOAD     0x61   // 读取接收数据指令
#define WR_TX_PLOAD     0xA0   // 写待发数据指令
#define FLUSH_TX        0xE1  // 冲洗发送 FIFO指令
#define FLUSH_RX        0xE2   // 冲洗接收 FIFO指令
#define REUSE_TX_PL     0xE3   // 定义重复装载数据指令
#define NOP             0xFF   // 保留
//*************************************SPI(nRF24L01)寄存器地址****************************************************
#define CONFIG          0x00  // 配置收发状态,CRC校验模式以及收发状态响应方式
#define EN_AA           0x01  // 自动应答功能设置
#define EN_RXADDR       0x02  // 可用信道设置
#define SETUP_AW        0x03  // 收发地址宽度设置
#define SETUP_RETR      0x04  // 自动重发功能设置
#define RF_CH           0x05  // 工作频率设置
#define RF_SETUP        0x06  // 发射速率、功耗功能设置
#define STATUS          0x07  // 状态寄存器
#define OBSERVE_TX      0x08  // 发送监测功能
#define CD              0x09  // 地址检测          
#define RX_ADDR_P0      0x0A  // 频道0接收数据地址
#define RX_ADDR_P1      0x0B  // 频道1接收数据地址
#define RX_ADDR_P2      0x0C  // 频道2接收数据地址
#define RX_ADDR_P3      0x0D  // 频道3接收数据地址
#define RX_ADDR_P4      0x0E  // 频道4接收数据地址
#define RX_ADDR_P5      0x0F  // 频道5接收数据地址
#define TX_ADDR         0x10  // 发送地址寄存器
#define RX_PW_P0        0x11  // 接收频道0接收数据长度
#define RX_PW_P1        0x12  // 接收频道0接收数据长度
#define RX_PW_P2        0x13  // 接收频道0接收数据长度
#define RX_PW_P3        0x14  // 接收频道0接收数据长度
#define RX_PW_P4        0x15  // 接收频道0接收数据长度
#define RX_PW_P5        0x16  // 接收频道0接收数据长度
#define FIFO_STATUS     0x17  // FIFO栈入栈出状态寄存器设置
//**************************************************************************************
void Delay(unsigned int s);
void Delayms(unsigned int xms);
void inerDelay_us(unsigned char n);
void init_NRF24L01(void);
uint SPI_RW(uint uchar);
uchar SPI_Read(uchar reg);
void SetRX_Mode(void);
uint SPI_RW_Reg(uchar reg, uchar value);
uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars);
uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars);
unsigned char nRF24L01_RxPacket(unsigned char* rx_buf);
void nRF24L01_TxPacket(unsigned char * tx_buf);
//***********************************延时xms毫秒******************************************
void Delayms(unsigned int xms)
{
   unsigned int i,j;
   for(i=xms;i>0;i--)
      for(j=110;j>0;j--);
}
   
//*****************************************长延时*****************************************
void Delay(unsigned int s)
{
 unsigned int i;
 for(i=0; i<s; i++);
 for(i=0; i<s; i++);
}
//******************************************************************************************
uint  bdata sta;   //状态标志
sbit RX_DR =sta^6;
sbit TX_DS =sta^5;
sbit MAX_RT =sta^4;
/******************************************************************************************
/*延时函数
/******************************************************************************************/
void inerDelay_us(unsigned char n)
{
 for(;n>0;n--)
  _nop_();
}
//****************************************************************************************
/*NRF24L01初始化
//***************************************************************************************/
void init_NRF24L01(void)
{
    inerDelay_us(100);
  CE=0;    // chip enable
  CSN=1;   // Spi disable
  SCK=0;   // Spi clock line init high
 SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);    // 写本地地址 
 SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); // 写接收端地址
 SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      //  频道0自动 ACK应答允许 
 SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  //  允许接收地址只有频道0,如果需要多频道可以参考Page21 
 SPI_RW_Reg(WRITE_REG + RF_CH, 0);        //   设置信道工作为2.4GHZ,收发必须一致
 SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度,本次设置为32字节
 SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);     //设置发射速率为1MHZ,发射功率为最大值0dB 
 SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);      // IRQ收发完成中断响应,16位CRC,主发送

}
/****************************************************************************************************
/*函数:uint SPI_RW(uint uchar)
/*功能:NRF24L01的SPI写时序
/****************************************************************************************************/
uint SPI_RW(uint uchar)
{
 uint bit_ctr;
    for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit
   { 
  MOSI = (uchar & 0x80);         // output 'uchar', MSB to MOSI
  uchar = (uchar << 1);           // shift next bit into MSB..
  SCK = 1;                      // Set SCK high..
  uchar |= MISO;           // capture current MISO bit
  SCK = 0;                // ..then set SCK low again
    }
    return(uchar);               // return read uchar
}
/****************************************************************************************************
/*函数:uchar SPI_Read(uchar reg)
/*功能:NRF24L01的SPI时序
/****************************************************************************************************/
uchar SPI_Read(uchar reg)
{
 uchar reg_val;
 
 CSN = 0;                // CSN low, initialize SPI communication...
 SPI_RW(reg);            // Select register to read from..
 reg_val = SPI_RW(0);    // ..then read registervalue
 CSN = 1;                // CSN high, terminate SPI communication
 
 return(reg_val);        // return register value
}
/****************************************************************************************************/
/*功能:NRF24L01读写寄存器函数
/****************************************************************************************************/
uint SPI_RW_Reg(uchar reg, uchar value)
{
 uint status;
 
 CSN = 0;                   // CSN low, init SPI transaction
 status = SPI_RW(reg);      // select register
 SPI_RW(value);             // ..and write value to it..
 CSN = 1;                   // CSN high again
 
 return(status);            // return nRF24L01 status uchar
}
/****************************************************************************************************/
/*函数:uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)
/*功能: 用于读数据,reg:为寄存器地址,pBuf:为待读出数据地址,uchars:读出数据的个数
/****************************************************************************************************/
uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)
{
 uint status,uchar_ctr;
 
 CSN = 0;                      // Set CSN low, init SPI tranaction
 status = SPI_RW(reg);         // Select register to write to and read status uchar
 
 for(uchar_ctr=0;uchar_ctr<uchars;uchar_ctr++)
  pBuf[uchar_ctr] = SPI_RW(0);    //
 
 CSN = 1;                          
 
 return(status);                    // return nRF24L01 status uchar
}
/*********************************************************************************************************
/*函数:uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
/*功能: 用于写数据:为寄存器地址,pBuf:为待写入数据地址,uchars:写入数据的个数
/*********************************************************************************************************/
uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
{
 uint status,uchar_ctr;
 
 CSN = 0;            //SPI使能      
 status = SPI_RW(reg);  
 for(uchar_ctr=0; uchar_ctr<uchars; uchar_ctr++) //
  SPI_RW(*pBuf++);
 CSN = 1;           //关闭SPI
 return(status);    //
}
/****************************************************************************************************/
/*函数:void SetRX_Mode(void)
/*功能:数据接收配置
/****************************************************************************************************/
void SetRX_Mode(void)
{
 CE=0;
 SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);     // IRQ收发完成中断响应,16位CRC ,主接收
 CE = 1;
 inerDelay_us(130);
}
/******************************************************************************************************/
/*函数:unsigned char nRF24L01_RxPacket(unsigned char* rx_buf)
/*功能:数据读取后放如rx_buf接收缓冲区中
/******************************************************************************************************/
unsigned char nRF24L01_RxPacket(unsigned char* rx_buf)
{
    unsigned char revale=0;
 sta=SPI_Read(STATUS); // 读取状态寄存其来判断数据接收状况
 if(RX_DR)    // 判断是否接收到数据
 {
     CE = 0;    //SPI使能
  SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);// read receive payload from RX_FIFO buffer
      CE=1;      //外加
    inerDelay_us(130);  //外加
  revale =1;   //读取数据完成标志
 }
 SPI_RW_Reg(WRITE_REG+STATUS,0x7e);   //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标志 //改为0通道
 return revale;       
}
/***********************************************************************************************************
/*函数:void nRF24L01_TxPacket(unsigned char * tx_buf)
/*功能:发送 tx_buf中数据
/**********************************************************************************************************/
void nRF24L01_TxPacket(unsigned char * tx_buf)
{
 CE=0;   //StandBy I模式 
 SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 装载接收端地址
 SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);     // 装载数据 
// SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);      // IRQ收发完成中断响应,16位CRC,主发送
 CE=1;    //置高CE,激发数据发送
 inerDelay_us(10);
}
//************************************主函数************************************************************


  
  void main(void)
  {
     uchar RE=0;
//     uchar packet;
     LCD_Init();
     init_NRF24L01() ;
     SetRX_Mode();
     Delayms(1);
     LCD_6x8(0,0,"start");
   while(1)
   {
     while(IRQ==1);  //
     RE= nRF24L01_RxPacket(TxBuf);
     if(RE)//如果接收成功;
     {            
    TxBuf=

     }   
   }
     } 
  
 
 以下为:"LQ12864.h"文件 

#include "REG51.h"
sbit LCD_SCL=P1^0; //时钟 D0(SCLK)
sbit LCD_SDA=P1^1; //D1(MOSI) 数据
sbit LCD_RST=P1^2; //复位
sbit LCD_DC =P1^3; //数据/命令控制
#define XLevelL  0x00
#define XLevelH  0x10
#define XLevel     ((XLevelH&0x0F)*16+XLevelL)
#define Max_Column 128
#define Max_Row  64
#define Brightness 0xCF
#define X_WIDTH 128
#define Y_WIDTH 64

void LCD_DLY_ms(unsigned int ms)  //LCD 延时1ms
{                        
   unsigned int a;
   while(ms)
   {
     a=1800;
     while(a--);
     ms--;
}
return;
}

void LCD_WrDat(unsigned char dat)   //**LCD写数据 
{
   unsigned char i=8;         
   LCD_DC=1; 
   for(i=0;i<8;i++) //发送一个八位数据
   {
     LCD_SCL=0;         
     LCD_SDA=dat&0x80;
     LCD_SCL=1;            
     dat<<=1;   
   }
}
void LCD_WrCmd(unsigned char cmd)   //****LCD写命令
{
  unsigned char i=8;        
  LCD_DC=0;
  for(i=0;i<8;i++) //发送一个八位数据
  {
    LCD_SCL=0;
    LCD_SDA=cmd&0x80;
    LCD_SCL=1;
    cmd<<=1;;  
  }  
}

void LCD_Setxy(unsigned char x, unsigned char y)  //LCD 设置坐标
{
  LCD_WrCmd(0xb0+y);
  LCD_WrCmd(((x&0xf0)>>4)|0x10);
  LCD_WrCmd((x&0x0f)|0x01);
}
void LCD_Fill(unsigned char bmp_dat)   //bmp_dat=0x00全屏灭,bmp_dat=0xff全屏亮
{
   unsigned char y,x;
   for(y=0;y<8;y++)
   {
     LCD_WrCmd(0xb0+y);
     LCD_WrCmd(0x01);
     LCD_WrCmd(0x10);
     for(x=0;x<X_WIDTH;x++)
        LCD_WrDat(bmp_dat);
}
}
/*void LCD_CLS(void) //LCD复位
{
   unsigned char y,x; 
   for(y=0;y<8;y++)
   {
     LCD_WrCmd(0xb0+y);
     LCD_WrCmd(0x01);
     LCD_WrCmd(0x10);
     for(x=0;x<X_WIDTH;x++)
         LCD_WrDat(0);
   }
}*/
void LCD_Init(void) //LCD初始化 

   LCD_SCL=1;
   LCD_RST=0;
   LCD_DLY_ms(50);
   LCD_RST=1;       //从上电到下面开始初始化要有足够的时间,即等待RC复位完毕  
   LCD_WrCmd(0xae);//--关闭显示                          turn off oled panel
   LCD_WrCmd(0x00);//---设置低列地址                                    set low column address
   LCD_WrCmd(0x10);//---高列地址                                        set high column address 
   LCD_WrCmd(0x40);//--设置起始地址映射内存显示开始行(0x 00 ~ 0x3f)   set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
   LCD_WrCmd(0x81);//--设置对比度控制寄存器                             set contrast control register
   LCD_WrCmd(0xcf); // 电流输出亮度设置赛格                             Set SEG Output Current Brightness
   LCD_WrCmd(0xa1);//--设置赛格/列映射  0xa0左右反置0xa1正常            Set SEG/Column Mapping     0xa0左右反置 0xa1正常
   LCD_WrCmd(0xc8);//设置网站/行扫描方向 0xc0上下反置 0xc8正常          Set COM/Row Scan Direction  
   LCD_WrCmd(0xa6);//--正常显示                                         set normal display
   LCD_WrCmd(0xa8);//--集复用率(1 - 64)                               set multiplex ratio(1 to 64)
   LCD_WrCmd(0x3f);//--1/64 duty
   LCD_WrCmd(0xd3);//-设置显示偏移位移映射内存计数器(0x 00 ~ 0x3f)    set display offset Shift Mapping RAM Counter (0x00~0x3F)
   LCD_WrCmd(0x00);//-不偏移                                            not offset
   LCD_WrCmd(0xd5);//--设置显示时钟的分频比/振荡器频率                  set display clock divide ratio/oscillator frequency
   LCD_WrCmd(0x80);//--组分比,时钟设置为100帧/秒                       set divide ratio, Set Clock as 100 Frames/Sec
   LCD_WrCmd(0xd9);//--设定充电周期                                     set pre-charge period
   LCD_WrCmd(0xf1);//15集充电放电1钟钟表                                Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
   LCD_WrCmd(0xda);//--设置组件的引脚配置硬件                           set com pins hardware configuration
   LCD_WrCmd(0x12);
   LCD_WrCmd(0xdb);//--集vcomh                                          set vcomh
   LCD_WrCmd(0x40);//威科姆取消水平集                                   Set VCOM Deselect Level
   LCD_WrCmd(0x20);//-设置页面寻址模式(0x 00 /将/ 0x02)               Set Page Addressing Mode (0x00/0x01/0x02)
   LCD_WrCmd(0x02);//
   LCD_WrCmd(0x8d);//--充电泵启用/禁用                                  set Charge Pump enable/disable
   LCD_WrCmd(0x14);//--集(0x 10个)禁用                                set(0x10) disable
   LCD_WrCmd(0xa4);// 使整个显示(0xa4 / 0xa5)                         Disable Entire Display On (0xa4/0xa5)
   LCD_WrCmd(0xa6);// 禁用反显示(0xa6 / 7)                            Disable Inverse Display On (0xa6/a7)
   LCD_WrCmd(0xaf);//--打开面板                                         turn on oled panel
   LCD_Fill(0x00);  //初始清屏
   LCD_Setxy(0,0);

void LCD_6x8(unsigned char x, y,unsigned char ch[])//显示6*8一组标准ASCII字符串 显示的坐标(x,y),y为页范围0~7
{
   unsigned char c=0,i=0,j=0;     
   while (ch[j]!='\0')
   {   
     c =ch[j]-32;
     if(x>126)
     {x=0;y++;}
     LCD_Setxy(x,y);   
     for(i=0;i<6;i++)    
       LCD_WrDat(F6x8[c][i]); 
     x+=6;
     j++;
   }
}
void LCD_Cler_6x8(unsigned char x,y,n)//清除N个6*8字符
{
   unsigned int i=0;
   LCD_Setxy(x,y);
   if(x>126)
  {x=0;y++;}
   for(i=0;i<6*n;i++)
       LCD_WrDat(0x00);
}
void ready(unsigned char x,y,unsigned int num)
{
      switch (num)
      {
     case 0:
        LCD_6x8(x,y,"0");break;
     case 1:
        LCD_6x8(x,y,"1");break;
     case 2:
        LCD_6x8(x,y,"2");break;
     case 3:
        LCD_6x8(x,y,"3");break;
     case 4:
        LCD_6x8(x,y,"4");break;
     case 5:
        LCD_6x8(x,y,"5");break;
     case 6:
        LCD_6x8(x,y,"6");break;
     case 7:
        LCD_6x8(x,y,"7");break;
     case 8:
        LCD_6x8(x,y,"8");break;
     case 9:
        LCD_6x8(x,y,"9");break; 
      } 
}
/*void LCD_8x16(unsigned char x, y,unsigned char ch[])//显示8*16一组标准ASCII字符串  显示的坐标(x,y),y为页范围0~7
{
  unsigned char c=0,i=0,j=0;
  while (ch[j]!='\0')
  {   
    c =ch[j]-32;
    if(x>120)
   {x=0;y++;}
    LCD_Setxy(x,y);   
    for(i=0;i<8;i++)    
      LCD_WrDat(F8X16[c*16+i]);
    LCD_Setxy(x,y+1);   
    for(i=0;i<8;i++)    
      LCD_WrDat(F8X16[c*16+i+8]); 
    x+=8;
    j++;
  }
}
void LCD_Cler_8x16(unsigned char x, y,n) //清除n个8*16字符
{
    unsigned char i;
    if(x>120)
   {x=0;y++;}
 LCD_Setxy(x,y);
 for(i=0;i<8*n;i++)
   LCD_WrDat(0x00);
    LCD_Setxy(x,y+1);
 for(i=0;i<8*n;i++)
   LCD_WrDat(0x00);   
}
void LCD_16x16(unsigned char x, y, N)//显示16*16点阵  显示的坐标(x,y),y为页范围0~7
{
  unsigned char wm=0;
  unsigned int adder=32*N;  //   
  LCD_Setxy(x , y);
  for(wm = 0;wm < 16;wm++)  //            
  {
    LCD_WrDat(F16x16[adder]); 
    adder += 1;
  }     
  LCD_Setxy(x,y + 1);
  for(wm = 0;wm < 16;wm++) //        
  {
    LCD_WrDat(F16x16[adder]);
    adder += 1;
  }     
}
void LCD_Cler_16x16(unsigned char x,y,n)//清除n个16*16字
{
  unsigned char i=0;
  LCD_Setxy(x,y);
  for(i=0;i<16*n;i++)
     LCD_WrDat(0x00);
  LCD_Setxy(x,y+1);
  for(i=0;i<16*n;i++)
     LCD_WrDat(0x00);
}
void Draw_BMP(unsigned char x0, y0,x1, y1,unsigned char BMP[])//显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*
{  
 unsigned int j=0;
 unsigned char x,y;
 
  if(y1%8==0)
     y=y1/8;     
  else
     y=y1/8+1;
  for(y=y0;y<y1;y++)
  {
     LCD_Setxy(x0,y);    
     for(x=x0;x<x1;x++)
  {     
     LCD_WrDat(BMP[j++]);      
  }
  }
}*/

 
 以下为:DHT11.h文件

//****************************************************************//
#include <reg51.h>
#include <intrins.h>
//
typedef unsigned char  U8;       /* defined for unsigned 8-bits integer variable    无符号8位整型变量  */
typedef signed   char  S8;       /* defined for signed 8-bits integer variable    有符号8位整型变量  */
typedef unsigned int   U16;      /* defined for unsigned 16-bits integer variable    无符号16位整型变量 */
typedef signed   int   S16;      /* defined for signed 16-bits integer variable    有符号16位整型变量 */
typedef unsigned long  U32;      /* defined for unsigned 32-bits integer variable    无符号32位整型变量 */
typedef signed   long  S32;      /* defined for signed 32-bits integer variable    有符号32位整型变量 */
typedef float          F32;      /* single precision floating point variable (32bits) 单精度浮点数(32位长度) */
typedef double         F64;      /* double precision floating point variable (64bits) 双精度浮点数(64位长度) */
//
#define uchar unsigned char
#define uint unsigned int
#define   Data_0_time    4

//----------------------------------------------//
//----------------IO口定义区--------------------//
//----------------------------------------------//
sbit  P2_0  = P2^0 ;

//----------------------------------------------//
//----------------定义区--------------------//
//----------------------------------------------//
U8  U8FLAG,k;
U8  U8count,U8temp;
U8  U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata;
U8  U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,U8RH_data_L_temp,U8checkdata_temp;
U8  U8comdata;
U8  count, count_r=0;
U16 U16temp1,U16temp2;
/***************************************************************
SendData(U8 *a)
{
 outdata[0] = a[0];
 outdata[1] = a[1];
 outdata[2] = a[2];
 outdata[3] = a[3];
 outdata[4] = a[4];
 count = 1;
 SBUF=outdata[0];
}
 *************************************************************/
       void Delay(U16 j)
    {      U8 i;
     for(;j>0;j--)
   {  
  for(i=0;i<27;i++);

   }
    }
       void  Delay_10us(void)
      {
        U8 i;
        i--;
        i--;
        i--;
        i--;
        i--;
        i--;
       }
 
        void  COM(void)
      {
    
         U8 i;
         
       for(i=0;i<8;i++)   
     {
  
         U8FLAG=2; 
     while((!P2_0)&&U8FLAG++);
   Delay_10us();
      Delay_10us();
   Delay_10us();
     U8temp=0;
      if(P2_0)U8temp=1;
      U8FLAG=2;
   while((P2_0)&&U8FLAG++);
     //超时则跳出for循环   
      if(U8FLAG==1)break;
     //判断数据位是0还是1 
       
  // 如果高电平高过预定0高电平值则数据位为 1
     
     U8comdata<<=1;
        U8comdata|=U8temp;        //0
      }//rof
   
 }
 //--------------------------------
 //-----湿度读取子程序 ------------
 //--------------------------------
 //----以下变量均为全局变量--------
 //----温度高8位== U8T_data_H------
 //----温度低8位== U8T_data_L------
 //----湿度高8位== U8RH_data_H-----
 //----湿度低8位== U8RH_data_L-----
 //----校验 8位 == U8checkdata-----
 //----调用相关子程序如下----------
 //---- Delay();, Delay_10us();,COM();
 //--------------------------------

 void RH(void)
 {
   //主机拉低18ms
       P2_0=0;
    Delay(180);
    P2_0=1;
  //总线由上拉电阻拉高 主机延时20us
    Delay_10us();
    Delay_10us();
    Delay_10us();
    Delay_10us();
  //主机设为输入 判断从机响应信号
    P2_0=1;
  //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行  
    if(!P2_0)   //T !  
    {
    U8FLAG=2;
  //判断从机是否发出 80us 的低电平响应信号是否结束 
    while((!P2_0)&&U8FLAG++);
    U8FLAG=2;
  //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
    while((P2_0)&&U8FLAG++);
  //数据接收状态  
    COM();
    U8RH_data_H_temp=U8comdata;
    COM();
    U8RH_data_L_temp=U8comdata;
    COM();
    U8T_data_H_temp=U8comdata;
    COM();
    U8T_data_L_temp=U8comdata;
    COM();
    U8checkdata_temp=U8comdata;
    P2_0=1;
  //数据校验
 
    U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp);
    if(U8temp==U8checkdata_temp)
    {
       U8RH_data_H=U8RH_data_H_temp;
       U8RH_data_L=U8RH_data_L_temp;
    U8T_data_H=U8T_data_H_temp;
       U8T_data_L=U8T_data_L_temp;
       U8checkdata=U8checkdata_temp;
    }//fi
    }//fi

 }

 

 

2.室外部分():

c文件部分:

#include "REG51.h"
#include "intrins.h"
#include "Tx_nrf.h"
#include "DHT11.h"
void main()
{
    unsigned int i,table=0,dish;
 unsigned char car[3],keyy[10];
 init_NRF24L01();

    while(1)
 {        
    //------------------------
      //调用温湿度读取子程序
      RH();
      //串口显示程序
      //--------------------------
      car[0]=U8RH_data_H;
      Delay(20000);
      IRQ=1;
        SPI_RW(FLUSH_TX );//清空TX_FIFO//此处必要。否则经常出错
        nRF24L01_TxPacket(car); // Transmit Tx buffer data
     CE=0; 
         while(IRQ==1);//等待发送完成
     sta=SPI_Read(STATUS);// 读取状态寄存其来判断数据接收状况
     if(TX_DS)//判断是否发送成功
     {
          for(i=0; i<8; i++)
                    {
//                    LCD_16x16(i*16,3,i+8);  //发送成功
                    }                           //SetRX_Mode() //变为接受状态
     }
    else
    {
       for(i=0; i<8; i++)                              //若要变为发送模式,init_NRF24L01() ;或CE=0;SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); 
       {
//           LCD_16x16(i*16,3,i+16);  //发送失败
       }
    }
    
    SPI_RW_Reg(WRITE_REG+STATUS,0X7e);     //RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清除中断标志 
       
   }

}

 

以下为TX—NRF.h部分:

#include <reg51.h>
#include <intrins.h>

typedef unsigned char uchar;
typedef unsigned char uint;
//****************************************IO端口定义***************************************
sbit CE     =P2^5;
sbit CSN     =P2^1;
sbit  SCK     =P2^4;
sbit MOSI =P2^0;
sbit  MISO =P2^3;
sbit IRQ  =P2^2;
//*********************************************NRF24L01*************************************
#define TX_ADR_WIDTH    5    // 5 uints TX address width
#define RX_ADR_WIDTH    5    // 5 uints RX address width
#define TX_PLOAD_WIDTH  32   // 20 uints TX payload
#define RX_PLOAD_WIDTH  32   // 20 uints TX payload
uint const TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x13}; //本地地址
uint const RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x13}; //接收地址
//***************************************NRF24L01寄存器指令*******************************************************
#define READ_REG        0x00   // 读寄存器指令
#define WRITE_REG       0x20  // 写寄存器指令
#define RD_RX_PLOAD     0x61   // 读取接收数据指令
#define WR_TX_PLOAD     0xA0   // 写待发数据指令
#define FLUSH_TX        0xE1  // 冲洗发送 FIFO指令
#define FLUSH_RX        0xE2   // 冲洗接收 FIFO指令
#define REUSE_TX_PL     0xE3   // 定义重复装载数据指令
#define NOP             0xFF   // 保留
//*************************************SPI(nRF24L01)寄存器地址****************************************************
#define CONFIG          0x00  // 配置收发状态,CRC校验模式以及收发状态响应方式
#define EN_AA           0x01  // 自动应答功能设置
#define EN_RXADDR       0x02  // 可用信道设置
#define SETUP_AW        0x03  // 收发地址宽度设置
#define SETUP_RETR      0x04  // 自动重发功能设置
#define RF_CH           0x05  // 工作频率设置
#define RF_SETUP        0x06  // 发射速率、功耗功能设置
#define STATUS          0x07  // 状态寄存器
#define OBSERVE_TX      0x08  // 发送监测功能
#define CD              0x09  // 地址检测          
#define RX_ADDR_P0      0x0A  // 频道0接收数据地址
#define RX_ADDR_P1      0x0B  // 频道1接收数据地址
#define RX_ADDR_P2      0x0C  // 频道2接收数据地址
#define RX_ADDR_P3      0x0D  // 频道3接收数据地址
#define RX_ADDR_P4      0x0E  // 频道4接收数据地址
#define RX_ADDR_P5      0x0F  // 频道5接收数据地址
#define TX_ADDR         0x10  // 发送地址寄存器
#define RX_PW_P0        0x11  // 接收频道0接收数据长度
#define RX_PW_P1        0x12  // 接收频道0接收数据长度
#define RX_PW_P2        0x13  // 接收频道0接收数据长度
#define RX_PW_P3        0x14  // 接收频道0接收数据长度
#define RX_PW_P4        0x15  // 接收频道0接收数据长度
#define RX_PW_P5        0x16  // 接收频道0接收数据长度
#define FIFO_STATUS     0x17  // FIFO栈入栈出状态寄存器设置
//**************************************************************************************
void Delay(unsigned int s);
void Delayms(unsigned int xms);
void inerDelay_us(unsigned char n);
void init_NRF24L01(void);
uint SPI_RW(uint uchar);
uchar SPI_Read(uchar reg);
void SetRX_Mode(void);
uint SPI_RW_Reg(uchar reg, uchar value);
uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars);
uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars);
unsigned char nRF24L01_RxPacket(unsigned char* rx_buf);
void nRF24L01_TxPacket(unsigned char * tx_buf);
//******************************************************************************************
uint  bdata sta;   //状态标志
sbit RX_DR =sta^6;
sbit TX_DS =sta^5;
sbit MAX_RT =sta^4;
/******************************************************************************************
/*延时函数
/******************************************************************************************/
void inerDelay_us(unsigned char n)
{
 for(;n>0;n--)
  _nop_();
}
//****************************************************************************************
/*NRF24L01初始化
//***************************************************************************************/
void init_NRF24L01(void)
{
    inerDelay_us(100);
  CE=0;    // chip enable
  CSN=1;   // Spi disable
  SCK=0;   // Spi clock line init high
 SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);    // 写本地地址 
 SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); // 写接收端地址
 SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      //  频道0自动 ACK应答允许
 SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1f); //自动重发15次、延时0.5ms+86us
 SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  //  允许接收地址只有频道0,如果需要多频道可以参考Page21 
 SPI_RW_Reg(WRITE_REG + RF_CH, 0);        //   设置信道工作为2.4GHZ,收发必须一致
 SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度,本次设置为32字节
 SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);     //设置发射速率为1MHZ,发射功率为最大值0dB 
 SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);     // IRQ收发完成中断响应,16位CRC,主发送

}
/****************************************************************************************************
/*函数:uint SPI_RW(uint uchar)
/*功能:NRF24L01的SPI写时序
/****************************************************************************************************/
uint SPI_RW(uint uchar)
{
 uint bit_ctr;
    for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit
   { 
  MOSI = (uchar & 0x80);         // output 'uchar', MSB to MOSI
  uchar = (uchar << 1);           // shift next bit into MSB..
  SCK = 1;                      // Set SCK high..
  uchar |= MISO;           // capture current MISO bit
  SCK = 0;                // ..then set SCK low again
    }
    return(uchar);               // return read uchar
}
/****************************************************************************************************
/*函数:uchar SPI_Read(uchar reg)
/*功能:NRF24L01的SPI时序
/****************************************************************************************************/
uchar SPI_Read(uchar reg)
{
 uchar reg_val;
 
 CSN = 0;                // CSN low, initialize SPI communication...
 SPI_RW(reg);            // Select register to read from..
 reg_val = SPI_RW(0);    // ..then read registervalue
 CSN = 1;                // CSN high, terminate SPI communication
 
 return(reg_val);        // return register value
}
/****************************************************************************************************/
/*功能:NRF24L01读写寄存器函数
/****************************************************************************************************/
uint SPI_RW_Reg(uchar reg, uchar value)
{
 uint status;
 CSN = 0;                   // CSN low, init SPI transaction
 status = SPI_RW(reg);      // select register
 SPI_RW(value);             // ..and write value to it..
 CSN = 1;                   // CSN high again 
 return(status);            // return nRF24L01 status uchar
}
/****************************************************************************************************/
/*函数:uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)
/*功能: 用于读数据,reg:为寄存器地址,pBuf:为待读出数据地址,uchars:读出数据的个数
/****************************************************************************************************/
uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)
{
 uint status,uchar_ctr;
 
 CSN = 0;                      // Set CSN low, init SPI tranaction
 status = SPI_RW(reg);         // Select register to write to and read status uchar
 
 for(uchar_ctr=0;uchar_ctr<uchars;uchar_ctr++)
  pBuf[uchar_ctr] = SPI_RW(0);    //
 
 CSN = 1;                          
 
 return(status);                    // return nRF24L01 status uchar
}
/*********************************************************************************************************
/*函数:uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
/*功能: 用于写数据:为寄存器地址,pBuf:为待写入数据地址,uchars:写入数据的个数
/*********************************************************************************************************/
uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
{
 uint status,uchar_ctr;
 
 CSN = 0;            //SPI使能      
 status = SPI_RW(reg);  
 for(uchar_ctr=0; uchar_ctr<uchars; uchar_ctr++) //
  SPI_RW(*pBuf++);
 CSN = 1;           //关闭SPI
 return(status);    //
}
/****************************************************************************************************/
/*函数:void SetRX_Mode(void)
/*功能:数据接收配置
/****************************************************************************************************/
void SetRX_Mode(void)
{
 CE=0;
 SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);     // IRQ收发完成中断响应,16位CRC ,主接收
 CE = 1;
 inerDelay_us(130);
}
/******************************************************************************************************/
/*函数:unsigned char nRF24L01_RxPacket(unsigned char* rx_buf)
/*功能:数据读取后放如rx_buf接收缓冲区中
/******************************************************************************************************/
unsigned char nRF24L01_RxPacket(unsigned char* rx_buf)
{
    unsigned char revale=0;
 sta=SPI_Read(STATUS); // 读取状态寄存其来判断数据接收状况
 if(RX_DR)    // 判断是否接收到数据
 {
     CE = 0;    //SPI使能
  SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);// read receive payload from RX_FIFO buffer
  revale =1;   //读取数据完成标志
 }
 SPI_RW_Reg(WRITE_REG+STATUS,0x7e);   //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标志
 return revale;
}
/***********************************************************************************************************
/*函数:void nRF24L01_TxPacket(unsigned char * tx_buf)
/*功能:发送 tx_buf中数据
/**********************************************************************************************************/
void nRF24L01_TxPacket(unsigned char * tx_buf)
{
 CE=0;   //StandBy I模式
// SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);      // IRQ收发完成中断响应,16位CRC,主发送 
 SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 装载接收端地址
 SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);     // 装载数据 

 CE=1;   //置高CE,激发数据发送
 inerDelay_us(10);
}

 

以下为DHT11。H部分:

//****************************************************************//
//                 DHT21使用范例
//单片机 : AT89S52 或 STC89C52RC
// 功能  :串口发送温湿度数据 晶振 11.0592M 波特率 9600
//硬件连接: P2.0口为通讯口连接DHT11,DHT11的电源和地连接单片机的电源和地,单片机串口加MAX232连接电脑
// 公司  :奥松电子   
//****************************************************************//

#include <reg51.h>
#include <intrins.h>
//
typedef unsigned char  U8;       /* defined for unsigned 8-bits integer variable    无符号8位整型变量  */
typedef signed   char  S8;       /* defined for signed 8-bits integer variable    有符号8位整型变量  */
typedef unsigned int   U16;      /* defined for unsigned 16-bits integer variable    无符号16位整型变量 */
typedef signed   int   S16;      /* defined for signed 16-bits integer variable    有符号16位整型变量 */
typedef unsigned long  U32;      /* defined for unsigned 32-bits integer variable    无符号32位整型变量 */
typedef signed   long  S32;      /* defined for signed 32-bits integer variable    有符号32位整型变量 */
typedef float          F32;      /* single precision floating point variable (32bits) 单精度浮点数(32位长度) */
typedef double         F64;      /* double precision floating point variable (64bits) 双精度浮点数(64位长度) */
//
#define uchar unsigned char
#define uint unsigned int
#define   Data_0_time    4

//----------------------------------------------//
//----------------IO口定义区--------------------//
//----------------------------------------------//
sbit  P2_0  = P1^2 ;
sbit  P2_1  = P2^1 ;

//----------------------------------------------//
//----------------定义区--------------------//
//----------------------------------------------//
U8  U8FLAG,k;
U8  U8count,U8temp;
U8  U8T_data_H,U8T_data_L,U8RH_data_H,U8RH_data_L,U8checkdata;
U8  U8T_data_H_temp,U8T_data_L_temp,U8RH_data_H_temp,U8RH_data_L_temp,U8checkdata_temp;
U8  U8comdata;
U8  count, count_r=0;
U16 U16temp1,U16temp2;
/***************************************************************
SendData(U8 *a)
{
 outdata[0] = a[0];
 outdata[1] = a[1];
 outdata[2] = a[2];
 outdata[3] = a[3];
 outdata[4] = a[4];
 count = 1;
 SBUF=outdata[0];
}
 *************************************************************/
       void Delay(U16 j)
    {      U8 i;
     for(;j>0;j--)
   {  
  for(i=0;i<27;i++);

   }
    }
       void  Delay_10us(void)
      {
        U8 i;
        i--;
        i--;
        i--;
        i--;
        i--;
        i--;
       }
 
        void  COM(void)
      {
    
         U8 i;
         
       for(i=0;i<8;i++)   
     {
  
         U8FLAG=2; 
     while((!P2_0)&&U8FLAG++);
   Delay_10us();
      Delay_10us();
   Delay_10us();
     U8temp=0;
      if(P2_0)U8temp=1;
      U8FLAG=2;
   while((P2_0)&&U8FLAG++);
     //超时则跳出for循环   
      if(U8FLAG==1)break;
     //判断数据位是0还是1 
       
  // 如果高电平高过预定0高电平值则数据位为 1
     
     U8comdata<<=1;
        U8comdata|=U8temp;        //0
      }//rof
   
 }
   void  COM2(void)
      {
    
         U8 i;
         
       for(i=0;i<8;i++)   
     {
  
         U8FLAG=2; 
     while((!P2_1)&&U8FLAG++);
   Delay_10us();
      Delay_10us();
   Delay_10us();
     U8temp=0;
      if(P2_1)U8temp=1;
      U8FLAG=2;
   while((P2_1)&&U8FLAG++);
     //超时则跳出for循环   
      if(U8FLAG==1)break;
     //判断数据位是0还是1 
       
  // 如果高电平高过预定0高电平值则数据位为 1
     
     U8comdata<<=1;
        U8comdata|=U8temp;        //0
      }//rof
   }
 //--------------------------------
 //-----湿度读取子程序 ------------
 //--------------------------------
 //----以下变量均为全局变量--------
 //----温度高8位== U8T_data_H------
 //----温度低8位== U8T_data_L------
 //----湿度高8位== U8RH_data_H-----
 //----湿度低8位== U8RH_data_L-----
 //----校验 8位 == U8checkdata-----
 //----调用相关子程序如下----------
 //---- Delay();, Delay_10us();,COM();
 //--------------------------------

 void RH(void)
 {
   //主机拉低18ms
       P2_0=0;
    Delay(180);
    P2_0=1;
  //总线由上拉电阻拉高 主机延时20us
    Delay_10us();
    Delay_10us();
    Delay_10us();
    Delay_10us();
  //主机设为输入 判断从机响应信号
    P2_0=1;
  //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行  
    if(!P2_0)   //T !  
    {
    U8FLAG=2;
  //判断从机是否发出 80us 的低电平响应信号是否结束 
    while((!P2_0)&&U8FLAG++);
    U8FLAG=2;
  //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
    while((P2_0)&&U8FLAG++);
  //数据接收状态  
    COM();
    U8RH_data_H_temp=U8comdata;
    COM();
    U8RH_data_L_temp=U8comdata;
    COM();
    U8T_data_H_temp=U8comdata;
    COM();
    U8T_data_L_temp=U8comdata;
    COM();
    U8checkdata_temp=U8comdata;
    P2_0=1;
  //数据校验
 
    U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp);
    if(U8temp==U8checkdata_temp)
    {
       U8RH_data_H=U8RH_data_H_temp;
       U8RH_data_L=U8RH_data_L_temp;
    U8T_data_H=U8T_data_H_temp;
       U8T_data_L=U8T_data_L_temp;
       U8checkdata=U8checkdata_temp;
    }//fi
    }//fi

 }
 
 void RH2(void)
 {
   //主机拉低18ms
       P2_1=0;
    Delay(180);
    P2_1=1;
  //总线由上拉电阻拉高 主机延时20us
    Delay_10us();
    Delay_10us();
    Delay_10us();
    Delay_10us();
  //主机设为输入 判断从机响应信号
    P2_1=1;
  //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行  
    if(!P2_1)   //T !  
    {
    U8FLAG=2;
  //判断从机是否发出 80us 的低电平响应信号是否结束 
    while((!P2_1)&&U8FLAG++);
    U8FLAG=2;
  //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
    while((P2_1)&&U8FLAG++);
  //数据接收状态  
    COM2();
    U8RH_data_H_temp=U8comdata;
    COM2();
    U8RH_data_L_temp=U8comdata;
    COM2();
    U8T_data_H_temp=U8comdata;
    COM2();
    U8T_data_L_temp=U8comdata;
    COM2();
    U8checkdata_temp=U8comdata;
    P2_1=1;
  //数据校验
 
    U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp);
    if(U8temp==U8checkdata_temp)
    {
       U8RH_data_H=U8RH_data_H_temp;
       U8RH_data_L=U8RH_data_L_temp;
    U8T_data_H=U8T_data_H_temp;
       U8T_data_L=U8T_data_L_temp;
       U8checkdata=U8checkdata_temp;
    }//fi
    }//fi
 }

 

 

over~~如果不正确或者不好的地方,请指出~

2019-07-04 11:53:43 baidu_38915797 阅读数 1539
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3992 人正在学习 去看看 朱有鹏

在这里插入图片描述
.
.
从上面导航图,我们可以看到,智能小车,共分为三步

外部检测,控制中心,轮子输出控制。

等于人的

眼睛,大脑,手脚。
.
.
因为控制中心和轮子输出控制是一样的,只有前面的外部检测,换个模块工作而已。
.
.

在这里插入图片描述

.
.
.

在这里我们先简单了解一下,上面两个外部检测,可以扩展什么功能。
,
.
红外线类
循迹
避障
循迹加避障
等等
.
.
超声波类
避障
魔法手
舵机式避障
等等
.
.
.
这些就是外部检测可以扩展的实验,其实还可以扩展更多外部检测的,但是只要理解一种实验,其它的外部检测就是换模块和换程序,非常简单。
.
.
我们以一个循迹小车为例子讲解,当你明白这个后,其它的实验你就明白了。
先来讲解一下公共的控制中心,和轮子输出的组装。
.
.

在这里插入图片描述.
.

组装小车,只需要三样东西。
1 车模。
2 控制中心板。
3 轮子电机驱动模块。
.
.

1车模。
对于新手来说你需要一个车模,当然也可以自己制作一个模型,下面这个是两个电机的智能小车。
.
.

在这里插入图片描述
.
.

上面这个车模包含有,1个车模底板,2个减速电机,2个轮子,1个万向轮(上面图片,电池盒下面那个),1个电池盒。
这种车模很多地方都有,你只要按照说明书组装成功就可以了。
.
.

2 主控板
另外你还需要一个单片机最小系统作为控制中心
.
.

在这里插入图片描述
.
.

这个主控板的单片机型号是,STC89C52RC,你也可以选择更高级类型的51单片机
.
.
3 轮子电机驱动模块。
.
.

在这里插入图片描述
.
.

这个电机驱动系统的模块是L298N(上面图片,最大黑色那个)
.
这种驱动模块是可以同时驱动两个电机的,完全可以满足你小车的驱动动力,为什么要驱动呢?因为主控板的电流太弱了,不够功率让电机运行,所以才会有电机驱动模块的产生。
.
.

但是,不论外部检测是什么,上面的小车基础配置是公用的
.
.

在这里插入图片描述
.
.
.
现在我们既然讲解的是循迹小车,那么你还需要循迹传感器
.
.

在这里插入图片描述
.
.

循迹模块安装位置,如下图所示

.
.

在这里插入图片描述

.
.
就是这么简单,我们的循迹小车,配置模块就是这么多,
.
.

在这里插入图片描述
.
.
再通过程序的编写。我们的循迹小车,就可以循黑色线走了,非常简单。

.
.

如果你想要更详细的智能小车制作方法和各种接线,

请关注徽信公众号:三步学会单片机

关注后,回复数字001就有资料下载了。

.
.
在这里插入图片描述

2008-01-17 15:46:00 mybirdsky 阅读数 329
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3992 人正在学习 去看看 朱有鹏
2006-04-27 21:40:04

字体变小 字体变大
单片机智能开发平台解决方案

一、单片机应用开发平台的意义

  单片机是最初的大型计算机的一个分支,主要用于:工业自动化控制、智能仪器、仪表、航海、航天、智能家电等领域。单片机作为一种嵌入式产品应用的主流控制芯片,应用十分广泛,而支持它的开发手段国内还比较落后,目前我国单片机嵌入式产品的开发行业中,仍实行随意性个体的自然经济的落后方式,即便技术力量较强的公司,也仍在实行“板凳模式”的产品开发方法,大量低水平的重复劳动形成了顽症。采用平台开发模式实行“阶梯模式”的开发方式从根本上解决了“板凳模式”的弊端。

二、单片机开发平台简介

  单片机应用智能开发平台是为单片机的应用开发提供的一套解决方案,包括有中文开发平台操作系统、基础平台、扩展功能函数库、仿真调试等功能。开发平台部分为用户提供了一个简易方便的开发环境,使用户可对单片机应用项目进行可视化开发。基础平台部分提供了一个MCU与基本外部扩展模块结合的硬件环境,其具有良好的通用性,最大化的内涵度以及非介入性的应用特点,主模块的整体构架经过优化、筛选、实行严格的标准化、系列化、规范化设计,最终要形成平台的硬件资源库。扩展功能函数库部分对于基础平台的扩展部分提供了详细的使用函数库,用户在平台的支持下通过对函数的简单调用便可实现对扩展部分的使用。仿真调试部分可通过平台对开发项目进行仿真调试。内嵌式实时多任务操作系统,可使对多任务编程变得十分简单。利用本系统开发单片机嵌入式应用项目,会大量节省研发费用,缩短研发周期,提高系统可靠性,达到事半功倍的效果。

三、基础平台及I/O模块

(一)基础模块

  按照目前单片机应用功能和通信接口的现状与未来发展,我们设计的基础模块应具备以下的功能:

1)8051兼容内核:

额定工作频率12MHz(最大16MHz);

3个16位定时器/计数器;

32条可编程的I/O线(部分功能需复用);

9个中断源,两个优先级(可扩展)。

2)前向数据采集通道:

8通道高精度12位ADC(片内电压基准、高转换速率可达5μs、DMA方式可选);

两个12位电压输出DAC;

扩展八路频率输入接口;

片内温度传感器。

3)存储器:

64KB Flash/EE 程序存储器;

2MB Flash 数据存储器;

256B RAM;

16MB外部数据存储地址空间。

4)人机对话通道接口:

LCD显示接口(字符/图形);

4×4键盘;

语音接口;

标准打印机接口(可选)。

5)数据通讯接口:

标准UART串口(RS232/422);

IrDA红外数据交换接口;

无线通信接口(蓝牙技术);

电话线(内置调制解调器)。

6)外围设备:

看门狗定时器;

时钟电路;

电源监视器;

扩展4路I2C总线输出;

扩展8路电流驱动口。

7)电源:

3V和5V电压工作(正常、空闲和掉电工作模式)。

基础模块大致功能接口如图2所示。

其中可选项是用户自己可按照我们规定的参数进行配备的硬件模块,同时用户也可用我们自己的配套功能模块。

(二)用户资源设计

这一部件是为了让一部分用户可在已有的资源不够用或者不能满足他的特殊要求时而设计的,如开关量的测量与输出、多种优先级方式的中断系统、其他特殊的IIC总线器件、多机通讯、与上位机通讯、其他通讯设备的连接、更大的程序存储区和数据存储区的扩展等等。所以需要扩展足够多的地址线和一定的I/O口线和其他接口。

(三)硬件框图

鉴于用户资源和该通用测控系统在同一MCU控制下,考虑整个系统的功能要求和构件的灵活性,以及当今硬件发展的潮流,选用一片FPGA来完成所有的扩展。基础模块的内部硬件结构简图如图3所示。

四、虚拟仪表

  虚拟仪器是随着计算机技术、现代测量技术发展起来的新型高科技产品,代表着当今仪器发展的新方向。它既有普通仪器的基本功能,又有其独特的功能。虚拟仪器给用户一个充分发挥才能和想象力的空间,用户可以根据自己的需求设计自己的仪器系统,满足各种各样的应用要求。在平台中,为了给用户调试带来方便,设计了虚拟仪表功能,主要包括了数字电压表、逻辑分析仪、波形发生器。

(一)逻辑分析仪

逻辑分析仪是仿真系统的一部分,它是对用户系统进行外部监视,使用户能够直观地了解到自身系统的状态。可为用户提供自身系统的状态数据,并进行数据分析,了解用户系统的工作状态。

总体设计框图:

实现目标:

1)为软件提供8路采集信号

2)实现数据的采集深度为32K

3)实现高频率的采集>20M<

4)实现不同频率的采集>20M,10M,100K,1K<

5)对数据进行简单的压缩

6)采用RS-232通讯

(二)波形发生器

波形发生器是一种数据信号发生器。在调试硬件时,要加入一些信号,以观察电路工作是否正常。本波形发生器可以定义串口数据,输出波形可变,通过逻辑探钩输出,调试起来简单快捷。其模块功能如下图5所示。其中一路波形的产生如图6所示。

波形发生器模块功能

波形发生器一路波形的产生

(三)数字电压表

因输入信号的变化范围较大(十几微伏~几伏)应分为几个档,为方便用户使用拟采用量程自动转换技术。即根据未知参数量值的范围,自动选择合适的增益或衰减,以切换到合适的量程。量程自动设置的方法是通过在采集通道中设置可变增益放大器,借助量程转换开关控制其通断,获得所需量程。数字电压表框图如图7所示。

数字电压表框图

五、仿真器调试器

  在单片机应用开发中,仿真器是一个重要的辅助开发工具,因此,平台有必要有一个仿真调试工具。满足使用智能平台做产品开发的用户对目标机仿真调试的要求,并且使用方便可靠。

功能要求:

1) 全地址空间的仿真。

2) 不占用任何用户资源。

3) 必须实现硬断点,并且具有灵活的断点管理功能。

4) 硬件实现单步执行功能。

5) 可跟踪用户程序执行。

6) 可观察用户程序执行过程中的变量和表达式。

7) 可中止用户程序的运行或用户程序复位。

  由于单片机应用开发平台集成了大量专业技术和优秀设计思想,把单片机嵌入式应用于开发中的基础硬件工程,解决在平台之中,平台的严密标准和规范化设计保证了平台化设计有较高的可靠性与良好的使用界面。使用单片机开发平台可使技术人员迅速成长,通过使用平台培训开发人员能迅速掌握产品开发技术,彻底根除产品开发中大量低水平重复工作。平台的知识集成减少了企业对个别技术人员的依赖性,技术人员的流动不会影响企业的技术实力,平台最大限度的包容性大大缩短了产品的开发周期,平台的可靠性积累,保证了基于平台开发的产品具有良好的可靠性。平台的标准化、系统化、规范化有利于嵌入式产品的大规模生产、售后服务和产品更新。

没有更多推荐了,返回首页