2019-08-16 16:16:56 XLazyDog 阅读数 97
  • 单片机控制第一个外设-LED灯-第1季第6部分

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

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

 

借助蓝牙调试器我们可以很轻易地通过各种控件操作变量,现在要考虑的是如何让单片机获知这些变量?

首先确定单片机和蓝牙串口模块的连接方式:

需要注意的是蓝牙串口模块与单片机之间的连接,其TX、RX与单片机TX、RX是交叉的。如果你使用STM32单片机的USART1的话,则 蓝牙的TX 连接 单片机的PA10口, 蓝牙的RX连接单片机的PA9口。

连接方式

连接好蓝牙串口模块后,就开始写单片机程序了。由于我已经编写好了可以自由配置的单片机端的程序,所以你可以很方便地实现收发功能。代码在这

1.数据结构设置

下面是我编写好的名为valuepack的代码,其是在STM32F103单片机运行的,你也可以针对不同的平台进行修改,在使用此功能前,你首先需要在valuepack.h中配置通信结构。

在valuepack.h中配置参数

1.1接收缓冲区尺寸

缓冲区用来暂存从手机接收到的数据包,每次执行readValuePack时将这些暂存的数据包解析。缓冲区的尺寸默认为1024。

1.2发送数据包结构 

这里定义发送到手机的数据包的结构,即状态回传。在这里你可以像在蓝牙调试器上一样设置数据包中五种变量的数目。需要确保在此设置的五种类型变量的数目与手机的“接收数据包结构”的设置相同。否则手机端将无法解析该数据包。

1.3接收数据包结构 

这里定义从手机接收的数据包的结构,需要确保在此设置的五种类型变量的数目与手机的“发送数据包结构”的设置相同。

接下来就可以通过调用其函数实现数据收发了。

2.串口配置

 

 

3.接收数据包

3.1接收数据包结构体

创建接收数据包

首先创建一个接收数据包,该数据包中包含了五个数组,对应不同的数据类型。比如rxpack.bools[0]可以访问bool类型的第一个变量。

3.2读包

在手机不断发送数据到单片机时,单片机需要定时执行readValuePack。读包的频率最好高于手机发送数据包的频率。

4.发送数据包

4.1发送数据包结构体

创建一个发送数据包,该数据包中包含了五个数组,对应不同的数据类型。比如txpack.bools[0]可以访问bool类型的第一个变量。

4.2发包

单片机定时执行sendValuePack函数,并传入要发送的数据包。sendValuePack函数执行频率不可过高,太高容易导致堵塞。

至此已经整个单片机端的数据收发就完成了。函数总共就三个 init、read和send,使用起来非常简单。

单片机端的源代码

2019-12-16 21:28:41 weixin_44906810 阅读数 28
  • 单片机控制第一个外设-LED灯-第1季第6部分

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

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

这一次做的是用ESP8266WIFI模块,让51单片机与后端交互数据。简单地发了一个字符串。
模块连接部分:VCC接电源,GND接地,模块的TXD接单片机的RXD,模块的RXD接单片机的TXD
需要注意的是在程序烧录进单片机之前,不能连接RXD和TXD。
建议在烧录代码之前先用XCOM发送指令检验WIFI模块是否能够正常使用,不然一直调试单片机的代码也是没有用的,一下代码实现的是单片机通过WIFI模块向后端发送数据。

#include <reg52.h>
#include <string.h>
#include <intrins.h>
typedef unsigned char u8;
typedef unsigned int u16;
unsigned char Usart_Receive[20]={0};
unsigned char Usart_Cnt=0;
bit Usart_AT_flage;
bit flag;
u8 dat;
 
void Init(void)//初始化串口 
{
	TMOD = 0x20;
    SCON = 0x50;
    TH1 = 0xFD;
    TL1 = TH1;
    PCON = 0x00;
    EA = 1;
    ES = 1;
    TR1 = 1;
	REN=1;
}
 
void delay5ms(void)  //延时函数 
{
    unsigned char a,b;
    for(b=15;b>0;b--)
        for(a=152;a>0;a--);
}
 
void delay1s(void)   //延时 
{
    unsigned char a,b,c;
    for(c=13;c>0;c--)
        for(b=247;b>0;b--)
            for(a=142;a>0;a--);
    _nop_();  //if Keil,require use intrins.h
}
 
void Sent_ZF(u8 dat) //串口发送字符 
{
	ES = 0;
	TI=0;
	SBUF = dat;
	while(!TI);
        TI = 0;
        ES = 1;
}
 
void AT_Send_String(u8 *string) //串口发送字符串 
{  while(*string)
  {
    Sent_ZF(*string++);
		delay5ms();
  }
}
 
void ESP8266_Init()//用串口向ESP8266发送命令 
{
	while(1)       
	{
		AT_Send_String("AT\r\n");
		delay1s();
		delay1s();
		if(Usart_AT_flage ==1)
		{
				Usart_AT_flage = 0;
				break;
			}	
		}
	
	while(1)
	{
		AT_Send_String("AT+CWMODE=1\r\n");   //设置为模式1 
		delay1s();
		delay1s();
		if(Usart_AT_flage ==1)
		{
				Usart_AT_flage = 0;
				break;
			}	
		
	}
	while(1)
	{
		AT_Send_String("AT+CWJAP=\"mumn\",\"123456789\"\r\n");	  //连接网络 ,输入自己的网络名的密码
		delay1s();
		delay1s();
		if(Usart_AT_flage ==1)
		{
				Usart_AT_flage = 0;
				break;
			}	
		}
	
	while(1)
	{
		AT_Send_String("AT+CIPSTART=\"TCP\",\"192.168.43.177\",8080\r\n");	//作为客户端	
		delay1s();
		delay1s();
		delay1s();
		if(Usart_AT_flage ==1)
		{
				Usart_AT_flage = 0;
				break;
			}	
		}
	while(1)
	{
		AT_Send_String("AT+CIPMODE=1\r\n");		
		delay1s();
		delay1s();
		delay1s();
		if(Usart_AT_flage ==1)
		{
				Usart_AT_flage = 0;
				break;
			}	
		}	
	
		while(1)
	{
		AT_Send_String("AT+CIPSEND\r\n");		
		delay1s();
		delay1s();
		delay1s();
		if(Usart_AT_flage ==1)
		{
				Usart_AT_flage = 0;
				break;
			}	
		}	
}	

void sendnumber()
{
	while(1)
	{
   AT_Send_String("12345");		
   delay1s();
		delay1s();
		delay1s();
		if(Usart_AT_flage ==1)
		{
				Usart_AT_flage = 0;
				break;
		}	
	}	
}

 
void main()
{
    Init();
    ESP8266_Init();
    sendnumber();
    while(1);
}
 
void InterruptUART(void) interrupt  4  //串口中断 
{
	if(RI)
	{
		RI=0;
		Usart_Receive[Usart_Cnt]=SBUF;
		Usart_Cnt++;
		if(Usart_Receive[Usart_Cnt]=='\0')   
		{
			Usart_Cnt=0;
			Usart_AT_flage=1;			
		}
	}
	else
		TI=0;
}

在电脑上写一段JAVA服务程序,运行出来等待客户端的连接,再烧录上面的代码进51单片机,就可以看见数据发送成功了

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Service {
     public static void main(String[] args) throws Exception {
            ServerSocket server = new ServerSocket(10012);
            byte[] msg = new byte[50];
            System.out.println("服务端ready,,,,");
            Socket client = server.accept();
            InputStream in = new DataInputStream(client.getInputStream());
            boolean accept = true;
            while (accept) {
                in.read(msg);
                System.out.println(new String(msg));
            }
            in.close();
            client.close();
            server.close();
        }
}
2016-05-27 18:05:58 sinat_30685475 阅读数 3465
  • 单片机控制第一个外设-LED灯-第1季第6部分

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

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

一、例程简介

    本例程51单片机与蓝牙模块连接,可通过蓝牙模块接收和发送字符串,从而控制测试灯的亮灭。其中使用51单片机的串行口2的工作方式1,即8位UART,波特率可变。波特率设为9600。缺省UART2在P1口。

    测试程序实现的功能:

    1、蓝牙模块接收到“0”~“6”字符串时,分别实现LED0~4的不同亮灭效果;

    2、执行字符串“6”对应效果后,通过蓝牙模块发送字符串“\rHello!”到模块连接的蓝牙设备。


二、硬件部分

C51芯片:STC12C5A60S2 PDIP-40

蓝牙模块:HC-05

晶振:11.0592MHz

-- 连接电路 --

最小系统

51单片机最小系统

(测试用BST-V51 51单片机学习板)

蓝牙模块

+5V 接 单片机VCTC

GND 接 单片机GND

TX 接 P1.2/RxD2

RX 接 P1.3/TxD2

其它引脚悬空


三、软件部分

-- C语言代码 --

#include "reg51.h"
#include "intrins.h"
#include "string.h"

typedef unsigned char uchar;
typedef unsigned int uint;

#define FOSC 11059200L //System frequency
#define BAUD 9600 //UART baudrate
#define PARITYBIT NONE_PARITY //Testing none parity

/*Define UART parity mode*/
/* Copy from STC12C5A60S2 Data Sheet*/
#define NONE_PARITY 0 //None parity
#define ODD_PARITY 1 //Odd parity
#define EVEN_PARITY 2 //Even parity
#define MARK_PARITY 3 //Mark parity
#define SPACE_PARITY 4 //Space parity

/*Declare SFR associated with the UART2 */
/* Copy from STC12C5A60S2 Data Sheet*/
sfr AUXR = 0x8e; //Auxiliary register
sfr AUXR1 = 0xa2;
sfr S2CON = 0x9a; //UART2 control register
sfr S2BUF = 0x9b; //UART2 data buffer
sfr BRT = 0x9c; //Baudrate generator
sfr IE2 = 0xaf; //Interrupt control 2
#define S2RI 0x01 //S2CON.0
#define S2TI 0x02 //S2CON.1
#define S2RB8 0x04 //S2CON.2
#define S2TB8 0x08 //S2CON.3

/* Define variables associated with the UART2*/
char UART_buff;
char Str[16];
uchar j = 0;

/*Define pin of LED for testing*/
sbit LED0 = P1^0;
sbit LED1 = P1^4;
sbit LED2 = P1^5;
sbit LED3 = P1^6;
sbit LED4 = P1^7;

// delay for x ms
void delayxms(uint x)
{
	uint i;
  uchar a,b;
	for(i=0;i<x;i++)
    for(b=18;b>0;b--)
        for(a=152;a>0;a--) ;
}

/* Copy from STC12C5A60S2 Data Sheet*/
void Uart2_Init()
{
	#if (PARITYBIT == NONE_PARITY)
		S2CON = 0x50; //8-bit variable UART
	#elif (PARITYBIT == ODD_PARITY) || (PARITYBIT == EVEN_PARITY) || (PARITYBIT == MARK_PARITY)
		S2CON = 0xda; //9-bit variable UART, parity bit initial to 1
	#elif (PARITYBIT == SPACE_PARITY)
		S2CON = 0xd5; //9-bit variable UART, parity bit initial to 0
	#endif
	BRT = -(FOSC/32/BAUD); //Set auto-reload vaule of baudrate generator
	AUXR = 0x14; //Baudrate generator work in 1T mode
//	AUXR1  |= 0x10; // If needed, switch UART2 Pin from P1 to P4
	IE2 = 0x01; //Enable UART2 interrupt
	EA = 1; //Open master interrupt switch
}

/*----------------------------
Send a string to UART
Input: s (address of string)
Output:None
----------------------------*/
void SendString(char *s)
{
	int i = 0;
	int l = strlen(s);
	for(i; i<l; i++)
	{
		S2BUF = s[i];
    while(!(S2CON&S2TI)) ;
    S2CON &= ~S2TI;;
	}  
}

void main()
{
	Uart2_Init();
	
	LED0 = 1;
	LED1 = 1;
	LED2 = 1;
	LED3 = 1;
	LED4 = 1;
	
	while(1) ;
}

/*----------------------------
UART2 interrupt service routine
----------------------------*/
void Uart2() interrupt 8 using 1
{
	if (S2CON & S2RI)
	{
		S2CON &= ~S2RI; //Clear receive interrupt flag
		UART_buff = S2BUF; //UART_buff to save UART data
		
		if(UART_buff != '\0')	// When it's not the end of message,
		{
			Str[j++] = UART_buff; // Continue to record character.
		}
		else // When message ends, do the specific job
		{
			Str[j] = UART_buff;
			if(strcmp(Str, "0") == 0)
			{
				LED0 = ~LED0;
				delayxms(100);
			}
			else if(strcmp(Str, "1") == 0)
			{
				LED1 = ~LED1;
				delayxms(100);
			}
			else if(strcmp(Str, "2") == 0)
			{
				LED2 = ~LED2;
				delayxms(100);
			}
			else if(strcmp(Str, "3") == 0)
			{
				LED3 = ~LED3;
				delayxms(100);
			}
			else if(strcmp(Str, "4") == 0)
			{
				LED4 = ~LED4;
				delayxms(100);
			}
			else if(strcmp(Str, "5") == 0)
			{
				LED1 = 0;
				LED2 = 0;
				LED3 = 0;
				LED4 = 0;
				delayxms(100);
			}
			else if(strcmp(Str, "6") == 0)
			{
				LED1 = 1;
				LED2 = 1;
				LED3 = 1;
				LED4 = 1;
				delayxms(100);
				SendString("\rHello!");
			}
			strcpy(Str, "");
			j = 0;
		}
	}
	if (S2CON & S2TI)
	{
		S2CON &= ~S2TI; //Clear transmit interrupt flag
	}
}




2019-07-31 17:26:50 weixin_44430455 阅读数 57
  • 单片机控制第一个外设-LED灯-第1季第6部分

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

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

Nrf24l01无线模块

一,模块介绍

二,接口电路,

在这里插入图片描述

模块连接注意点:
(1) VCC 脚接电压范围为 1.9V~3.6V 之间,不能在这个区间之外,超
过 3.6V 将会烧毁模块。推荐电压 3.3V 左右。
(2) 除电源 VCC 和接地端,其余脚都可以直接和普通的 5V 单片机 IO

直接相连,无需电平转换。当然对 3V 左右的单片机更加适用了。
(3) 硬件上面没有 SPI 的单片机也可以控制本模块,用普通单片机 IO
口模拟 SPI 不需要单片机真正的串口介入,只需要普通的单片机 IO 口
就可以了,当然用串口也可以了。

然后我接的就是CE连的A4,CSN连的C4,SCK连的A5,MOSI连的A7,MISO连的A6,IRQ是中断脚,可以接外部中断,不过我没有接。这里注意一下哈,中断脚要想低电平触发的三种情况:1,发送端发送完了数据并接收到接收端的ACK应答;2,接收端接受到数据;3,达到最大重发次数(外部中断的时候需要考虑的)

三,工作模式

工作模式由 PWR_UP register 、PRIM_RX register 和 CE 决定,有如下表格中那么多的工作模式
在这里插入图片描述
(英文版)
在这里插入图片描述
(中文版)
其中收发模式有 Enhanced ShockBurstTM 收发模式、ShockBurstTM 收
发模式和直接收发模式三种,收发模式由器件配置字决定,但是主要用到的是 Enhanced ShockBurstTM 收发模式,只有该模式支持自动ANK,和自动重发。
下面也都是介绍的这个接收模式。

在这里插入图片描述
就是上面这张图,想象一下,这一个圈就是一个带有8个爪子的无线模块,RX是接收功能的(设为接收模式)模块,TX是发送功能的(设为发送模式)模块,这样就是被设为接收模式的端子有6个接受通道,而被,设为发送模式的端子有1个发送通道,它们的传输是这样子的:
发送端子的TX_add寄存器存放的是接收端子6个通道中的其中一个通道的地址,然后传送完数据之后,接收端在确认收到数据后记录发送端的地址,并以此地址(接收端某个通道的地址)为目标地址发送应答信号这个是自动的,不是程序设置的,应属于硬件实现)
发送端的2401会用自己接收通道0来接受接收端的2401发送来的相应信号。但是接收端的2401发送应答信号的时候,也发送的地址就是接收端的某个接受通道的地址。所以发送端的接收通道0的地址要设置成这个地址。注意就只能是发送通道的通道0作为应答信号
通道0有40位自身地址,通道1—5都为8位自身地址和32位公用地址。

例子:

TX5:TX_ADDR=0xB3B4B5B605

TX5:RX_ADDR_P0=0xB3B4B5B605

RX:RX_ADDR_P5=0xB3B4B5B605

介绍完模式之后就来看

该模式的发送的流程以及初始化该发送模式
在这里插入图片描述
在这里插入图片描述
该模式的接收流程以及初始化该接收模式
在这里插入图片描述

在这里插入图片描述

知道了这个无线模块的接收和发送操作流程还有接收和发送的模式配置,然后就要关注它的通信方式spi了:发送spi读写指令,并对寄存器读写,(读出寄存器里面的值或者像寄存器里面写入数据)主要学习的是库函数的版本,与之有关的寄存器也要了解一下哈~

四,相关寄存器介绍

这里是重点,找机会补上。

五, spi通信有关的库函数调用

stm32是有硬件spi的,这里连的是a5,6,7三个脚,(虽然一般上认为spi通信是4个脚,但是有一个是片选脚,在spi封装的库函数模块里面,没有加进去)
然后原子例程里是由现成的spi封装好的函数模块的,可以直接加进去用来着。

无线模块有关的库函数调用

NRF24L01初始化函数,因为是原子的代码,MINI板的测试代码,
这里NRF24L01也是使用的SPI1,和W25Q64以及SD卡等共用一个SPI接口,所以在使用的时候,他们分时复用SPI1。所以需要把SD卡和W25Q64的片选信号置高,以防止这两个器件对NRF24L01的通信造成干扰。所以也对没有用到的脚进行了拉高处理,就是代码中的A2,A3脚。所以自己实际在用的过程中可以不去处理这两个脚。emmmm大佬们都是可以自己写的,我只会拉人家的来用~(卑微)

void NRF24L01_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_4);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; //上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4);

SPI1_Init(); //初始化 SPI
SPI_Cmd(SPI1, DISABLE); //
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
//设置 SPI 单向或者双向的数据模式:SPI 设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置为主 SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 8 位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟悬空低电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //数据捕获于第一个时钟沿
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //内部 NSS 信号有 SSI 位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
//定义波特率预分频的值:波特率预分频值为 256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从 MSB 位开始
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC 值计算的多项式
SPI_Init(SPI1, &SPI_InitStructure); //初始化外设 SPIx 寄存器
NRF24L01_CE=0; //使能 24L01
NRF24L01_CSN=1; //SPI 片选取消
}//检测 24L01 是否存在
//返回值:0,成功;1,失败

然后是模式设置,就是上面第三点所说的,如下是接收模式

void NRF24L01_RX_Mode(void)
{
NRF24L01_CE=0;
NRF24L01_Write_Buf(WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);
//写 RX 节点地址
NRF24L01_Write_Reg(WRITE_REG+EN_AA,0x01); //使能通道 0 的自动应答
NRF24L01_Write_Reg(WRITE_REG+EN_RXADDR,0x01);//使能通道 0 的接收地址
NRF24L01_Write_Reg(WRITE_REG+RF_CH,40); //设置 RF 通信频率
NRF24L01_Write_Reg(WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
//选择通道 0 的有效数据宽度
NRF24L01_Write_Reg(WRITE_REG+RF_SETUP,0x0f);
//设置 TX 发射参数,0db 增益,2Mbps,低噪声增益开启
NRF24L01_Write_Reg(WRITE_REG+CONFIG, 0x0f);
//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式
NRF24L01_CE = 1; //CE 为高,进入接收模式
}

还有发送模式

void NRF24L01_TX_Mode(void)
{
NRF24L01_CE=0;
NRF24L01_Write_Buf(WRITE_REG+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);
//写 TX 节点地址
NRF24L01_Write_Buf(WRITE_REG+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);
//设置 TX 节点地址,主要为了使能 ACK
NRF24L01_Write_Reg(WRITE_REG+EN_AA,0x01); //使能通道 0 的自动应答
NRF24L01_Write_Reg(WRITE_REG+EN_RXADDR,0x01); //使能通道 0 的接收地址
NRF24L01_Write_Reg(WRITE_REG+SETUP_RETR,0x1a);
//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10 次
NRF24L01_Write_Reg(WRITE_REG+RF_CH,40); //设置 RF 通道为 40
NRF24L01_Write_Reg(WRITE_REG+RF_SETUP,0x0f);
//设置 TX 发射参数,0db 增益,2Mbps,低噪声增益开启
NRF24L01_Write_Reg(WRITE_REG+CONFIG,0x0e);
//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
NRF24L01_CE=1;//CE 为高,10us 后启动发送
}

模式确定完了就要写具体的收发流程,如果是接受模式,那接收流程如下


u8 NRF24L01_RxPacket(u8 *rxbuf)
{
u8 sta;
SPI2_SetSpeed(SPI_BaudRatePrescaler_8); //spi 速度为 9Mhz
sta=NRF24L01_Read_Reg(STATUS); //读取状态寄存器的值
NRF24L01_Write_Reg(WRITE_REG+STATUS,sta); //清除 TX_DS 或 MAX_RT 中断标志
if(sta&RX_OK)//接收到数据
{
NRF24L01_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除 RX FIFO 寄存器
return 0;
}
return 1;//没收到任何数据
}

若为发送模式,发送流程为

u8 NRF24L01_TxPacket(u8 *txbuf)
{
u8 sta;
SPI2_SetSpeed(SPI_BaudRatePrescaler_8);//spi 速度为 9Mhz
NRF24L01_CE=0;
NRF24L01_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH); //写数据到 TX BUF
NRF24L01_CE=1; //启动发送
while(NRF24L01_IRQ!=0); //等待发送完成
sta=NRF24L01_Read_Reg(STATUS); //读取状态寄存器的值
NRF24L01_Write_Reg(WRITE_REG+STATUS,sta); //清除 TX_DS 或 MAX_RT 中断标志
if(sta&MAX_TX)//达到最大重发次数
{
NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除 TX FIFO 寄存器
return MAX_TX;
}
if(sta&TX_OK) return TX_OK;//发送完成
return 0xff;//其他原因发送失败
}

接收和发送的操作是基于用spi的通信方式对无线模块寄存器的读和写的操作,所以,spi读写寄存器的指令如下

u8 NRF24L01_Write_Reg(u8 reg,u8 value)
{
u8 status;
NRF24L01_CSN=0; //使能 SPI 传输
status =SPI2_ReadWriteByte(reg);//发送寄存器号
SPI2_ReadWriteByte(value); //写入寄存器的值
NRF24L01_CSN=1; //禁止 SPI 传输
return(status); //返回状态值
}

u8 NRF24L01_Read_Reg(u8 reg)
{
u8 reg_val;
NRF24L01_CSN = 0; //使能 SPI 传输
SPI2_ReadWriteByte(reg); //发送寄存器号
reg_val=SPI2_ReadWriteByte(0XFF);//读取寄存器内容
NRF24L01_CSN = 1; //禁止 SPI 传输
return(reg_val); //返回状态值
}

指令发送了,就是说好啦,寄存器,我要开始对你进行读写数据了,然后就是对寄存器里面的数据进行读写

读寄存器的值

u8 NRF24L01_Read_Buf(u8 reg,u8 *pBuf,u8 len)
{
u8 status,u8_ctr;
NRF24L01_CSN = 0; //使能 SPI 传输
status=SPI2_ReadWriteByte(reg);//发送寄存器值(位置),并读取状态值
for(u8_ctr=0;u8_ctr<len;u8_ctr++)pBuf[u8_ctr]=SPI2_ReadWriteByte(0XFF);
NRF24L01_CSN=1; //关闭 SPI 传输
return status; //返回读到的状态值
}

像寄存器写入数据

u8 NRF24L01_Write_Buf(u8 reg, u8 *pBuf, u8 len)
{
u8 status,u8_ctr;
NRF24L01_CSN = 0; //使能 SPI 传输
status = SPI2_ReadWriteByte(reg);//发送寄存器值(位置),并读取状态值
for(u8_ctr=0; u8_ctr<len; u8_ctr++)SPI2_ReadWriteByte(*pBuf++); //写入数据
NRF24L01_CSN = 1; //关闭 SPI 传输
return status; //返回读到的状态值
}

这就是关于无线模块24L01的数据传输的函数部分了,最后我们还要写一个自检函数,这个是为了检测能不能检测到有24l01的存在

u8 NRF24L01_Check(void)
{
u8 buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5}; u8 i;
SPI2_SetSpeed(SPI_BaudRatePrescaler_8); //spi 速度为 9Mhz
NRF24L01_Write_Buf(WRITE_REG+TX_ADDR,buf,5);//写入 5 个字节的地址.
NRF24L01_Read_Buf(TX_ADDR,buf,5); //读出写入的地址
for(i=0;i<5;i++)if(buf[i]!=0XA5)break;
if(i!=5)return 1;//检测 24L01 错误
return 0; //检测到 24L01
}

好啦,然后就可以写一个主函数来检测是否能够通信啦~~~~

2016-08-31 22:36:05 wgp2hpp 阅读数 3
  • 单片机控制第一个外设-LED灯-第1季第6部分

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

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

近日玩了下microchip的无线wifi模块,配置相当简单,可以与单片机进行串口连接,今天分享给大家 如何快速配置这款模块,使其可以连入家庭Wifi

0?wx_fmt=jpeg

0?wx_fmt=jpeg

拿到任何一个模块首先恢复工厂设置,配置到自己的网络,才能连接使用,首先我们需要安装一个终端Tera Term,配置为串口模式,安装 Tera Term终端,可以选择不同的语言,我们选择简体中文;将电脑与microchip  Wifi 模块连接,安装USB转串口驱动,自动安装成功后,板载的LED灯会闪烁。

打开终端配置为串口模式,并配置波特率,串口号,数据位,停止位等参数如下显示

0?wx_fmt=jpeg

按模块上的RESET 按键将模块复位重启,在终端 Tera Term上会显示,进入命令模式,输入$$$,则终端回送CMD,证明进入命令模式,输入命令 factory RESET 将模块恢复工厂设置,然后reboot重启模块

0?wx_fmt=jpeg

扫描网络,通过命令scan可以扫描到wifi网络有连个,如上图所示,其中第一个是我的wifi,为了将microchip的无线模块连接如家庭wifi,需要进行配置,使用命令如下图所示:需配置Wifi名称,密码,自动连接,保存,然后reboot

0?wx_fmt=jpeg

0?wx_fmt=jpeg

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