2018-11-20 11:18:59 XiaoCaiDaYong 阅读数 2367

先展示我的硬件部分图片:

要求完成的功能:

1.两个模块和两个单片机相连,分别称为单片机A,单片机B

2.功能:单片机A上的两个按键控制单片机B上的P2口等四个灯的亮灭;单片机B上的两个按键控制单片机A上的P2口等四个灯的亮灭

代码如何实现呢,只要你对我之前的文章《2.4G无线模块(NRF24L01)学习(1)——串口实现两个模块之间信息交互》学习完之后再来实现这个功能那就太简单了,简直就不值得下手的感觉,但我认为虽然简单,但为了学好这个NRF24L01模块还是值得的,只有这样才能逐步达到灵活使用模块。

代码如下:

【提示】这里的2401.h代码依然没有改动,因此这里就不涉及2401.h代码,直接使用。下面主要看两个主函数文件的代码如何实现的?

单片机A代码:

#include"2401.h"

#define uint unsigned int
#define uchar unsigned char

sbit KEY1=P3^5;	 				//发送按键 
sbit KEY2=P3^4;	 				//发送按键 


sbit beep=P1^7;					//喇叭 
sbit LED6=P1^6;	 				//发送数据时显示灯+接收到数据后的功能实现灯

 
/*------------------------------------------------
延时函数
------------------------------------------------*/
void delay_ms(uint z)			//延时函数 
{
	uint y;
	while(z--)
		for(y=110;y>0;y--);
}
/*------------------------------------------------
main函数
------------------------------------------------*/
void main()
{
     uchar Tx_Buf1[]={1};			//发送的信息1 
     uchar Rx_Buf[32];  				//接收到的数据暂存器,最多32字节数据 
	 LED6=1;				//初始灯6熄灭   
	 init_NRF24L01();		//初始化24L01

	 while(NRF24L01_Check())					//检查不到24l01则报警 
	 {
		beep=0;
		delay_ms(200);
		beep=1;
		delay_ms(200);
	 }
	 while(1)
	 {	
		RX_Mode();							//接收模式  
		while(!nRF24L01_RxPacket(Rx_Buf)) 	//等待接收数据,返回1则接收到数据,在等待接收数据期间,可以随时变成发送模式  
	    {
			if(KEY1==0)	 					//按了按键8,则变成发送模式,发送对应数据,发送完后变成接收模式 
			{	
				delay_ms(5);//消抖动 
				if(KEY1==0)
				{
			 		while(!KEY1);
                    Tx_Buf1[0]=1;
					TX_Mode();	 //发送模式 
			    	nRF24L01_TxPacket(Tx_Buf1);		//发送命令数据
					LED6=0;
			    	delay_ms(300);
					LED6=1;
			    	delay_ms(300);					//发送后LED6闪一下 
					break;							//退出最近的循环,从而变回接收模式,这句关键
				 }	
			 }
             if(KEY2==0)	 					//按了按键8,则变成发送模式,发送对应数据,发送完后变成接收模式 
			{	
				delay_ms(5);//消抖动 
				if(KEY2==0)
				{
			 		while(!KEY2);
                    Tx_Buf1[0]=2;
					TX_Mode();	 //发送模式 
			    	nRF24L01_TxPacket(Tx_Buf1);		//发送命令数据
					LED6=0;
			    	delay_ms(300);
					LED6=1;
			    	delay_ms(300);					//发送后LED6闪一下 
					break;							//退出最近的循环,从而变回接收模式,这句关键
				 }	
			 }
		 }
		switch(Rx_Buf[0]){//对数据进行分析来控制灯亮
		case 1:
			Rx_Buf[0]=0;				//清空数据
            P2=0X0F; 
            LED6=0;
			delay_ms(300);			
            LED6=1;
			delay_ms(300);	
			break;
		case 2:
			Rx_Buf[0]=0;				//清空数据 
		    P2=0XF0;
            LED6=0;
			delay_ms(300);
            LED6=1;
			delay_ms(300);	
			break;
        default:
            break;
		}
	 }
}

 

单片机B的代码:

#include"2401.h"

#define uint unsigned int
#define uchar unsigned char

sbit KEY1=P3^5;	 				//发送按键 
sbit KEY2=P3^4;	 				//发送按键 

sbit beep=P1^7;					//喇叭 
sbit LED6=P1^6;	 				//发送数据时显示灯


void delay_ms(uint z)			//延时函数 
{
	uint y;
	while(z--)
		for(y=110;y>0;y--);
}
void main()
{
	 uchar Tx_Buf1[]={1};	//发送的信息1 
	 uchar Rx_Buf[32];  	//接收到的数据暂存器,最多32字节数据  
	 init_NRF24L01();
	 LED6=1;				//初始灯6熄灭   

	while(NRF24L01_Check())					//检查不到24l01则报警 
	{
		beep=0;
		delay_ms(200);
		beep=1;
		delay_ms(200);
	}
	while(1)
	{	
		RX_Mode();							//接收模式  
		while(!nRF24L01_RxPacket(Rx_Buf)) 	//等待接收数据,返回1则接收到数据,在等待接收数据期间,可以随时变成发送模式  
	    {
			if(KEY1==0)	 					//按了按键8,则变成发送模式,发送对应数据,发送完后变成接收模式 
			{	
				delay_ms(5);//消抖动 
				if(KEY1==0)
				{
			 		while(!KEY1);
                    Tx_Buf1[0]=1;
					TX_Mode();	 //发送模式 
			    	nRF24L01_TxPacket(Tx_Buf1);		//发送命令数据
					LED6=0;
			    	delay_ms(300);
					LED6=1;
			    	delay_ms(300);					//发送后LED6闪一下 
					break;							//退出最近的循环,从而变回接收模式,这句关键
				 }	
			 }
             if(KEY2==0)	 					//按了按键8,则变成发送模式,发送对应数据,发送完后变成接收模式 
			{	
				delay_ms(5);//消抖动 
				if(KEY2==0)
				{
			 		while(!KEY2);
                    Tx_Buf1[0]=2;
					TX_Mode();	 //发送模式 
			    	nRF24L01_TxPacket(Tx_Buf1);		//发送命令数据
					LED6=0;
			    	delay_ms(300);
					LED6=1;
			    	delay_ms(300);					//发送后LED6闪一下 
					break;							//退出最近的循环,从而变回接收模式,这句关键
				 }	
			 }
		 }
		switch(Rx_Buf[0]){//对数据进行分析来控制灯亮
		case 1:
			Rx_Buf[0]=0;				//清空数据
            P2=0X0F; 
            LED6=0;
			delay_ms(300);			
            LED6=1;
			delay_ms(300);	
			break;
		case 2:
			Rx_Buf[0]=0;				//清空数据 
		    P2=0XF0;
            LED6=0;
			delay_ms(300);
            LED6=1;
			delay_ms(300);	
			break;
        default:
            break;
		}	 	
	}
}

你会发现这两个代码基本一致,因为这两个代码中都有发送和接受的过程,而且实现是一样的效果。

效果展示:

2014-10-17 16:15:25 weiyidianliu 阅读数 18190

在无线通信中,NORDIC公司生产的NRF24L01无线收发模块是许多玩家的选择,它是2.4GHz~2.5GHz的ISM 频段的单片无线收发器芯片,具有功能较强而控制较方便并且价格便宜的优点。一块NRF24L01可以同时接收6个通道的发送数据,同时可以采用变频手段改变通信频道来避免无线通信干扰,下面简单介绍一下这种芯片的使用。

本次采用了两块单片机进行无线通信,一块型号为:STC90C51 16RD+        ,接收器:NRF24L01

                                                                      另一块为:STC12C5A60S2             ,发送器:NRF24L01

一、硬件方面

1>引脚介绍


引脚1:GND,接地端;引脚2:VCC,1.9V~3.6V

引脚3:CE, NRF24L01模式控制端

引脚4:CSN,片选信号

引脚5:SCK,SPI时钟输入端

引脚6:MOSI,SPI数据输入端

引脚7:MISO,SPI数据输出端

引脚8:IRQ,中断输出端,低电平使能,即中断输出低电平

对于电源不要超过3.6V,否则可能损坏芯片

对于端口引脚,可以耐压5V,即可以接TTL端口

2>工作模式


3>增强型shockburst模式

NRF24L01默认是增强型shockburst模式,即能自动应带,此模式下可减轻单片机负担,可使程序简化,本次将采用默认方式发送接收数据。

在此方式下,通讯协议如下:

对发送方(配置PRIM_RX为低):发送方启动发送后,即CE拉高至少10us,发送方发送数据,发送完数据后使用通道0接收终端应答ASK信号,如果没有收到ASK,发送方将重发相同的数据包,直到收到应答信号或重发次数超过设定最大值为止。若超过最大次数,将会产生MAX—RT中断,IRQ输出低电平。若收到了ASK信号,发送发认为发送成功,将产生TX_DS中断。

对接收方(配置PRIM_RX为高):接收方启动接收后,即CE拉高至少10us,若接收到的数据通过CRC校验正确,则将数据存储在RX_FIFO中。

4>数据通道地址配置方法


           

图示中,以地址宽度为5字节示例

对于NRF24L01(发送方、接收方)通道0地址32位数据均可配置

对于接收方,而通道1-通道5中前4字节地址必须相同,第五字节不能相同

对于发送方,通道0地址 和 发送地址 必须一致,而且与接收方所要通信通道地址相同!

5>SPI指令设置

每一条完整指令的写入都必须通过一次CSN由高到低的变化

6>SPI指令格式


访问多字节寄存器时,应该先读/写低字节的高位。当多字节寄存器在写完之前若结束SPI写操作,则高位字节内容可保持不变。

对于中断,若向中断源TX_DS、RX_DR、MAX_RT写入1,则中断响应被屏蔽。

7>SPI时序

写NEF24L01中寄存器时必须处于待机或掉电模式!


8>寄存器表格

共有18个寄存器,而对于点对点通信的NRF24L01只用到不到10个寄存器即可,其它可保持默认配置,详情见程序配置,寄存器说明见NORDIC公司的datasheet。

二、软件部分

下篇继续》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

****************************************************************************************************************

详情请咨询:                                                 http://shop108408772.taobao.com/

**************************************************************************************************************

2017-05-11 14:13:44 HES_C 阅读数 3922

 

前言,这里我不教基础,因为这些东西都很基础。

本教程需要51单片机知识,了解什么是2.4G遥控器,冻手能力,信心,耐心(没有这些请绕道)

如果以上这些你都具备那么可以往下面看吧。


1-)准备材料
                        keil编译软件 
                        stc-isp烧录软件
                        接收机的源码链接: 链接: https://pan.baidu.com/s/1geJNMMn 密码: dmj4

                  电路图链接: https://pan.baidu.com/s/1o77ypwI 密码: 725e
                        usb转ttl下载器(淘宝上面随便搜的)
                     
                        
2-)电路制作材
                           stc12c5a60s2 dip-40

              12M晶振

              30p陶瓷电容

              稳压芯片AMS117 3.3一个,78m05或AMS1117 5.0一个
                               NRF24L01模块;

           12864一个.(带不带字库都无所谓,5V和3V要选好)

              油门摇杆电位器和普通摇杆电位器(区别:油门电位器不自动回中,如果制作目的是车船遥控器,可以都用普通摇杆)

              10K电阻、20K电阻一个(选1%精度的)

              按键7个

              100uf 16V电容三个

              104瓷片电容一个

              耳机插座一个(用于输入输出PPM模拟信号)

              蜂鸣器一个

              2段开关3个

              3段开关2个

              (旋钮开关)3个电位器10K就够了


3)焊接电路(这个才是重点)

              可以根据这个草图焊接

          

       1,先焊接上单片机、电容晶振并下载程序。
看到这估计你手中的烙铁已经饥渴难耐了,首先打一下预防针,焊接不及格会出现各种问题:
  不要堆太多锡,最好让板面整洁,可以像楼主那样使用电阻腿当导线;
  板子上残留焊锡膏、焊点之间如果有奇怪的残留物,会有用万用表量不出来的问题
  

2,焊接显示屏,如果下载程序正确,会有显示效果。单片机和液晶屏电压的关系详见下面的遥控器供电介绍
 

下面焊接好其它器件,基本上不会有什么问题的(大家买的元器件可能会和我的不一样,但是xi)


关于遥控器供电:
如果电池用3S(11.1V),那么5V稳压只能用7805,如果用开关电源,滤波一点要做好;
如果电池用2S(7.4V),那么5V稳压可以选择AMS1117 5.0(注意引脚顺序和7805不一样,左负右输入,中间是5V输出。这个芯片3S会发热);
如果电池用1S(3.7V),单片机必须更换为STC12LE5A60S2,屏也必须改成3V屏!然后两个稳压芯片都换成HT7333(注意引脚顺序和7805不一样,左负,中间是输入,右是3.3V输出)就可以了,这个方案也可以支持2S电池。另外,蜂鸣器要加三极管放大。

》》》最后要说的是无线模块的选取。市面上各种模块质量参差不齐,如果你想获得更远的距离,那一定要买好的模块

常见问题解答 Q and A:


Q:按菜单键没有反应怎么办?
A:没有勾选“复位做IO“选项。这个问题强调很多遍,然而经常还有人出错……Q_Q
*很多问题都是下载时没有正确设置造成的。

Q:出现一些奇怪的问题、不正常工作了怎么办?
A:有可能是数据保存出错照成的,勾选“下次下载程序时擦除EEPROM”并重新下载两次,可以将单片机恢复到最初的状态。
*遥控器开机时长按菜单键也可以强制恢复出厂。

Q:12864液晶出现倒显、镜像等问题?
A:液晶屏的电压过低导致,如果用单节锂电供电,液晶屏需要改成HT7333稳压(板载的3V稳压芯片压降大);

Q:只焊接单片机可以下载程序,全部做好后不能下载了?
A:这是下载器电流不足引起的,可以拆掉大容量电容再试试。
*如果你的下载器是CH340g,那么5V和VCC一定要连接在一起。
*如果还不行,那么可以尝试外接电源下载法,遥控只接GND、TX、RX,点击下载后,再接通外部5V电源。

Q:遥控和接收怎么对频?
A:有三种方法进入等待对频状态:
┌——如果是新制作的接收机,那么第一次开机就是等待对频状态;
├——接收机通过第二条Q A的方法也可恢复为第一次开机状态;
└——使用金属物品,将接收机5/6通道相互连通在一起(就是把单片机5/6通的引脚短接),然后通电,也可以重新对频;
*如何判断等待对频状态:上电后LED直接高亮;
*如何判断已经对过频:上电时LED灯会闪一下再熄灭。如果此时遥控没有开机,2秒后会再亮;
*如何判断故障状态:上电时LED灯会快速闪烁。可能是模块接线不良或电源不稳;
*确认进入等待对频状态,遥控器选择对频,屏幕会显示通信成功。
*如果很长时间不能成功,那么不要折腾怎么对频了、对频怎么这么麻烦、到底怎么对频……(*>﹏<*),这是电路出现问题,检查电路吧。

Q:遥控可以和接收机通信,但舵机乱响不受控制什么原因?
A:使用晶振的接收机下载时一定注意不能勾选“内部时钟”。

Q:我做了好几个接收机,怎么用一个遥控控制它们?
A:虽然是多个接收机,但肯定是不同时间分别工作的,所以遥控只需个性化设置一次,然后分别与每个接收机对频即可。



教程出来很久了,对于大部分在制作过程中出现的异常问题,现在可以总结,90%是焊接和连线不合格,5%是看教程不仔细造成的。
因此如果出现问题,首先检查的就是线路是否良好以及是否遗漏了什么步骤。此外如果你不懂电子的话就不要随意改动,每一步都必须按教程来,没有做不出来的道理。

排除法、替换法 
DIY的过程中很容易出错,所谓自己动手丰衣足食,自己多思考思考,多备点元器件,把怀疑有问题的换下来,一般的问题很容易自己解决的

2018-01-21 20:09:34 qq_35158400 阅读数 4409

本文主要介绍怎么通过遥控接收机的信号控制单片机的IO口。试验器材:

天地飞WFT09II 9通道2.4G遥控器+接收机

STC15F104W单片机


这里接收机输出的是频率为50hz,周期为20mspwm波形,通过单片机外部中断口接收pwm信号,启用定时器/计数器对pwm高电平的持续时间进行计数。

Arduino中的pulseIn函数可以直截了当地读取pwm的值,可以参考其底层的实现方法,这里有一个链接介绍pulseIn函数读取pwm的思想。

http://blog.csdn.net/soso90soso/article/details/78599621?locationNum=5&fps=1

文中关键部分:

unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) {
  pinMode(pin, INPUT);
  uint32_t start = micros();
  while(digitalRead(pin) == state && (micros() - start) < timeout);
  while(digitalRead(pin) != state && (micros() - start) < timeout);
  start = micros();
  while(digitalRead(pin) == state && (micros() - start) < timeout);
  return micros() - start;
}

微妙级,死循环读取引脚电平。因为不确定IO口接收到输入的pwm的瞬间是高电平还是低电平,所以While循环里先判断高电平,再判断低电平,再判断一次高电平,从而获得准确的占空比。

至于怎么在单片机上读取pwm呢?在网上查找一些资料后,我了解到可以通过外部中断+定时器来实现。最初我参考这个源码:

//转发请注明:http://bbs.5imx.com
//芯片型号为STC15F100W-STC15F104W,烧写程序时请选择IRC频率12M.
//STC15F100W芯片的P3.2脚为模型接收机PWM信号输入脚.
//本程序可根据个人需求更改判断变量a的值来达到相应的要求.
//变量a的值单位为微秒:1000us=1ms,1500=1.5ms,2000=2.0ms.
#include<reg51.h>
sfr AUXR = 0x8E;
unsigned int a=0;
sbit led1=P3^3;
sbit led2=P3^4;
sbit led3=P3^5;
bit HL;
                       
void Timer0Init(void)		
{
	AUXR &= 0x7F;		
	TMOD &= 0xF0;	
	TL0 = 0x00;		
	TH0 = 0x00;		
	TF0 = 0;	
	TR0 = 0;		
}

void main()
{   
    EA   = 1;
	INT0 = 1;
	EX0  = 1; 
	IT0  = 0;                    
    Timer0Init();
while(1){  
		 if(a>980&&a<1020)led2=0;  else led2=1;
		 if(a>1480&&a<1520)led3=0; else led3=1;
        }
}

void INT_0 (void) interrupt 0  using 2
{
   HL = INT0;
   if(HL==1)TR0 = 1;
   if(HL==0){
   TR0 = 0;
   a   = TH0;
   a   = a*256+TL0;
   TL0 = 0x00;
   TH0 = 0x00; 
              }
}
这个代码里面有一个问题就是,当单片机满足中断条件,就会不断跳到外部中断处理函数中,感觉这样太占用cpu资源,可以编写一个函数,在监听pwm值时开启外部中断,在获取到pwm值时关闭中断。具体方法如下:

#include<reg51.h>
sfr AUXR = 0x8E;
unsigned int a0=0;
unsigned int a1=0;
//sbit led1=P3^3;
sbit led2=P3^4;
sbit led1=P3^5;
bit HL;
                   
void pulseIn0();
void pulseIn1();


void Timer0Init(void)
{
  AUXR &= 0x7F;
  TMOD &= 0xF0;
  TL0 = 0x00;
  TH0 = 0x00;
  TF0 = 0;
  TR0 = 0;
}


void main()
{   
  EA   = 1;
  //INT0 = 1;
  EX0  = 0; 
  IT0  = 0;  
  EX1  = 0; 
  IT1  = 0;
  Timer0Init();
  while(1){  
    pulseIn1();
    if(a0>980&&a0<1020)led2=0;  else led2=1;
    pulseIn0();
    if(a1>1480&&a1<1520)led1=0; else led1=1;
  }
}


void INT_0 (void) interrupt 0  using 2
{
   HL = INT0;
   if(HL==1)TR0 = 1;
   if(HL==0){
     TR0 = 0;
     a0   = TH0;
     a0   = a0*256+TL0;
     TL0 = 0x00;
     TH0 = 0x00; 
     EX0  = 0; 
   }
}
void INT_1 (void) interrupt 2  using 2
{
   HL = INT1;
   if(HL==1)TR0 = 1;
   if(HL==0){
     TR0 = 0;
     a1   = TH0;
     a1  = a1*256+TL0;
     TL0 = 0x00;
     TH0 = 0x00; 
     EX1  = 0; 
   }
}
void pulseIn0(){
  while(INT0==1);
  EX0  = 1; 
}
void pulseIn1(){
  while(INT1==1);
  EX1  = 1; 
}
STC15F104W单片机外部中断0(INT0)和外部中断1(INT1)触发有两种发方式,上升沿或下降沿均可发方式和仅下降沿发方式。
TCON寄存器中的IT0/TCON.0和IT1/TCON.2决定了外部中断0和1是上升沿和下降沿均可发还是仅下降沿发。如果ITx = 0(x = 0,1),那么系统在INTx(x = 0,1)脚探测到上升沿或下降沿后均可产生外部中断。如果ITx = 1(x = 0,1),那么系统在INTx( x= 0,1)脚探测下降沿后才可产生外部中断。

程序中

IT0  = 0;  
IT1  = 0;

所以上升沿或下降沿后均可产生外部中断,我设想是通过上升沿触发中断,

void pulseIn0(){
  while(INT0==1);
  EX0  = 1; 
}
该段代码的意思是,如果接收到的pwm信号正处于高电平,先进入死循环,等pwm信号处于低电平再开启中断,那么下一个上升沿即可触发中断,触发中断后立即启用定时器0正好可以对高电平进行计数,到下一个下降沿时关闭中断。


试验效果如下:

INT1口接收到的pwm信号满足a1>1480&&a1<1520,led1熄灭。

而且用Arduino读取到的pwm值也在这个区间内,由此可见,用这种方法读取pwm的值精度是很高的,以后可以用STC15F104W单片机代替Arduino,通过pwm控制单片机的IO口。




2019-12-30 21:10:31 u012910342 阅读数 24

介绍与实验篇
技术框架篇

前端测试:www.a135.xyz

框架图
在这里插入图片描述
先简要描述一下:

本地设备端

1、2.4G无线模块之间的通信,通过一定的协议进行,协议已经封装好,C语言代码。
2、ESP WIFI是ESP8266模块,添加了设备管理,以便让设备具备即插即用的功能。
3、STC单片机通过PWM控制设备。

服务端

1、设备在线管理。
2、控制设备。
需要添加:开通查询、设置设备等接口。
需要添加:设备改名等功能,以便更好管理设备。

应用端

前端网页、APP、小程序等。

更多细节待完善。

前端测试:www.a135.xyz

介绍与实验篇
技术框架篇

G38.2 指令

阅读数 2073

单片机 矩阵式按键

阅读数 6383

29 JAN 2011 Note

阅读数 192

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